1// Copyright The OpenTelemetry Authors
2// SPDX-License-Identifier: Apache-2.0
3
4package propagation // import "go.opentelemetry.io/otel/propagation"
5
6import (
7 "context"
8 "net/http"
9)
10
11// TextMapCarrier is the storage medium used by a TextMapPropagator.
12type TextMapCarrier interface {
13 // DO NOT CHANGE: any modification will not be backwards compatible and
14 // must never be done outside of a new major release.
15
16 // Get returns the value associated with the passed key.
17 Get(key string) string
18 // DO NOT CHANGE: any modification will not be backwards compatible and
19 // must never be done outside of a new major release.
20
21 // Set stores the key-value pair.
22 Set(key string, value string)
23 // DO NOT CHANGE: any modification will not be backwards compatible and
24 // must never be done outside of a new major release.
25
26 // Keys lists the keys stored in this carrier.
27 Keys() []string
28 // DO NOT CHANGE: any modification will not be backwards compatible and
29 // must never be done outside of a new major release.
30}
31
32// MapCarrier is a TextMapCarrier that uses a map held in memory as a storage
33// medium for propagated key-value pairs.
34type MapCarrier map[string]string
35
36// Compile time check that MapCarrier implements the TextMapCarrier.
37var _ TextMapCarrier = MapCarrier{}
38
39// Get returns the value associated with the passed key.
40func (c MapCarrier) Get(key string) string {
41 return c[key]
42}
43
44// Set stores the key-value pair.
45func (c MapCarrier) Set(key, value string) {
46 c[key] = value
47}
48
49// Keys lists the keys stored in this carrier.
50func (c MapCarrier) Keys() []string {
51 keys := make([]string, 0, len(c))
52 for k := range c {
53 keys = append(keys, k)
54 }
55 return keys
56}
57
58// HeaderCarrier adapts http.Header to satisfy the TextMapCarrier interface.
59type HeaderCarrier http.Header
60
61// Get returns the value associated with the passed key.
62func (hc HeaderCarrier) Get(key string) string {
63 return http.Header(hc).Get(key)
64}
65
66// Set stores the key-value pair.
67func (hc HeaderCarrier) Set(key string, value string) {
68 http.Header(hc).Set(key, value)
69}
70
71// Keys lists the keys stored in this carrier.
72func (hc HeaderCarrier) Keys() []string {
73 keys := make([]string, 0, len(hc))
74 for k := range hc {
75 keys = append(keys, k)
76 }
77 return keys
78}
79
80// TextMapPropagator propagates cross-cutting concerns as key-value text
81// pairs within a carrier that travels in-band across process boundaries.
82type TextMapPropagator interface {
83 // DO NOT CHANGE: any modification will not be backwards compatible and
84 // must never be done outside of a new major release.
85
86 // Inject set cross-cutting concerns from the Context into the carrier.
87 Inject(ctx context.Context, carrier TextMapCarrier)
88 // DO NOT CHANGE: any modification will not be backwards compatible and
89 // must never be done outside of a new major release.
90
91 // Extract reads cross-cutting concerns from the carrier into a Context.
92 Extract(ctx context.Context, carrier TextMapCarrier) context.Context
93 // DO NOT CHANGE: any modification will not be backwards compatible and
94 // must never be done outside of a new major release.
95
96 // Fields returns the keys whose values are set with Inject.
97 Fields() []string
98 // DO NOT CHANGE: any modification will not be backwards compatible and
99 // must never be done outside of a new major release.
100}
101
102type compositeTextMapPropagator []TextMapPropagator
103
104func (p compositeTextMapPropagator) Inject(ctx context.Context, carrier TextMapCarrier) {
105 for _, i := range p {
106 i.Inject(ctx, carrier)
107 }
108}
109
110func (p compositeTextMapPropagator) Extract(ctx context.Context, carrier TextMapCarrier) context.Context {
111 for _, i := range p {
112 ctx = i.Extract(ctx, carrier)
113 }
114 return ctx
115}
116
117func (p compositeTextMapPropagator) Fields() []string {
118 unique := make(map[string]struct{})
119 for _, i := range p {
120 for _, k := range i.Fields() {
121 unique[k] = struct{}{}
122 }
123 }
124
125 fields := make([]string, 0, len(unique))
126 for k := range unique {
127 fields = append(fields, k)
128 }
129 return fields
130}
131
132// NewCompositeTextMapPropagator returns a unified TextMapPropagator from the
133// group of passed TextMapPropagator. This allows different cross-cutting
134// concerns to be propagates in a unified manner.
135//
136// The returned TextMapPropagator will inject and extract cross-cutting
137// concerns in the order the TextMapPropagators were provided. Additionally,
138// the Fields method will return a de-duplicated slice of the keys that are
139// set with the Inject method.
140func NewCompositeTextMapPropagator(p ...TextMapPropagator) TextMapPropagator {
141 return compositeTextMapPropagator(p)
142}