propagation.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  	"net/http"
   9  )
  10  
  11  // TextMapCarrier is the storage medium used by a TextMapPropagator.
  12  // See ValuesGetter for how a TextMapCarrier can get multiple values for a key.
  13  type TextMapCarrier interface {
  14  	// DO NOT CHANGE: any modification will not be backwards compatible and
  15  	// must never be done outside of a new major release.
  16  
  17  	// Get returns the value associated with the passed key.
  18  	Get(key string) string
  19  	// DO NOT CHANGE: any modification will not be backwards compatible and
  20  	// must never be done outside of a new major release.
  21  
  22  	// Set stores the key-value pair.
  23  	Set(key, value string)
  24  	// DO NOT CHANGE: any modification will not be backwards compatible and
  25  	// must never be done outside of a new major release.
  26  
  27  	// Keys lists the keys stored in this carrier.
  28  	Keys() []string
  29  	// DO NOT CHANGE: any modification will not be backwards compatible and
  30  	// must never be done outside of a new major release.
  31  }
  32  
  33  // ValuesGetter can return multiple values for a single key,
  34  // with contrast to TextMapCarrier.Get which returns a single value.
  35  type ValuesGetter interface {
  36  	// DO NOT CHANGE: any modification will not be backwards compatible and
  37  	// must never be done outside of a new major release.
  38  
  39  	// Values returns all values associated with the passed key.
  40  	Values(key string) []string
  41  	// DO NOT CHANGE: any modification will not be backwards compatible and
  42  	// must never be done outside of a new major release.
  43  }
  44  
  45  // MapCarrier is a TextMapCarrier that uses a map held in memory as a storage
  46  // medium for propagated key-value pairs.
  47  type MapCarrier map[string]string
  48  
  49  // Compile time check that MapCarrier implements the TextMapCarrier.
  50  var _ TextMapCarrier = MapCarrier{}
  51  
  52  // Get returns the value associated with the passed key.
  53  func (c MapCarrier) Get(key string) string {
  54  	return c[key]
  55  }
  56  
  57  // Set stores the key-value pair.
  58  func (c MapCarrier) Set(key, value string) {
  59  	c[key] = value
  60  }
  61  
  62  // Keys lists the keys stored in this carrier.
  63  func (c MapCarrier) Keys() []string {
  64  	keys := make([]string, 0, len(c))
  65  	for k := range c {
  66  		keys = append(keys, k)
  67  	}
  68  	return keys
  69  }
  70  
  71  // HeaderCarrier adapts http.Header to satisfy the TextMapCarrier and ValuesGetter interfaces.
  72  type HeaderCarrier http.Header
  73  
  74  // Compile time check that HeaderCarrier implements ValuesGetter.
  75  var _ TextMapCarrier = HeaderCarrier{}
  76  
  77  // Compile time check that HeaderCarrier implements TextMapCarrier.
  78  var _ ValuesGetter = HeaderCarrier{}
  79  
  80  // Get returns the first value associated with the passed key.
  81  func (hc HeaderCarrier) Get(key string) string {
  82  	return http.Header(hc).Get(key)
  83  }
  84  
  85  // Values returns all values associated with the passed key.
  86  func (hc HeaderCarrier) Values(key string) []string {
  87  	return http.Header(hc).Values(key)
  88  }
  89  
  90  // Set stores the key-value pair.
  91  func (hc HeaderCarrier) Set(key, value string) {
  92  	http.Header(hc).Set(key, value)
  93  }
  94  
  95  // Keys lists the keys stored in this carrier.
  96  func (hc HeaderCarrier) Keys() []string {
  97  	keys := make([]string, 0, len(hc))
  98  	for k := range hc {
  99  		keys = append(keys, k)
 100  	}
 101  	return keys
 102  }
 103  
 104  // TextMapPropagator propagates cross-cutting concerns as key-value text
 105  // pairs within a carrier that travels in-band across process boundaries.
 106  type TextMapPropagator interface {
 107  	// DO NOT CHANGE: any modification will not be backwards compatible and
 108  	// must never be done outside of a new major release.
 109  
 110  	// Inject set cross-cutting concerns from the Context into the carrier.
 111  	Inject(ctx context.Context, carrier TextMapCarrier)
 112  	// DO NOT CHANGE: any modification will not be backwards compatible and
 113  	// must never be done outside of a new major release.
 114  
 115  	// Extract reads cross-cutting concerns from the carrier into a Context.
 116  	// Implementations may check if the carrier implements ValuesGetter,
 117  	// to support extraction of multiple values per key.
 118  	Extract(ctx context.Context, carrier TextMapCarrier) context.Context
 119  	// DO NOT CHANGE: any modification will not be backwards compatible and
 120  	// must never be done outside of a new major release.
 121  
 122  	// Fields returns the keys whose values are set with Inject.
 123  	Fields() []string
 124  	// DO NOT CHANGE: any modification will not be backwards compatible and
 125  	// must never be done outside of a new major release.
 126  }
 127  
 128  type compositeTextMapPropagator []TextMapPropagator
 129  
 130  func (p compositeTextMapPropagator) Inject(ctx context.Context, carrier TextMapCarrier) {
 131  	for _, i := range p {
 132  		i.Inject(ctx, carrier)
 133  	}
 134  }
 135  
 136  func (p compositeTextMapPropagator) Extract(ctx context.Context, carrier TextMapCarrier) context.Context {
 137  	for _, i := range p {
 138  		ctx = i.Extract(ctx, carrier)
 139  	}
 140  	return ctx
 141  }
 142  
 143  func (p compositeTextMapPropagator) Fields() []string {
 144  	unique := make(map[string]struct{})
 145  	for _, i := range p {
 146  		for _, k := range i.Fields() {
 147  			unique[k] = struct{}{}
 148  		}
 149  	}
 150  
 151  	fields := make([]string, 0, len(unique))
 152  	for k := range unique {
 153  		fields = append(fields, k)
 154  	}
 155  	return fields
 156  }
 157  
 158  // NewCompositeTextMapPropagator returns a unified TextMapPropagator from the
 159  // group of passed TextMapPropagator. This allows different cross-cutting
 160  // concerns to be propagates in a unified manner.
 161  //
 162  // The returned TextMapPropagator will inject and extract cross-cutting
 163  // concerns in the order the TextMapPropagators were provided. Additionally,
 164  // the Fields method will return a de-duplicated slice of the keys that are
 165  // set with the Inject method.
 166  func NewCompositeTextMapPropagator(p ...TextMapPropagator) TextMapPropagator {
 167  	return compositeTextMapPropagator(p)
 168  }
 169