propagator.go raw

   1  // Copyright The OpenTelemetry Authors
   2  // SPDX-License-Identifier: Apache-2.0
   3  
   4  package global // import "go.opentelemetry.io/otel/internal/global"
   5  
   6  import (
   7  	"context"
   8  	"sync"
   9  
  10  	"go.opentelemetry.io/otel/propagation"
  11  )
  12  
  13  // textMapPropagator is a default TextMapPropagator that delegates calls to a
  14  // registered delegate if one is set, otherwise it defaults to delegating the
  15  // calls to a the default no-op propagation.TextMapPropagator.
  16  type textMapPropagator struct {
  17  	mtx      sync.Mutex
  18  	once     sync.Once
  19  	delegate propagation.TextMapPropagator
  20  	noop     propagation.TextMapPropagator
  21  }
  22  
  23  // Compile-time guarantee that textMapPropagator implements the
  24  // propagation.TextMapPropagator interface.
  25  var _ propagation.TextMapPropagator = (*textMapPropagator)(nil)
  26  
  27  func newTextMapPropagator() *textMapPropagator {
  28  	return &textMapPropagator{
  29  		noop: propagation.NewCompositeTextMapPropagator(),
  30  	}
  31  }
  32  
  33  // SetDelegate sets a delegate propagation.TextMapPropagator that all calls are
  34  // forwarded to. Delegation can only be performed once, all subsequent calls
  35  // perform no delegation.
  36  func (p *textMapPropagator) SetDelegate(delegate propagation.TextMapPropagator) {
  37  	if delegate == nil {
  38  		return
  39  	}
  40  
  41  	p.mtx.Lock()
  42  	p.once.Do(func() { p.delegate = delegate })
  43  	p.mtx.Unlock()
  44  }
  45  
  46  // effectiveDelegate returns the current delegate of p if one is set,
  47  // otherwise the default noop TextMapPropagator is returned. This method
  48  // can be called concurrently.
  49  func (p *textMapPropagator) effectiveDelegate() propagation.TextMapPropagator {
  50  	p.mtx.Lock()
  51  	defer p.mtx.Unlock()
  52  	if p.delegate != nil {
  53  		return p.delegate
  54  	}
  55  	return p.noop
  56  }
  57  
  58  // Inject set cross-cutting concerns from the Context into the carrier.
  59  func (p *textMapPropagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) {
  60  	p.effectiveDelegate().Inject(ctx, carrier)
  61  }
  62  
  63  // Extract reads cross-cutting concerns from the carrier into a Context.
  64  func (p *textMapPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context {
  65  	return p.effectiveDelegate().Extract(ctx, carrier)
  66  }
  67  
  68  // Fields returns the keys whose values are set with Inject.
  69  func (p *textMapPropagator) Fields() []string {
  70  	return p.effectiveDelegate().Fields()
  71  }
  72