OpenTelemetry Jaeger Propagator for seamlessly integrating OpenTelemetry tracing with Jaeger's uber-trace-id format
npx @tessl/cli install tessl/pypi-opentelemetry-propagator-jaeger@1.36.0OpenTelemetry Jaeger Propagator enables seamless integration between OpenTelemetry tracing and Jaeger by handling the conversion of trace context between OpenTelemetry's internal representation and Jaeger's uber-trace-id format. It implements the TextMapPropagator interface to extract and inject trace information including trace IDs, span IDs, parent span relationships, and baggage data across service boundaries, supporting both trace sampling flags and debug modes.
pip install opentelemetry-propagator-jaegeropentelemetry-api ~= 1.3from opentelemetry.propagators.jaeger import JaegerPropagatorEntry point import (when using OpenTelemetry's propagator registry):
# Via entry point configuration
from opentelemetry.propagate import get_global_textmap
# JaegerPropagator registered as 'jaeger' entry pointfrom opentelemetry.propagators.jaeger import JaegerPropagator
from opentelemetry import trace
from opentelemetry.context import Context
# Create propagator instance
propagator = JaegerPropagator()
# Extract trace context from incoming HTTP headers
incoming_headers = {
"uber-trace-id": "000000000000000000000000deadbeef:00000000deadbef0:00000000:01"
}
context = propagator.extract(incoming_headers)
# Get current span from context
span = trace.get_current_span(context)
span_context = span.get_span_context()
# Inject trace context into outgoing HTTP headers
outgoing_headers = {}
propagator.inject(outgoing_headers, context=context)
print(outgoing_headers) # Contains uber-trace-id header
# Check fields used by propagator
print(propagator.fields) # {'uber-trace-id'}The JaegerPropagator implements OpenTelemetry's TextMapPropagator interface to provide bidirectional conversion between OpenTelemetry trace contexts and Jaeger's uber-trace-id format. The propagator handles:
The uber-trace-id format follows the pattern: {trace-id}:{span-id}:{parent-span-id}:{flags}
Extracts trace context from carrier headers using Jaeger's uber-trace-id format, creating OpenTelemetry SpanContext objects with proper trace relationships and flags.
def extract(
self,
carrier: CarrierT,
context: typing.Optional[Context] = None,
getter: Getter = default_getter,
) -> Context:
"""
Extract trace context from carrier using Jaeger format.
Parameters:
- carrier: The carrier containing trace headers (typically HTTP headers dict)
- context: Optional existing context to merge with extracted context
- getter: Getter implementation for extracting values from carrier
Returns:
Context with extracted trace information and baggage
"""Usage example:
from opentelemetry.propagators.jaeger import JaegerPropagator
propagator = JaegerPropagator()
# Extract from HTTP headers
headers = {
"uber-trace-id": "000000000000000000000000deadbeef:00000000deadbef0:00000000:01",
"uberctx-user-id": "john.doe",
"uberctx-session": "abc123"
}
context = propagator.extract(headers)
span = trace.get_current_span(context)
print(f"Trace ID: {span.get_span_context().trace_id}")Injects trace context into carrier headers using Jaeger's uber-trace-id format, including baggage propagation with uberctx- prefixed headers.
def inject(
self,
carrier: CarrierT,
context: typing.Optional[Context] = None,
setter: Setter = default_setter,
) -> None:
"""
Inject trace context into carrier using Jaeger format.
Parameters:
- carrier: The carrier to inject headers into (typically HTTP headers dict)
- context: Optional context containing trace information (uses current if None)
- setter: Setter implementation for injecting values into carrier
Returns:
None (modifies carrier in-place)
Note: When injecting sampled traces, the DEBUG_FLAG (0x02) is OR'd with
existing trace flags in the uber-trace-id format.
"""Usage example:
from opentelemetry.propagators.jaeger import JaegerPropagator
from opentelemetry import baggage, trace
propagator = JaegerPropagator()
# Set baggage in current context
context = baggage.set_baggage("user-id", "john.doe")
context = baggage.set_baggage("session", "abc123", context)
# Inject into HTTP headers
headers = {}
propagator.inject(headers, context=context)
print(headers)
# Output: {'uber-trace-id': '...', 'uberctx-user-id': 'john.doe', 'uberctx-session': 'abc123'}Returns the set of header field names used by this propagator for trace context propagation.
@property
def fields(self) -> typing.Set[str]:
"""
Get the fields used by this propagator.
Returns:
Set of header field names used for trace propagation
"""Usage example:
from opentelemetry.propagators.jaeger import JaegerPropagator
propagator = JaegerPropagator()
print(propagator.fields) # {'uber-trace-id'}The JaegerPropagator class defines several constants used in Jaeger trace propagation:
class JaegerPropagator(TextMapPropagator):
TRACE_ID_KEY = "uber-trace-id" # Header key for Jaeger trace ID
BAGGAGE_PREFIX = "uberctx-" # Prefix for baggage headers
DEBUG_FLAG = 0x02 # Debug flag OR'd with sampled tracesCarrierT = typing.TypeVar('CarrierT')Type variable representing the carrier object (typically a dictionary for HTTP headers).
class Getter(typing.Protocol):
def get(self, carrier: CarrierT, key: str) -> typing.Optional[typing.List[str]]: ...
def keys(self, carrier: CarrierT) -> typing.List[str]: ...Protocol for extracting values from carriers. The default_getter handles dictionary-like carriers.
class Setter(typing.Protocol):
def set(self, carrier: CarrierT, key: str, value: str) -> None: ...Protocol for setting values in carriers. The default_setter handles dictionary-like carriers.
from opentelemetry.context import ContextOpenTelemetry context object that holds trace and baggage information.
The propagator handles various error conditions gracefully:
Example with invalid trace header:
from opentelemetry.propagators.jaeger import JaegerPropagator
propagator = JaegerPropagator()
# Invalid trace header (wrong number of components)
headers = {
"uber-trace-id": "invalid:format",
"uberctx-user-id": "john.doe" # Baggage still extracted
}
context = propagator.extract(headers)
# Trace context will be invalid, but baggage is still availableThe JaegerPropagator is registered as an OpenTelemetry propagator plugin and can be used with the OpenTelemetry SDK:
from opentelemetry import propagate
from opentelemetry.propagators.jaeger import JaegerPropagator
# Register as global propagator
propagate.set_global_textmap(JaegerPropagator())
# Or combine with other propagators
from opentelemetry.propagators.composite import CompositePropagator
from opentelemetry.propagators.b3 import B3SingleFormatPropagator
composite = CompositePropagator([
JaegerPropagator(),
B3SingleFormatPropagator()
])
propagate.set_global_textmap(composite)