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