feat(observability): OpenTelemetry tracing — manual spans + opt-in NodeSDK#197
Merged
feat(observability): OpenTelemetry tracing — manual spans + opt-in NodeSDK#197
Conversation
…t-in NodeSDK
Wires `@opentelemetry/api` through the runtime so every request gets a
SERVER span, with an opt-in NodeSDK + OTLP HTTP exporter for
deployments that have an OTel collector.
Two layers:
1. Manual server spans (always on). New `requestTracing` middleware
in `lib/tracing.ts` extracts the inbound W3C trace context off
the request headers, opens a SERVER span parented under it, and
records:
- http.request.method / url.path / http.route
- http.response.status_code
- wb.request_id (mirrored from the existing `requestId`
middleware so logs and spans correlate)
- exception event + ERROR status when Hono's onError fires
Without an SDK registered the spans are no-ops, so the wiring is
essentially free.
2. NodeSDK + auto-instrumentation (opt-in). New
`runtime.tracing.{enabled,serviceName,exporterUrl}` config block;
when `enabled: true`, `initOtelFromConfig` lazy-imports the SDK,
OTLP HTTP exporter, and the standard auto-instrumentations bundle.
Standard `OTEL_*` env vars are honored verbatim (sampler,
headers, endpoint).
For full HTTP / fetch / pino auto-instrumentation, operators preload
the SDK at process launch via the new `lib/tracing-preload.ts` module:
node --import ./dist/lib/tracing-preload.js dist/root.js
`root.ts` calls `otel.shutdown()` during the existing graceful drain
so in-flight spans flush before exit.
Tests (`tests/lib/tracing.test.ts`):
- SERVER span emitted with method + route + status attributes
- 5xx error path records exception + sets ERROR status
- Inbound traceparent links the new span to the caller's trace
Docs: `docs/production.md` gains a tracing section covering both
in-config activation and the `--import` preload path.
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
Third in the post-architecture-review stack (#195 supply-chain, #196 CSRF). Wires `@opentelemetry/api` through the runtime so every request gets a SERVER span, with an opt-in NodeSDK + OTLP HTTP exporter for deployments that have a collector.
Two layers:
Manual server spans (always on). New `requestTracing` middleware in `lib/tracing.ts` extracts the inbound W3C trace context, opens a SERVER span parented under it, and records:
Without an SDK registered the spans are no-ops, so the wiring is essentially free.
NodeSDK + auto-instrumentation (opt-in). New `runtime.tracing.{enabled,serviceName,exporterUrl}` config block; when `enabled: true`, `initOtelFromConfig` lazy-imports the SDK, OTLP HTTP exporter, and standard auto-instrumentations. `OTEL_*` env vars (sampler, headers, endpoint) are honored verbatim.
For full HTTP / fetch / pino auto-instrumentation, operators preload the SDK at process launch via the new `lib/tracing-preload.ts` module:
```sh
node --import ./dist/lib/tracing-preload.js dist/root.js
```
`root.ts` calls `otel.shutdown()` during the existing graceful drain so in-flight spans flush before exit.
Test plan
Migration / compat