forked from open-telemetry/opentelemetry-python
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding a working propagator, adding to integrations and example
Adding a full, end-to-end example of propagation at work in the example application, including a test. Adding the use of propagators into the integrations.
- Loading branch information
1 parent
876f34c
commit 384496c
Showing
8 changed files
with
184 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
opentelemetry-api/src/opentelemetry/context/propagation/tracestatehttptextformat.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import opentelemetry.trace as trace | ||
from opentelemetry.context.propagation import httptextformat | ||
|
||
|
||
class TraceStateHTTPTextFormat(httptextformat.HTTPTextFormat): | ||
"""TODO: a propagator that extracts and injects tracestate. | ||
""" | ||
|
||
def extract( | ||
self, _get_from_carrier: httptextformat.Getter, _carrier: object | ||
) -> trace.SpanContext: | ||
return trace.INVALID_SPAN_CONTEXT | ||
|
||
def inject( | ||
self, | ||
context: trace.SpanContext, | ||
set_in_carrier: httptextformat.Setter, | ||
carrier: object, | ||
) -> None: | ||
pass |
77 changes: 77 additions & 0 deletions
77
opentelemetry-api/src/opentelemetry/propagator/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import typing | ||
|
||
import opentelemetry.context.propagation.httptextformat as httptextformat | ||
import opentelemetry.trace as trace | ||
from opentelemetry.context.propagation.tracestatehttptextformat import ( | ||
TraceStateHTTPTextFormat, | ||
) | ||
|
||
|
||
class Propagator: | ||
"""Class which encapsulates propagation of values to and from context. | ||
In contrast to using the formatters directly, a propagator object can | ||
help own configuration around which formatters to use, as well as | ||
help simplify the work require for integrations to use the intended | ||
formatters. | ||
""" | ||
|
||
def __init__(self, httptextformat_instance: httptextformat.HTTPTextFormat): | ||
self._httptextformat = httptextformat_instance | ||
|
||
def extract( | ||
self, get_from_carrier: httptextformat.Getter, carrier: object | ||
) -> typing.Union[trace.SpanContext, trace.Span, None]: | ||
"""Load the parent SpanContext from values in the carrier. | ||
Using the specified HTTPTextFormatter, the propagator will | ||
extract a SpanContext from the carrier. If one is found, | ||
it will be set as the parent context of the current span. | ||
Args: | ||
get_from_carrier: a function that can retrieve zero | ||
or more values from the carrier. In the case that | ||
the value does not exist, return an empty list. | ||
carrier: and object which contains values that are | ||
used to construct a SpanContext. This object | ||
must be paired with an appropriate get_from_carrier | ||
which understands how to extract a value from it. | ||
""" | ||
span_context = self._httptextformat.extract(get_from_carrier, carrier) | ||
return span_context if span_context else trace.Tracer.CURRENT_SPAN | ||
|
||
def inject( | ||
self, | ||
tracer: trace.Tracer, | ||
set_in_carrier: httptextformat.Setter, | ||
carrier: object, | ||
) -> None: | ||
"""Inject values from the current context into the carrier. | ||
inject enables the propagation of values into HTTP clients or | ||
other objects which perform an HTTP request. Implementations | ||
should use the set_in_carrier method to set values on the | ||
carrier. | ||
Args: | ||
set_in_carrier: A setter function that can set values | ||
on the carrier. | ||
carrier: An object that a place to define HTTP headers. | ||
Should be paired with set_in_carrier, which should | ||
know how to set header values on the carrier. | ||
""" | ||
self._httptextformat.inject( | ||
tracer.get_current_span().get_context(), set_in_carrier, carrier | ||
) | ||
|
||
|
||
_PROPAGATOR = Propagator(TraceStateHTTPTextFormat()) | ||
|
||
|
||
def get_global_propagator() -> Propagator: | ||
return _PROPAGATOR | ||
|
||
|
||
def set_global_propagator(propagator: Propagator) -> None: | ||
global _PROPAGATOR # pylint:disable=global-statement | ||
_PROPAGATOR = propagator |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,57 @@ | ||
import unittest | ||
from unittest import mock | ||
|
||
import requests | ||
from werkzeug.test import Client | ||
from werkzeug.wrappers import BaseResponse | ||
|
||
import opentelemetry_example_app.flask_example as flask_example | ||
from opentelemetry.sdk import trace | ||
from opentelemetry.sdk.context.propagation import b3_format | ||
|
||
|
||
class TestFlaskExample(unittest.TestCase): | ||
@classmethod | ||
def setUpClass(cls): | ||
cls.app = flask_example.app | ||
|
||
def setUp(self): | ||
mocked_response = requests.models.Response() | ||
mocked_response.status_code = 200 | ||
mocked_response.reason = "Roger that!" | ||
self.send_patcher = mock.patch.object( | ||
requests.Session, | ||
"send", | ||
autospec=True, | ||
spec_set=True, | ||
return_value=mocked_response, | ||
) | ||
self.send = self.send_patcher.start() | ||
|
||
def tearDown(self): | ||
self.send_patcher.stop() | ||
|
||
def test_full_path(self): | ||
with self.app.test_client() as client: | ||
response = client.get("/") | ||
assert response.data.decode() == "hello" | ||
trace_id = trace.generate_trace_id() | ||
# We need to use the Werkzeug test app because | ||
# The headers are injected at the wsgi layer. | ||
# The flask test app will not include these, and | ||
# result in the values not propagated. | ||
client = Client(self.app.wsgi_app, BaseResponse) | ||
# emulate b3 headers | ||
client.get( | ||
"/", | ||
headers={ | ||
"x-b3-traceid": b3_format.format_trace_id(trace_id), | ||
"x-b3-spanid": b3_format.format_span_id( | ||
trace.generate_span_id() | ||
), | ||
"x-b3-sampled": "1", | ||
}, | ||
) | ||
# assert the http request header was propagated through. | ||
prepared_request = self.send.call_args[0][1] | ||
headers = prepared_request.headers | ||
for required_header in {"x-b3-traceid", "x-b3-spanid", "x-b3-sampled"}: | ||
assert required_header in headers | ||
assert headers["x-b3-traceid"] == b3_format.format_trace_id(trace_id) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters