feat(backend): OpenTelemetry instrumentation with trace IDs in logs - #162
Conversation
Closes the D11 debt for the backend (ADR-0010): TracerProvider with no span processor -- spans are real and carry real trace IDs but nothing is exported until Tempo lands. FastAPI extracts W3C traceparent from HTTP headers; the gRPC server gets the aio_server_interceptor added explicitly to its interceptor list (the GrpcAioInstrumentorServer monkeypatch depends on import order and was rejected). Every log line now carries trace_id via a logging filter attached to the root handlers; the canary's journey trace IDs appear verbatim on backend log lines for the same requests, so log-trace correlation works in Loki today. Health and metrics endpoints are excluded from span creation with end-anchored patterns -- a bare /metrics exclusion would also swallow the real POST /metrics/frontend web-vitals route (regression-tested). Log format stays plain text; the JSON conversion is separate D6 debt, noted in the README.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
WalkthroughAdds OpenTelemetry tracing to the backend’s FastAPI and gRPC servers, propagates trace context, correlates logs with trace IDs, excludes selected endpoints, and adds documentation and tests for the new behaviour. ChangesOpenTelemetry tracing
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Sequence Diagram(s)sequenceDiagram
participant HTTPClient
participant FastAPIApp
participant OpenTelemetry
participant Logger
HTTPClient->>FastAPIApp: HTTP request with traceparent
FastAPIApp->>OpenTelemetry: Create or propagate server span
OpenTelemetry->>Logger: Inject active trace_id
Logger-->>FastAPIApp: Emit trace-correlated log
sequenceDiagram
participant GRPCClient
participant GRPCServer
participant OTELInterceptor
participant SpanExporter
GRPCClient->>GRPCServer: RPC with traceparent metadata
GRPCServer->>OTELInterceptor: Extract W3C trace context
OTELInterceptor->>SpanExporter: Record server span
SpanExporter-->>GRPCServer: No production export configured
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The phase tags were never pushed. origin carries only v1.1.0-v1.5.0, so `git diff phase-2..phase-3` fails for everyone who clones this repo -- the course promised a history workflow no reader could run, in eleven places. Pushing them was the alternative, and it is worse. Every tag predates the loopback port binding and the dashboard uid fix: all eight publish ports on every interface (8 mappings at phase-0, rising to 18 at rfc-0002) and none pins a dashboard uid. Publishing eight trees that put Postgres on the wire, to an audience that will check them out and run them, is not worth a diff convenience. Better to not ship the footgun than to document it. The construction history is unaffected: every phase is a run of PRs on main, RFC-0001 Section 9 lists what each delivered, and the ADRs froze the decisions. The Tag column, the checkout instruction, the read-only-checkpoint paragraph, and the two "the rfc-000N tag will mark it" promises are gone. Tags deleted locally, recreatable from these commits if ever wanted: phase-0 8775267 Phase 0: repo restructure, CI, baseline hardening (#143) phase-1 99d458a Phase 1: three-layer monitoring, canary v1 (#159) phase-2 23170c3 Phase 2: contract-first gRPC + OpenTelemetry (#162) phase-3 a8ccbc0 Phase 3: Go analytics, pipeline-lag canary v2 (#167) phase-4 ec4810b Phase 4: load profile, Alertmanager, e2e gate (#172) phase-5 9cb1b1f Phase 5: historical seeder, workshop mode (#175) phase-6 393989a Phase 6: Kotlin reports, report load, canary v3 (#180) rfc-0002 e4bbafc RFC-0002: reports-ui Caddy static SPA (#182) All eight are ancestors of main, so the commits stay reachable regardless.
Closes the D11 debt for the backend (ADR-0010): TracerProvider with no span processor -- spans are real and carry real trace IDs but nothing is exported until Tempo lands. FastAPI extracts W3C traceparent from HTTP headers; the gRPC server gets the aio_server_interceptor added explicitly to its interceptor list (the GrpcAioInstrumentorServer monkeypatch depends on import order and was rejected). Every log line now carries trace_id via a logging filter attached to the root handlers; the canary's journey trace IDs appear verbatim on backend log lines for the same requests, so log-trace correlation works in Loki today.
Health and metrics endpoints are excluded from span creation with end-anchored patterns -- a bare /metrics exclusion would also swallow the real POST /metrics/frontend web-vitals route (regression-tested). Log format stays plain text; the JSON conversion is separate D6 debt, noted in the README.
Summary by CodeRabbit