feat(api): add OpenTelemetry tracing (HTTP + DB spans)#18
Merged
Conversation
Add opt-in OpenTelemetry distributed tracing. When --tracing-enabled, the server exports spans over OTLP/HTTP — configured entirely through the standard OTEL_* environment variables, with no bespoke endpoint/sampler flags — covering inbound HTTP requests (otelhttp server spans, named by operation, infra routes excluded) and PostgreSQL queries (otelpgx), with W3C trace-context propagation and a flush on graceful shutdown. Tracing defaults off because it needs an external collector, unlike the self-contained authz and rate-limit tiers. The bootstrap lives in internal/observability; service.name/version default to the app name and build version and are overridable via OTEL_SERVICE_NAME / OTEL_RESOURCE_ATTRIBUTES. The infrastructure routes (/healthz, /readyz, /metrics) are filtered out so health checks and scrapes are not traced. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds opt-in OpenTelemetry distributed tracing. When
--tracing-enabled, the server exports spans over OTLP/HTTP, configured entirely through the standardOTEL_*environment variables (no bespoke endpoint/sampler flags). It covers inbound HTTP requests and PostgreSQL queries, with W3C trace-context propagation and a flush on graceful shutdown.Design (decisions confirmed with the maintainer)
OTEL_*env + a single--tracing-enabledmaster switch.otlptracehttp.NewreadsOTEL_EXPORTER_OTLP_ENDPOINT,OTEL_TRACES_SAMPLER, etc. natively, so deployments tune tracing the OpenTelemetry way.service.name/service.versiondefault to the app name and build version, overridable viaOTEL_SERVICE_NAME/OTEL_RESOURCE_ATTRIBUTES.otelhttp(edge handler, W3C propagation, named by operation for low cardinality, infra routes filtered out) and PostgreSQL query spans viaotelpgxon the pool — a trace shows the SQL under the request that issued it.Layering
internal/observability/tracing.go:NewTracerProvider(ctx, cfg)(OTLP exporter + resource + batching provider + global registration + W3C propagator; returns a flush-on-shutdown func, or nil when disabled), andTraceSpanNamer— a router-agnostic Huma middleware that renames the active server span to the operation ID.internal/adapter/http:RouterDeps.Tracingwraps the mux withotelhttp.NewHandler(filtering/healthz,/readyz,/metrics) and installs the span namer before registration.internal/adapter/postgres:Config.Tracinginstalls theotelpgxquery tracer (gated, zero-overhead when off).internal/app: builds the provider, wiresTracingthrough the router and the pool, and flushes the provider on shutdown (mirrorsclosePool/stopRateLimiter) on a fresh grace-bounded context.internal/config:--tracing-enabled(default false).When disabled, nothing is installed (the global no-op provider stays), the handler is unwrapped, and the pgx tracer is absent — zero overhead.
Testing
NewTracerProviderenabled/disabled (globals saved/restored);TraceSpanNamerrenames the active span to the operation ID (humatest + an in-memorytracetestexporter);traceableRequestexcludes infra routes;NewRouter{Tracing:true}still serves requests.moon run root:checkgreen (incl.openapi-check— tracing is middleware/transport-level, so the spec is unchanged);moon run root:test-integrationgreen againstpostgres:17-alpine(default tracing-off path, no regression).🤖 Generated with Claude Code