ENG-9166 feat(otel): built-in OpenTelemetry trace points, metrics and the reflex-otel instrumentor (1/3)
Merged
FA
1mo ago+2034+2034+0123456789012345678901234567890123456789-9-9-0123456789
Part of #6227 (ENG-9166). Stack: 1/3 (this) โ 2/3 compile spans + log correlation โ 3/3 browser plugin.
What
Makes the framework instrumentation-aware but zero-cost without the instrumentation package:
reflex-basegets a hard dependency onopentelemetry-api(>=1.30). All trace points live inreflex_base/otel.pybehind a module-levelenabledbool โ one attribute read per event when off, no OTel objects created.- New package
packages/reflex-otel(reflex_otel.ReflexInstrumentor, aBaseInstrumentorwith the standardopentelemetry_instrumentorentry point) flips the flag.
When enabled:
- One span per event handler run:
SERVERfor events from the frontend (new trace, or child of the browser span if the event carries atraceparentfield),INTERNALfor chained events, parented under the span that enqueued them via a context snapshot inEventContext.fork(). Attributes:reflex.event.name/txid/parent_txid/background,session.id,code.function.name; exceptions recorded on the span. Events are never parented under the websocket span. - The ASGI app is wrapped in the contrib ASGI middleware (
/pingexcluded, per-message websocket spans off). - Metrics:
reflex.event.duration(+error.type),reflex.state.acquire.duration,reflex.websocket.message.size,reflex.websocket.connections.
Design
Follows the pattern used by Shiny for Python and pydantic-ai (first-party trace points + opentelemetry-api no-op) rather than wrapt monkeypatching. Survey of other frameworks and the measured no-op costs are in the ticket.
Notes
reflex-otelpinsreflex-base >= <workspace dev version>like the other workspace packages; re-pin at the next release (check_min_deps --check-dev-pinsis the publish gate).- Registered in
publish.yml,dispatch_release.yml,detect.sh. - Verified end to end with Jaeger (traces) and Prometheus (metrics) on a demo app.
Tests
tests/units/reflex_base/test_otel.py, tests/units/reflex_otel/, otel cases in test_app.py, test_event_processor.py, test_base_state_processor.py; shared otel_sdk fixture in tests/units/conftest.py.