ENG-9166: Suggestions for otel 1/3
Merged
MA
2mo ago+916+916+012345678901234567890123456789-156-156-012345678901234567890123456789
Review follow-ups for #6899 (built-in trace points in reflex-base and the reflex-otel instrumentor), one finding per commit so each patch can be reviewed on its own. The findings come from a production-readiness pass over the stack: demo apps against OTLP/HTTP, OTLP/gRPC and console exporters, hostile event payloads, uploads, chained and background events, and the zero-code opentelemetry-instrument path.
What changes
Security and privacy
- The client token no longer leaves the process.
session.idis a truncated SHA-256 of the token, andtoken=is redacted fromhttp.url/url.full/url.queryon ASGI spans. - Only the W3C
traceparent/tracestatestrings are read from an event payload, through a dedicated propagator. Baggage or malformed fields sent by a client are ignored and never raise.
Span correctness
- Events from the browser are CONSUMER spans, paired with the browser's PRODUCER span; chained events are INTERNAL children.
reflex.event.parent_txidis set only on chained events, andcode.function.nameis fully qualified.- Stream-delta handlers nest under the caller's span, and the events returned by the backend exception handler parent under the failed event's span.
- Socket message sizes are measured without encoding a copy.
Configuration and defaults
- The ASGI middleware uses the stable HTTP semantic conventions.
OTEL_SEMCONV_STABILITY_OPT_IN=httpis set at import time unless already set, before any contrib instrumentor reads it. - The mounted frontend's asset prefix is excluded from ASGI spans by default, an empty excluded-URLs variable is honoured, and so is
OTEL_SDK_DISABLED=true. ReflexInstrumentor().instrument()is self-sufficient: it is a no-op when already instrumented, so the app module needs nois_instrumented_by_opentelemetryguard, and it configures the SDK fromOTEL_TRACES_EXPORTER/OTEL_METRICS_EXPORTERwhen no provider has been set.
Packaging
opentelemetry-apiis a dependency ofreflex-otelonly. reflex-base imports nothing from opentelemetry untilenable()runs, andenable()binds the API modules, tracer and propagator once, so no trace point carries an import statement or anassert.- The reflex-base floor is
>= 0.9.10.post3.dev0, the smallest dev version above the newest published release. The release tooling lifts it onto the next reflex-base release automatically. The runtime dependency re-check (instrumentation_dependencies()and theinstrumentsextra) is gone: reflex-base is a hard dependency and the resolver enforces the floor. py.typed,__all__,reflex_otelregistered as a logging package, README rewritten around the fixed behaviour.
Review notes
http.targetneeds no redaction: at the floor (0.49b0) and current ASGI instrumentation it holds the bare path; the query string only reacheshttp.urlandurl.query, which are redacted.OTEL_SDK_DISABLEDis read once atinstrument()time, as the SDK's own providers read it once at construction. Toggling it in a running process is not a supported flow;uninstrument()theninstrument()resets.
Follow-up work (out of scope here)
reflex.websocket.connectionsis an up/down counter and drifts if instrumentation is toggled while sockets are open (connections opened beforeinstrument()are counted down but never up). An observable gauge over the live session map cannot drift.- Handler exception messages and stack traces are exported verbatim, which is standard OpenTelemetry behaviour. A
record_exceptionswitch oninstrument()would let deployments opt out; the docs already say what leaves the process. - The reflex-base floor has to chase the 0.9.10 hotfix line (
post1,post2so far) until reflex-base ships a release from main, because the workspace versions itself as0.9.10.post<distance>.dev0and cannot express "the next minor". The min-deps job fails loudly if a published release ever satisfies the floor.
Type of change
- Bug fix (non-breaking change which fixes an issue)
- This change requires a documentation update (the
reflex-otelREADME is updated here; the docs page is updated in #7070)
Changes To Core Features:
- Have you added an explanation of what your changes do and why you'd like us to include them? (each commit message carries its rationale)
- Have you written new tests for your core changes, as applicable?
- Have you successfully ran tests with your changes locally? (full unit suite,
check_min_deps.pyfor reflex-base and reflex-otel)
🤖 Generated with Claude Code