1# Copyright The OpenTelemetry Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import abc
16import typing
17
18from opentelemetry.context.context import Context
19
20CarrierT = typing.TypeVar("CarrierT")
21# pylint: disable=invalid-name
22CarrierValT = typing.Union[typing.List[str], str]
23
24
25class Getter(abc.ABC, typing.Generic[CarrierT]):
26 """This class implements a Getter that enables extracting propagated
27 fields from a carrier.
28 """
29
30 @abc.abstractmethod
31 def get(
32 self, carrier: CarrierT, key: str
33 ) -> typing.Optional[typing.List[str]]:
34 """Function that can retrieve zero
35 or more values from the carrier. In the case that
36 the value does not exist, returns None.
37
38 Args:
39 carrier: An object which contains values that are used to
40 construct a Context.
41 key: key of a field in carrier.
42 Returns: first value of the propagation key or None if the key doesn't
43 exist.
44 """
45
46 @abc.abstractmethod
47 def keys(self, carrier: CarrierT) -> typing.List[str]:
48 """Function that can retrieve all the keys in a carrier object.
49
50 Args:
51 carrier: An object which contains values that are
52 used to construct a Context.
53 Returns:
54 list of keys from the carrier.
55 """
56
57
58class Setter(abc.ABC, typing.Generic[CarrierT]):
59 """This class implements a Setter that enables injecting propagated
60 fields into a carrier.
61 """
62
63 @abc.abstractmethod
64 def set(self, carrier: CarrierT, key: str, value: str) -> None:
65 """Function that can set a value into a carrier""
66
67 Args:
68 carrier: An object which contains values that are used to
69 construct a Context.
70 key: key of a field in carrier.
71 value: value for a field in carrier.
72 """
73
74
75class DefaultGetter(Getter[typing.Mapping[str, CarrierValT]]):
76 def get(
77 self, carrier: typing.Mapping[str, CarrierValT], key: str
78 ) -> typing.Optional[typing.List[str]]:
79 """Getter implementation to retrieve a value from a dictionary.
80
81 Args:
82 carrier: dictionary in which to get value
83 key: the key used to get the value
84 Returns:
85 A list with a single string with the value if it exists, else None.
86 """
87 val = carrier.get(key, None)
88 if val is None:
89 return None
90 if isinstance(val, typing.Iterable) and not isinstance(val, str):
91 return list(val)
92 return [val]
93
94 def keys(
95 self, carrier: typing.Mapping[str, CarrierValT]
96 ) -> typing.List[str]:
97 """Keys implementation that returns all keys from a dictionary."""
98 return list(carrier.keys())
99
100
101default_getter: Getter[CarrierT] = DefaultGetter() # type: ignore
102
103
104class DefaultSetter(Setter[typing.MutableMapping[str, CarrierValT]]):
105 def set(
106 self,
107 carrier: typing.MutableMapping[str, CarrierValT],
108 key: str,
109 value: CarrierValT,
110 ) -> None:
111 """Setter implementation to set a value into a dictionary.
112
113 Args:
114 carrier: dictionary in which to set value
115 key: the key used to set the value
116 value: the value to set
117 """
118 carrier[key] = value
119
120
121default_setter: Setter[CarrierT] = DefaultSetter() # type: ignore
122
123
124class TextMapPropagator(abc.ABC):
125 """This class provides an interface that enables extracting and injecting
126 context into headers of HTTP requests. HTTP frameworks and clients
127 can integrate with TextMapPropagator by providing the object containing the
128 headers, and a getter and setter function for the extraction and
129 injection of values, respectively.
130
131 """
132
133 @abc.abstractmethod
134 def extract(
135 self,
136 carrier: CarrierT,
137 context: typing.Optional[Context] = None,
138 getter: Getter[CarrierT] = default_getter,
139 ) -> Context:
140 """Create a Context from values in the carrier.
141
142 The extract function should retrieve values from the carrier
143 object using getter, and use values to populate a
144 Context value and return it.
145
146 Args:
147 getter: a function that can retrieve zero
148 or more values from the carrier. In the case that
149 the value does not exist, return an empty list.
150 carrier: and object which contains values that are
151 used to construct a Context. This object
152 must be paired with an appropriate getter
153 which understands how to extract a value from it.
154 context: an optional Context to use. Defaults to root
155 context if not set.
156 Returns:
157 A Context with configuration found in the carrier.
158
159 """
160
161 @abc.abstractmethod
162 def inject(
163 self,
164 carrier: CarrierT,
165 context: typing.Optional[Context] = None,
166 setter: Setter[CarrierT] = default_setter,
167 ) -> None:
168 """Inject values from a Context into a carrier.
169
170 inject enables the propagation of values into HTTP clients or
171 other objects which perform an HTTP request. Implementations
172 should use the `Setter` 's set method to set values on the
173 carrier.
174
175 Args:
176 carrier: An object that a place to define HTTP headers.
177 Should be paired with setter, which should
178 know how to set header values on the carrier.
179 context: an optional Context to use. Defaults to current
180 context if not set.
181 setter: An optional `Setter` object that can set values
182 on the carrier.
183
184 """
185
186 @property
187 @abc.abstractmethod
188 def fields(self) -> typing.Set[str]:
189 """
190 Gets the fields set in the carrier by the `inject` method.
191
192 If the carrier is reused, its fields that correspond with the ones
193 present in this attribute should be deleted before calling `inject`.
194
195 Returns:
196 A set with the fields set in `inject`.
197 """