Documentation
¶
Index ¶
- Constants
- func EnsureTraceID(ctx context.Context) string
- func ExtractFromHeaders(ctx context.Context, headers HeaderAccessor) context.Context
- func GenerateTraceParent() string
- func IDFromContext(ctx context.Context) (string, bool)
- func InjectIntoHeaders(ctx context.Context, headers HeaderAccessor)
- func ParentFromContext(ctx context.Context) (string, bool)
- func StateFromContext(ctx context.Context) (string, bool)
- func ValidateRequestID(id string) string
- func ValidateTraceParent(tp string) string
- func ValidateTraceState(ts string) string
- func WithTraceID(ctx context.Context, traceID string) context.Context
- func WithTraceParent(ctx context.Context, traceParent string) context.Context
- func WithTraceState(ctx context.Context, traceState string) context.Context
- type HeaderAccessor
Constants ¶
const ( // HeaderXRequestID is the standard header name for request tracing HeaderXRequestID = "X-Request-ID" // HeaderTraceParent is the W3C trace context header name HeaderTraceParent = "traceparent" // HeaderTraceState is the W3C trace context "tracestate" header name HeaderTraceState = "tracestate" )
const MaxTraceParentBytes = 255
MaxTraceParentBytes bounds a future version's additive fields. Forward compatibility is not a reason to accept an unbounded header: the value is stored per delivery and re-emitted on every outbound hop, and 255 is the same ceiling the request id answers to, for the same reason.
const MaxTraceStateBytes = 512
MaxTraceStateBytes is the W3C-recommended limit on a tracestate header. It is a cap and nothing more: the grammar is deliberately NOT validated here, and OTel's ParseTraceState is deliberately NOT used, because that would put an OpenTelemetry dependency underneath server, messaging and outbox for a value this framework only stores and forwards. A cap bounds the real harm — unbounded storage and unbounded re-emission on every outbound hop — at a fraction of the coupling. That is a deliberate trade, not an oversight (ADR-070).
Variables ¶
This section is empty.
Functions ¶
func EnsureTraceID ¶
EnsureTraceID returns an existing trace ID from context or generates a new one
func ExtractFromHeaders ¶
func ExtractFromHeaders(ctx context.Context, headers HeaderAccessor) context.Context
ExtractFromHeaders extracts trace context from transport headers
func GenerateTraceParent ¶
func GenerateTraceParent() string
GenerateTraceParent creates a minimal W3C traceparent header value. Format: version(2)-trace-id(32)-span-id(16)-flags(2), e.g., "00-<32>-<16>-01"
func IDFromContext ¶
IDFromContext returns a trace ID from context if present
func InjectIntoHeaders ¶
func InjectIntoHeaders(ctx context.Context, headers HeaderAccessor)
InjectIntoHeaders writes the trace context (X-Request-ID, traceparent, and optionally tracestate) into the given transport headers. Always overwrites any existing values — the trace ID is forced to align with the traceparent so log/metric correlation across services stays consistent.
HeaderXRequestID is always written, always as a Go string: a caller needing the outbound trace identity — the AMQP publish path does, for the message's CorrelationId — reads it back from that header rather than deriving its own, which would skip the alignment above.
Historically this routed through an InjectIntoHeadersWithOptions variant that supported a Preserve mode (set-if-missing). Preserve mode had zero callers across the framework, tools, and tests, so the mode-selector API was removed in W4-H. Add it back with a fresh design if a real consumer need surfaces.
func ParentFromContext ¶
ParentFromContext returns a traceparent from context if present
func StateFromContext ¶
StateFromContext returns a tracestate from context if present
func ValidateRequestID ¶ added in v0.60.0
ValidateRequestID returns id when it is a safe request identifier, otherwise "". A caller that gets "" must fall back to a trusted source — a traceparent-derived id or a fresh UUID — and must never truncate: truncation silently forges correlation by mapping distinct upstream ids onto one, which is why W3C, OpenTelemetry and Heroku all independently refuse it.
func ValidateTraceParent ¶ added in v0.60.0
ValidateTraceParent returns tp when it is a well-formed, non-zero W3C traceparent, otherwise "". Rejecting the all-zero trace-id and parent-id mirrors OpenTelemetry's own Extract, which treats them as absent rather than as a trace to join.
Version handling follows the spec's forward-compatibility rule rather than a flat 55-character match. Version 00 is exactly 55 characters and anything longer is malformed. Versions 01..fe are FUTURE versions, which the spec defines as additive: a receiver parses trace-id, parent-id and flags from the version-00 positions and ignores whatever dash-delimited fields follow. A stricter reader would discard traceparents that later versions consider valid, dropping real upstream traces the day a version 01 appears on the wire.
Forward compatible is not the same as unbounded, though. Those extra fields must still be dash-delimited printable non-space ASCII — the pattern's [[:graph:]], not hex — and the whole value must still fit MaxTraceParentBytes, because everything this seam accepts is stored per delivery and re-emitted on every outbound hop. A future version whose fields fall outside that charset is discarded like any other unparseable traceparent — the delivery continues on a framework-minted id, which is the same outcome this function has always produced for input it cannot vouch for.
func ValidateTraceState ¶ added in v0.60.0
ValidateTraceState returns ts when it is a usable tracestate, otherwise "". The rule is the cap plus a control-byte refusal — no grammar; see MaxTraceStateBytes and traceStatePattern.
It exists as a function rather than as a bare comparison against the constant so every door applies the SAME rule, not the same number: a door that inlines `len(ts) <= MaxTraceStateBytes` keeps compiling on the day this gains a second clause, and silently stops matching the others. That is the failure mode ADR-070 was written to prevent — and this function having gained exactly such a clause is the demonstration.
func WithTraceID ¶
WithTraceID adds a trace ID to the context
func WithTraceParent ¶
WithTraceParent adds a W3C traceparent value to the context