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