Skip to content

Commit 6e8d433

Browse files
committed
Authoring a propagator class
A Propagator class can help streamline integrations that require extracting and injecting context.
1 parent 1f37b2a commit 6e8d433

File tree

5 files changed

+144
-1
lines changed

5 files changed

+144
-1
lines changed

ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from urllib.parse import urlparse
2222

2323
from requests.sessions import Session
24+
from opentelemetry import propagator
2425

2526

2627
# NOTE: Currently we force passing a tracer. But in turn, this forces the user
@@ -77,6 +78,10 @@ def instrumented_request(self, method, url, *args, **kwargs):
7778
span.set_attribute("http.status_code", result.status_code)
7879
span.set_attribute("http.status_text", result.reason)
7980

81+
propagator.global_propagator().inject(
82+
result.headers.set, result.headers
83+
)
84+
8085
return result
8186

8287
# TODO: How to handle exceptions? Should we create events for them? Set

ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import wsgiref.util as wsgiref_util
2323

2424
from opentelemetry import trace
25+
from opentelemetry import propagator
2526
from opentelemetry.ext.wsgi.version import __version__ # noqa
2627

2728

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Copyright 2019, 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+
import abc
15+
from opentelemetry import loader
16+
import opentelemetry.propagator.httptextformat as httptextformat
17+
import opentelemetry.propagator.binaryformat as binaryformat
18+
from opentelemetry.context import BaseRuntimeContext, Context
19+
20+
21+
class Propagator(abc.ABC):
22+
"""Class which encapsulates propagation of values to and from context.
23+
24+
In contract to using the formatters directly, a propagator object can
25+
help own configuration around which formatters to use, as well as
26+
help simplify the work require for integrations to use the intended
27+
formatters.
28+
"""
29+
30+
def __init__(
31+
self,
32+
context: BaseRuntimeContext,
33+
http_format: httptextformat.HTTPTextFormat,
34+
binary_format: binaryformat.BinaryFormat,
35+
):
36+
self._context = context
37+
self._http_format = http_format
38+
self._binary_format = binary_format
39+
40+
@classmethod
41+
def create(
42+
cls,
43+
http_format: httptextformat.HTTPTextFormat,
44+
binary_format: binaryformat.BinaryFormat,
45+
) -> "Propagator":
46+
"""Create a propagator with the current context."""
47+
return Propagator(Context, http_format, binary_format)
48+
49+
@abc.abstractmethod
50+
def extract(
51+
self, get_from_carrier: httptextformat.Getter, carrier: object
52+
):
53+
"""Extract context data from the carrier, add to the context.
54+
55+
Using the http_format specified in the constructor, extract the
56+
data form the carrier passed and add values into the context object.
57+
58+
Args:
59+
get_from_carrier: a function that can retrieve zero
60+
or more values from the carrier. In the case that
61+
the value does not exist, return an empty list.
62+
carrier: and object which contains values that are
63+
used to construct a SpanContext. This object
64+
must be paired with an appropriate get_from_carrier
65+
which understands how to extract a value from it.
66+
"""
67+
68+
@abc.abstractmethod
69+
def inject(
70+
self, set_in_carrier: httptextformat.Setter, carrier: object
71+
) -> None:
72+
"""Inject values from context into a carrier.
73+
74+
inject enables the propagation of values into HTTP clients or
75+
other objects which perform an HTTP request. Using the
76+
httptextformat configured, inject the context data into
77+
the carrier with the set_in_carrier method passed.
78+
79+
Args:
80+
set_in_carrier: A setter function that can set values
81+
on the carrier.
82+
carrier: An object that a place to define HTTP headers.
83+
Should be paired with set_in_carrier, which should
84+
know how to set header values on the carrier.
85+
"""
86+
87+
@abc.abstractmethod
88+
def from_bytes(self, byte_representation: bytes) -> None:
89+
"""Populate context with data that existed in the byte representation.
90+
91+
Using the configured binary_format, extract values from the bytes object
92+
passed into the context object configured.
93+
94+
Args:
95+
byte_representation: the bytes to deserialize.
96+
"""
97+
98+
@abc.abstractmethod
99+
def to_bytes(self) -> bytes:
100+
"""Creates a byte representation of the context configured.
101+
102+
to_bytes should read values from the configured context and
103+
return a bytes object to represent it.
104+
105+
Returns:
106+
A bytes representation of the DistributedContext.
107+
"""
108+
109+
110+
def set_propagator(propagator_instance: Propagator) -> None:
111+
"""Set the propagator instance singleton.
112+
"""
113+
global _PROPAGATOR
114+
_PROPAGATOR = propagator_instance
115+
116+
117+
def global_propagator() -> Propagator:
118+
"""Return the singleton propagator instance."""
119+
return _PROPAGATOR
120+
121+
122+
_PROPAGATOR = None # type: typing.Optional[Propagator]

opentelemetry-api/src/opentelemetry/propagator/binaryformat.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def to_bytes(context: BaseRuntimeContext) -> bytes:
4545
def from_bytes(
4646
context: BaseRuntimeContext, byte_representation: bytes
4747
) -> None:
48-
"""Populate context with context data that existed in the byte representation.
48+
"""Populate context with data that existed in the byte representation.
4949
5050
from_bytes should add values into the context from the data serialized in the
5151
byte_representation passed. If it is not possible to read in a proper
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from opentelemetry.propagator import Propagator as PropagatorAPI
2+
3+
4+
class Propagator(PropagatorAPI):
5+
def extract(self, get_from_carrier, carrier):
6+
self.http_format.extract(self.context, get_from_carrier, carrier)
7+
8+
def inject(self, set_in_carrier, carrier):
9+
self.http_format.inject(self.context, set_in_carrier, carrier)
10+
11+
def from_bytes(self, byte_representation):
12+
self.binary_formatter.from_bytes(self.context, byte_representation)
13+
14+
def to_bytes(self):
15+
return self.binary_formatter.to_bytes(self.context)

0 commit comments

Comments
 (0)