baggage.go raw

   1  // Copyright The OpenTelemetry Authors
   2  // SPDX-License-Identifier: Apache-2.0
   3  
   4  package propagation // import "go.opentelemetry.io/otel/propagation"
   5  
   6  import (
   7  	"context"
   8  
   9  	"go.opentelemetry.io/otel/baggage"
  10  )
  11  
  12  const baggageHeader = "baggage"
  13  
  14  // Baggage is a propagator that supports the W3C Baggage format.
  15  //
  16  // This propagates user-defined baggage associated with a trace. The complete
  17  // specification is defined at https://www.w3.org/TR/baggage/.
  18  type Baggage struct{}
  19  
  20  var _ TextMapPropagator = Baggage{}
  21  
  22  // Inject sets baggage key-values from ctx into the carrier.
  23  func (Baggage) Inject(ctx context.Context, carrier TextMapCarrier) {
  24  	bStr := baggage.FromContext(ctx).String()
  25  	if bStr != "" {
  26  		carrier.Set(baggageHeader, bStr)
  27  	}
  28  }
  29  
  30  // Extract returns a copy of parent with the baggage from the carrier added.
  31  // If carrier implements [ValuesGetter] (e.g. [HeaderCarrier]), Values is invoked
  32  // for multiple values extraction. Otherwise, Get is called.
  33  func (Baggage) Extract(parent context.Context, carrier TextMapCarrier) context.Context {
  34  	if multiCarrier, ok := carrier.(ValuesGetter); ok {
  35  		return extractMultiBaggage(parent, multiCarrier)
  36  	}
  37  	return extractSingleBaggage(parent, carrier)
  38  }
  39  
  40  // Fields returns the keys who's values are set with Inject.
  41  func (Baggage) Fields() []string {
  42  	return []string{baggageHeader}
  43  }
  44  
  45  func extractSingleBaggage(parent context.Context, carrier TextMapCarrier) context.Context {
  46  	bStr := carrier.Get(baggageHeader)
  47  	if bStr == "" {
  48  		return parent
  49  	}
  50  
  51  	bag, err := baggage.Parse(bStr)
  52  	if err != nil {
  53  		return parent
  54  	}
  55  	return baggage.ContextWithBaggage(parent, bag)
  56  }
  57  
  58  func extractMultiBaggage(parent context.Context, carrier ValuesGetter) context.Context {
  59  	bVals := carrier.Values(baggageHeader)
  60  	if len(bVals) == 0 {
  61  		return parent
  62  	}
  63  	var members []baggage.Member
  64  	for _, bStr := range bVals {
  65  		currBag, err := baggage.Parse(bStr)
  66  		if err != nil {
  67  			continue
  68  		}
  69  		members = append(members, currBag.Members()...)
  70  	}
  71  
  72  	b, err := baggage.New(members...)
  73  	if err != nil || b.Len() == 0 {
  74  		return parent
  75  	}
  76  	return baggage.ContextWithBaggage(parent, b)
  77  }
  78