Context propagation enables passing trace context and baggage across service boundaries using standardized formats.
import (
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/baggage"
)OpenTelemetry Go supports:
import (
"net/http"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
)
func main() {
// Setup composite propagator
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{},
))
}
// Inject context into HTTP headers
func makeRequest(ctx context.Context) {
req, _ := http.NewRequest("GET", "https://api.example.com", nil)
otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(req.Header))
// Send request
}
// Extract context from HTTP headers
func handleRequest(w http.ResponseWriter, r *http.Request) {
ctx := otel.GetTextMapPropagator().Extract(r.Context(),
propagation.HeaderCarrier(r.Header))
// Use context
}type TextMapPropagator interface {
// Inject set cross-cutting concerns from the Context into the carrier.
Inject(ctx context.Context, carrier TextMapCarrier)
// Extract reads cross-cutting concerns from the carrier into a Context.
Extract(ctx context.Context, carrier TextMapCarrier) context.Context
// Fields returns the keys who's values are set with Inject.
Fields() []string
}// W3C Trace Context propagator
type TraceContext struct{}
// W3C Baggage propagator
type Baggage struct{}
// Composite propagator (combines multiple)
func NewCompositeTextMapPropagator(propagators ...TextMapPropagator) TextMapPropagatortype TextMapCarrier interface {
// Get returns the value associated with the passed key.
Get(key string) string
// Set stores the key-value pair.
Set(key, value string)
// Keys lists the keys stored in this carrier.
Keys() []string
}type HeaderCarrier http.Header
func (hc HeaderCarrier) Get(key string) string
func (hc HeaderCarrier) Set(key, value string)
func (hc HeaderCarrier) Keys() []string
func (hc HeaderCarrier) Values(key string) []stringtype MapCarrier map[string]string
func (c MapCarrier) Get(key string) string
func (c MapCarrier) Set(key, value string)
func (c MapCarrier) Keys() []stringtype Baggage struct {
// Has unexported fields.
}
// Create baggage
func New(members ...Member) (Baggage, error)
// Parse from string
func Parse(bStr string) (Baggage, error)
// Get from context
func FromContext(ctx context.Context) Baggage
// Methods
func (b Baggage) Member(key string) Member
func (b Baggage) Members() []Member
func (b Baggage) SetMember(member Member) (Baggage, error)
func (b Baggage) DeleteMember(key string) Baggage
func (b Baggage) Len() int
func (b Baggage) String() stringtype Member struct {
// Has unexported fields.
}
// Create member
func NewMember(key, value string, props ...Property) (Member, error)
func NewMemberRaw(key, value string, props ...Property) (Member, error)
// Methods
func (m Member) Key() string
func (m Member) Value() string
func (m Member) Properties() []Property
func (m Member) String() stringtype Property struct {
// Has unexported fields.
}
// Create property
func NewKeyProperty(key string) (Property, error)
func NewKeyValueProperty(key, value string) (Property, error)
func NewKeyValuePropertyRaw(key, value string) (Property, error)
// Methods
func (p Property) Key() string
func (p Property) Value() (string, bool)
func (p Property) String() string// Store baggage in context
func ContextWithBaggage(parent context.Context, b Baggage) context.Context
// Remove baggage from context
func ContextWithoutBaggage(parent context.Context) context.Contextfunc makeHTTPRequest(ctx context.Context, url string) error {
// Create request
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return err
}
// Inject trace context and baggage
otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(req.Header))
// Make request
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
return nil
}func handleRequest(w http.ResponseWriter, r *http.Request) {
// Extract trace context and baggage
ctx := otel.GetTextMapPropagator().Extract(
r.Context(),
propagation.HeaderCarrier(r.Header),
)
// Use extracted context
tracer := otel.Tracer("server")
ctx, span := tracer.Start(ctx, "handle-request")
defer span.End()
// Access baggage
bag := baggage.FromContext(ctx)
userID := bag.Member("user.id").Value()
// Process request...
}// Create baggage members
member1, _ := baggage.NewMemberRaw("user.id", "12345")
member2, _ := baggage.NewMemberRaw("session.id", "abc-123")
// Create baggage
bag, _ := baggage.New(member1, member2)
// Store in context
ctx := baggage.ContextWithBaggage(context.Background(), bag)
// Add to existing baggage
bag = baggage.FromContext(ctx)
member3, _ := baggage.NewMemberRaw("request.id", "xyz-789")
bag, _ = bag.SetMember(member3)
ctx = baggage.ContextWithBaggage(ctx, bag)
// Read from baggage
userID := bag.Member("user.id").Value()
sessionID := bag.Member("session.id").Value()
// Delete member
bag = bag.DeleteMember("session.id")