Overview
Baggage is a mechanism for propagating name-value pairs across service boundaries. It allows you to attach custom attributes to telemetry context that can be accessed by any service in the call chain.
Baggage is not automatically added to spans, metrics, or logs. You must explicitly read baggage entries and add them to your telemetry.
What is baggage?
Baggage is a set of key-value pairs that:
Travels with the context across process boundaries
Can be read and modified by any service
Follows the W3C Baggage specification
Has size and count limits for safety
Limits
const MAX_KEY_VALUE_PAIRS : usize = 64 ;
const MAX_LEN_OF_ALL_PAIRS : usize = 8192 ;
Maximum entries : 64 key-value pairs
Maximum size : 8192 bytes total
Basic usage
Creating baggage
use opentelemetry :: baggage :: Baggage ;
let mut baggage = Baggage :: new ();
baggage . insert ( "user.id" , "12345" );
baggage . insert ( "tenant.name" , "acme-corp" );
baggage . insert ( "feature.flag" , "experimental" );
Reading baggage
if let Some ( user_id ) = baggage . get ( "user.id" ) {
println! ( "User ID: {}" , user_id );
}
use opentelemetry :: baggage :: { Baggage , BaggageMetadata };
let mut baggage = Baggage :: new ();
let metadata = BaggageMetadata :: from ( "ttl=3600" );
baggage . insert_with_metadata ( "session.id" , "abc-123" , metadata );
// Retrieve with metadata
if let Some (( value , metadata )) = baggage . get_with_metadata ( "session.id" ) {
println! ( "Session: {}, Metadata: {:?}" , value , metadata );
}
BaggageExt trait
The BaggageExt trait extends Context with baggage management:
use opentelemetry :: Context ;
use opentelemetry :: baggage :: BaggageExt ;
// Get baggage from context
let cx = Context :: current ();
let baggage = cx . baggage ();
// Create context with baggage
let mut new_baggage = Baggage :: new ();
new_baggage . insert ( "request.id" , "req-789" );
let cx = cx . with_baggage ( new_baggage );
Propagation
Baggage automatically propagates when using the BaggagePropagator:
use opentelemetry :: global;
use opentelemetry :: propagation :: TextMapCompositePropagator ;
use opentelemetry_sdk :: propagation :: { BaggagePropagator , TraceContextPropagator };
// Configure propagator to include baggage
let propagator = TextMapCompositePropagator :: new ( vec! [
Box :: new ( TraceContextPropagator :: new ()),
Box :: new ( BaggagePropagator :: new ()),
]);
global :: set_text_map_propagator ( propagator );
Complete example
Service A (upstream)
use opentelemetry :: {
baggage :: { Baggage , BaggageExt },
global,
trace :: { Tracer , TraceContextExt },
Context , KeyValue ,
};
use std :: collections :: HashMap ;
fn make_request () {
let tracer = global :: tracer ( "service-a" );
let mut span = tracer . start ( "process_request" );
// Create baggage
let mut baggage = Baggage :: new ();
baggage . insert ( "user.id" , "12345" );
baggage . insert ( "request.source" , "mobile-app" );
// Attach to context
let cx = Context :: current ()
. with_span ( span )
. with_baggage ( baggage );
// Inject into HTTP headers
let mut headers = HashMap :: new ();
global :: get_text_map_propagator ( | propagator | {
propagator . inject_context ( & cx , & mut headers );
});
// Send request with headers
send_http_request ( & headers );
}
Service B (downstream)
use opentelemetry :: {
baggage :: BaggageExt ,
global,
trace :: { Tracer , TraceContextExt },
KeyValue ,
};
use std :: collections :: HashMap ;
fn handle_request ( headers : HashMap < String , String >) {
// Extract context from headers
let parent_cx = global :: get_text_map_propagator ( | propagator | {
propagator . extract ( & headers )
});
// Read baggage
let baggage = parent_cx . baggage ();
let tracer = global :: tracer ( "service-b" );
let mut span = tracer
. span_builder ( "handle_request" )
. start_with_context ( & tracer , & parent_cx );
// Add baggage values as span attributes
if let Some ( user_id ) = baggage . get ( "user.id" ) {
span . set_attribute ( KeyValue :: new ( "user.id" , user_id . to_string ()));
}
if let Some ( source ) = baggage . get ( "request.source" ) {
span . set_attribute ( KeyValue :: new ( "request.source" , source . to_string ()));
}
// Process request...
span . end ();
}
Common use cases
1. User identification
let mut baggage = Baggage :: new ();
baggage . insert ( "user.id" , "12345" );
baggage . insert ( "user.email" , "[email protected] " );
baggage . insert ( "user.role" , "admin" );
2. Request tracking
let mut baggage = Baggage :: new ();
baggage . insert ( "request.id" , generate_request_id ());
baggage . insert ( "correlation.id" , correlation_id );
3. Feature flags
let mut baggage = Baggage :: new ();
baggage . insert ( "feature.new_ui" , "enabled" );
baggage . insert ( "experiment.variant" , "b" );
4. Multi-tenancy
let mut baggage = Baggage :: new ();
baggage . insert ( "tenant.id" , "tenant-123" );
baggage . insert ( "tenant.tier" , "enterprise" );
Iterating over baggage
use opentelemetry :: baggage :: Baggage ;
let mut baggage = Baggage :: new ();
baggage . insert ( "key1" , "value1" );
baggage . insert ( "key2" , "value2" );
// Iterate over entries
for ( key , ( value , metadata )) in baggage . iter () {
println! ( "{}: {} (metadata: {:?})" , key , value , metadata );
}
Adding baggage to telemetry
Add to spans
use opentelemetry :: { baggage :: BaggageExt , trace :: TraceContextExt , Context , KeyValue };
let cx = Context :: current ();
let baggage = cx . baggage ();
let span = cx . span ();
// Add all baggage as span attributes
for ( key , ( value , _ )) in baggage . iter () {
span . set_attribute ( KeyValue :: new ( key . to_string (), value . to_string ()));
}
Add to metrics
use opentelemetry :: { baggage :: BaggageExt , Context , KeyValue };
let cx = Context :: current ();
let baggage = cx . baggage ();
let mut attributes = vec! [];
if let Some ( tenant ) = baggage . get ( "tenant.id" ) {
attributes . push ( KeyValue :: new ( "tenant.id" , tenant . to_string ()));
}
counter . add ( & cx , 1 , & attributes );
Best practices
Keep baggage small - Baggage is sent with every request. Keep the size minimal to avoid network overhead.
No sensitive data - Baggage propagates across all services and may be logged. Never put passwords, tokens, or PII in baggage.
Explicit attachment - Remember that baggage values don’t automatically appear in telemetry. You must explicitly read and attach them.
Validation - Baggage keys must follow RFC2616 token format. Invalid keys are rejected.
Baggage vs span attributes
Feature Baggage Span Attributes Propagation Across services Within span only Visibility All downstream services Current span Size limits 64 entries, 8KB total No hard limit Automatic attachment No Yes (to span) Use case Cross-cutting concerns Span-specific data
Propagators Configure context propagation
Context propagation Learn about context flow