Trace Context
Understanding Trace Context¶
Trace context is the mechanism that enables distributed tracing systems to correlate spans across service boundaries. In a microservices architecture, where requests traverse multiple services, trace context headers ensure that all components of a single request share the same trace ID and span ID, allowing end-to-end visibility. Without proper trace context propagation, traces would fragment, making debugging and performance analysis infeasible.
Modern systems rely on standardized headers like W3C TraceContext (RFC 9514) and legacy headers like B3 (from the Zipkin project) to carry trace metadata. OpenTelemetry supports both, but W3C is the recommended standard due to its broader compatibility and extensibility.
W3C TraceContext Headers¶
The W3C TraceContext standard defines two key headers:
traceparent¶
This header contains the core trace context information:
- Trace ID: A 64-bit hexadecimal string (e.g., 123e4567e89b12d3a456c78901234567)
- Span ID: A 64-bit hexadecimal string (e.g., 123e4567e89b12d3)
- Trace Flags: Indicates if the trace is sampled (01 for sampled, 00 for not sampled)
- Debug Flag: Optional, used for debugging (not part of the standard)
Example:
tracestate¶
This header carries vendor-specific or custom data (e.g., baggage for OpenTelemetry). It is a semicolon-separated list of key-value pairs:
B3 Headers (Legacy)¶
B3 headers are used in older systems and are less standardized. They include:
- traceid (128-bit hex)
- spanid (64-bit hex)
- flags (sampled or not)
- baggage (custom metadata)
Example:
While B3 is still used in some environments, W3C is preferred for new systems due to its extensibility and support for multiple tracing backends.
Propagation in OpenTelemetry¶
OpenTelemetry SDKs automatically inject and extract trace context headers when making HTTP requests. By default, it uses W3C headers, but you can configure it to use B3 if needed.
Example: Injecting Headers with OpenTelemetry¶
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(
BatchSpanProcessor(OTLPSpanExporter())
)
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("example-span") as span:
# HTTP request will automatically include traceparent and tracestate headers
pass
Example: Extracting Headers in a Server¶
// Java (Spring Boot)
@RestController
public class TraceController {
@GetMapping("/trace")
public ResponseEntity<String> trace() {
Span span = Span.current();
String traceId = span.getSpanContext().getTraceId();
String spanId = span.getSpanContext().getSpanId();
return ResponseEntity.ok("Trace ID: " + traceId + ", Span ID: " + spanId);
}
}
Implementation Considerations¶
- Header Compatibility: Ensure all services in your ecosystem support the same trace context format (prefer W3C).
- Sampling: Use trace flags to control whether traces are sampled (reduces data volume).
- Tracestate Extensibility: Leverage
tracestatefor vendor-specific metadata (e.g.,baggagefor OpenTelemetry). - Header Injection: Always inject trace context headers in outgoing requests (e.g., HTTP clients, messaging systems).
Key takeaways¶
- Trace context headers (W3C/B3) are essential for correlating spans across services.
- W3C TraceContext is the modern standard, offering better extensibility and compatibility.
- OpenTelemetry SDKs automatically handle header injection/extractioN when configured properly.
- Always validate that all services in your system propagate trace context headers consistently.