Skip to main content

Overview

Context propagation is fundamental to distributed tracing. It allows OpenTelemetry to:
  1. Link related operations - Connect spans within a single process
  2. Trace across services - Maintain trace continuity as requests flow between services
  3. Share metadata - Propagate baggage and other contextual information
OpenTelemetry provides two types of context propagation:
  • In-process propagation - Using the Context API
  • Cross-service propagation - Using propagators to inject/extract context from message headers

In-Process Context Propagation

The Context type is an immutable, execution-scoped collection of values that flows through your application.

Creating and Using Context

Contexts are immutable. Operations like with_value() return a new context containing both the original and new values.

Attaching Context to the Current Thread

Use attach() to make a context active for the current thread:
You must assign the guard to a variable (not _) or Rust will drop it immediately, restoring the previous context.

Nested Contexts

Contexts can be nested, creating a stack of active contexts:

Context with Spans

Spans are automatically stored in the context:

Async Context Propagation

For async code, use FutureExt to propagate context across .await points:

Cross-Service Propagation

When a request crosses service boundaries (e.g., HTTP, gRPC), context must be serialized into message headers and deserialized on the receiving side.

Propagators

Propagators handle serialization and deserialization of context. OpenTelemetry provides several standard propagators:
  • TraceContext - W3C Trace Context standard (recommended)
  • Baggage - W3C Baggage standard
  • Jaeger - Jaeger-specific format
  • B3 - Zipkin B3 format

Setting Up Propagation

Injecting Context (Client Side)

When making an outbound request, inject the current context into headers:
This adds headers like:

Extracting Context (Server Side)

When receiving a request, extract the context from headers:

Complete HTTP Example

Here’s a complete example of context propagation between HTTP client and server: Client:
Server:

Baggage

Baggage allows you to propagate arbitrary key-value pairs across service boundaries. Unlike span attributes, baggage is propagated to all downstream services.

Using Baggage

Propagating Baggage Across Services

To propagate baggage, use a composite propagator:
Now both trace context and baggage will be propagated via HTTP headers:

Baggage in Spans and Logs

Baggage is not automatically added to spans or logs. You need custom processors:
Use baggage sparingly: Baggage is propagated to all downstream services and can add significant overhead. Only include essential key-value pairs.

Custom Propagators

You can implement custom propagators for proprietary formats:

Telemetry Suppression

OpenTelemetry components can suppress telemetry generation to prevent infinite loops:
This is primarily used by OpenTelemetry SDK components (exporters, processors) to prevent generating telemetry about telemetry operations.

Best Practices

Use W3C Trace Context: TraceContextPropagator is the recommended standard for interoperability.
Always inject and extract: Client-side code should inject context, server-side code should extract it.
Propagate context in async code: Use with_context() to ensure context flows across .await points.
Minimize baggage: Only propagate essential information as baggage—it’s sent with every request.
Don’t forget the guard variable: let _guard = ctx.attach() not just ctx.attach().

Next Steps

Signals

Learn about traces, metrics, and logs

Exporters

Configure where to send your telemetry data