Class Tracing
babelqueue-go/otel, Python babelqueue.otel and Node @babelqueue/core/otel
helpers.
Cross-hop trace propagation works at two layered levels:
trace_id↔ OTel trace id (ADR-0025, v0.1): the envelope'strace_id— a UUID — maps 1:1 to a 32-hex OpenTelemetry trace id (traceIdOf(java.lang.String)/uuidOf(java.lang.String); a non-UUIDtrace_idis hashed deterministically, SHA-256). Every hop that shares atrace_idshares one OTel trace — correlation and per-hop timing with zero wire/transport change.- W3C
traceparenttransport header (ADR-0028, v0.2): the producer also injects the active span context as atraceparent(andtracestate) onto an out-of-band header map that rides beside the frozen envelope, never inside it (GR-1). The consumer reads it and starts its span as a true child of the producer span — real cross-hop parent→child linkage and per-hop span timing, not just a shared trace. With notraceparentpresent it falls back to the v0.1trace_idbehaviour, so enabling propagation is a strict, backward-compatible upgrade — never a regression.
- Consumer:
wrapHandler(Tracer, Handler)emits aCONSUMERspanprocess <urn>parented on thetrace_id-derived trace (v0.1). Theheaders overloadadditionally reads the delivered message's out-of-band headers and, when they carry a validtraceparent, parents the span as a true child of the producer span (v0.2). It reuses the sharedHandler, so it composes withIdempotent.wrap/SchemaValidation.wrap. - Producer:
publish(Tracer, String, Map, String, Sender)emits aPRODUCERspanpublish <urn>that carries the active trace's id into the message'strace_id(v0.1), then writes it via aSender. TheHeaderSender overloadadditionally injects the active span'straceparentonto an out-of-band header map handed to the transport (v0.2).
The wire envelope is untouched (GR-1) and the core never imports OpenTelemetry on a
non-opt-in path: io.opentelemetry:opentelemetry-api (which itself ships OTel's W3C
propagator) is an optional dependency, so the core stays zero-dependency for users who do
not opt in (GR-7).
Transport wiring is a documented follow-up. The Java transports live in separate
artifacts (babelqueue-java-sqs, babelqueue-java-redis, babelqueue-spring).
This core delivers the v0.2 mechanism — the out-of-band header seam (HeaderSender
produce-side, a delivered-headers Supplier consume-side) plus the traceparent
inject/extract. Carrying the header map on each transport's native per-message metadata channel
(AMQP headers, SQS MessageAttributes, a Redis transport-owned frame), beside the contract
bq-*/x-* headers, is the per-transport rollout — the same seam ADR-0027 and the
broker bindings roll out per SDK. Until a transport wires it, propagation degrades to the v0.1
trace_id correlation with no error.
-
Method Summary
Modifier and TypeMethodDescriptionstatic Stringpublish(io.opentelemetry.api.trace.Tracer tracer, String urn, Map<String, Object> data, HeaderSender send) Publishes(urn, data)to the"default"queue under aPRODUCERspan, propagating a W3Ctraceparenton the out-of-band header map (ADR-0028).static StringPublishes(urn, data)to the"default"queue under aPRODUCERspan.static Stringpublish(io.opentelemetry.api.trace.Tracer tracer, String urn, Map<String, Object> data, String queue, HeaderSender send) Emits aPRODUCERspanpublish <urn>and propagates the trace downstream two ways (ADR-0028): It injects the active span context as a W3Ctraceparent(andtracestate) onto a fresh out-of-band header map, so a consumer can start its span as a true child of this producer span — real cross-hop parent→child linkage (v0.2).static Stringpublish(io.opentelemetry.api.trace.Tracer tracer, String urn, Map<String, Object> data, String queue, Sender send) Emits aPRODUCERspanpublish <urn>, carrying the active trace's id into the built envelope'strace_idso the downstream consumer recovers the same trace, then writes the envelope viasend.static StringMaps an envelopetrace_idto a deterministic 32-hex OTel trace id: a UUID maps to its hex bytes; any other string is hashed (SHA-256, first 16 bytes).static StringFormats a 32-hex OTel trace id as a canonical UUID string — the form a producer stamps into the message'strace_idso a consumer can recover the same trace id viatraceIdOf(java.lang.String).static HandlerwrapHandler(io.opentelemetry.api.trace.Tracer tracer, Handler handler) Wraps a consume handler to emit aCONSUMERspan per message, in the OTel trace derived from the envelope'strace_id(ADR-0025 Option 1), recording the handler's error/status.static HandlerwrapHandler(io.opentelemetry.api.trace.Tracer tracer, Handler handler, Supplier<Map<String, String>> headers) Wraps a consume handler to emit aCONSUMERspan per message, recording the handler's error/status.
-
Method Details
-
traceIdOf
Maps an envelopetrace_idto a deterministic 32-hex OTel trace id: a UUID maps to its hex bytes; any other string is hashed (SHA-256, first 16 bytes). Never the all-zero (invalid) trace id. The inverse ofuuidOf(java.lang.String)for the UUID case.- Parameters:
traceId- the envelopetrace_id- Returns:
- a valid 32-hex OTel trace id
-
uuidOf
Formats a 32-hex OTel trace id as a canonical UUID string — the form a producer stamps into the message'strace_idso a consumer can recover the same trace id viatraceIdOf(java.lang.String).- Parameters:
traceIdHex- a 32-hex OTel trace id- Returns:
- the canonical UUID string
-
wrapHandler
Wraps a consume handler to emit aCONSUMERspan per message, in the OTel trace derived from the envelope'strace_id(ADR-0025 Option 1), recording the handler's error/status. The handler receives the fullEnvelopeas before.This is the v0.1 shape: it parents the span on the
trace_id-derived trace only. To additionally start the span as a true child of the producer span when a W3Ctraceparentwas carried beside the envelope, usewrapHandler(Tracer, Handler, Supplier).- Parameters:
tracer- the OTel tracerhandler- the handler to instrument- Returns:
- the wrapped handler
-
wrapHandler
public static Handler wrapHandler(io.opentelemetry.api.trace.Tracer tracer, Handler handler, Supplier<Map<String, String>> headers) Wraps a consume handler to emit aCONSUMERspan per message, recording the handler's error/status. The handler receives the fullEnvelopeas before.Parent selection (ADR-0028): when
headerssupplies the delivered message's out-of-band headers and they carry a valid W3Ctraceparent, the span is started as a true child of the producer span — real cross-hop parent→child linkage with per-hop span timing. When notraceparentis present (anullsupplier, anullor empty map, or a malformed value) it falls back to the v0.1 behaviour: a remote parent derived from the envelope'strace_id(ADR-0025 Option 1), which shares the trace but not the exact span edge. So enablingtraceparentpropagation is a strict, backward-compatible upgrade — no regression for messages produced without it.headersis aSuppliera transport adapter wires to a reserved message's out-of-band headers (e.g.Redrive.Reserved.headers()); it is read once per delivery, after the envelope is in hand. The Java transports live in separate artifacts, so wiring this supplier to each broker's per-message metadata channel is a documented follow-up.- Parameters:
tracer- the OTel tracerhandler- the handler to instrumentheaders- a supplier of the delivered message's out-of-band headers, ornullto always use the v0.1trace_id-derived parent- Returns:
- the wrapped handler
-
publish
public static String publish(io.opentelemetry.api.trace.Tracer tracer, String urn, Map<String, Object> data, Sender send) throws ExceptionPublishes(urn, data)to the"default"queue under aPRODUCERspan. Seepublish(Tracer, String, Map, String, Sender).- Parameters:
tracer- the OTel tracerurn- the message URNdata- the message datasend- the transport write- Returns:
- the published message id (
meta.id) - Throws:
Exception- ifsendfails (recorded on the span and re-thrown)
-
publish
public static String publish(io.opentelemetry.api.trace.Tracer tracer, String urn, Map<String, Object> data, String queue, Sender send) throws ExceptionEmits aPRODUCERspanpublish <urn>, carrying the active trace's id into the built envelope'strace_idso the downstream consumer recovers the same trace, then writes the envelope viasend.- Parameters:
tracer- the OTel tracerurn- the message URNdata- the message dataqueue- the destination queuesend- the transport write- Returns:
- the published message id (
meta.id) - Throws:
Exception- ifsendfails (recorded on the span and re-thrown)
-
publish
public static String publish(io.opentelemetry.api.trace.Tracer tracer, String urn, Map<String, Object> data, HeaderSender send) throws ExceptionPublishes(urn, data)to the"default"queue under aPRODUCERspan, propagating a W3Ctraceparenton the out-of-band header map (ADR-0028). Seepublish(Tracer, String, Map, String, HeaderSender).- Parameters:
tracer- the OTel tracerurn- the message URNdata- the message datasend- the transport write, receiving the envelope and its out-of-band headers- Returns:
- the published message id (
meta.id) - Throws:
Exception- ifsendfails (recorded on the span and re-thrown)
-
publish
public static String publish(io.opentelemetry.api.trace.Tracer tracer, String urn, Map<String, Object> data, String queue, HeaderSender send) throws ExceptionEmits aPRODUCERspanpublish <urn>and propagates the trace downstream two ways (ADR-0028):- It injects the active span context as a W3C
traceparent(andtracestate) onto a fresh out-of-band header map, so a consumer can start its span as a true child of this producer span — real cross-hop parent→child linkage (v0.2). The header rides beside the frozen envelope, never in it (GR-1); a transport that cannot carry headers may simply ignore the map (thetraceparentis then not propagated — no error). - It also carries the active trace's id into the built envelope's
trace_id(the v0.1 behaviour), so even a consumer that ignores the header — or a transport that drops it — still recovers the same trace (correlation without exact span linkage).
The header map is handed to
sendalongside the built envelope.- Parameters:
tracer- the OTel tracerurn- the message URNdata- the message dataqueue- the destination queuesend- the transport write, receiving the envelope and its out-of-band headers- Returns:
- the published message id (
meta.id) - Throws:
Exception- ifsendfails (recorded on the span and re-thrown)
- It injects the active span context as a W3C
-