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(self, carrier: Mapping[str, CarrierValT], key: str) -> list[str] | None:
65 """Getter implementation to retrieve a value from a dictionary.
66
67 Args:
68 carrier: dictionary in which to get value
69 key: the key used to get the value
70 Returns:
71 A list with a single string with the value if it exists, else None.
72 """
73 val = carrier.get(key, None)
74 if val is None:
75 return None
76 if isinstance(val, Iterable) and not isinstance(val, str):
77 return list(val)
78 return [val]
79
80 def keys(self, carrier: Mapping[str, CarrierValT]) -> list[str]:
81 """Keys implementation that returns all keys from a dictionary."""
82 return list(carrier.keys())
83
84
85default_getter: Getter[CarrierT] = DefaultGetter() # type: ignore
86
87
88class DefaultSetter(Setter[MutableMapping[str, CarrierValT]]):
89 def set(
90 self,
91 carrier: MutableMapping[str, CarrierValT],
92 key: str,
93 value: CarrierValT,
94 ) -> None:
95 """Setter implementation to set a value into a dictionary.
96
97 Args:
98 carrier: dictionary in which to set value
99 key: the key used to set the value
100 value: the value to set
101 """
102 carrier[key] = value
103
104
105default_setter: Setter[CarrierT] = DefaultSetter() # type: ignore
106
107
108class TextMapPropagator(abc.ABC):
109 """This class provides an interface that enables extracting and injecting
110 context into headers of HTTP requests. HTTP frameworks and clients
111 can integrate with TextMapPropagator by providing the object containing the
112 headers, and a getter and setter function for the extraction and
113 injection of values, respectively.
114
115 """
116
117 @abc.abstractmethod
118 def extract(
119 self,
120 carrier: CarrierT,
121 context: Context | None = None,
122 getter: Getter[CarrierT] = default_getter,
123 ) -> Context:
124 """Create a Context from values in the carrier.
125
126 The extract function should retrieve values from the carrier
127 object using getter, and use values to populate a
128 Context value and return it.
129
130 Args:
131 getter: a function that can retrieve zero
132 or more values from the carrier. In the case that
133 the value does not exist, return an empty list.
134 carrier: and object which contains values that are
135 used to construct a Context. This object
136 must be paired with an appropriate getter
137 which understands how to extract a value from it.
138 context: an optional Context to use. Defaults to root
139 context if not set.
140 Returns:
141 A Context with configuration found in the carrier.
142
143 """
144
145 @abc.abstractmethod
146 def inject(
147 self,
148 carrier: CarrierT,
149 context: Context | None = None,
150 setter: Setter[CarrierT] = default_setter,
151 ) -> None:
152 """Inject values from a Context into a carrier.
153
154 inject enables the propagation of values into HTTP clients or
155 other objects which perform an HTTP request. Implementations
156 should use the `Setter` 's set method to set values on the
157 carrier.
158
159 Args:
160 carrier: An object that a place to define HTTP headers.
161 Should be paired with setter, which should
162 know how to set header values on the carrier.
163 context: an optional Context to use. Defaults to current
164 context if not set.
165 setter: An optional `Setter` object that can set values
166 on the carrier.
167
168 """
169
170 @property
171 @abc.abstractmethod
172 def fields(self) -> set[str]:
173 """
174 Gets the fields set in the carrier by the `inject` method.
175
176 If the carrier is reused, its fields that correspond with the ones
177 present in this attribute should be deleted before calling `inject`.
178
179 Returns:
180 A set with the fields set in `inject`.
181 """