13a12e6591
Phase 2 of ADR-0012 — closes the loop SPA → BFF → DB. With this PR a single user action (page load, click, form submit) produces one trace whose root span is owned by the SPA and whose child spans cover the BFF request, Postgres queries, and (eventually) Redis / downstream-API hops. Runtime libs added (production deps): - @opentelemetry/sdk-trace-web browser tracer + provider - @opentelemetry/exporter-trace-otlp-http OTLP/HTTP+JSON exporter - @opentelemetry/instrumentation auto-instrumentation runtime - @opentelemetry/instrumentation-fetch fetch + W3C traceparent propagation - @opentelemetry/instrumentation-document-load initial-paint timings - @opentelemetry/instrumentation-user-interaction click / keypress / submit Code: - apps/portal-shell/src/observability/tracing.ts — WebTracerProvider bootstrap. Documents the load-order constraint inline (must be the very first import of main.ts, same pattern as the BFF). No context-zone package because the workspace is zoneless (per ADR-0004); the default StackContextManager covers the auto-instrumentation cases. - main.ts now imports the tracing module as line 1. CORS plumbing for end-to-end propagation: - BFF (apps/portal-bff/src/main.ts) calls enableCors with a minimal dev allowlist (http://localhost:4200) and explicit permission for the W3C traceparent and tracestate headers. The full security-grade CORS belongs to phase-2 security ADR; this is the strict minimum for the SPA→BFF link to keep the trace context across origins. - OTel Collector (infra/local/otel-collector.yaml) gains a cors block on its OTLP/HTTP receiver so the browser's OTLP POST clears its own pre-flight. ADR-0012 §Confirmation: a new "Wired in the SPA foundation PR (phase 2)" block enumerates what landed here; the carry-over "Wired as features land" list is updated to drop the SPA-side SDK item that used to live there and to add a CORS-grade follow-up note. Verified locally: - pnpm exec nx run-many -t lint test build → 8 projects green. - pnpm audit clean. - After ./infra/local/dev.sh up observability and nx serve portal-shell, opening http://localhost:4200 produces a document_load trace in Jaeger with the SPA service.name; a manual fetch from DevTools to /api/health on the BFF produces a child span on the same trace.
78 lines
2.3 KiB
YAML
78 lines
2.3 KiB
YAML
# OpenTelemetry Collector config for the local-dev stack.
|
|
#
|
|
# v1 scope (per ADR-0012):
|
|
# - Accept OTLP from the BFF and the SPA on gRPC (4317) and HTTP
|
|
# (4318). The default OTEL_EXPORTER_OTLP_ENDPOINT in dev points
|
|
# here.
|
|
# - Batch + log everything to stdout via the `debug` exporter — the
|
|
# dev sees what their app emits without standing up a backend.
|
|
# - When the `observability` Compose profile is active, additionally
|
|
# forward to Jaeger (`jaeger:4317` on the internal Compose
|
|
# network). When the profile is inactive, the OTLP→Jaeger export
|
|
# fails at warn level but does not impact the debug pipeline.
|
|
#
|
|
# Production replaces the debug exporter with the proper backend
|
|
# (chosen in the future on-prem infrastructure ADR — likely Tempo +
|
|
# Loki + Mimir, or an OpenTelemetry-friendly all-in-one).
|
|
|
|
receivers:
|
|
otlp:
|
|
protocols:
|
|
grpc:
|
|
endpoint: 0.0.0.0:4317
|
|
http:
|
|
endpoint: 0.0.0.0:4318
|
|
# CORS for the SPA-side OTLP/HTTP exporter (per ADR-0012,
|
|
# phase 2). The browser's pre-flight needs both the origin
|
|
# and the W3C trace headers in the allow-list — without it,
|
|
# the OTLP POST is blocked client-side and SPA spans never
|
|
# reach the Collector.
|
|
cors:
|
|
allowed_origins:
|
|
- http://localhost:4200
|
|
allowed_headers:
|
|
- content-type
|
|
- traceparent
|
|
- tracestate
|
|
|
|
processors:
|
|
batch:
|
|
# Small batches in dev so the developer sees output quickly.
|
|
timeout: 5s
|
|
send_batch_size: 100
|
|
|
|
exporters:
|
|
debug:
|
|
verbosity: detailed
|
|
otlp/jaeger:
|
|
endpoint: jaeger:4317
|
|
tls:
|
|
insecure: true
|
|
sending_queue:
|
|
enabled: true
|
|
# When jaeger isn't running (profile off), retries fall back
|
|
# to a small queue rather than blocking the pipeline.
|
|
queue_size: 100
|
|
retry_on_failure:
|
|
enabled: true
|
|
initial_interval: 5s
|
|
max_interval: 30s
|
|
|
|
service:
|
|
pipelines:
|
|
traces:
|
|
receivers: [otlp]
|
|
processors: [batch]
|
|
exporters: [debug, otlp/jaeger]
|
|
logs:
|
|
receivers: [otlp]
|
|
processors: [batch]
|
|
exporters: [debug]
|
|
metrics:
|
|
receivers: [otlp]
|
|
processors: [batch]
|
|
exporters: [debug]
|
|
telemetry:
|
|
logs:
|
|
level: info
|