1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package autoprop // import "go.opentelemetry.io/contrib/propagators/autoprop"
import (
"errors"
"fmt"
"strings"
"sync"
"go.opentelemetry.io/contrib/propagators/aws/xray"
"go.opentelemetry.io/contrib/propagators/b3"
"go.opentelemetry.io/contrib/propagators/jaeger"
"go.opentelemetry.io/contrib/propagators/ot"
"go.opentelemetry.io/otel/propagation"
)
// none is the special "propagator" name that means no propagator shall be
// configured.
const none = "none"
// propagators is the registry of TextMapPropagators registered with this
// package. It includes all the OpenTelemetry defaults at startup.
var propagators = ®istry{
names: map[string]propagation.TextMapPropagator{
// W3C Trace Context.
"tracecontext": propagation.TraceContext{},
// W3C Baggage.
"baggage": propagation.Baggage{},
// B3 single-header format.
"b3": b3.New(),
// B3 multi-header format.
"b3multi": b3.New(b3.WithInjectEncoding(b3.B3MultipleHeader)),
// Jaeger.
"jaeger": jaeger.Jaeger{},
// AWS X-Ray.
"xray": xray.Propagator{},
// OpenTracing Trace.
"ottrace": ot.OT{},
// No-op TextMapPropagator.
none: propagation.NewCompositeTextMapPropagator(),
},
}
// registry maintains a map of propagator names to TextMapPropagator
// implementations that is safe for concurrent use by multiple goroutines
// without additional locking or coordination.
type registry struct {
mu sync.Mutex
names map[string]propagation.TextMapPropagator
}
// load returns the value stored in the registry index for a key, or nil if no
// value is present. The ok result indicates whether value was found in the
// index.
func (r *registry) load(key string) (p propagation.TextMapPropagator, ok bool) {
r.mu.Lock()
p, ok = r.names[key]
r.mu.Unlock()
return p, ok
}
var errDupReg = errors.New("duplicate registration")
// store sets the value for a key if is not already in the registry. errDupReg
// is returned if the registry already contains key.
func (r *registry) store(key string, value propagation.TextMapPropagator) error {
r.mu.Lock()
defer r.mu.Unlock()
if r.names == nil {
r.names = map[string]propagation.TextMapPropagator{key: value}
return nil
}
if _, ok := r.names[key]; ok {
return fmt.Errorf("%w: %q", errDupReg, key)
}
r.names[key] = value
return nil
}
// drop removes key from the registry if it exists, otherwise nothing.
func (r *registry) drop(key string) {
r.mu.Lock()
delete(r.names, key)
r.mu.Unlock()
}
// RegisterTextMapPropagator sets the TextMapPropagator p to be used when the
// OTEL_PROPAGATORS environment variable contains the propagator name. This
// will panic if name has already been registered or is a default
// (tracecontext, baggage, b3, b3multi, jaeger, xray, or ottrace).
func RegisterTextMapPropagator(name string, p propagation.TextMapPropagator) {
if err := propagators.store(name, p); err != nil {
// envRegistry.store will return errDupReg if name is already
// registered. Panic here so the user is made aware of the duplicate
// registration, which could be done by malicious code trying to
// intercept cross-cutting concerns.
//
// Panic for all other errors as well. At this point there should not
// be any other errors returned from the store operation. If there
// are, alert the developer that adding them as soon as possible that
// they need to be handled here.
panic(err)
}
}
// TextMapPropagator returns a TextMapPropagator composed from the
// passed names of registered TextMapPropagators. Each name must match an
// already registered TextMapPropagator (see the RegisterTextMapPropagator
// function for more information) or a default (tracecontext, baggage, b3,
// b3multi, jaeger, xray, or ottrace).
//
// If "none" is included in the arguments, or no names are provided, the
// returned TextMapPropagator will be a no-operation implementation.
//
// An error is returned for any un-registered names. The remaining, known,
// names will be used to compose a TextMapPropagator that is returned with the
// error.
func TextMapPropagator(names ...string) (propagation.TextMapPropagator, error) {
var (
props []propagation.TextMapPropagator
unknown []string
)
for _, name := range names {
if name == none {
// If "none" is passed in combination with any other propagator,
// the result still needs to be a no-op propagator. Therefore,
// short-circuit here.
return propagation.NewCompositeTextMapPropagator(), nil
}
p, ok := propagators.load(name)
if !ok {
unknown = append(unknown, name)
continue
}
props = append(props, p)
}
var err error
if len(unknown) > 0 {
joined := strings.Join(unknown, ",")
err = fmt.Errorf("%w: %s", errUnknownPropagator, joined)
}
switch len(props) {
case 0:
return nil, err
case 1:
// Do not return a composite of a single propagator.
return props[0], err
default:
return propagation.NewCompositeTextMapPropagator(props...), err
}
}
|