Skip to content

Commit 266c69a

Browse files
committed
feat(otel): W3C traceparent transport-header propagation — Node core (ADR-0028)
Adds a HeaderCarrier seam (Record<string,string>, additive — the envelope stays frozen, GR-1) and W3C traceparent inject/extract in otel.ts: the producer writes the active span's traceparent onto an out-of-band header carrier; the consumer starts its span as a child of that remote parent (true cross-hop linkage). No header falls back to the v0.1 trace_id behaviour (no regression). traceparent parse/format is hand-rolled — core stays dependency-free (GR-7). Per-adapter wiring (babelqueue-node-adapters: bullmq/redis/rabbitmq/sqs) is a documented follow-up.
1 parent 11fbb7d commit 266c69a

5 files changed

Lines changed: 442 additions & 25 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,27 @@ The envelope wire format is versioned separately by `meta.schema_version`
99

1010
## [Unreleased]
1111

12+
### Added
13+
- **OpenTelemetry v0.2 — W3C `traceparent` cross-hop span linkage (ADR-0028).** The
14+
`@babelqueue/core/otel` module now propagates the active span as a W3C `traceparent`
15+
(and `tracestate`) **transport header** so a consumer span is a true **child** of the
16+
producer span — not just a shared `trace_id` trace.
17+
- New `HeaderCarrier` type (a `Record<string, string>` out-of-band header map) — the
18+
seam the core and the `babelqueue-node-adapters` transports agree on. It rides
19+
**beside** the frozen envelope, never inside it (`schema_version` stays **1**, GR-1).
20+
- `publish(...)` takes an optional `options.headers` carrier and writes the producer
21+
span's `traceparent` into it; `wrapHandler(tracer, handler, headers?)` reads a
22+
delivered message's headers (a carrier or a sync/async getter) and starts the consumer
23+
span as a remote-parent child. **No header ⇒ v0.1 `trace_id` fallback** (no regression);
24+
fully opt-in and backward compatible.
25+
- New low-level exports `injectTraceparent`, `remoteParentFromHeaders`,
26+
`HEADER_TRACEPARENT`, `HEADER_TRACESTATE`. The W3C parse/format is implemented against
27+
the frozen Trace Context format, so the optional dependency stays at `@opentelemetry/api`
28+
only — the core itself remains zero-runtime-dependency (GR-7).
29+
- **Per-adapter transport wiring** (bullmq/redis/rabbitmq/sqs in the separate
30+
`babelqueue-node-adapters` repo) is a documented follow-up; until wired, propagation
31+
degrades to v0.1 `trace_id` correlation with no error.
32+
1233
## [1.0.0] - 2026-06-07
1334

1435
**1.0.0 — the public API is now SemVer-stable**: breaking changes require a MAJOR,

‎src/contracts.ts‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,23 @@ export interface HasTraceId {
1818
/** The trace id to reuse, or null/undefined to mint a new one. */
1919
getBabelTraceId(): string | null | undefined;
2020
}
21+
22+
/**
23+
* Out-of-band per-message transport metadata that rides **beside** the frozen wire
24+
* envelope, never inside it (GR-1: the envelope stays `schema_version: 1`). It is a
25+
* plain string→string map — the seam the core and the `babelqueue-node-adapters`
26+
* transports (bullmq/redis/rabbitmq/sqs) agree on for metadata that must not become an
27+
* envelope field.
28+
*
29+
* The first rider is the W3C `traceparent` (and `tracestate`) header for true cross-hop
30+
* span parent-child linkage (ADR-0028) — see `@babelqueue/core/otel`. It is the Node
31+
* counterpart of the Go `HeaderPublisher.PublishWithHeaders` / `ReceivedMessage.Headers`
32+
* seam and the same shape used by the replay-bypass marker (ADR-0027).
33+
*
34+
* An adapter carries it on its transport's native per-message metadata channel (e.g.
35+
* AMQP message headers, SQS `MessageAttributes`, a Redis transport-owned frame), merging
36+
* it beside the contract `bq-*`/`x-*` headers without clobbering them. A transport that
37+
* has no such channel simply does not carry it, and propagation degrades to the v0.1
38+
* `trace_id` correlation with no error — exactly as the Go side degrades.
39+
*/
40+
export type HeaderCarrier = Record<string, string>;

‎src/index.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export type {
2323
Meta,
2424
} from "./codec.js";
2525

26-
export type { HasTraceId, PolyglotMessage } from "./contracts.js";
26+
export type { HasTraceId, HeaderCarrier, PolyglotMessage } from "./contracts.js";
2727

2828
export { annotate } from "./deadLetter.js";
2929
export type { AnnotateOptions } from "./deadLetter.js";

0 commit comments

Comments
 (0)