ENG-9166 feat(otel): built-in OpenTelemetry trace points, metrics and the reflex-otel instrumentor (1/3) - #6899
ENG-9166 feat(otel): built-in OpenTelemetry trace points, metrics and the reflex-otel instrumentor (1/3)#6899FarhanAliRaza wants to merge 8 commits into
Conversation
…emetry-api >=1.30)
…rt, /ping excluded, shared test fixtures
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b2435892c4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Greptile SummaryThe PR adds built-in OpenTelemetry event tracing and runtime metrics, plus a separately installable instrumentor that activates the trace points and wraps the generated ASGI application.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| packages/reflex-base/src/reflex_base/otel.py | Defines the opt-in tracing and metric instruments, context propagation, ASGI middleware factory, and enable/disable lifecycle. |
| packages/reflex-otel/src/reflex_otel/init.py | Implements the OpenTelemetry instrumentor and configures the ASGI middleware and framework-native instruments. |
| reflex/app.py | Installs the configured ASGI wrapper and records Socket.IO message sizes and connection counts. |
| packages/reflex-base/src/reflex_base/event/processor/event_processor.py | Wraps enabled event-handler execution in OpenTelemetry spans while retaining the disabled fast path. |
| packages/reflex-base/src/reflex_base/event/processor/base_state_processor.py | Records state-acquisition duration and restores captured context for exception-handler event chains. |
| packages/reflex-base/src/reflex_base/event/context.py | Captures the active OpenTelemetry context when forking chained event contexts. |
| packages/reflex-otel/README.md | Documents setup, emitted telemetry, configuration options, and the supported instrumentation lifecycle. |
| .github/workflows/dispatch_release.yml | Adds reflex-otel as a selectable package in manually dispatched releases. |
| .github/workflows/publish.yml | Adds reflex-otel to the shared package publishing workflow. |
Reviews (5): Last reviewed commit: "fix(otel): parse excluded_urls for the A..." | Re-trigger Greptile
b243589 to
54ec281
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
There was a problem hiding this comment.
Review completed against the latest diff
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
1 issue found across 7 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="tests/units/reflex_otel/test_init.py">
<violation number="1" location="tests/units/reflex_otel/test_init.py:61">
P3: The first parametrize case `(None, True)` is non-deterministic: when `excluded_urls` is omitted, `ReflexInstrumentor._instrument` falls back to `os.environ.get("OTEL_PYTHON_REFLEX_EXCLUDED_URLS") or os.environ.get("OTEL_PYTHON_EXCLUDED_URLS") or "/ping"`. If either env var is set in the user's or CI environment, `/ping` will not be the effective excluded URL and the assertion `url_disabled("/ping") is True` fails. Clear or monkeypatch both env vars (e.g. `monkeypatch.delenv(..., raising=False)`) around the `instrument()` call to make the test hermetic.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Alek99
left a comment
There was a problem hiding this comment.
Local end-to-end OTel review: browser/backend propagation works on the current lockfile, but these package/runtime issues remain.
…ion inside the span opentelemetry-instrumentation-asgi < 0.56b0 stores excluded_urls verbatim and calls .url_disabled() on it, so the default "/ping" string made every request raise AttributeError. Parse with parse_excluded_urls first. Move the event-duration histogram record inside the event span so exporter latency is excluded from the sample and exemplars keep the trace/span IDs.
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.packages/reflex-otel(reflex_otel.ReflexInstrumentor, aBaseInstrumentorwith the standardopentelemetry_instrumentorentry point) flips the flag.When enabled:
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./pingexcluded, per-message websocket spans off).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-apino-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).publish.yml,dispatch_release.yml,detect.sh.Tests
tests/units/reflex_base/test_otel.py,tests/units/reflex_otel/, otel cases intest_app.py,test_event_processor.py,test_base_state_processor.py; sharedotel_sdkfixture intests/units/conftest.py.