open-telemetry / open-telemetry/opentelemetry-python-contrib
Quart apps are not autoinstrumented
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.1k
- Forks
- 1.1k
- Avg merge
- 4d 15h
- Merged PRs (30d)
- 16
Description
Describe your environment
OS: macOS
Python version: Python 3.12.13
Package version: opentelemetry-distro 0.65b0, opentelemetry-instrumentation-flask 0.65b0
Other: quart 0.22.0, flask 3.1.3
What happened?
A Quart app running under opentelemetry-instrument produces no server spans. The equivalent flask app does.
Steps to Reproduce
Sample self-contained test:
❯ uv run --with quart==0.22.0 \
--with opentelemetry-distro==0.65b0 \
--with opentelemetry-instrumentation-flask==0.65b0 \
--with opentelemetry-instrumentation-asgi==0.65b0 \
--with pytest \
pytest test_repro.py
# test_quart.py
import asyncio
from opentelemetry import trace
from opentelemetry.instrumentation.auto_instrumentation._load import _load_instrumentors
from opentelemetry.instrumentation.distro import DefaultDistro
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
def test_quart_request_produces_a_server_span():
exporter = InMemorySpanExporter()
provider = TracerProvider()
provider.add_span_processor(SimpleSpanProcessor(exporter))
trace.set_tracer_provider(provider)
# Equivalent to a `opentelemetry-instrument` run
_load_instrumentors(DefaultDistro())
# Only import quart after instrumenting
from quart import Quart
app = Quart(__name__)
@app.get("/")
async def index() -> str:
return "ok"
response = asyncio.run(app.test_client().get("/"))
assert response.status_code == 200
spans = exporter.get_finished_spans()
server = [s for s in spans if s.kind is trace.SpanKind.SERVER]
# This assert fails
assert len(server) == 1
Expected Result
Expect to see server spans with the method, route, etc.
Actual Result
No server spans are emitted for Quart
Additional context
Most of the work can be done by the asgi instrumentation, with some additional logic for wiring up the http.route specifically.
Is there any preference to moving some logic down to asgi vs. having all the wiring done in a quart instrumentation?
Would you like to implement a fix?
Yes
Tip
React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Run the supplied Quart reproduction and start with _load_instrumentors(DefaultDistro()) and the existing ASGI instrumentation entry point. Compare the Quart and Flask loading paths, focusing on how the HTTP route is wired. Done means the reproduction emits one SERVER span for the Quart request with method and route information, while the existing instrumentation tests continue to pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend, observability
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 70/100