From 8ec609f966c5853a8b51475807940fa77faf7251 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 11 Mar 2021 15:58:17 -0600 Subject: [PATCH 01/28] Remove setters and getters Fixes #1644 --- .github/workflows/test.yml | 2 +- CHANGELOG.md | 3 + docs/conf.py | 1 - docs/examples/auto-instrumentation/README.rst | 2 +- docs/examples/auto-instrumentation/client.py | 2 +- .../server_instrumented.py | 3 +- docs/examples/datadog_exporter/client.py | 2 +- docs/examples/django/client.py | 2 +- .../baggage/propagation/__init__.py | 84 +++--- .../src/opentelemetry/propagate/__init__.py | 53 ++-- .../opentelemetry/propagators/composite.py | 46 ++-- .../src/opentelemetry/propagators/textmap.py | 127 ++------- .../trace/propagation/tracecontext.py | 128 ++++----- .../src/opentelemetry/trace/span.py | 38 +-- .../tests/baggage/test_baggage_propagation.py | 150 +++++------ .../tests/propagators/test_composite.py | 54 ++-- .../propagators/test_global_httptextformat.py | 38 ++- .../test_tracecontexthttptextformat.py | 146 +++++----- .../tests/trace/test_tracestate.py | 42 +-- .../opentelemetry/propagators/b3/__init__.py | 80 ++---- .../propagation/test_benchmark_b3_format.py | 3 - .../tests/test_b3_format.py | 253 +++++++++--------- .../propagators/jaeger/__init__.py | 138 ++++------ .../tests/test_jaeger_propagator.py | 83 +++--- .../shim/opentracing_shim/__init__.py | 6 +- .../tests/test_shim.py | 16 +- .../src/opentelemetry/test/mock_textmap.py | 73 ++--- 27 files changed, 666 insertions(+), 909 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 908cf71caa3..48099d10b83 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: 5bc0fa1611502be47a1f4eb550fe255e4b707ba1 + CONTRIB_REPO_SHA: 1300fcec899a37bb41145b602c938221c696607b jobs: build: diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a8e24366d1..8b13214748e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v0.18b0...HEAD) +- Remove setters and getters + ([#1690](https://github.com/open-telemetry/opentelemetry-python/pull/1690)) + ### Added - Document how to work with fork process web server models(Gunicorn, uWSGI etc...) ([#1609](https://github.com/open-telemetry/opentelemetry-python/pull/1609)) diff --git a/docs/conf.py b/docs/conf.py index d23cebfe96c..5d44c24dd22 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -104,7 +104,6 @@ ("py:class", "opentelemetry.trace._LinkBase",), # TODO: Understand why sphinx is not able to find this local class ("py:class", "opentelemetry.propagators.textmap.TextMapPropagator",), - ("py:class", "opentelemetry.propagators.textmap.DictGetter",), ("any", "opentelemetry.propagators.textmap.TextMapPropagator.extract",), ("any", "opentelemetry.propagators.textmap.TextMapPropagator.inject",), ] diff --git a/docs/examples/auto-instrumentation/README.rst b/docs/examples/auto-instrumentation/README.rst index 607aa1b44b7..0a6c07bb408 100644 --- a/docs/examples/auto-instrumentation/README.rst +++ b/docs/examples/auto-instrumentation/README.rst @@ -37,7 +37,7 @@ Manually instrumented server def server_request(): with tracer.start_as_current_span( "server_request", - context=propagators.extract(DictGetter(), request.headers + context=propagators.extract(request.headers ), ): print(request.args.get("param")) diff --git a/docs/examples/auto-instrumentation/client.py b/docs/examples/auto-instrumentation/client.py index fefc1f67b98..cc948cc54b8 100644 --- a/docs/examples/auto-instrumentation/client.py +++ b/docs/examples/auto-instrumentation/client.py @@ -37,7 +37,7 @@ with tracer.start_as_current_span("client-server"): headers = {} - propagators.inject(dict.__setitem__, headers) + propagators.inject(headers) requested = get( "http://localhost:8082/server_request", params={"param": argv[1]}, diff --git a/docs/examples/auto-instrumentation/server_instrumented.py b/docs/examples/auto-instrumentation/server_instrumented.py index 1ac1bd6b71b..652358e3a2e 100644 --- a/docs/examples/auto-instrumentation/server_instrumented.py +++ b/docs/examples/auto-instrumentation/server_instrumented.py @@ -17,7 +17,6 @@ from opentelemetry import trace from opentelemetry.instrumentation.wsgi import collect_request_attributes from opentelemetry.propagate import extract -from opentelemetry.propagators.textmap import DictGetter from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( ConsoleSpanExporter, @@ -38,7 +37,7 @@ def server_request(): with tracer.start_as_current_span( "server_request", - context=extract(DictGetter(), request.headers), + context=extract(request.headers), kind=trace.SpanKind.SERVER, attributes=collect_request_attributes(request.environ), ): diff --git a/docs/examples/datadog_exporter/client.py b/docs/examples/datadog_exporter/client.py index 6b4b5d00ec1..7c6196ad4ab 100644 --- a/docs/examples/datadog_exporter/client.py +++ b/docs/examples/datadog_exporter/client.py @@ -47,7 +47,7 @@ with tracer.start_as_current_span("client-server"): headers = {} - inject(dict.__setitem__, headers) + inject(headers) requested = get( "http://localhost:8082/server_request", params={"param": argv[1]}, diff --git a/docs/examples/django/client.py b/docs/examples/django/client.py index bc3606cbe76..3ae0cb6e1cf 100644 --- a/docs/examples/django/client.py +++ b/docs/examples/django/client.py @@ -36,7 +36,7 @@ with tracer.start_as_current_span("client-server"): headers = {} - inject(dict.__setitem__, headers) + inject(headers) requested = get( "http://localhost:8000", params={"param": argv[1]}, diff --git a/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py b/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py index e6d1c4207bc..20337ad81f3 100644 --- a/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py +++ b/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py @@ -11,29 +11,26 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# -import typing -import urllib.parse + +from typing import Dict, Optional, Set +from urllib.parse import quote_plus, unquote from opentelemetry import baggage from opentelemetry.context import get_current from opentelemetry.context.context import Context -from opentelemetry.propagators import textmap +from opentelemetry.propagators.textmap import TextMapPropagator -class W3CBaggagePropagator(textmap.TextMapPropagator): +class W3CBaggagePropagator(TextMapPropagator): """Extracts and injects Baggage which is used to annotate telemetry.""" - _MAX_HEADER_LENGTH = 8192 - _MAX_PAIR_LENGTH = 4096 - _MAX_PAIRS = 180 - _BAGGAGE_HEADER_NAME = "baggage" + _baggage_header_name = "baggage" + _max_header_length = 9182 + _max_pairs = 180 + _max_pair_length = 4096 def extract( - self, - getter: textmap.Getter[textmap.TextMapPropagatorT], - carrier: textmap.TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> Context: """Extract Baggage from the carrier. @@ -44,38 +41,31 @@ def extract( if context is None: context = get_current() - header = _extract_first_element( - getter.get(carrier, self._BAGGAGE_HEADER_NAME) - ) + header = carrier.get(self._baggage_header_name) - if not header or len(header) > self._MAX_HEADER_LENGTH: + if header is None or len(header) > self._max_header_length: return context - baggage_entries = header.split(",") - total_baggage_entries = self._MAX_PAIRS - for entry in baggage_entries: + total_baggage_entries = self._max_pairs + + for entry in header.split(","): if total_baggage_entries <= 0: return context total_baggage_entries -= 1 - if len(entry) > self._MAX_PAIR_LENGTH: + if len(entry) > self._max_pair_length: continue - try: + if "=" in entry: name, value = entry.split("=", 1) - except Exception: # pylint: disable=broad-except - continue - context = baggage.set_baggage( - urllib.parse.unquote(name).strip(), - urllib.parse.unquote(value).strip(), - context=context, - ) + context = baggage.set_baggage( + unquote(name).strip(), + unquote(value).strip(), + context=context, + ) return context def inject( - self, - set_in_carrier: textmap.Setter[textmap.TextMapPropagatorT], - carrier: textmap.TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> None: """Injects Baggage into the carrier. @@ -83,28 +73,14 @@ def inject( `opentelemetry.propagators.textmap.TextMapPropagator.inject` """ baggage_entries = baggage.get_all(context=context) - if not baggage_entries: - return - baggage_string = _format_baggage(baggage_entries) - set_in_carrier(carrier, self._BAGGAGE_HEADER_NAME, baggage_string) + if baggage_entries: + carrier[self._baggage_header_name] = ",".join( + key + "=" + quote_plus(str(value)) + for key, value in baggage_entries.items() + ) @property - def fields(self) -> typing.Set[str]: + def fields(self) -> Set[str]: """Returns a set with the fields set in `inject`.""" - return {self._BAGGAGE_HEADER_NAME} - - -def _format_baggage(baggage_entries: typing.Mapping[str, object]) -> str: - return ",".join( - key + "=" + urllib.parse.quote_plus(str(value)) - for key, value in baggage_entries.items() - ) - - -def _extract_first_element( - items: typing.Optional[typing.Iterable[textmap.TextMapPropagatorT]], -) -> typing.Optional[textmap.TextMapPropagatorT]: - if items is None: - return None - return next(iter(items), None) + return {self._baggage_header_name} diff --git a/opentelemetry-api/src/opentelemetry/propagate/__init__.py b/opentelemetry-api/src/opentelemetry/propagate/__init__.py index 44f9897a532..569c53d2f21 100644 --- a/opentelemetry-api/src/opentelemetry/propagate/__init__.py +++ b/opentelemetry-api/src/opentelemetry/propagate/__init__.py @@ -40,23 +40,12 @@ PROPAGATOR = propagators.get_global_textmap() - def get_header_from_flask_request(request, key): - return request.headers.get_all(key) - - def set_header_into_requests_request(request: requests.Request, - key: str, value: str): - request.headers[key] = value - def example_route(): - context = PROPAGATOR.extract( - get_header_from_flask_request, - flask.request - ) + context = PROPAGATOR.extract(flask.request) request_to_downstream = requests.Request( "GET", "http://httpbin.org/get" ) PROPAGATOR.inject( - set_header_into_requests_request, request_to_downstream, context=context ) @@ -68,23 +57,22 @@ def example_route(): https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/api-propagators.md """ -import typing from logging import getLogger from os import environ +from typing import Dict, Optional from pkg_resources import iter_entry_points from opentelemetry.context.context import Context from opentelemetry.environment_variables import OTEL_PROPAGATORS -from opentelemetry.propagators import composite, textmap +from opentelemetry.propagators import composite +from opentelemetry.propagators.textmap import TextMapPropagator -logger = getLogger(__name__) +_logger = getLogger(__name__) def extract( - getter: textmap.Getter[textmap.TextMapPropagatorT], - carrier: textmap.TextMapPropagatorT, - context: typing.Optional[Context] = None, + carrier: Dict[str, str], context: Optional[Context] = None, ) -> Context: """Uses the configured propagator to extract a Context from the carrier. @@ -99,26 +87,21 @@ def extract( context: an optional Context to use. Defaults to current context if not set. """ - return get_global_textmap().extract(getter, carrier, context) + return get_global_textmap().extract(carrier, context) def inject( - set_in_carrier: textmap.Setter[textmap.TextMapPropagatorT], - carrier: textmap.TextMapPropagatorT, - context: typing.Optional[Context] = None, + carrier: Dict[str, str], context: Optional[Context] = None, ) -> None: """Uses the configured propagator to inject a Context into the carrier. Args: - set_in_carrier: A setter function that can set values - on the carrier. - carrier: An object that contains a representation of HTTP - headers. Should be paired with set_in_carrier, which - should know how to set header values on the carrier. + carrier: A dict-like object that contains a representation of HTTP + headers. context: an optional Context to use. Defaults to current context if not set. """ - get_global_textmap().inject(set_in_carrier, carrier, context) + get_global_textmap().inject(carrier, context) try: @@ -138,16 +121,16 @@ def inject( ) except Exception: # pylint: disable=broad-except - logger.exception("Failed to load configured propagators") + _logger.error("Failed to load configured propagators") raise -_HTTP_TEXT_FORMAT = composite.CompositeHTTPPropagator(propagators) # type: ignore +_textmap_propagator = composite.CompositeHTTPPropagator(propagators) # type: ignore -def get_global_textmap() -> textmap.TextMapPropagator: - return _HTTP_TEXT_FORMAT +def get_global_textmap() -> TextMapPropagator: + return _textmap_propagator -def set_global_textmap(http_text_format: textmap.TextMapPropagator,) -> None: - global _HTTP_TEXT_FORMAT # pylint:disable=global-statement - _HTTP_TEXT_FORMAT = http_text_format # type: ignore +def set_global_textmap(http_text_format: TextMapPropagator,) -> None: + global _textmap_propagator # pylint:disable=global-statement + _textmap_propagator = http_text_format # type: ignore diff --git a/opentelemetry-api/src/opentelemetry/propagators/composite.py b/opentelemetry-api/src/opentelemetry/propagators/composite.py index 92dc6b8a380..858483a69dd 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/composite.py +++ b/opentelemetry-api/src/opentelemetry/propagators/composite.py @@ -11,16 +11,17 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import logging -import typing + +from logging import getLogger +from typing import Dict, Optional, Sequence, Set from opentelemetry.context.context import Context -from opentelemetry.propagators import textmap +from opentelemetry.propagators.textmap import TextMapPropagator -logger = logging.getLogger(__name__) +_logger = getLogger(__name__) -class CompositeHTTPPropagator(textmap.TextMapPropagator): +class CompositeHTTPPropagator(TextMapPropagator): """CompositeHTTPPropagator provides a mechanism for combining multiple propagators into a single one. @@ -28,46 +29,39 @@ class CompositeHTTPPropagator(textmap.TextMapPropagator): propagators: the list of propagators to use """ - def __init__( - self, propagators: typing.Sequence[textmap.TextMapPropagator] - ) -> None: + def __init__(self, propagators: Sequence[TextMapPropagator]) -> None: self._propagators = propagators def extract( - self, - getter: textmap.Getter[textmap.TextMapPropagatorT], - carrier: textmap.TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> Context: - """Run each of the configured propagators with the given context and carrier. + """Run each of the configured propagators with the given context and + carrier. Propagators are run in the order they are configured, if multiple - propagators write the same context key, the propagator later in the list - will override previous propagators. + propagators write the same context key, the last propagator that writes + the context key will override previous propagators. See `opentelemetry.propagators.textmap.TextMapPropagator.extract` """ for propagator in self._propagators: - context = propagator.extract(getter, carrier, context) + context = propagator.extract(carrier, context) return context # type: ignore def inject( - self, - set_in_carrier: textmap.Setter[textmap.TextMapPropagatorT], - carrier: textmap.TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> None: - """Run each of the configured propagators with the given context and carrier. - Propagators are run in the order they are configured, if multiple - propagators write the same carrier key, the propagator later in the list - will override previous propagators. + """Run each of the configured propagators with the given context and + carrier. Propagators are run in the order they are configured, if + multiple propagators write the same carrier key, the last propagator + that writes the carrier key will override previous propagators. See `opentelemetry.propagators.textmap.TextMapPropagator.inject` """ for propagator in self._propagators: - propagator.inject(set_in_carrier, carrier, context) + propagator.inject(carrier, context) @property - def fields(self) -> typing.Set[str]: + def fields(self) -> Set[str]: """Returns a set with the fields set in `inject`. See diff --git a/opentelemetry-api/src/opentelemetry/propagators/textmap.py b/opentelemetry-api/src/opentelemetry/propagators/textmap.py index cf93d1d6319..22b5946ad09 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/textmap.py +++ b/opentelemetry-api/src/opentelemetry/propagators/textmap.py @@ -12,139 +12,56 @@ # See the License for the specific language governing permissions and # limitations under the License. -import abc -import typing +from abc import ABC, abstractmethod +from typing import Dict, Optional, Set from opentelemetry.context.context import Context -TextMapPropagatorT = typing.TypeVar("TextMapPropagatorT") -CarrierValT = typing.Union[typing.List[str], str] -Setter = typing.Callable[[TextMapPropagatorT, str, str], None] - - -class Getter(typing.Generic[TextMapPropagatorT]): - """This class implements a Getter that enables extracting propagated - fields from a carrier. - """ - - def get( - self, carrier: TextMapPropagatorT, key: str - ) -> typing.Optional[typing.List[str]]: - """Function that can retrieve zero - or more values from the carrier. In the case that - the value does not exist, returns None. - - Args: - carrier: An object which contains values that are used to - construct a Context. - key: key of a field in carrier. - Returns: first value of the propagation key or None if the key doesn't - exist. - """ - raise NotImplementedError() - - def keys(self, carrier: TextMapPropagatorT) -> typing.List[str]: - """Function that can retrieve all the keys in a carrier object. - - Args: - carrier: An object which contains values that are - used to construct a Context. - Returns: - list of keys from the carrier. - """ - raise NotImplementedError() - - -class DictGetter(Getter[typing.Dict[str, CarrierValT]]): - def get( - self, carrier: typing.Dict[str, CarrierValT], key: str - ) -> typing.Optional[typing.List[str]]: - """Getter implementation to retrieve a value from a dictionary. - - Args: - carrier: dictionary in which header - key: the key used to get the value - Returns: - A list with a single string with the value if it exists, else None. - """ - val = carrier.get(key, None) - if val is None: - return None - if isinstance(val, typing.Iterable) and not isinstance(val, str): - return list(val) - return [val] - - def keys(self, carrier: typing.Dict[str, CarrierValT]) -> typing.List[str]: - """Keys implementation that returns all keys from a dictionary.""" - return list(carrier.keys()) - - -class TextMapPropagator(abc.ABC): +class TextMapPropagator(ABC): """This class provides an interface that enables extracting and injecting - context into headers of HTTP requests. HTTP frameworks and clients - can integrate with TextMapPropagator by providing the object containing the - headers, and a getter and setter function for the extraction and - injection of values, respectively. - + context into headers of HTTP requests. HTTP frameworks and clients can + integrate with TextMapPropagator by providing the object containing the + headers. """ - @abc.abstractmethod + @abstractmethod def extract( - self, - getter: Getter[TextMapPropagatorT], - carrier: TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> Context: """Create a Context from values in the carrier. - The extract function should retrieve values from the carrier - object using getter, and use values to populate a - Context value and return it. + Retrieves values from the carrier object and uses them to populate a + context and returns it afterwards. Args: - getter: 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 Context. This object - must be paired with an appropriate getter - which understands how to extract a value from it. - context: an optional Context to use. Defaults to current - context if not set. + carrier: and object which contains values that are used to + construct a Context. + context: an optional Context to use. Defaults to current context if + not set. Returns: - A Context with configuration found in the carrier. - + A Context with the configuration found in the carrier. """ - @abc.abstractmethod + @abstractmethod def inject( - self, - set_in_carrier: Setter[TextMapPropagatorT], - carrier: TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> None: """Inject values from a Context into a 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. + Enables the propagation of values into HTTP clients or other objects + which perform an HTTP request. 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. + carrier: An dict-like object where to store HTTP headers. context: an optional Context to use. Defaults to current context if not set. """ @property - @abc.abstractmethod - def fields(self) -> typing.Set[str]: + @abstractmethod + def fields(self) -> Set[str]: """ Gets the fields set in the carrier by the `inject` method. diff --git a/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py b/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py index 480e716bf78..5f5dc2df810 100644 --- a/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py +++ b/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py @@ -11,111 +11,117 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# -import re -import typing -import opentelemetry.trace as trace +from re import compile as compile_ +from re import search +from typing import Dict, Optional, Set + from opentelemetry.context.context import Context -from opentelemetry.propagators import textmap -from opentelemetry.trace import format_span_id, format_trace_id +from opentelemetry.propagators.textmap import TextMapPropagator +from opentelemetry.trace import ( + INVALID_SPAN, + INVALID_SPAN_CONTEXT, + NonRecordingSpan, + SpanContext, + TraceFlags, + format_span_id, + format_trace_id, + get_current_span, + set_span_in_context, +) from opentelemetry.trace.span import TraceState -class TraceContextTextMapPropagator(textmap.TextMapPropagator): +class TraceContextTextMapPropagator(TextMapPropagator): """Extracts and injects using w3c TraceContext's headers.""" - _TRACEPARENT_HEADER_NAME = "traceparent" - _TRACESTATE_HEADER_NAME = "tracestate" - _TRACEPARENT_HEADER_FORMAT = ( - "^[ \t]*([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})" - + "(-.*)?[ \t]*$" + _traceparent_header_name = "traceparent" + _tracestate_header_name = "tracestate" + _traceparent_header_format_re = compile_( + r"^\s*(?P[0-9a-f]{2})-" + r"(?P[0-9a-f]{32})-" + r"(?P[0-9a-f]{16})-" + r"(?P[0-9a-f]{2})" + r"(?P.+?)?\s*$" ) - _TRACEPARENT_HEADER_FORMAT_RE = re.compile(_TRACEPARENT_HEADER_FORMAT) def extract( - self, - getter: textmap.Getter[textmap.TextMapPropagatorT], - carrier: textmap.TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> Context: """Extracts SpanContext from the carrier. See `opentelemetry.propagators.textmap.TextMapPropagator.extract` """ - header = getter.get(carrier, self._TRACEPARENT_HEADER_NAME) + header = carrier.get(self._traceparent_header_name) + + if header is None: + return set_span_in_context(INVALID_SPAN, context) - if not header: - return trace.set_span_in_context(trace.INVALID_SPAN, context) + match = search(self._traceparent_header_format_re, header) + if match is None: + return set_span_in_context(INVALID_SPAN, context) - match = re.search(self._TRACEPARENT_HEADER_FORMAT_RE, header[0]) - if not match: - return trace.set_span_in_context(trace.INVALID_SPAN, context) + version = match.group("version") + trace_id = match.group("trace_id") + span_id = match.group("span_id") - version = match.group(1) - trace_id = match.group(2) - span_id = match.group(3) - trace_flags = match.group(4) + if ( + version == "ff" + or trace_id == "0" * 32 + or span_id == "0" * 16 + or (version == "00" and match.group("remainder")) + ): - if trace_id == "0" * 32 or span_id == "0" * 16: - return trace.set_span_in_context(trace.INVALID_SPAN, context) + return set_span_in_context(INVALID_SPAN, context) - if version == "00": - if match.group(5): - return trace.set_span_in_context(trace.INVALID_SPAN, context) - if version == "ff": - return trace.set_span_in_context(trace.INVALID_SPAN, context) + tracestate_headers = carrier.get(self._tracestate_header_name) - tracestate_headers = getter.get(carrier, self._TRACESTATE_HEADER_NAME) if tracestate_headers is None: tracestate = None else: tracestate = TraceState.from_header(tracestate_headers) - span_context = trace.SpanContext( - trace_id=int(trace_id, 16), - span_id=int(span_id, 16), - is_remote=True, - trace_flags=trace.TraceFlags(trace_flags), - trace_state=tracestate, - ) - return trace.set_span_in_context( - trace.NonRecordingSpan(span_context), context + return set_span_in_context( + NonRecordingSpan( + SpanContext( + trace_id=int(trace_id, 16), + span_id=int(span_id, 16), + is_remote=True, + trace_flags=TraceFlags(match.group("trace_flags")), + trace_state=tracestate, + ) + ), + context, ) def inject( - self, - set_in_carrier: textmap.Setter[textmap.TextMapPropagatorT], - carrier: textmap.TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> None: """Injects SpanContext into the carrier. See `opentelemetry.propagators.textmap.TextMapPropagator.inject` """ - span = trace.get_current_span(context) - span_context = span.get_span_context() - if span_context == trace.INVALID_SPAN_CONTEXT: + span_context = get_current_span(context).get_span_context() + if span_context == INVALID_SPAN_CONTEXT: return - traceparent_string = "00-{trace_id}-{span_id}-{:02x}".format( + carrier[ + self._traceparent_header_name + ] = "00-{trace_id}-{span_id}-{:02x}".format( span_context.trace_flags, trace_id=format_trace_id(span_context.trace_id), span_id=format_span_id(span_context.span_id), ) - set_in_carrier( - carrier, self._TRACEPARENT_HEADER_NAME, traceparent_string - ) + if span_context.trace_state: - tracestate_string = span_context.trace_state.to_header() - set_in_carrier( - carrier, self._TRACESTATE_HEADER_NAME, tracestate_string - ) + carrier[ + self._tracestate_header_name + ] = span_context.trace_state.to_header() @property - def fields(self) -> typing.Set[str]: + def fields(self) -> Set[str]: """Returns a set with the fields set in `inject`. See `opentelemetry.propagators.textmap.TextMapPropagator.fields` """ - return {self._TRACEPARENT_HEADER_NAME, self._TRACESTATE_HEADER_NAME} + return {self._traceparent_header_name, self._tracestate_header_name} diff --git a/opentelemetry-api/src/opentelemetry/trace/span.py b/opentelemetry-api/src/opentelemetry/trace/span.py index d04cdfa49dd..095811b0df2 100644 --- a/opentelemetry-api/src/opentelemetry/trace/span.py +++ b/opentelemetry-api/src/opentelemetry/trace/span.py @@ -335,11 +335,11 @@ def to_header(self) -> str: return ",".join(key + "=" + value for key, value in self._dict.items()) @classmethod - def from_header(cls, header_list: typing.List[str]) -> "TraceState": + def from_header(cls, header: str) -> "TraceState": """Parses one or more w3c tracestate header into a TraceState. Args: - header_list: one or more w3c tracestate headers. + header: one W3C tracestate headers. Returns: A valid TraceState that contains values extracted from @@ -351,24 +351,24 @@ def from_header(cls, header_list: typing.List[str]) -> "TraceState": If the number of keys is beyond the maximum, all values will be discarded and an empty tracestate will be returned. """ + pairs = OrderedDict() - for header in header_list: - for member in re.split(_delimiter_pattern, header): - # empty members are valid, but no need to process further. - if not member: - continue - match = _member_pattern.fullmatch(member) - if not match: - _logger.warning( - "Member doesn't match the w3c identifiers format %s", - member, - ) - return cls() - key, _eq, value = match.groups() - # duplicate keys are not legal in header - if key in pairs: - return cls() - pairs[key] = value + for member in re.split(_delimiter_pattern, header): + # empty members are valid, but no need to process further. + if not member: + continue + match = _member_pattern.fullmatch(member) + if not match: + _logger.warning( + "Member doesn't match the w3c identifiers format %s", + member, + ) + return cls() + key, _eq, value = match.groups() + # duplicate keys are not legal in header + if key in pairs: + return cls() + pairs[key] = value return cls(list(pairs.items())) @classmethod diff --git a/opentelemetry-api/tests/baggage/test_baggage_propagation.py b/opentelemetry-api/tests/baggage/test_baggage_propagation.py index 3047ddbbe46..772b62d90fe 100644 --- a/opentelemetry-api/tests/baggage/test_baggage_propagation.py +++ b/opentelemetry-api/tests/baggage/test_baggage_propagation.py @@ -11,28 +11,24 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# -# type: ignore -import unittest -from unittest.mock import Mock, patch +from unittest import TestCase +from unittest.mock import patch from opentelemetry import baggage from opentelemetry.baggage.propagation import W3CBaggagePropagator from opentelemetry.context import get_current -from opentelemetry.propagators.textmap import DictGetter - -carrier_getter = DictGetter() -class TestBaggagePropagation(unittest.TestCase): +class TestBaggagePropagation(TestCase): def setUp(self): self.propagator = W3CBaggagePropagator() def _extract(self, header_value): """Test helper""" - header = {"baggage": [header_value]} - return baggage.get_all(self.propagator.extract(carrier_getter, header)) + return baggage.get_all( + self.propagator.extract({"baggage": header_value}) + ) def _inject(self, values): """Test helper""" @@ -40,122 +36,114 @@ def _inject(self, values): for k, v in values.items(): ctx = baggage.set_baggage(k, v, context=ctx) output = {} - self.propagator.inject(dict.__setitem__, output, context=ctx) + self.propagator.inject(output, context=ctx) return output.get("baggage") def test_no_context_header(self): - baggage_entries = baggage.get_all( - self.propagator.extract(carrier_getter, {}) - ) - self.assertEqual(baggage_entries, {}) + self.assertEqual(baggage.get_all(self.propagator.extract({})), {}) def test_empty_context_header(self): - header = "" - self.assertEqual(self._extract(header), {}) + self.assertEqual(self._extract(""), {}) def test_valid_header(self): - header = "key1=val1,key2=val2" - expected = {"key1": "val1", "key2": "val2"} - self.assertEqual(self._extract(header), expected) + self.assertEqual( + self._extract("key1=val1,key2=val2"), + {"key1": "val1", "key2": "val2"}, + ) def test_valid_header_with_space(self): - header = "key1 = val1, key2 =val2 " - expected = {"key1": "val1", "key2": "val2"} - self.assertEqual(self._extract(header), expected) + self.assertEqual( + self._extract("key1 = val1, key2 =val2 "), + {"key1": "val1", "key2": "val2"}, + ) def test_valid_header_with_properties(self): - header = "key1=val1,key2=val2;prop=1" - expected = {"key1": "val1", "key2": "val2;prop=1"} - self.assertEqual(self._extract(header), expected) + self.assertEqual( + self._extract("key1=val1,key2=val2;prop=1"), + {"key1": "val1", "key2": "val2;prop=1"}, + ) def test_valid_header_with_url_escaped_comma(self): - header = "key%2C1=val1,key2=val2%2Cval3" - expected = {"key,1": "val1", "key2": "val2,val3"} - self.assertEqual(self._extract(header), expected) + self.assertEqual( + self._extract("key%2C1=val1,key2=val2%2Cval3"), + {"key,1": "val1", "key2": "val2,val3"}, + ) def test_valid_header_with_invalid_value(self): - header = "key1=val1,key2=val2,a,val3" - expected = {"key1": "val1", "key2": "val2"} - self.assertEqual(self._extract(header), expected) + self.assertEqual( + self._extract("key1=val1,key2=val2,a,val3"), + {"key1": "val1", "key2": "val2"}, + ) def test_valid_header_with_empty_value(self): - header = "key1=,key2=val2" - expected = {"key1": "", "key2": "val2"} - self.assertEqual(self._extract(header), expected) + self.assertEqual( + self._extract("key1=,key2=val2"), {"key1": "", "key2": "val2"} + ) def test_invalid_header(self): - header = "header1" - expected = {} - self.assertEqual(self._extract(header), expected) + self.assertEqual(self._extract("header1"), {}) def test_header_too_long(self): - long_value = "s" * (W3CBaggagePropagator._MAX_HEADER_LENGTH + 1) - header = "key1={}".format(long_value) - expected = {} - self.assertEqual(self._extract(header), expected) + self.assertEqual( + self._extract( + "key1={}".format( + "s" * (W3CBaggagePropagator._max_header_length + 1) + ) + ), + {}, + ) def test_header_contains_too_many_entries(self): - header = ",".join( - [ - "key{}=val".format(k) - for k in range(W3CBaggagePropagator._MAX_PAIRS + 1) - ] - ) self.assertEqual( - len(self._extract(header)), W3CBaggagePropagator._MAX_PAIRS + len( + self._extract( + ",".join( + "key{}=val".format(k) + for k in range(W3CBaggagePropagator._max_pairs + 1) + ) + ) + ), + W3CBaggagePropagator._max_pairs, ) def test_header_contains_pair_too_long(self): - long_value = "s" * (W3CBaggagePropagator._MAX_PAIR_LENGTH + 1) - header = "key1=value1,key2={},key3=value3".format(long_value) - expected = {"key1": "value1", "key3": "value3"} - self.assertEqual(self._extract(header), expected) + self.assertEqual( + self._extract( + "key1=value1,key2={},key3=value3".format( + "s" * (W3CBaggagePropagator._max_pair_length + 1) + ) + ), + {"key1": "value1", "key3": "value3"}, + ) def test_inject_no_baggage_entries(self): - values = {} - output = self._inject(values) - self.assertEqual(None, output) + self.assertEqual(None, self._inject({})) def test_inject(self): - values = { - "key1": "val1", - "key2": "val2", - } - output = self._inject(values) + output = self._inject({"key1": "val1", "key2": "val2"}) self.assertIn("key1=val1", output) self.assertIn("key2=val2", output) def test_inject_escaped_values(self): - values = { - "key1": "val1,val2", - "key2": "val3=4", - } - output = self._inject(values) + output = self._inject({"key1": "val1,val2", "key2": "val3=4"}) self.assertIn("key1=val1%2Cval2", output) self.assertIn("key2=val3%3D4", output) def test_inject_non_string_values(self): - values = { - "key1": True, - "key2": 123, - "key3": 123.567, - } - output = self._inject(values) + output = self._inject({"key1": True, "key2": 123, "key3": 123.567}) self.assertIn("key1=True", output) self.assertIn("key2=123", output) self.assertIn("key3=123.567", output) @patch("opentelemetry.baggage.propagation.baggage") - @patch("opentelemetry.baggage.propagation._format_baggage") - def test_fields(self, mock_format_baggage, mock_baggage): + def test_fields(self, mock_baggage): - mock_set_in_carrier = Mock() - - self.propagator.inject(mock_set_in_carrier, {}) + mock_baggage.configure_mock( + **{"get_all.return_value": {"a": "b", "c": "d"}} + ) - inject_fields = set() + carrier = {} - for mock_call in mock_set_in_carrier.mock_calls: - inject_fields.add(mock_call[1][1]) + self.propagator.inject(carrier) - self.assertEqual(inject_fields, self.propagator.fields) + self.assertEqual(carrier.keys(), self.propagator.fields) diff --git a/opentelemetry-api/tests/propagators/test_composite.py b/opentelemetry-api/tests/propagators/test_composite.py index e33649bbdd8..f898b65a2df 100644 --- a/opentelemetry-api/tests/propagators/test_composite.py +++ b/opentelemetry-api/tests/propagators/test_composite.py @@ -20,22 +20,15 @@ from opentelemetry.propagators.composite import CompositeHTTPPropagator -def get_as_list(dict_object, key): - value = dict_object.get(key) - return [value] if value is not None else [] - - def mock_inject(name, value="data"): - def wrapped(setter, carrier=None, context=None): + def wrapped(carrier=None, context=None): carrier[name] = value - setter({}, "inject_field_{}_0".format(name), None) - setter({}, "inject_field_{}_1".format(name), None) return wrapped def mock_extract(name, value="context"): - def wrapped(getter, carrier=None, context=None): + def wrapped(carrier=None, context=None): new_context = context.copy() new_context[name] = value return new_context @@ -69,24 +62,20 @@ def setUpClass(cls): def test_no_propagators(self): propagator = CompositeHTTPPropagator([]) new_carrier = {} - propagator.inject(dict.__setitem__, carrier=new_carrier) + propagator.inject(carrier=new_carrier) self.assertEqual(new_carrier, {}) - context = propagator.extract( - get_as_list, carrier=new_carrier, context={} - ) + context = propagator.extract(carrier=new_carrier, context={}) self.assertEqual(context, {}) def test_single_propagator(self): propagator = CompositeHTTPPropagator([self.mock_propagator_0]) new_carrier = {} - propagator.inject(dict.__setitem__, carrier=new_carrier) + propagator.inject(carrier=new_carrier) self.assertEqual(new_carrier, {"mock-0": "data"}) - context = propagator.extract( - get_as_list, carrier=new_carrier, context={} - ) + context = propagator.extract(carrier=new_carrier, context={}) self.assertEqual(context, {"mock-0": "context"}) def test_multiple_propagators(self): @@ -95,12 +84,10 @@ def test_multiple_propagators(self): ) new_carrier = {} - propagator.inject(dict.__setitem__, carrier=new_carrier) + propagator.inject(carrier=new_carrier) self.assertEqual(new_carrier, {"mock-0": "data", "mock-1": "data"}) - context = propagator.extract( - get_as_list, carrier=new_carrier, context={} - ) + context = propagator.extract(carrier=new_carrier, context={}) self.assertEqual(context, {"mock-0": "context", "mock-1": "context"}) def test_multiple_propagators_same_key(self): @@ -111,12 +98,10 @@ def test_multiple_propagators_same_key(self): ) new_carrier = {} - propagator.inject(dict.__setitem__, carrier=new_carrier) + propagator.inject(carrier=new_carrier) self.assertEqual(new_carrier, {"mock-0": "data2"}) - context = propagator.extract( - get_as_list, carrier=new_carrier, context={} - ) + context = propagator.extract(carrier=new_carrier, context={}) self.assertEqual(context, {"mock-0": "context2"}) def test_fields(self): @@ -128,13 +113,14 @@ def test_fields(self): ] ) - mock_set_in_carrier = Mock() - - propagator.inject(mock_set_in_carrier, {}) - - inject_fields = set() + propagator.inject({}) - for mock_call in mock_set_in_carrier.mock_calls: - inject_fields.add(mock_call[1][1]) - - self.assertEqual(inject_fields, propagator.fields) + self.assertEqual( + { + "inject_field_mock-0_0", + "inject_field_mock-0_1", + "inject_field_mock-1_0", + "inject_field_mock-1_1", + }, + propagator.fields, + ) diff --git a/opentelemetry-api/tests/propagators/test_global_httptextformat.py b/opentelemetry-api/tests/propagators/test_global_httptextformat.py index 6ba32e46183..f2d7a2a6ff8 100644 --- a/opentelemetry-api/tests/propagators/test_global_httptextformat.py +++ b/opentelemetry-api/tests/propagators/test_global_httptextformat.py @@ -18,45 +18,43 @@ from opentelemetry import baggage, trace from opentelemetry.propagate import extract, inject -from opentelemetry.propagators.textmap import DictGetter from opentelemetry.trace import get_current_span, set_span_in_context from opentelemetry.trace.span import format_span_id, format_trace_id -carrier_getter = DictGetter() - class TestDefaultGlobalPropagator(unittest.TestCase): """Test ensures the default global composite propagator works as intended""" - TRACE_ID = int("12345678901234567890123456789012", 16) # type:int - SPAN_ID = int("1234567890123456", 16) # type:int + trace_id = int("12345678901234567890123456789012", 16) # type:int + span_id = int("1234567890123456", 16) # type:int def test_propagation(self): traceparent_value = "00-{trace_id}-{span_id}-00".format( - trace_id=format_trace_id(self.TRACE_ID), - span_id=format_span_id(self.SPAN_ID), + trace_id=format_trace_id(self.trace_id), + span_id=format_span_id(self.span_id), + ) + + ctx = extract( + { + "baggage": "key1=val1,key2=val2", + "traceparent": traceparent_value, + "tracestate": "foo=1,bar=2,baz=3", + } + ) + self.assertEqual( + baggage.get_all(context=ctx), {"key1": "val1", "key2": "val2"} ) - tracestate_value = "foo=1,bar=2,baz=3" - headers = { - "baggage": ["key1=val1,key2=val2"], - "traceparent": [traceparent_value], - "tracestate": [tracestate_value], - } - ctx = extract(carrier_getter, headers) - baggage_entries = baggage.get_all(context=ctx) - expected = {"key1": "val1", "key2": "val2"} - self.assertEqual(baggage_entries, expected) span_context = get_current_span(context=ctx).get_span_context() - self.assertEqual(span_context.trace_id, self.TRACE_ID) - self.assertEqual(span_context.span_id, self.SPAN_ID) + self.assertEqual(span_context.trace_id, self.trace_id) + self.assertEqual(span_context.span_id, self.span_id) span = trace.NonRecordingSpan(span_context) ctx = baggage.set_baggage("key3", "val3") ctx = baggage.set_baggage("key4", "val4", context=ctx) ctx = set_span_in_context(span, context=ctx) output = {} - inject(dict.__setitem__, output, context=ctx) + inject(output, context=ctx) self.assertEqual(traceparent_value, output["traceparent"]) self.assertIn("key3=val3", output["baggage"]) self.assertIn("key4=val4", output["baggage"]) diff --git a/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py b/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py index 79683d43d94..af5fc515161 100644 --- a/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py +++ b/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py @@ -15,22 +15,26 @@ # type: ignore import typing -import unittest +from unittest import TestCase from unittest.mock import Mock, patch -from opentelemetry import trace -from opentelemetry.propagators.textmap import DictGetter +from opentelemetry.trace import ( + INVALID_SPAN, + INVALID_SPAN_CONTEXT, + NonRecordingSpan, + SpanContext, + get_current_span, + set_span_in_context, +) from opentelemetry.trace.propagation import tracecontext from opentelemetry.trace.span import TraceState FORMAT = tracecontext.TraceContextTextMapPropagator() -carrier_getter = DictGetter() - -class TestTraceContextFormat(unittest.TestCase): - TRACE_ID = int("12345678901234567890123456789012", 16) # type:int - SPAN_ID = int("1234567890123456", 16) # type:int +class TestTraceContextFormat(TestCase): + trace_id = int("12345678901234567890123456789012", 16) # type:int + span_id = int("1234567890123456", 16) # type:int def test_no_traceparent_header(self): """When tracecontext headers are not present, a new SpanContext @@ -42,38 +46,37 @@ def test_no_traceparent_header(self): trace-id and parent-id that represents the current request. """ output = {} # type:typing.Dict[str, typing.List[str]] - span = trace.get_current_span(FORMAT.extract(carrier_getter, output)) - self.assertIsInstance(span.get_span_context(), trace.SpanContext) + span = get_current_span(FORMAT.extract(output)) + self.assertIsInstance(span.get_span_context(), SpanContext) def test_headers_with_tracestate(self): """When there is a traceparent and tracestate header, data from both should be addded to the SpanContext. """ traceparent_value = "00-{trace_id}-{span_id}-00".format( - trace_id=format(self.TRACE_ID, "032x"), - span_id=format(self.SPAN_ID, "016x"), + trace_id=format(self.trace_id, "032x"), + span_id=format(self.span_id, "016x"), ) tracestate_value = "foo=1,bar=2,baz=3" - span_context = trace.get_current_span( + span_context = get_current_span( FORMAT.extract( - carrier_getter, { - "traceparent": [traceparent_value], - "tracestate": [tracestate_value], + "traceparent": traceparent_value, + "tracestate": tracestate_value, }, ) ).get_span_context() - self.assertEqual(span_context.trace_id, self.TRACE_ID) - self.assertEqual(span_context.span_id, self.SPAN_ID) + self.assertEqual(span_context.trace_id, self.trace_id) + self.assertEqual(span_context.span_id, self.span_id) self.assertEqual( span_context.trace_state, {"foo": "1", "bar": "2", "baz": "3"} ) self.assertTrue(span_context.is_remote) output = {} # type:typing.Dict[str, str] - span = trace.NonRecordingSpan(span_context) + span = NonRecordingSpan(span_context) - ctx = trace.set_span_in_context(span) - FORMAT.inject(dict.__setitem__, output, ctx) + ctx = set_span_in_context(span) + FORMAT.inject(output, ctx) self.assertEqual(output["traceparent"], traceparent_value) for pair in ["foo=1", "bar=2", "baz=3"]: self.assertIn(pair, output["tracestate"]) @@ -98,18 +101,18 @@ def test_invalid_trace_id(self): Note that the opposite is not true: failure to parse tracestate MUST NOT affect the parsing of traceparent. """ - span = trace.get_current_span( + span = get_current_span( FORMAT.extract( - carrier_getter, { - "traceparent": [ - "00-00000000000000000000000000000000-1234567890123456-00" - ], - "tracestate": ["foo=1,bar=2,foo=3"], + "traceparent": ( + "00-00000000000000000000000000000000-" + "1234567890123456-00" + ), + "tracestate": "foo=1,bar=2,foo=3", }, ) ) - self.assertEqual(span.get_span_context(), trace.INVALID_SPAN_CONTEXT) + self.assertEqual(span.get_span_context(), INVALID_SPAN_CONTEXT) def test_invalid_parent_id(self): """If the parent id is invalid, we must ignore the full traceparent @@ -129,18 +132,18 @@ def test_invalid_parent_id(self): Note that the opposite is not true: failure to parse tracestate MUST NOT affect the parsing of traceparent. """ - span = trace.get_current_span( + span = get_current_span( FORMAT.extract( - carrier_getter, { - "traceparent": [ - "00-00000000000000000000000000000000-0000000000000000-00" - ], - "tracestate": ["foo=1,bar=2,foo=3"], + "traceparent": ( + "00-00000000000000000000000000000000-" + "0000000000000000-00" + ), + "tracestate": "foo=1,bar=2,foo=3", }, ) ) - self.assertEqual(span.get_span_context(), trace.INVALID_SPAN_CONTEXT) + self.assertEqual(span.get_span_context(), INVALID_SPAN_CONTEXT) def test_no_send_empty_tracestate(self): """If the tracestate is empty, do not set the header. @@ -151,11 +154,12 @@ def test_no_send_empty_tracestate(self): empty tracestate headers but SHOULD avoid sending them. """ output = {} # type:typing.Dict[str, str] - span = trace.NonRecordingSpan( - trace.SpanContext(self.TRACE_ID, self.SPAN_ID, is_remote=False) + span = NonRecordingSpan( + SpanContext(self.trace_id, self.span_id, is_remote=False) ) - ctx = trace.set_span_in_context(span) - FORMAT.inject(dict.__setitem__, output, ctx) + ctx = set_span_in_context(span) + + FORMAT.inject(output, ctx) self.assertTrue("traceparent" in output) self.assertFalse("tracestate" in output) @@ -167,37 +171,36 @@ def test_format_not_supported(self): If the version cannot be parsed, return an invalid trace header. """ - span = trace.get_current_span( + span = get_current_span( FORMAT.extract( - carrier_getter, { - "traceparent": [ + "traceparent": ( "00-12345678901234567890123456789012-" "1234567890123456-00-residue" - ], - "tracestate": ["foo=1,bar=2,foo=3"], + ), + "tracestate": "foo=1,bar=2,foo=3", }, ) ) - self.assertEqual(span.get_span_context(), trace.INVALID_SPAN_CONTEXT) + self.assertEqual(span.get_span_context(), INVALID_SPAN_CONTEXT) def test_propagate_invalid_context(self): """Do not propagate invalid trace context.""" output = {} # type:typing.Dict[str, str] - ctx = trace.set_span_in_context(trace.INVALID_SPAN) - FORMAT.inject(dict.__setitem__, output, context=ctx) + ctx = set_span_in_context(INVALID_SPAN) + FORMAT.inject(output, context=ctx) self.assertFalse("traceparent" in output) def test_tracestate_empty_header(self): """Test tracestate with an additional empty header (should be ignored)""" - span = trace.get_current_span( + span = get_current_span( FORMAT.extract( - carrier_getter, { - "traceparent": [ - "00-12345678901234567890123456789012-1234567890123456-00" - ], - "tracestate": ["foo=1", ""], + "traceparent": ( + "00-12345678901234567890123456789012-" + "1234567890123456-00" + ), + "tracestate": "foo=1, ", }, ) ) @@ -205,14 +208,14 @@ def test_tracestate_empty_header(self): def test_tracestate_header_with_trailing_comma(self): """Do not propagate invalid trace context.""" - span = trace.get_current_span( + span = get_current_span( FORMAT.extract( - carrier_getter, { - "traceparent": [ - "00-12345678901234567890123456789012-1234567890123456-00" - ], - "tracestate": ["foo=1,"], + "traceparent": ( + "00-12345678901234567890123456789012-" + "1234567890123456-00" + ), + "tracestate": "foo=1,", }, ) ) @@ -228,15 +231,14 @@ def test_tracestate_keys(self): "foo-_*/bar=bar4", ] ) - span = trace.get_current_span( + span = get_current_span( FORMAT.extract( - carrier_getter, { - "traceparent": [ + "traceparent": ( "00-12345678901234567890123456789012-" "1234567890123456-00" - ], - "tracestate": [tracestate_value], + ), + "tracestate": tracestate_value, }, ) ) @@ -251,9 +253,8 @@ def test_tracestate_keys(self): span.get_span_context().trace_state["foo-_*/bar"], "bar4" ) - @patch("opentelemetry.trace.INVALID_SPAN_CONTEXT") - @patch("opentelemetry.trace.get_current_span") - def test_fields(self, mock_get_current_span, mock_invalid_span_context): + @patch("opentelemetry.trace.propagation.tracecontext.get_current_span") + def test_fields(self, mock_get_current_span): mock_get_current_span.configure_mock( return_value=Mock( @@ -270,13 +271,8 @@ def test_fields(self, mock_get_current_span, mock_invalid_span_context): ) ) - mock_set_in_carrier = Mock() - - FORMAT.inject(mock_set_in_carrier, {}) - - inject_fields = set() + carrier = {} - for mock_call in mock_set_in_carrier.mock_calls: - inject_fields.add(mock_call[1][1]) + FORMAT.inject(carrier) - self.assertEqual(inject_fields, FORMAT.fields) + self.assertEqual(carrier.keys(), {"traceparent", "tracestate"}) diff --git a/opentelemetry-api/tests/trace/test_tracestate.py b/opentelemetry-api/tests/trace/test_tracestate.py index 6665dd612dd..d777e280365 100644 --- a/opentelemetry-api/tests/trace/test_tracestate.py +++ b/opentelemetry-api/tests/trace/test_tracestate.py @@ -72,27 +72,31 @@ def test_tracestate_delete_preserved(self): self.assertLessEqual(a_place, c_place) def test_tracestate_from_header(self): - entries = [ - "1a-2f@foo=bar1", - "1a-_*/2b@foo=bar2", - "foo=bar3", - "foo-_*/bar=bar4", - ] - header_list = [",".join(entries)] - state = TraceState.from_header(header_list) - self.assertEqual(state.to_header(), ",".join(entries)) + header = ",".join( + [ + "1a-2f@foo=bar1", + "1a-_*/2b@foo=bar2", + "foo=bar3", + "foo-_*/bar=bar4", + ] + ) + self.assertEqual(TraceState.from_header(header).to_header(), header) def test_tracestate_order_changed(self): - entries = [ - "1a-2f@foo=bar1", - "1a-_*/2b@foo=bar2", - "foo=bar3", - "foo-_*/bar=bar4", - ] - header_list = [",".join(entries)] - state = TraceState.from_header(header_list) - new_state = state.update("foo", "bar33") - entries = list(new_state.items()) # type: ignore + entries = list( + TraceState.from_header( + ",".join( + [ + "1a-2f@foo=bar1", + "1a-_*/2b@foo=bar2", + "foo=bar3", + "foo-_*/bar=bar4", + ] + ) + ) + .update("foo", "bar33") + .items() + ) foo_place = entries.index(("foo", "bar33")) # type: ignore prev_first_place = entries.index(("1a-2f@foo", "bar1")) # type: ignore self.assertLessEqual(foo_place, prev_first_place) diff --git a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py index 01abcc7c879..2c093f76630 100644 --- a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py +++ b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py @@ -12,17 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import typing -from re import compile as re_compile +from re import compile as compile_ +from typing import Dict, Optional, Set import opentelemetry.trace as trace from opentelemetry.context import Context -from opentelemetry.propagators.textmap import ( - Getter, - Setter, - TextMapPropagator, - TextMapPropagatorT, -) +from opentelemetry.propagators.textmap import TextMapPropagator from opentelemetry.trace import format_span_id, format_trace_id @@ -39,24 +34,21 @@ class B3Format(TextMapPropagator): SAMPLED_KEY = "x-b3-sampled" FLAGS_KEY = "x-b3-flags" _SAMPLE_PROPAGATE_VALUES = set(["1", "True", "true", "d"]) - _trace_id_regex = re_compile(r"[\da-fA-F]{16}|[\da-fA-F]{32}") - _span_id_regex = re_compile(r"[\da-fA-F]{16}") + _trace_id_regex = compile_(r"[\da-fA-F]{16}|[\da-fA-F]{32}") + _span_id_regex = compile_(r"[\da-fA-F]{16}") def extract( - self, - getter: Getter[TextMapPropagatorT], - carrier: TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> Context: + trace_id = format_trace_id(trace.INVALID_TRACE_ID) span_id = format_span_id(trace.INVALID_SPAN_ID) sampled = "0" flags = None - single_header = _extract_first_element( - getter.get(carrier, self.SINGLE_HEADER_KEY) - ) - if single_header: + single_header = carrier.get(self.SINGLE_HEADER_KEY) + + if single_header is not None: # The b3 spec calls for the sampling state to be # "deferred", which is unspecified. This concept does not # translate to SpanContext, so we set it as recorded. @@ -74,22 +66,10 @@ def extract( else: return trace.set_span_in_context(trace.INVALID_SPAN) else: - trace_id = ( - _extract_first_element(getter.get(carrier, self.TRACE_ID_KEY)) - or trace_id - ) - span_id = ( - _extract_first_element(getter.get(carrier, self.SPAN_ID_KEY)) - or span_id - ) - sampled = ( - _extract_first_element(getter.get(carrier, self.SAMPLED_KEY)) - or sampled - ) - flags = ( - _extract_first_element(getter.get(carrier, self.FLAGS_KEY)) - or flags - ) + trace_id = carrier.get(self.TRACE_ID_KEY, False) or trace_id + span_id = carrier.get(self.SPAN_ID_KEY, False) or span_id + sampled = carrier.get(self.SAMPLED_KEY, False) or sampled + flags = carrier.get(self.FLAGS_KEY, False) or flags if ( self._trace_id_regex.fullmatch(trace_id) is None @@ -126,11 +106,9 @@ def extract( ) def inject( - self, - set_in_carrier: Setter[TextMapPropagatorT], - carrier: TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> None: + span = trace.get_current_span(context=context) span_context = span.get_span_context() @@ -138,34 +116,20 @@ def inject( return sampled = (trace.TraceFlags.SAMPLED & span_context.trace_flags) != 0 - set_in_carrier( - carrier, self.TRACE_ID_KEY, format_trace_id(span_context.trace_id), - ) - set_in_carrier( - carrier, self.SPAN_ID_KEY, format_span_id(span_context.span_id) - ) + carrier[self.TRACE_ID_KEY] = format_trace_id(span_context.trace_id) + carrier[self.SPAN_ID_KEY] = format_span_id(span_context.span_id) span_parent = getattr(span, "parent", None) if span_parent is not None: - set_in_carrier( - carrier, - self.PARENT_SPAN_ID_KEY, - format_span_id(span_parent.span_id), + carrier[self.PARENT_SPAN_ID_KEY] = format_span_id( + span_parent.span_id ) - set_in_carrier(carrier, self.SAMPLED_KEY, "1" if sampled else "0") + carrier[self.SAMPLED_KEY] = "1" if sampled else "0" @property - def fields(self) -> typing.Set[str]: + def fields(self) -> Set[str]: return { self.TRACE_ID_KEY, self.SPAN_ID_KEY, self.PARENT_SPAN_ID_KEY, self.SAMPLED_KEY, } - - -def _extract_first_element( - items: typing.Iterable[TextMapPropagatorT], -) -> typing.Optional[TextMapPropagatorT]: - if items is None: - return None - return next(iter(items), None) diff --git a/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py b/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py index 5048f495f06..3a7a251ad88 100644 --- a/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py +++ b/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py @@ -14,7 +14,6 @@ import opentelemetry.propagators.b3 as b3_format import opentelemetry.sdk.trace as trace -from opentelemetry.propagators.textmap import DictGetter FORMAT = b3_format.B3Format() @@ -22,7 +21,6 @@ def test_extract_single_header(benchmark): benchmark( FORMAT.extract, - DictGetter(), { FORMAT.SINGLE_HEADER_KEY: "bdb5b63237ed38aea578af665aa5aa60-c32d953d73ad2251-1-11fd79a30b0896cd285b396ae102dd76" }, @@ -35,7 +33,6 @@ def test_inject_empty_context(benchmark): with tracer.start_as_current_span("Child Span"): benchmark( FORMAT.inject, - dict.__setitem__, { FORMAT.TRACE_ID_KEY: "bdb5b63237ed38aea578af665aa5aa60", FORMAT.SPAN_ID_KEY: "00000000000000000c32d953d73ad225", diff --git a/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py b/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py index f9d3bce1adb..a9a9b478f55 100644 --- a/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py +++ b/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py @@ -12,31 +12,37 @@ # See the License for the specific language governing permissions and # limitations under the License. -import unittest -from unittest.mock import Mock, patch +from unittest import TestCase +from unittest.mock import patch -import opentelemetry.propagators.b3 as b3_format # pylint: disable=no-name-in-module,import-error -import opentelemetry.sdk.trace as trace -import opentelemetry.sdk.trace.id_generator as id_generator -import opentelemetry.trace as trace_api +from opentelemetry import trace from opentelemetry.context import get_current -from opentelemetry.propagators.textmap import DictGetter - -FORMAT = b3_format.B3Format() - - -carrier_getter = DictGetter() +from opentelemetry.propagators.b3 import ( + B3Format, + format_span_id, + format_trace_id, +) +from opentelemetry.sdk.trace import TracerProvider, _Span, id_generator +from opentelemetry.trace import ( + INVALID_SPAN_ID, + INVALID_TRACE_ID, + SpanContext, + get_current_span, + set_span_in_context, +) + +format_ = B3Format() def get_child_parent_new_carrier(old_carrier): - ctx = FORMAT.extract(carrier_getter, old_carrier) - parent_span_context = trace_api.get_current_span(ctx).get_span_context() + ctx = format_.extract(old_carrier) + parent_span_context = get_current_span(ctx).get_span_context() - parent = trace._Span("parent", parent_span_context) - child = trace._Span( + parent = _Span("parent", parent_span_context) + child = _Span( "child", - trace_api.SpanContext( + SpanContext( parent_span_context.trace_id, id_generator.RandomIdGenerator().generate_span_id(), is_remote=False, @@ -47,30 +53,27 @@ def get_child_parent_new_carrier(old_carrier): ) new_carrier = {} - ctx = trace_api.set_span_in_context(child) - FORMAT.inject(dict.__setitem__, new_carrier, context=ctx) + ctx = set_span_in_context(child) + + format_.inject(new_carrier, context=ctx) return child, parent, new_carrier -class TestB3Format(unittest.TestCase): +class TestB3Format(TestCase): @classmethod def setUpClass(cls): generator = id_generator.RandomIdGenerator() - cls.serialized_trace_id = b3_format.format_trace_id( + cls.serialized_trace_id = format_trace_id( generator.generate_trace_id() ) - cls.serialized_span_id = b3_format.format_span_id( - generator.generate_span_id() - ) - cls.serialized_parent_id = b3_format.format_span_id( - generator.generate_span_id() - ) + cls.serialized_span_id = format_span_id(generator.generate_span_id()) + cls.serialized_parent_id = format_span_id(generator.generate_span_id()) def setUp(self) -> None: - tracer_provider = trace.TracerProvider() - patcher = unittest.mock.patch.object( - trace_api, "get_tracer_provider", return_value=tracer_provider + tracer_provider = TracerProvider() + patcher = patch.object( + trace, "get_tracer_provider", return_value=tracer_provider ) patcher.start() self.addCleanup(patcher.stop) @@ -79,52 +82,53 @@ def test_extract_multi_header(self): """Test the extraction of B3 headers.""" child, parent, new_carrier = get_child_parent_new_carrier( { - FORMAT.TRACE_ID_KEY: self.serialized_trace_id, - FORMAT.SPAN_ID_KEY: self.serialized_span_id, - FORMAT.PARENT_SPAN_ID_KEY: self.serialized_parent_id, - FORMAT.SAMPLED_KEY: "1", + format_.TRACE_ID_KEY: self.serialized_trace_id, + format_.SPAN_ID_KEY: self.serialized_span_id, + format_.PARENT_SPAN_ID_KEY: self.serialized_parent_id, + format_.SAMPLED_KEY: "1", } ) self.assertEqual( - new_carrier[FORMAT.TRACE_ID_KEY], - b3_format.format_trace_id(child.context.trace_id), + new_carrier[format_.TRACE_ID_KEY], + format_trace_id(child.context.trace_id), ) self.assertEqual( - new_carrier[FORMAT.SPAN_ID_KEY], - b3_format.format_span_id(child.context.span_id), + new_carrier[format_.SPAN_ID_KEY], + format_span_id(child.context.span_id), ) + self.assertEqual( - new_carrier[FORMAT.PARENT_SPAN_ID_KEY], - b3_format.format_span_id(parent.context.span_id), + new_carrier[format_.PARENT_SPAN_ID_KEY], + format_span_id(parent.context.span_id), ) self.assertTrue(parent.context.is_remote) - self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1") + self.assertEqual(new_carrier[format_.SAMPLED_KEY], "1") def test_extract_single_header(self): """Test the extraction from a single b3 header.""" child, parent, new_carrier = get_child_parent_new_carrier( { - FORMAT.SINGLE_HEADER_KEY: "{}-{}".format( + format_.SINGLE_HEADER_KEY: "{}-{}".format( self.serialized_trace_id, self.serialized_span_id ) } ) self.assertEqual( - new_carrier[FORMAT.TRACE_ID_KEY], - b3_format.format_trace_id(child.context.trace_id), + new_carrier[format_.TRACE_ID_KEY], + format_trace_id(child.context.trace_id), ) self.assertEqual( - new_carrier[FORMAT.SPAN_ID_KEY], - b3_format.format_span_id(child.context.span_id), + new_carrier[format_.SPAN_ID_KEY], + format_span_id(child.context.span_id), ) - self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1") + self.assertEqual(new_carrier[format_.SAMPLED_KEY], "1") self.assertTrue(parent.context.is_remote) child, parent, new_carrier = get_child_parent_new_carrier( { - FORMAT.SINGLE_HEADER_KEY: "{}-{}-1-{}".format( + format_.SINGLE_HEADER_KEY: "{}-{}-1-{}".format( self.serialized_trace_id, self.serialized_span_id, self.serialized_parent_id, @@ -133,19 +137,19 @@ def test_extract_single_header(self): ) self.assertEqual( - new_carrier[FORMAT.TRACE_ID_KEY], - b3_format.format_trace_id(child.context.trace_id), + new_carrier[format_.TRACE_ID_KEY], + format_trace_id(child.context.trace_id), ) self.assertEqual( - new_carrier[FORMAT.SPAN_ID_KEY], - b3_format.format_span_id(child.context.span_id), + new_carrier[format_.SPAN_ID_KEY], + format_span_id(child.context.span_id), ) self.assertEqual( - new_carrier[FORMAT.PARENT_SPAN_ID_KEY], - b3_format.format_span_id(parent.context.span_id), + new_carrier[format_.PARENT_SPAN_ID_KEY], + format_span_id(parent.context.span_id), ) self.assertTrue(parent.context.is_remote) - self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1") + self.assertEqual(new_carrier[format_.SAMPLED_KEY], "1") def test_extract_header_precedence(self): """A single b3 header should take precedence over multiple @@ -155,17 +159,17 @@ def test_extract_header_precedence(self): _, _, new_carrier = get_child_parent_new_carrier( { - FORMAT.SINGLE_HEADER_KEY: "{}-{}".format( + format_.SINGLE_HEADER_KEY: "{}-{}".format( single_header_trace_id, self.serialized_span_id ), - FORMAT.TRACE_ID_KEY: self.serialized_trace_id, - FORMAT.SPAN_ID_KEY: self.serialized_span_id, - FORMAT.SAMPLED_KEY: "1", + format_.TRACE_ID_KEY: self.serialized_trace_id, + format_.SPAN_ID_KEY: self.serialized_span_id, + format_.SAMPLED_KEY: "1", } ) self.assertEqual( - new_carrier[FORMAT.TRACE_ID_KEY], single_header_trace_id + new_carrier[format_.TRACE_ID_KEY], single_header_trace_id ) def test_enabled_sampling(self): @@ -173,50 +177,50 @@ def test_enabled_sampling(self): for variant in ["1", "True", "true", "d"]: _, _, new_carrier = get_child_parent_new_carrier( { - FORMAT.TRACE_ID_KEY: self.serialized_trace_id, - FORMAT.SPAN_ID_KEY: self.serialized_span_id, - FORMAT.SAMPLED_KEY: variant, + format_.TRACE_ID_KEY: self.serialized_trace_id, + format_.SPAN_ID_KEY: self.serialized_span_id, + format_.SAMPLED_KEY: variant, } ) - self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1") + self.assertEqual(new_carrier[format_.SAMPLED_KEY], "1") def test_disabled_sampling(self): """Test b3 sample key variants that turn off sampling.""" for variant in ["0", "False", "false", None]: _, _, new_carrier = get_child_parent_new_carrier( { - FORMAT.TRACE_ID_KEY: self.serialized_trace_id, - FORMAT.SPAN_ID_KEY: self.serialized_span_id, - FORMAT.SAMPLED_KEY: variant, + format_.TRACE_ID_KEY: self.serialized_trace_id, + format_.SPAN_ID_KEY: self.serialized_span_id, + format_.SAMPLED_KEY: variant, } ) - self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "0") + self.assertEqual(new_carrier[format_.SAMPLED_KEY], "0") def test_flags(self): """x-b3-flags set to "1" should result in propagation.""" _, _, new_carrier = get_child_parent_new_carrier( { - FORMAT.TRACE_ID_KEY: self.serialized_trace_id, - FORMAT.SPAN_ID_KEY: self.serialized_span_id, - FORMAT.FLAGS_KEY: "1", + format_.TRACE_ID_KEY: self.serialized_trace_id, + format_.SPAN_ID_KEY: self.serialized_span_id, + format_.FLAGS_KEY: "1", } ) - self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1") + self.assertEqual(new_carrier[format_.SAMPLED_KEY], "1") def test_flags_and_sampling(self): """Propagate if b3 flags and sampling are set.""" _, _, new_carrier = get_child_parent_new_carrier( { - FORMAT.TRACE_ID_KEY: self.serialized_trace_id, - FORMAT.SPAN_ID_KEY: self.serialized_span_id, - FORMAT.FLAGS_KEY: "1", + format_.TRACE_ID_KEY: self.serialized_trace_id, + format_.SPAN_ID_KEY: self.serialized_span_id, + format_.FLAGS_KEY: "1", } ) - self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1") + self.assertEqual(new_carrier[format_.SAMPLED_KEY], "1") def test_64bit_trace_id(self): """64 bit trace ids should be padded to 128 bit trace ids.""" @@ -224,36 +228,36 @@ def test_64bit_trace_id(self): _, _, new_carrier = get_child_parent_new_carrier( { - FORMAT.TRACE_ID_KEY: trace_id_64_bit, - FORMAT.SPAN_ID_KEY: self.serialized_span_id, - FORMAT.FLAGS_KEY: "1", + format_.TRACE_ID_KEY: trace_id_64_bit, + format_.SPAN_ID_KEY: self.serialized_span_id, + format_.FLAGS_KEY: "1", } ) self.assertEqual( - new_carrier[FORMAT.TRACE_ID_KEY], "0" * 16 + trace_id_64_bit + new_carrier[format_.TRACE_ID_KEY], "0" * 16 + trace_id_64_bit ) def test_invalid_single_header(self): """If an invalid single header is passed, return an invalid SpanContext. """ - carrier = {FORMAT.SINGLE_HEADER_KEY: "0-1-2-3-4-5-6-7"} - ctx = FORMAT.extract(carrier_getter, carrier) - span_context = trace_api.get_current_span(ctx).get_span_context() - self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) - self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) + carrier = {format_.SINGLE_HEADER_KEY: "0-1-2-3-4-5-6-7"} + ctx = format_.extract(carrier) + span_context = get_current_span(ctx).get_span_context() + self.assertEqual(span_context.trace_id, INVALID_TRACE_ID) + self.assertEqual(span_context.span_id, INVALID_SPAN_ID) def test_missing_trace_id(self): """If a trace id is missing, populate an invalid trace id.""" carrier = { - FORMAT.SPAN_ID_KEY: self.serialized_span_id, - FORMAT.FLAGS_KEY: "1", + format_.SPAN_ID_KEY: self.serialized_span_id, + format_.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier_getter, carrier) - span_context = trace_api.get_current_span(ctx).get_span_context() - self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) + ctx = format_.extract(carrier) + span_context = get_current_span(ctx).get_span_context() + self.assertEqual(span_context.trace_id, INVALID_TRACE_ID) @patch( "opentelemetry.sdk.trace.id_generator.RandomIdGenerator.generate_trace_id" @@ -270,13 +274,13 @@ def test_invalid_trace_id( mock_generate_span_id.configure_mock(return_value=2) carrier = { - FORMAT.TRACE_ID_KEY: "abc123", - FORMAT.SPAN_ID_KEY: self.serialized_span_id, - FORMAT.FLAGS_KEY: "1", + format_.TRACE_ID_KEY: "abc123", + format_.SPAN_ID_KEY: self.serialized_span_id, + format_.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier_getter, carrier) - span_context = trace_api.get_current_span(ctx).get_span_context() + ctx = format_.extract(carrier) + span_context = get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, 1) self.assertEqual(span_context.span_id, 2) @@ -296,13 +300,13 @@ def test_invalid_span_id( mock_generate_span_id.configure_mock(return_value=2) carrier = { - FORMAT.TRACE_ID_KEY: self.serialized_trace_id, - FORMAT.SPAN_ID_KEY: "abc123", - FORMAT.FLAGS_KEY: "1", + format_.TRACE_ID_KEY: self.serialized_trace_id, + format_.SPAN_ID_KEY: "abc123", + format_.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier_getter, carrier) - span_context = trace_api.get_current_span(ctx).get_span_context() + ctx = format_.extract(carrier) + span_context = get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, 1) self.assertEqual(span_context.span_id, 2) @@ -310,49 +314,38 @@ def test_invalid_span_id( def test_missing_span_id(self): """If a trace id is missing, populate an invalid trace id.""" carrier = { - FORMAT.TRACE_ID_KEY: self.serialized_trace_id, - FORMAT.FLAGS_KEY: "1", + format_.TRACE_ID_KEY: self.serialized_trace_id, + format_.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier_getter, carrier) - span_context = trace_api.get_current_span(ctx).get_span_context() - self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) + ctx = format_.extract(carrier) + span_context = get_current_span(ctx).get_span_context() + self.assertEqual(span_context.span_id, INVALID_SPAN_ID) - @staticmethod - def test_inject_empty_context(): + def test_inject_empty_context(self): """If the current context has no span, don't add headers""" new_carrier = {} - FORMAT.inject(dict.__setitem__, new_carrier, get_current()) - assert len(new_carrier) == 0 - - @staticmethod - def test_default_span(): - """Make sure propagator does not crash when working with NonRecordingSpan""" - - class CarrierGetter(DictGetter): - def get(self, carrier, key): - return carrier.get(key, None) + format_.inject(new_carrier, get_current()) + self.assertEqual(len(new_carrier), 0) - def setter(carrier, key, value): - carrier[key] = value + def test_default_span(self): + """Make sure propagator does not crash when working with + NonRecordingSpan""" - ctx = FORMAT.extract(CarrierGetter(), {}) - FORMAT.inject(setter, {}, ctx) + try: + format_.inject({}, format_.extract({})) + except Exception: # pylint: disable=broad-except + self.fail("propagator crashed when working with NonRecordingSpan") def test_fields(self): """Make sure the fields attribute returns the fields used in inject""" - tracer = trace.TracerProvider().get_tracer("sdk_tracer_provider") + tracer = TracerProvider().get_tracer("sdk_tracer_provider") - mock_set_in_carrier = Mock() + carrier = {} with tracer.start_as_current_span("parent"): with tracer.start_as_current_span("child"): - FORMAT.inject(mock_set_in_carrier, {}) - - inject_fields = set() - - for call in mock_set_in_carrier.mock_calls: - inject_fields.add(call[1][1]) + format_.inject(carrier) - self.assertEqual(FORMAT.fields, inject_fields) + self.assertEqual(format_.fields, carrier.keys()) diff --git a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py index 8e7fe5f69ff..3bda496db6f 100644 --- a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py +++ b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py @@ -12,19 +12,25 @@ # See the License for the specific language governing permissions and # limitations under the License. -import typing -import urllib.parse +from typing import Dict, Optional, Set +from urllib.parse import quote, unquote -import opentelemetry.trace as trace from opentelemetry import baggage from opentelemetry.context import Context, get_current -from opentelemetry.propagators.textmap import ( - Getter, - Setter, - TextMapPropagator, - TextMapPropagatorT, +from opentelemetry.propagators.textmap import TextMapPropagator +from opentelemetry.trace import ( + INVALID_SPAN, + INVALID_SPAN_CONTEXT, + INVALID_SPAN_ID, + INVALID_TRACE_ID, + NonRecordingSpan, + SpanContext, + TraceFlags, + format_span_id, + format_trace_id, + get_current_span, + set_span_in_context, ) -from opentelemetry.trace import format_span_id, format_trace_id class JaegerPropagator(TextMapPropagator): @@ -33,73 +39,68 @@ class JaegerPropagator(TextMapPropagator): See: https://www.jaegertracing.io/docs/1.19/client-libraries/#propagation-format """ - TRACE_ID_KEY = "uber-trace-id" - BAGGAGE_PREFIX = "uberctx-" - DEBUG_FLAG = 0x02 + _trace_id_key = "uber-trace-id" + _baggage_prefix = "uberctx-" + _debug_flag = 0x02 def extract( - self, - getter: Getter[TextMapPropagatorT], - carrier: TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> Context: if context is None: context = get_current() - header = getter.get(carrier, self.TRACE_ID_KEY) - if not header: - return trace.set_span_in_context(trace.INVALID_SPAN, context) - fields = _extract_first_element(header).split(":") + header = carrier.get(self._trace_id_key) + if header is None: + return set_span_in_context(INVALID_SPAN, context) + fields = header.split(":") + + for key in [ + key + for key in carrier.keys() + if key.startswith(self._baggage_prefix) + ]: + context = baggage.set_baggage( + key.replace(self._baggage_prefix, ""), + unquote(carrier[key]).strip(), + context=context, + ) - context = self._extract_baggage(getter, carrier, context) if len(fields) != 4: - return trace.set_span_in_context(trace.INVALID_SPAN, context) + return set_span_in_context(INVALID_SPAN, context) trace_id, span_id, _parent_id, flags = fields - if ( - trace_id == trace.INVALID_TRACE_ID - or span_id == trace.INVALID_SPAN_ID - ): - return trace.set_span_in_context(trace.INVALID_SPAN, context) - - span = trace.NonRecordingSpan( - trace.SpanContext( + if trace_id == INVALID_TRACE_ID or span_id == INVALID_SPAN_ID: + return set_span_in_context(INVALID_SPAN, context) + + span = NonRecordingSpan( + SpanContext( trace_id=int(trace_id, 16), span_id=int(span_id, 16), is_remote=True, - trace_flags=trace.TraceFlags( - int(flags, 16) & trace.TraceFlags.SAMPLED - ), + trace_flags=TraceFlags(int(flags, 16) & TraceFlags.SAMPLED), ) ) - return trace.set_span_in_context(span, context) + return set_span_in_context(span, context) def inject( - self, - set_in_carrier: Setter[TextMapPropagatorT], - carrier: TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> None: - span = trace.get_current_span(context=context) + span = get_current_span(context=context) span_context = span.get_span_context() - if span_context == trace.INVALID_SPAN_CONTEXT: + if span_context == INVALID_SPAN_CONTEXT: return span_parent_id = span.parent.span_id if span.parent else 0 trace_flags = span_context.trace_flags if trace_flags.sampled: - trace_flags |= self.DEBUG_FLAG + trace_flags |= self._debug_flag # set span identity - set_in_carrier( - carrier, - self.TRACE_ID_KEY, - _format_uber_trace_id( - span_context.trace_id, - span_context.span_id, - span_parent_id, - trace_flags, - ), + carrier[self._trace_id_key] = _format_uber_trace_id( + span_context.trace_id, + span_context.span_id, + span_parent_id, + trace_flags, ) # set span baggage, if any @@ -107,43 +108,18 @@ def inject( if not baggage_entries: return for key, value in baggage_entries.items(): - baggage_key = self.BAGGAGE_PREFIX + key - set_in_carrier( - carrier, baggage_key, urllib.parse.quote(str(value)) - ) + baggage_key = self._baggage_prefix + key + carrier[baggage_key] = quote(str(value)) @property - def fields(self) -> typing.Set[str]: - return {self.TRACE_ID_KEY} - - def _extract_baggage(self, getter, carrier, context): - baggage_keys = [ - key - for key in getter.keys(carrier) - if key.startswith(self.BAGGAGE_PREFIX) - ] - for key in baggage_keys: - value = _extract_first_element(getter.get(carrier, key)) - context = baggage.set_baggage( - key.replace(self.BAGGAGE_PREFIX, ""), - urllib.parse.unquote(value).strip(), - context=context, - ) - return context + def fields(self) -> Set[str]: + return {self._trace_id_key} def _format_uber_trace_id(trace_id, span_id, parent_span_id, flags): - return "{trace_id}:{span_id}:{parent_id}:{:02x}".format( - flags, + return "{trace_id}:{span_id}:{parent_id}:{flags:02x}".format( trace_id=format_trace_id(trace_id), span_id=format_span_id(span_id), parent_id=format_span_id(parent_span_id), + flags=flags, ) - - -def _extract_first_element( - items: typing.Iterable[TextMapPropagatorT], -) -> typing.Optional[TextMapPropagatorT]: - if items is None: - return None - return next(iter(items), None) diff --git a/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py b/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py index da8a855edbe..c5f4f150cd5 100644 --- a/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py +++ b/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py @@ -12,27 +12,23 @@ # See the License for the specific language governing permissions and # limitations under the License. -import unittest -from unittest.mock import Mock +from unittest import TestCase import opentelemetry.sdk.trace as trace import opentelemetry.sdk.trace.id_generator as id_generator import opentelemetry.trace as trace_api from opentelemetry import baggage -from opentelemetry.propagators import ( # pylint: disable=no-name-in-module - jaeger, +from opentelemetry.propagators.jaeger import ( # pylint: disable=no-name-in-module + JaegerPropagator, + _format_uber_trace_id, ) -from opentelemetry.propagators.textmap import DictGetter -FORMAT = jaeger.JaegerPropagator() - - -carrier_getter = DictGetter() +format_ = JaegerPropagator() def get_context_new_carrier(old_carrier, carrier_baggage=None): - ctx = FORMAT.extract(carrier_getter, old_carrier) + ctx = format_.extract(old_carrier) if carrier_baggage: for key, value in carrier_baggage.items(): ctx = baggage.set_baggage(key, value, ctx) @@ -54,93 +50,94 @@ def get_context_new_carrier(old_carrier, carrier_baggage=None): new_carrier = {} ctx = trace_api.set_span_in_context(child, ctx) - FORMAT.inject(dict.__setitem__, new_carrier, context=ctx) + format_.inject(new_carrier, context=ctx) return ctx, new_carrier -class TestJaegerPropagator(unittest.TestCase): +class TestJaegerPropagator(TestCase): + # pylint: disable=protected-access @classmethod def setUpClass(cls): generator = id_generator.RandomIdGenerator() cls.trace_id = generator.generate_trace_id() cls.span_id = generator.generate_span_id() cls.parent_span_id = generator.generate_span_id() - cls.serialized_uber_trace_id = jaeger._format_uber_trace_id( # pylint: disable=protected-access + cls.serialized_uber_trace_id = _format_uber_trace_id( cls.trace_id, cls.span_id, cls.parent_span_id, 11 ) def test_extract_valid_span(self): - old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} - ctx = FORMAT.extract(carrier_getter, old_carrier) + old_carrier = {format_._trace_id_key: self.serialized_uber_trace_id} + ctx = format_.extract(old_carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, self.trace_id) self.assertEqual(span_context.span_id, self.span_id) def test_missing_carrier(self): old_carrier = {} - ctx = FORMAT.extract(carrier_getter, old_carrier) + ctx = format_.extract(old_carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) def test_trace_id(self): - old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} + old_carrier = {format_._trace_id_key: self.serialized_uber_trace_id} _, new_carrier = get_context_new_carrier(old_carrier) self.assertEqual( self.serialized_uber_trace_id.split(":")[0], - new_carrier[FORMAT.TRACE_ID_KEY].split(":")[0], + new_carrier[format_._trace_id_key].split(":")[0], ) def test_parent_span_id(self): - old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} + old_carrier = {format_._trace_id_key: self.serialized_uber_trace_id} _, new_carrier = get_context_new_carrier(old_carrier) span_id = self.serialized_uber_trace_id.split(":")[1] - parent_span_id = new_carrier[FORMAT.TRACE_ID_KEY].split(":")[2] + parent_span_id = new_carrier[format_._trace_id_key].split(":")[2] self.assertEqual(span_id, parent_span_id) def test_sampled_flag_set(self): - old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} + old_carrier = {format_._trace_id_key: self.serialized_uber_trace_id} _, new_carrier = get_context_new_carrier(old_carrier) sample_flag_value = ( - int(new_carrier[FORMAT.TRACE_ID_KEY].split(":")[3]) & 0x01 + int(new_carrier[format_._trace_id_key].split(":")[3]) & 0x01 ) self.assertEqual(1, sample_flag_value) def test_debug_flag_set(self): - old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} + old_carrier = {format_._trace_id_key: self.serialized_uber_trace_id} _, new_carrier = get_context_new_carrier(old_carrier) debug_flag_value = ( - int(new_carrier[FORMAT.TRACE_ID_KEY].split(":")[3]) - & FORMAT.DEBUG_FLAG + int(new_carrier[format_._trace_id_key].split(":")[3]) + & format_._debug_flag ) - self.assertEqual(FORMAT.DEBUG_FLAG, debug_flag_value) + self.assertEqual(format_._debug_flag, debug_flag_value) def test_sample_debug_flags_unset(self): - uber_trace_id = jaeger._format_uber_trace_id( # pylint: disable=protected-access + uber_trace_id = _format_uber_trace_id( self.trace_id, self.span_id, self.parent_span_id, 0 ) - old_carrier = {FORMAT.TRACE_ID_KEY: uber_trace_id} + old_carrier = {format_._trace_id_key: uber_trace_id} _, new_carrier = get_context_new_carrier(old_carrier) - flags = int(new_carrier[FORMAT.TRACE_ID_KEY].split(":")[3]) + flags = int(new_carrier[format_._trace_id_key].split(":")[3]) sample_flag_value = flags & 0x01 - debug_flag_value = flags & FORMAT.DEBUG_FLAG + debug_flag_value = flags & format_._debug_flag self.assertEqual(0, sample_flag_value) self.assertEqual(0, debug_flag_value) def test_baggage(self): - old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} + old_carrier = {format_._trace_id_key: self.serialized_uber_trace_id} input_baggage = {"key1": "value1"} _, new_carrier = get_context_new_carrier(old_carrier, input_baggage) - ctx = FORMAT.extract(carrier_getter, new_carrier) + ctx = format_.extract(new_carrier) self.assertDictEqual(input_baggage, ctx["baggage"]) def test_non_string_baggage(self): - old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} + old_carrier = {format_._trace_id_key: self.serialized_uber_trace_id} input_baggage = {"key1": 1, "key2": True} formatted_baggage = {"key1": "1", "key2": "True"} _, new_carrier = get_context_new_carrier(old_carrier, input_baggage) - ctx = FORMAT.extract(carrier_getter, new_carrier) + ctx = format_.extract(new_carrier) self.assertDictEqual(formatted_baggage, ctx["baggage"]) def test_extract_invalid_uber_trace_id(self): @@ -149,7 +146,7 @@ def test_extract_invalid_uber_trace_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = FORMAT.extract(carrier_getter, old_carrier) + context = format_.extract(old_carrier) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) @@ -160,7 +157,7 @@ def test_extract_invalid_trace_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = FORMAT.extract(carrier_getter, old_carrier) + context = format_.extract(old_carrier) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) @@ -171,18 +168,18 @@ def test_extract_invalid_span_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = FORMAT.extract(carrier_getter, old_carrier) + context = format_.extract(old_carrier) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) def test_fields(self): tracer = trace.TracerProvider().get_tracer("sdk_tracer_provider") - mock_set_in_carrier = Mock() + + carrier = {} + with tracer.start_as_current_span("parent"): with tracer.start_as_current_span("child"): - FORMAT.inject(mock_set_in_carrier, {}) - inject_fields = set() - for call in mock_set_in_carrier.mock_calls: - inject_fields.add(call[1][1]) - self.assertEqual(FORMAT.fields, inject_fields) + format_.inject(carrier) + + self.assertEqual(format_.fields, carrier.keys()) diff --git a/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py b/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py index b7a365302f9..2327abbfae1 100644 --- a/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py +++ b/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py @@ -102,7 +102,6 @@ from opentelemetry.baggage import get_baggage, set_baggage from opentelemetry.context import Context, attach, detach, get_value, set_value from opentelemetry.propagate import get_global_textmap -from opentelemetry.propagators.textmap import DictGetter from opentelemetry.shim.opentracing_shim import util from opentelemetry.shim.opentracing_shim.version import __version__ from opentelemetry.trace import INVALID_SPAN_CONTEXT, Link, NonRecordingSpan @@ -527,7 +526,6 @@ def __init__(self, tracer: OtelTracer): Format.TEXT_MAP, Format.HTTP_HEADERS, ) - self._carrier_getter = DictGetter() def unwrap(self): """Returns the :class:`opentelemetry.trace.Tracer` object that is @@ -684,7 +682,7 @@ def inject(self, span_context, format: object, carrier: object): propagator = get_global_textmap() ctx = set_span_in_context(NonRecordingSpan(span_context.unwrap())) - propagator.inject(type(carrier).__setitem__, carrier, context=ctx) + propagator.inject(carrier, context=ctx) def extract(self, format: object, carrier: object): """Returns an ``opentracing.SpanContext`` instance extracted from a @@ -712,7 +710,7 @@ def extract(self, format: object, carrier: object): raise UnsupportedFormatException propagator = get_global_textmap() - ctx = propagator.extract(self._carrier_getter, carrier) + ctx = propagator.extract(carrier) span = get_current_span(ctx) if span is not None: otel_context = span.get_span_context() diff --git a/shim/opentelemetry-opentracing-shim/tests/test_shim.py b/shim/opentelemetry-opentracing-shim/tests/test_shim.py index a27d30de718..ef73843073f 100644 --- a/shim/opentelemetry-opentracing-shim/tests/test_shim.py +++ b/shim/opentelemetry-opentracing-shim/tests/test_shim.py @@ -493,9 +493,9 @@ def test_inject_http_headers(self): headers = {} self.shim.inject(context, opentracing.Format.HTTP_HEADERS, headers) self.assertEqual( - headers[MockTextMapPropagator.TRACE_ID_KEY], str(1220) + headers[MockTextMapPropagator.trace_id_key], str(1220) ) - self.assertEqual(headers[MockTextMapPropagator.SPAN_ID_KEY], str(7478)) + self.assertEqual(headers[MockTextMapPropagator.span_id_key], str(7478)) def test_inject_text_map(self): """Test `inject()` method for Format.TEXT_MAP.""" @@ -509,10 +509,10 @@ def test_inject_text_map(self): text_map = {} self.shim.inject(context, opentracing.Format.TEXT_MAP, text_map) self.assertEqual( - text_map[MockTextMapPropagator.TRACE_ID_KEY], str(1220) + text_map[MockTextMapPropagator.trace_id_key], str(1220) ) self.assertEqual( - text_map[MockTextMapPropagator.SPAN_ID_KEY], str(7478) + text_map[MockTextMapPropagator.span_id_key], str(7478) ) def test_inject_binary(self): @@ -531,8 +531,8 @@ def test_extract_http_headers(self): """Test `extract()` method for Format.HTTP_HEADERS.""" carrier = { - MockTextMapPropagator.TRACE_ID_KEY: 1220, - MockTextMapPropagator.SPAN_ID_KEY: 7478, + MockTextMapPropagator.trace_id_key: 1220, + MockTextMapPropagator.span_id_key: 7478, } ctx = self.shim.extract(opentracing.Format.HTTP_HEADERS, carrier) @@ -557,8 +557,8 @@ def test_extract_text_map(self): """Test `extract()` method for Format.TEXT_MAP.""" carrier = { - MockTextMapPropagator.TRACE_ID_KEY: 1220, - MockTextMapPropagator.SPAN_ID_KEY: 7478, + MockTextMapPropagator.trace_id_key: 1220, + MockTextMapPropagator.span_id_key: 7478, } ctx = self.shim.extract(opentracing.Format.TEXT_MAP, carrier) diff --git a/tests/util/src/opentelemetry/test/mock_textmap.py b/tests/util/src/opentelemetry/test/mock_textmap.py index 1edd079042f..82cbbfd8a60 100644 --- a/tests/util/src/opentelemetry/test/mock_textmap.py +++ b/tests/util/src/opentelemetry/test/mock_textmap.py @@ -12,15 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -import typing +from typing import Dict, Optional -from opentelemetry import trace from opentelemetry.context import Context, get_current -from opentelemetry.propagators.textmap import ( - Getter, - Setter, - TextMapPropagator, - TextMapPropagatorT, +from opentelemetry.propagators.textmap import TextMapPropagator +from opentelemetry.trace import ( + INVALID_SPAN, + NonRecordingSpan, + SpanContext, + get_current_span, + set_span_in_context, ) @@ -32,18 +33,12 @@ class NOOPTextMapPropagator(TextMapPropagator): """ def extract( - self, - getter: Getter[TextMapPropagatorT], - carrier: TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> Context: return get_current() def inject( - self, - set_in_carrier: Setter[TextMapPropagatorT], - carrier: TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> None: return None @@ -55,45 +50,33 @@ def fields(self): class MockTextMapPropagator(TextMapPropagator): """Mock propagator for testing purposes.""" - TRACE_ID_KEY = "mock-traceid" - SPAN_ID_KEY = "mock-spanid" + trace_id_key = "mock-traceid" + span_id_key = "mock-spanid" def extract( - self, - getter: Getter[TextMapPropagatorT], - carrier: TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> Context: - trace_id_list = getter.get(carrier, self.TRACE_ID_KEY) - span_id_list = getter.get(carrier, self.SPAN_ID_KEY) - - if not trace_id_list or not span_id_list: - return trace.set_span_in_context(trace.INVALID_SPAN) - - return trace.set_span_in_context( - trace.NonRecordingSpan( - trace.SpanContext( - trace_id=int(trace_id_list[0]), - span_id=int(span_id_list[0]), - is_remote=True, + trace_id = carrier.get(self.trace_id_key) + span_id = carrier.get(self.span_id_key) + + if trace_id is None or span_id is None: + return set_span_in_context(INVALID_SPAN) + + return set_span_in_context( + NonRecordingSpan( + SpanContext( + trace_id=trace_id, span_id=span_id, is_remote=True, ) ) ) def inject( - self, - set_in_carrier: Setter[TextMapPropagatorT], - carrier: TextMapPropagatorT, - context: typing.Optional[Context] = None, + self, carrier: Dict[str, str], context: Optional[Context] = None, ) -> None: - span = trace.get_current_span(context) - set_in_carrier( - carrier, self.TRACE_ID_KEY, str(span.get_span_context().trace_id) - ) - set_in_carrier( - carrier, self.SPAN_ID_KEY, str(span.get_span_context().span_id) - ) + span = get_current_span(context) + carrier[self.trace_id_key] = str(span.get_span_context().trace_id) + carrier[self.span_id_key] = str(span.get_span_context().span_id) @property def fields(self): - return {self.TRACE_ID_KEY, self.SPAN_ID_KEY} + return {self.trace_id_key, self.span_id_key} From cfd4dc7f683792743c41a7e501becce8779d212a Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Mon, 22 Mar 2021 11:02:09 -0600 Subject: [PATCH 02/28] Remove code cleanup --- .github/workflows/test.yml | 2 +- .../baggage/propagation/__init__.py | 50 ++-- .../src/opentelemetry/propagate/__init__.py | 25 +- .../opentelemetry/propagators/composite.py | 40 ++-- .../src/opentelemetry/propagators/textmap.py | 22 +- .../trace/propagation/tracecontext.py | 118 +++++----- .../tests/baggage/test_baggage_propagation.py | 117 +++++----- .../propagators/test_global_httptextformat.py | 12 +- .../tests/trace/propagation/test_textmap.py | 44 ---- .../test_tracecontexthttptextformat.py | 63 +++-- .../tests/trace/test_tracestate.py | 42 ++-- .../opentelemetry/propagators/b3/__init__.py | 18 +- .../tests/test_b3_format.py | 218 +++++++++--------- .../propagators/jaeger/__init__.py | 99 ++++---- .../tests/test_jaeger_propagator.py | 71 +++--- .../tests/test_shim.py | 16 +- .../src/opentelemetry/test/mock_textmap.py | 50 ++-- 17 files changed, 485 insertions(+), 522 deletions(-) delete mode 100644 opentelemetry-api/tests/trace/propagation/test_textmap.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 48099d10b83..e3174a5f641 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: 1300fcec899a37bb41145b602c938221c696607b + CONTRIB_REPO_SHA: a1bda203e3d84acf95641fe97e8c080361c8528e jobs: build: diff --git a/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py b/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py index 20337ad81f3..0c0dc25663e 100644 --- a/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py +++ b/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py @@ -11,26 +11,28 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - -from typing import Dict, Optional, Set -from urllib.parse import quote_plus, unquote +# +import typing +import urllib.parse from opentelemetry import baggage from opentelemetry.context import get_current from opentelemetry.context.context import Context -from opentelemetry.propagators.textmap import TextMapPropagator +from opentelemetry.propagators import textmap -class W3CBaggagePropagator(TextMapPropagator): +class W3CBaggagePropagator(textmap.TextMapPropagator): """Extracts and injects Baggage which is used to annotate telemetry.""" - _baggage_header_name = "baggage" - _max_header_length = 9182 - _max_pairs = 180 - _max_pair_length = 4096 + _MAX_HEADER_LENGTH = 8192 + _MAX_PAIR_LENGTH = 4096 + _MAX_PAIRS = 180 + _BAGGAGE_HEADER_NAME = "baggage" def extract( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> Context: """Extract Baggage from the carrier. @@ -41,31 +43,33 @@ def extract( if context is None: context = get_current() - header = carrier.get(self._baggage_header_name) + header = carrier.get(self._BAGGAGE_HEADER_NAME) - if header is None or len(header) > self._max_header_length: + if not header or len(header) > self._MAX_HEADER_LENGTH: return context - total_baggage_entries = self._max_pairs - - for entry in header.split(","): + baggage_entries = header.split(",") + total_baggage_entries = self._MAX_PAIRS + for entry in baggage_entries: if total_baggage_entries <= 0: return context total_baggage_entries -= 1 - if len(entry) > self._max_pair_length: + if len(entry) > self._MAX_PAIR_LENGTH: continue if "=" in entry: name, value = entry.split("=", 1) context = baggage.set_baggage( - unquote(name).strip(), - unquote(value).strip(), + urllib.parse.unquote(name).strip(), + urllib.parse.unquote(value).strip(), context=context, ) return context def inject( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> None: """Injects Baggage into the carrier. @@ -75,12 +79,12 @@ def inject( baggage_entries = baggage.get_all(context=context) if baggage_entries: - carrier[self._baggage_header_name] = ",".join( - key + "=" + quote_plus(str(value)) + carrier[self._BAGGAGE_HEADER_NAME] = ",".join( + key + "=" + urllib.parse.quote_plus(str(value)) for key, value in baggage_entries.items() ) @property - def fields(self) -> Set[str]: + def fields(self) -> typing.Set[str]: """Returns a set with the fields set in `inject`.""" - return {self._baggage_header_name} + return {self._BAGGAGE_HEADER_NAME} diff --git a/opentelemetry-api/src/opentelemetry/propagate/__init__.py b/opentelemetry-api/src/opentelemetry/propagate/__init__.py index 569c53d2f21..02fb165271a 100644 --- a/opentelemetry-api/src/opentelemetry/propagate/__init__.py +++ b/opentelemetry-api/src/opentelemetry/propagate/__init__.py @@ -57,22 +57,21 @@ def example_route(): https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/api-propagators.md """ +import typing from logging import getLogger from os import environ -from typing import Dict, Optional from pkg_resources import iter_entry_points from opentelemetry.context.context import Context from opentelemetry.environment_variables import OTEL_PROPAGATORS -from opentelemetry.propagators import composite -from opentelemetry.propagators.textmap import TextMapPropagator +from opentelemetry.propagators import composite, textmap -_logger = getLogger(__name__) +logger = getLogger(__name__) def extract( - carrier: Dict[str, str], context: Optional[Context] = None, + carrier: typing.Dict[str, str], context: typing.Optional[Context] = None, ) -> Context: """Uses the configured propagator to extract a Context from the carrier. @@ -91,7 +90,7 @@ def extract( def inject( - carrier: Dict[str, str], context: Optional[Context] = None, + carrier: typing.Dict[str, str], context: typing.Optional[Context] = None, ) -> None: """Uses the configured propagator to inject a Context into the carrier. @@ -121,16 +120,16 @@ def inject( ) except Exception: # pylint: disable=broad-except - _logger.error("Failed to load configured propagators") + logger.exception("Failed to load configured propagators") raise -_textmap_propagator = composite.CompositeHTTPPropagator(propagators) # type: ignore +_HTTP_TEXT_FORMAT = composite.CompositeHTTPPropagator(propagators) # type: ignore -def get_global_textmap() -> TextMapPropagator: - return _textmap_propagator +def get_global_textmap() -> textmap.TextMapPropagator: + return _HTTP_TEXT_FORMAT -def set_global_textmap(http_text_format: TextMapPropagator,) -> None: - global _textmap_propagator # pylint:disable=global-statement - _textmap_propagator = http_text_format # type: ignore +def set_global_textmap(http_text_format: textmap.TextMapPropagator,) -> None: + global _HTTP_TEXT_FORMAT # pylint:disable=global-statement + _HTTP_TEXT_FORMAT = http_text_format # type: ignore diff --git a/opentelemetry-api/src/opentelemetry/propagators/composite.py b/opentelemetry-api/src/opentelemetry/propagators/composite.py index 858483a69dd..82f5c3fc46b 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/composite.py +++ b/opentelemetry-api/src/opentelemetry/propagators/composite.py @@ -11,17 +11,16 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - -from logging import getLogger -from typing import Dict, Optional, Sequence, Set +import logging +import typing from opentelemetry.context.context import Context -from opentelemetry.propagators.textmap import TextMapPropagator +from opentelemetry.propagators import textmap -_logger = getLogger(__name__) +logger = logging.getLogger(__name__) -class CompositeHTTPPropagator(TextMapPropagator): +class CompositeHTTPPropagator(textmap.TextMapPropagator): """CompositeHTTPPropagator provides a mechanism for combining multiple propagators into a single one. @@ -29,17 +28,20 @@ class CompositeHTTPPropagator(TextMapPropagator): propagators: the list of propagators to use """ - def __init__(self, propagators: Sequence[TextMapPropagator]) -> None: + def __init__( + self, propagators: typing.Sequence[textmap.TextMapPropagator] + ) -> None: self._propagators = propagators def extract( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> Context: - """Run each of the configured propagators with the given context and - carrier. + """Run each of the configured propagators with the given context and carrier. Propagators are run in the order they are configured, if multiple - propagators write the same context key, the last propagator that writes - the context key will override previous propagators. + propagators write the same context key, the propagator later in the list + will override previous propagators. See `opentelemetry.propagators.textmap.TextMapPropagator.extract` """ @@ -48,12 +50,14 @@ def extract( return context # type: ignore def inject( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> None: - """Run each of the configured propagators with the given context and - carrier. Propagators are run in the order they are configured, if - multiple propagators write the same carrier key, the last propagator - that writes the carrier key will override previous propagators. + """Run each of the configured propagators with the given context and carrier. + Propagators are run in the order they are configured, if multiple + propagators write the same carrier key, the propagator later in the list + will override previous propagators. See `opentelemetry.propagators.textmap.TextMapPropagator.inject` """ @@ -61,7 +65,7 @@ def inject( propagator.inject(carrier, context) @property - def fields(self) -> Set[str]: + def fields(self) -> typing.Set[str]: """Returns a set with the fields set in `inject`. See diff --git a/opentelemetry-api/src/opentelemetry/propagators/textmap.py b/opentelemetry-api/src/opentelemetry/propagators/textmap.py index 22b5946ad09..aa4a4589f20 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/textmap.py +++ b/opentelemetry-api/src/opentelemetry/propagators/textmap.py @@ -12,22 +12,24 @@ # See the License for the specific language governing permissions and # limitations under the License. -from abc import ABC, abstractmethod -from typing import Dict, Optional, Set +import abc +import typing from opentelemetry.context.context import Context -class TextMapPropagator(ABC): +class TextMapPropagator(abc.ABC): """This class provides an interface that enables extracting and injecting context into headers of HTTP requests. HTTP frameworks and clients can integrate with TextMapPropagator by providing the object containing the headers. """ - @abstractmethod + @abc.abstractmethod def extract( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> Context: """Create a Context from values in the carrier. @@ -43,9 +45,11 @@ def extract( A Context with the configuration found in the carrier. """ - @abstractmethod + @abc.abstractmethod def inject( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> None: """Inject values from a Context into a carrier. @@ -60,8 +64,8 @@ def inject( """ @property - @abstractmethod - def fields(self) -> Set[str]: + @abc.abstractmethod + def fields(self) -> typing.Set[str]: """ Gets the fields set in the carrier by the `inject` method. diff --git a/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py b/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py index 5f5dc2df810..11248025c0b 100644 --- a/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py +++ b/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py @@ -11,101 +11,92 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# +import re +import typing -from re import compile as compile_ -from re import search -from typing import Dict, Optional, Set - +import opentelemetry.trace as trace from opentelemetry.context.context import Context -from opentelemetry.propagators.textmap import TextMapPropagator -from opentelemetry.trace import ( - INVALID_SPAN, - INVALID_SPAN_CONTEXT, - NonRecordingSpan, - SpanContext, - TraceFlags, - format_span_id, - format_trace_id, - get_current_span, - set_span_in_context, -) +from opentelemetry.propagators import textmap +from opentelemetry.trace import format_span_id, format_trace_id from opentelemetry.trace.span import TraceState -class TraceContextTextMapPropagator(TextMapPropagator): +class TraceContextTextMapPropagator(textmap.TextMapPropagator): """Extracts and injects using w3c TraceContext's headers.""" - _traceparent_header_name = "traceparent" - _tracestate_header_name = "tracestate" - _traceparent_header_format_re = compile_( - r"^\s*(?P[0-9a-f]{2})-" - r"(?P[0-9a-f]{32})-" - r"(?P[0-9a-f]{16})-" - r"(?P[0-9a-f]{2})" - r"(?P.+?)?\s*$" + _TRACEPARENT_HEADER_NAME = "traceparent" + _TRACESTATE_HEADER_NAME = "tracestate" + _TRACEPARENT_HEADER_FORMAT = ( + "^[ \t]*([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})" + + "(-.*)?[ \t]*$" ) + _TRACEPARENT_HEADER_FORMAT_RE = re.compile(_TRACEPARENT_HEADER_FORMAT) def extract( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> Context: """Extracts SpanContext from the carrier. See `opentelemetry.propagators.textmap.TextMapPropagator.extract` """ - header = carrier.get(self._traceparent_header_name) + header = carrier.get(self._TRACEPARENT_HEADER_NAME) - if header is None: - return set_span_in_context(INVALID_SPAN, context) + if not header: + return trace.set_span_in_context(trace.INVALID_SPAN, context) - match = search(self._traceparent_header_format_re, header) - if match is None: - return set_span_in_context(INVALID_SPAN, context) + match = re.search(self._TRACEPARENT_HEADER_FORMAT_RE, header) + if not match: + return trace.set_span_in_context(trace.INVALID_SPAN, context) - version = match.group("version") - trace_id = match.group("trace_id") - span_id = match.group("span_id") + version = match.group(1) + trace_id = match.group(2) + span_id = match.group(3) + trace_flags = match.group(4) - if ( - version == "ff" - or trace_id == "0" * 32 - or span_id == "0" * 16 - or (version == "00" and match.group("remainder")) - ): + if trace_id == "0" * 32 or span_id == "0" * 16: + return trace.set_span_in_context(trace.INVALID_SPAN, context) - return set_span_in_context(INVALID_SPAN, context) - - tracestate_headers = carrier.get(self._tracestate_header_name) + if version == "00": + if match.group(5): + return trace.set_span_in_context(trace.INVALID_SPAN, context) + if version == "ff": + return trace.set_span_in_context(trace.INVALID_SPAN, context) + tracestate_headers = carrier.get(self._TRACESTATE_HEADER_NAME) if tracestate_headers is None: tracestate = None else: tracestate = TraceState.from_header(tracestate_headers) - return set_span_in_context( - NonRecordingSpan( - SpanContext( - trace_id=int(trace_id, 16), - span_id=int(span_id, 16), - is_remote=True, - trace_flags=TraceFlags(match.group("trace_flags")), - trace_state=tracestate, - ) - ), - context, + span_context = trace.SpanContext( + trace_id=int(trace_id, 16), + span_id=int(span_id, 16), + is_remote=True, + trace_flags=trace.TraceFlags(trace_flags), + trace_state=tracestate, + ) + return trace.set_span_in_context( + trace.NonRecordingSpan(span_context), context ) def inject( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> None: """Injects SpanContext into the carrier. See `opentelemetry.propagators.textmap.TextMapPropagator.inject` """ - span_context = get_current_span(context).get_span_context() - if span_context == INVALID_SPAN_CONTEXT: + span = trace.get_current_span(context) + span_context = span.get_span_context() + if span_context == trace.INVALID_SPAN_CONTEXT: return carrier[ - self._traceparent_header_name + self._TRACEPARENT_HEADER_NAME ] = "00-{trace_id}-{span_id}-{:02x}".format( span_context.trace_flags, trace_id=format_trace_id(span_context.trace_id), @@ -113,15 +104,14 @@ def inject( ) if span_context.trace_state: - carrier[ - self._tracestate_header_name - ] = span_context.trace_state.to_header() + tracestate_string = span_context.trace_state.to_header() + carrier[self._TRACESTATE_HEADER_NAME] = tracestate_string @property - def fields(self) -> Set[str]: + def fields(self) -> typing.Set[str]: """Returns a set with the fields set in `inject`. See `opentelemetry.propagators.textmap.TextMapPropagator.fields` """ - return {self._traceparent_header_name, self._tracestate_header_name} + return {self._TRACEPARENT_HEADER_NAME, self._TRACESTATE_HEADER_NAME} diff --git a/opentelemetry-api/tests/baggage/test_baggage_propagation.py b/opentelemetry-api/tests/baggage/test_baggage_propagation.py index 772b62d90fe..11bdc2429af 100644 --- a/opentelemetry-api/tests/baggage/test_baggage_propagation.py +++ b/opentelemetry-api/tests/baggage/test_baggage_propagation.py @@ -11,8 +11,10 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# +# type: ignore -from unittest import TestCase +import unittest from unittest.mock import patch from opentelemetry import baggage @@ -20,7 +22,7 @@ from opentelemetry.context import get_current -class TestBaggagePropagation(TestCase): +class TestBaggagePropagation(unittest.TestCase): def setUp(self): self.propagator = W3CBaggagePropagator() @@ -43,94 +45,97 @@ def test_no_context_header(self): self.assertEqual(baggage.get_all(self.propagator.extract({})), {}) def test_empty_context_header(self): - self.assertEqual(self._extract(""), {}) + header = "" + self.assertEqual(self._extract(header), {}) def test_valid_header(self): - self.assertEqual( - self._extract("key1=val1,key2=val2"), - {"key1": "val1", "key2": "val2"}, - ) + header = "key1=val1,key2=val2" + expected = {"key1": "val1", "key2": "val2"} + self.assertEqual(self._extract(header), expected) def test_valid_header_with_space(self): - self.assertEqual( - self._extract("key1 = val1, key2 =val2 "), - {"key1": "val1", "key2": "val2"}, - ) + header = "key1 = val1, key2 =val2 " + expected = {"key1": "val1", "key2": "val2"} + self.assertEqual(self._extract(header), expected) def test_valid_header_with_properties(self): - self.assertEqual( - self._extract("key1=val1,key2=val2;prop=1"), - {"key1": "val1", "key2": "val2;prop=1"}, - ) + header = "key1=val1,key2=val2;prop=1" + expected = {"key1": "val1", "key2": "val2;prop=1"} + self.assertEqual(self._extract(header), expected) def test_valid_header_with_url_escaped_comma(self): - self.assertEqual( - self._extract("key%2C1=val1,key2=val2%2Cval3"), - {"key,1": "val1", "key2": "val2,val3"}, - ) + header = "key%2C1=val1,key2=val2%2Cval3" + expected = {"key,1": "val1", "key2": "val2,val3"} + self.assertEqual(self._extract(header), expected) def test_valid_header_with_invalid_value(self): - self.assertEqual( - self._extract("key1=val1,key2=val2,a,val3"), - {"key1": "val1", "key2": "val2"}, - ) + header = "key1=val1,key2=val2,a,val3" + expected = {"key1": "val1", "key2": "val2"} + self.assertEqual(self._extract(header), expected) def test_valid_header_with_empty_value(self): - self.assertEqual( - self._extract("key1=,key2=val2"), {"key1": "", "key2": "val2"} - ) + header = "key1=,key2=val2" + expected = {"key1": "", "key2": "val2"} + self.assertEqual(self._extract(header), expected) def test_invalid_header(self): - self.assertEqual(self._extract("header1"), {}) + header = "header1" + expected = {} + self.assertEqual(self._extract(header), expected) def test_header_too_long(self): - self.assertEqual( - self._extract( - "key1={}".format( - "s" * (W3CBaggagePropagator._max_header_length + 1) - ) - ), - {}, - ) + long_value = "s" * (W3CBaggagePropagator._MAX_HEADER_LENGTH + 1) + header = "key1={}".format(long_value) + expected = {} + self.assertEqual(self._extract(header), expected) def test_header_contains_too_many_entries(self): + header = ",".join( + [ + "key{}=val".format(k) + for k in range(W3CBaggagePropagator._MAX_PAIRS + 1) + ] + ) self.assertEqual( - len( - self._extract( - ",".join( - "key{}=val".format(k) - for k in range(W3CBaggagePropagator._max_pairs + 1) - ) - ) - ), - W3CBaggagePropagator._max_pairs, + len(self._extract(header)), W3CBaggagePropagator._MAX_PAIRS ) def test_header_contains_pair_too_long(self): - self.assertEqual( - self._extract( - "key1=value1,key2={},key3=value3".format( - "s" * (W3CBaggagePropagator._max_pair_length + 1) - ) - ), - {"key1": "value1", "key3": "value3"}, - ) + long_value = "s" * (W3CBaggagePropagator._MAX_PAIR_LENGTH + 1) + header = "key1=value1,key2={},key3=value3".format(long_value) + expected = {"key1": "value1", "key3": "value3"} + self.assertEqual(self._extract(header), expected) def test_inject_no_baggage_entries(self): - self.assertEqual(None, self._inject({})) + values = {} + output = self._inject(values) + self.assertEqual(None, output) def test_inject(self): - output = self._inject({"key1": "val1", "key2": "val2"}) + values = { + "key1": "val1", + "key2": "val2", + } + output = self._inject(values) self.assertIn("key1=val1", output) self.assertIn("key2=val2", output) def test_inject_escaped_values(self): - output = self._inject({"key1": "val1,val2", "key2": "val3=4"}) + values = { + "key1": "val1,val2", + "key2": "val3=4", + } + output = self._inject(values) self.assertIn("key1=val1%2Cval2", output) self.assertIn("key2=val3%3D4", output) def test_inject_non_string_values(self): - output = self._inject({"key1": True, "key2": 123, "key3": 123.567}) + values = { + "key1": True, + "key2": 123, + "key3": 123.567, + } + output = self._inject(values) self.assertIn("key1=True", output) self.assertIn("key2=123", output) self.assertIn("key3=123.567", output) diff --git a/opentelemetry-api/tests/propagators/test_global_httptextformat.py b/opentelemetry-api/tests/propagators/test_global_httptextformat.py index f2d7a2a6ff8..30e39f11865 100644 --- a/opentelemetry-api/tests/propagators/test_global_httptextformat.py +++ b/opentelemetry-api/tests/propagators/test_global_httptextformat.py @@ -25,13 +25,13 @@ class TestDefaultGlobalPropagator(unittest.TestCase): """Test ensures the default global composite propagator works as intended""" - trace_id = int("12345678901234567890123456789012", 16) # type:int - span_id = int("1234567890123456", 16) # type:int + TRACE_ID = int("12345678901234567890123456789012", 16) # type:int + SPAN_ID = int("1234567890123456", 16) # type:int def test_propagation(self): traceparent_value = "00-{trace_id}-{span_id}-00".format( - trace_id=format_trace_id(self.trace_id), - span_id=format_span_id(self.span_id), + trace_id=format_trace_id(self.TRACE_ID), + span_id=format_span_id(self.SPAN_ID), ) ctx = extract( @@ -46,8 +46,8 @@ def test_propagation(self): ) span_context = get_current_span(context=ctx).get_span_context() - self.assertEqual(span_context.trace_id, self.trace_id) - self.assertEqual(span_context.span_id, self.span_id) + self.assertEqual(span_context.trace_id, self.TRACE_ID) + self.assertEqual(span_context.span_id, self.SPAN_ID) span = trace.NonRecordingSpan(span_context) ctx = baggage.set_baggage("key3", "val3") diff --git a/opentelemetry-api/tests/trace/propagation/test_textmap.py b/opentelemetry-api/tests/trace/propagation/test_textmap.py deleted file mode 100644 index e47a0d22cb4..00000000000 --- a/opentelemetry-api/tests/trace/propagation/test_textmap.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright The OpenTelemetry Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# type: ignore - -import unittest - -from opentelemetry.propagators.textmap import DictGetter - - -class TestDictGetter(unittest.TestCase): - def test_get_none(self): - getter = DictGetter() - carrier = {} - val = getter.get(carrier, "test") - self.assertIsNone(val) - - def test_get_str(self): - getter = DictGetter() - carrier = {"test": "val"} - val = getter.get(carrier, "test") - self.assertEqual(val, ["val"]) - - def test_get_iter(self): - getter = DictGetter() - carrier = {"test": ["val"]} - val = getter.get(carrier, "test") - self.assertEqual(val, ["val"]) - - def test_keys(self): - getter = DictGetter() - keys = getter.keys({"test": "val"}) - self.assertEqual(keys, ["test"]) diff --git a/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py b/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py index af5fc515161..916417096d2 100644 --- a/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py +++ b/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py @@ -15,26 +15,19 @@ # type: ignore import typing -from unittest import TestCase +import unittest from unittest.mock import Mock, patch -from opentelemetry.trace import ( - INVALID_SPAN, - INVALID_SPAN_CONTEXT, - NonRecordingSpan, - SpanContext, - get_current_span, - set_span_in_context, -) +from opentelemetry import trace from opentelemetry.trace.propagation import tracecontext from opentelemetry.trace.span import TraceState FORMAT = tracecontext.TraceContextTextMapPropagator() -class TestTraceContextFormat(TestCase): - trace_id = int("12345678901234567890123456789012", 16) # type:int - span_id = int("1234567890123456", 16) # type:int +class TestTraceContextFormat(unittest.TestCase): + TRACE_ID = int("12345678901234567890123456789012", 16) # type:int + SPAN_ID = int("1234567890123456", 16) # type:int def test_no_traceparent_header(self): """When tracecontext headers are not present, a new SpanContext @@ -46,19 +39,19 @@ def test_no_traceparent_header(self): trace-id and parent-id that represents the current request. """ output = {} # type:typing.Dict[str, typing.List[str]] - span = get_current_span(FORMAT.extract(output)) - self.assertIsInstance(span.get_span_context(), SpanContext) + span = trace.get_current_span(FORMAT.extract(output)) + self.assertIsInstance(span.get_span_context(), trace.SpanContext) def test_headers_with_tracestate(self): """When there is a traceparent and tracestate header, data from both should be addded to the SpanContext. """ traceparent_value = "00-{trace_id}-{span_id}-00".format( - trace_id=format(self.trace_id, "032x"), - span_id=format(self.span_id, "016x"), + trace_id=format(self.TRACE_ID, "032x"), + span_id=format(self.SPAN_ID, "016x"), ) tracestate_value = "foo=1,bar=2,baz=3" - span_context = get_current_span( + span_context = trace.get_current_span( FORMAT.extract( { "traceparent": traceparent_value, @@ -66,16 +59,16 @@ def test_headers_with_tracestate(self): }, ) ).get_span_context() - self.assertEqual(span_context.trace_id, self.trace_id) - self.assertEqual(span_context.span_id, self.span_id) + self.assertEqual(span_context.trace_id, self.TRACE_ID) + self.assertEqual(span_context.span_id, self.SPAN_ID) self.assertEqual( span_context.trace_state, {"foo": "1", "bar": "2", "baz": "3"} ) self.assertTrue(span_context.is_remote) output = {} # type:typing.Dict[str, str] - span = NonRecordingSpan(span_context) + span = trace.NonRecordingSpan(span_context) - ctx = set_span_in_context(span) + ctx = trace.set_span_in_context(span) FORMAT.inject(output, ctx) self.assertEqual(output["traceparent"], traceparent_value) for pair in ["foo=1", "bar=2", "baz=3"]: @@ -101,7 +94,7 @@ def test_invalid_trace_id(self): Note that the opposite is not true: failure to parse tracestate MUST NOT affect the parsing of traceparent. """ - span = get_current_span( + span = trace.get_current_span( FORMAT.extract( { "traceparent": ( @@ -112,7 +105,7 @@ def test_invalid_trace_id(self): }, ) ) - self.assertEqual(span.get_span_context(), INVALID_SPAN_CONTEXT) + self.assertEqual(span.get_span_context(), trace.INVALID_SPAN_CONTEXT) def test_invalid_parent_id(self): """If the parent id is invalid, we must ignore the full traceparent @@ -132,7 +125,7 @@ def test_invalid_parent_id(self): Note that the opposite is not true: failure to parse tracestate MUST NOT affect the parsing of traceparent. """ - span = get_current_span( + span = trace.get_current_span( FORMAT.extract( { "traceparent": ( @@ -143,7 +136,7 @@ def test_invalid_parent_id(self): }, ) ) - self.assertEqual(span.get_span_context(), INVALID_SPAN_CONTEXT) + self.assertEqual(span.get_span_context(), trace.INVALID_SPAN_CONTEXT) def test_no_send_empty_tracestate(self): """If the tracestate is empty, do not set the header. @@ -154,10 +147,10 @@ def test_no_send_empty_tracestate(self): empty tracestate headers but SHOULD avoid sending them. """ output = {} # type:typing.Dict[str, str] - span = NonRecordingSpan( - SpanContext(self.trace_id, self.span_id, is_remote=False) + span = trace.NonRecordingSpan( + trace.SpanContext(self.TRACE_ID, self.SPAN_ID, is_remote=False) ) - ctx = set_span_in_context(span) + ctx = trace.set_span_in_context(span) FORMAT.inject(output, ctx) self.assertTrue("traceparent" in output) @@ -171,7 +164,7 @@ def test_format_not_supported(self): If the version cannot be parsed, return an invalid trace header. """ - span = get_current_span( + span = trace.get_current_span( FORMAT.extract( { "traceparent": ( @@ -182,18 +175,18 @@ def test_format_not_supported(self): }, ) ) - self.assertEqual(span.get_span_context(), INVALID_SPAN_CONTEXT) + self.assertEqual(span.get_span_context(), trace.INVALID_SPAN_CONTEXT) def test_propagate_invalid_context(self): """Do not propagate invalid trace context.""" output = {} # type:typing.Dict[str, str] - ctx = set_span_in_context(INVALID_SPAN) + ctx = trace.set_span_in_context(trace.INVALID_SPAN) FORMAT.inject(output, context=ctx) self.assertFalse("traceparent" in output) def test_tracestate_empty_header(self): """Test tracestate with an additional empty header (should be ignored)""" - span = get_current_span( + span = trace.get_current_span( FORMAT.extract( { "traceparent": ( @@ -208,7 +201,7 @@ def test_tracestate_empty_header(self): def test_tracestate_header_with_trailing_comma(self): """Do not propagate invalid trace context.""" - span = get_current_span( + span = trace.get_current_span( FORMAT.extract( { "traceparent": ( @@ -231,7 +224,7 @@ def test_tracestate_keys(self): "foo-_*/bar=bar4", ] ) - span = get_current_span( + span = trace.get_current_span( FORMAT.extract( { "traceparent": ( @@ -253,7 +246,7 @@ def test_tracestate_keys(self): span.get_span_context().trace_state["foo-_*/bar"], "bar4" ) - @patch("opentelemetry.trace.propagation.tracecontext.get_current_span") + @patch("opentelemetry.trace.get_current_span") def test_fields(self, mock_get_current_span): mock_get_current_span.configure_mock( diff --git a/opentelemetry-api/tests/trace/test_tracestate.py b/opentelemetry-api/tests/trace/test_tracestate.py index d777e280365..9126ceabd75 100644 --- a/opentelemetry-api/tests/trace/test_tracestate.py +++ b/opentelemetry-api/tests/trace/test_tracestate.py @@ -72,31 +72,27 @@ def test_tracestate_delete_preserved(self): self.assertLessEqual(a_place, c_place) def test_tracestate_from_header(self): - header = ",".join( - [ - "1a-2f@foo=bar1", - "1a-_*/2b@foo=bar2", - "foo=bar3", - "foo-_*/bar=bar4", - ] - ) - self.assertEqual(TraceState.from_header(header).to_header(), header) + entries = [ + "1a-2f@foo=bar1", + "1a-_*/2b@foo=bar2", + "foo=bar3", + "foo-_*/bar=bar4", + ] + header_list = ",".join(entries) + state = TraceState.from_header(header_list) + self.assertEqual(state.to_header(), ",".join(entries)) def test_tracestate_order_changed(self): - entries = list( - TraceState.from_header( - ",".join( - [ - "1a-2f@foo=bar1", - "1a-_*/2b@foo=bar2", - "foo=bar3", - "foo-_*/bar=bar4", - ] - ) - ) - .update("foo", "bar33") - .items() - ) + entries = [ + "1a-2f@foo=bar1", + "1a-_*/2b@foo=bar2", + "foo=bar3", + "foo-_*/bar=bar4", + ] + header_list = ",".join(entries) + state = TraceState.from_header(header_list) + new_state = state.update("foo", "bar33") + entries = list(new_state.items()) # type: ignore foo_place = entries.index(("foo", "bar33")) # type: ignore prev_first_place = entries.index(("1a-2f@foo", "bar1")) # type: ignore self.assertLessEqual(foo_place, prev_first_place) diff --git a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py index 2c093f76630..9527ff4b471 100644 --- a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py +++ b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from re import compile as compile_ -from typing import Dict, Optional, Set +import typing +from re import compile as re_compile import opentelemetry.trace as trace from opentelemetry.context import Context @@ -34,11 +34,13 @@ class B3Format(TextMapPropagator): SAMPLED_KEY = "x-b3-sampled" FLAGS_KEY = "x-b3-flags" _SAMPLE_PROPAGATE_VALUES = set(["1", "True", "true", "d"]) - _trace_id_regex = compile_(r"[\da-fA-F]{16}|[\da-fA-F]{32}") - _span_id_regex = compile_(r"[\da-fA-F]{16}") + _trace_id_regex = re_compile(r"[\da-fA-F]{16}|[\da-fA-F]{32}") + _span_id_regex = re_compile(r"[\da-fA-F]{16}") def extract( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> Context: trace_id = format_trace_id(trace.INVALID_TRACE_ID) @@ -106,7 +108,9 @@ def extract( ) def inject( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> None: span = trace.get_current_span(context=context) @@ -126,7 +130,7 @@ def inject( carrier[self.SAMPLED_KEY] = "1" if sampled else "0" @property - def fields(self) -> Set[str]: + def fields(self) -> typing.Set[str]: return { self.TRACE_ID_KEY, self.SPAN_ID_KEY, diff --git a/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py b/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py index a9a9b478f55..3343ac0f5c4 100644 --- a/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py +++ b/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py @@ -12,37 +12,27 @@ # See the License for the specific language governing permissions and # limitations under the License. -from unittest import TestCase +import unittest from unittest.mock import patch -from opentelemetry import trace +import opentelemetry.propagators.b3 as b3_format # pylint: disable=no-name-in-module,import-error +import opentelemetry.sdk.trace as trace +import opentelemetry.sdk.trace.id_generator as id_generator +import opentelemetry.trace as trace_api from opentelemetry.context import get_current -from opentelemetry.propagators.b3 import ( - B3Format, - format_span_id, - format_trace_id, -) -from opentelemetry.sdk.trace import TracerProvider, _Span, id_generator -from opentelemetry.trace import ( - INVALID_SPAN_ID, - INVALID_TRACE_ID, - SpanContext, - get_current_span, - set_span_in_context, -) - -format_ = B3Format() + +FORMAT = b3_format.B3Format() def get_child_parent_new_carrier(old_carrier): - ctx = format_.extract(old_carrier) - parent_span_context = get_current_span(ctx).get_span_context() + ctx = FORMAT.extract(old_carrier) + parent_span_context = trace_api.get_current_span(ctx).get_span_context() - parent = _Span("parent", parent_span_context) - child = _Span( + parent = trace._Span("parent", parent_span_context) + child = trace._Span( "child", - SpanContext( + trace_api.SpanContext( parent_span_context.trace_id, id_generator.RandomIdGenerator().generate_span_id(), is_remote=False, @@ -53,27 +43,31 @@ def get_child_parent_new_carrier(old_carrier): ) new_carrier = {} - ctx = set_span_in_context(child) + ctx = trace_api.set_span_in_context(child) - format_.inject(new_carrier, context=ctx) + FORMAT.inject(new_carrier, context=ctx) return child, parent, new_carrier -class TestB3Format(TestCase): +class TestB3Format(unittest.TestCase): @classmethod def setUpClass(cls): generator = id_generator.RandomIdGenerator() - cls.serialized_trace_id = format_trace_id( + cls.serialized_trace_id = b3_format.format_trace_id( generator.generate_trace_id() ) - cls.serialized_span_id = format_span_id(generator.generate_span_id()) - cls.serialized_parent_id = format_span_id(generator.generate_span_id()) + cls.serialized_span_id = b3_format.format_span_id( + generator.generate_span_id() + ) + cls.serialized_parent_id = b3_format.format_span_id( + generator.generate_span_id() + ) def setUp(self) -> None: - tracer_provider = TracerProvider() - patcher = patch.object( - trace, "get_tracer_provider", return_value=tracer_provider + tracer_provider = trace.TracerProvider() + patcher = unittest.mock.patch.object( + trace_api, "get_tracer_provider", return_value=tracer_provider ) patcher.start() self.addCleanup(patcher.stop) @@ -82,53 +76,53 @@ def test_extract_multi_header(self): """Test the extraction of B3 headers.""" child, parent, new_carrier = get_child_parent_new_carrier( { - format_.TRACE_ID_KEY: self.serialized_trace_id, - format_.SPAN_ID_KEY: self.serialized_span_id, - format_.PARENT_SPAN_ID_KEY: self.serialized_parent_id, - format_.SAMPLED_KEY: "1", + FORMAT.TRACE_ID_KEY: self.serialized_trace_id, + FORMAT.SPAN_ID_KEY: self.serialized_span_id, + FORMAT.PARENT_SPAN_ID_KEY: self.serialized_parent_id, + FORMAT.SAMPLED_KEY: "1", } ) self.assertEqual( - new_carrier[format_.TRACE_ID_KEY], - format_trace_id(child.context.trace_id), + new_carrier[FORMAT.TRACE_ID_KEY], + b3_format.format_trace_id(child.context.trace_id), ) self.assertEqual( - new_carrier[format_.SPAN_ID_KEY], - format_span_id(child.context.span_id), + new_carrier[FORMAT.SPAN_ID_KEY], + b3_format.format_span_id(child.context.span_id), ) self.assertEqual( - new_carrier[format_.PARENT_SPAN_ID_KEY], - format_span_id(parent.context.span_id), + new_carrier[FORMAT.PARENT_SPAN_ID_KEY], + b3_format.format_span_id(parent.context.span_id), ) self.assertTrue(parent.context.is_remote) - self.assertEqual(new_carrier[format_.SAMPLED_KEY], "1") + self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1") def test_extract_single_header(self): """Test the extraction from a single b3 header.""" child, parent, new_carrier = get_child_parent_new_carrier( { - format_.SINGLE_HEADER_KEY: "{}-{}".format( + FORMAT.SINGLE_HEADER_KEY: "{}-{}".format( self.serialized_trace_id, self.serialized_span_id ) } ) self.assertEqual( - new_carrier[format_.TRACE_ID_KEY], - format_trace_id(child.context.trace_id), + new_carrier[FORMAT.TRACE_ID_KEY], + b3_format.format_trace_id(child.context.trace_id), ) self.assertEqual( - new_carrier[format_.SPAN_ID_KEY], - format_span_id(child.context.span_id), + new_carrier[FORMAT.SPAN_ID_KEY], + b3_format.format_span_id(child.context.span_id), ) - self.assertEqual(new_carrier[format_.SAMPLED_KEY], "1") + self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1") self.assertTrue(parent.context.is_remote) child, parent, new_carrier = get_child_parent_new_carrier( { - format_.SINGLE_HEADER_KEY: "{}-{}-1-{}".format( + FORMAT.SINGLE_HEADER_KEY: "{}-{}-1-{}".format( self.serialized_trace_id, self.serialized_span_id, self.serialized_parent_id, @@ -137,19 +131,19 @@ def test_extract_single_header(self): ) self.assertEqual( - new_carrier[format_.TRACE_ID_KEY], - format_trace_id(child.context.trace_id), + new_carrier[FORMAT.TRACE_ID_KEY], + b3_format.format_trace_id(child.context.trace_id), ) self.assertEqual( - new_carrier[format_.SPAN_ID_KEY], - format_span_id(child.context.span_id), + new_carrier[FORMAT.SPAN_ID_KEY], + b3_format.format_span_id(child.context.span_id), ) self.assertEqual( - new_carrier[format_.PARENT_SPAN_ID_KEY], - format_span_id(parent.context.span_id), + new_carrier[FORMAT.PARENT_SPAN_ID_KEY], + b3_format.format_span_id(parent.context.span_id), ) self.assertTrue(parent.context.is_remote) - self.assertEqual(new_carrier[format_.SAMPLED_KEY], "1") + self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1") def test_extract_header_precedence(self): """A single b3 header should take precedence over multiple @@ -159,17 +153,17 @@ def test_extract_header_precedence(self): _, _, new_carrier = get_child_parent_new_carrier( { - format_.SINGLE_HEADER_KEY: "{}-{}".format( + FORMAT.SINGLE_HEADER_KEY: "{}-{}".format( single_header_trace_id, self.serialized_span_id ), - format_.TRACE_ID_KEY: self.serialized_trace_id, - format_.SPAN_ID_KEY: self.serialized_span_id, - format_.SAMPLED_KEY: "1", + FORMAT.TRACE_ID_KEY: self.serialized_trace_id, + FORMAT.SPAN_ID_KEY: self.serialized_span_id, + FORMAT.SAMPLED_KEY: "1", } ) self.assertEqual( - new_carrier[format_.TRACE_ID_KEY], single_header_trace_id + new_carrier[FORMAT.TRACE_ID_KEY], single_header_trace_id ) def test_enabled_sampling(self): @@ -177,50 +171,50 @@ def test_enabled_sampling(self): for variant in ["1", "True", "true", "d"]: _, _, new_carrier = get_child_parent_new_carrier( { - format_.TRACE_ID_KEY: self.serialized_trace_id, - format_.SPAN_ID_KEY: self.serialized_span_id, - format_.SAMPLED_KEY: variant, + FORMAT.TRACE_ID_KEY: self.serialized_trace_id, + FORMAT.SPAN_ID_KEY: self.serialized_span_id, + FORMAT.SAMPLED_KEY: variant, } ) - self.assertEqual(new_carrier[format_.SAMPLED_KEY], "1") + self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1") def test_disabled_sampling(self): """Test b3 sample key variants that turn off sampling.""" for variant in ["0", "False", "false", None]: _, _, new_carrier = get_child_parent_new_carrier( { - format_.TRACE_ID_KEY: self.serialized_trace_id, - format_.SPAN_ID_KEY: self.serialized_span_id, - format_.SAMPLED_KEY: variant, + FORMAT.TRACE_ID_KEY: self.serialized_trace_id, + FORMAT.SPAN_ID_KEY: self.serialized_span_id, + FORMAT.SAMPLED_KEY: variant, } ) - self.assertEqual(new_carrier[format_.SAMPLED_KEY], "0") + self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "0") def test_flags(self): """x-b3-flags set to "1" should result in propagation.""" _, _, new_carrier = get_child_parent_new_carrier( { - format_.TRACE_ID_KEY: self.serialized_trace_id, - format_.SPAN_ID_KEY: self.serialized_span_id, - format_.FLAGS_KEY: "1", + FORMAT.TRACE_ID_KEY: self.serialized_trace_id, + FORMAT.SPAN_ID_KEY: self.serialized_span_id, + FORMAT.FLAGS_KEY: "1", } ) - self.assertEqual(new_carrier[format_.SAMPLED_KEY], "1") + self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1") def test_flags_and_sampling(self): """Propagate if b3 flags and sampling are set.""" _, _, new_carrier = get_child_parent_new_carrier( { - format_.TRACE_ID_KEY: self.serialized_trace_id, - format_.SPAN_ID_KEY: self.serialized_span_id, - format_.FLAGS_KEY: "1", + FORMAT.TRACE_ID_KEY: self.serialized_trace_id, + FORMAT.SPAN_ID_KEY: self.serialized_span_id, + FORMAT.FLAGS_KEY: "1", } ) - self.assertEqual(new_carrier[format_.SAMPLED_KEY], "1") + self.assertEqual(new_carrier[FORMAT.SAMPLED_KEY], "1") def test_64bit_trace_id(self): """64 bit trace ids should be padded to 128 bit trace ids.""" @@ -228,36 +222,36 @@ def test_64bit_trace_id(self): _, _, new_carrier = get_child_parent_new_carrier( { - format_.TRACE_ID_KEY: trace_id_64_bit, - format_.SPAN_ID_KEY: self.serialized_span_id, - format_.FLAGS_KEY: "1", + FORMAT.TRACE_ID_KEY: trace_id_64_bit, + FORMAT.SPAN_ID_KEY: self.serialized_span_id, + FORMAT.FLAGS_KEY: "1", } ) self.assertEqual( - new_carrier[format_.TRACE_ID_KEY], "0" * 16 + trace_id_64_bit + new_carrier[FORMAT.TRACE_ID_KEY], "0" * 16 + trace_id_64_bit ) def test_invalid_single_header(self): """If an invalid single header is passed, return an - invalid SpanContext. + invalid trace_api.SpanContext. """ - carrier = {format_.SINGLE_HEADER_KEY: "0-1-2-3-4-5-6-7"} - ctx = format_.extract(carrier) - span_context = get_current_span(ctx).get_span_context() - self.assertEqual(span_context.trace_id, INVALID_TRACE_ID) - self.assertEqual(span_context.span_id, INVALID_SPAN_ID) + carrier = {FORMAT.SINGLE_HEADER_KEY: "0-1-2-3-4-5-6-7"} + ctx = FORMAT.extract(carrier) + span_context = trace_api.get_current_span(ctx).get_span_context() + self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) + self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) def test_missing_trace_id(self): """If a trace id is missing, populate an invalid trace id.""" carrier = { - format_.SPAN_ID_KEY: self.serialized_span_id, - format_.FLAGS_KEY: "1", + FORMAT.SPAN_ID_KEY: self.serialized_span_id, + FORMAT.FLAGS_KEY: "1", } - ctx = format_.extract(carrier) - span_context = get_current_span(ctx).get_span_context() - self.assertEqual(span_context.trace_id, INVALID_TRACE_ID) + ctx = FORMAT.extract(carrier) + span_context = trace_api.get_current_span(ctx).get_span_context() + self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) @patch( "opentelemetry.sdk.trace.id_generator.RandomIdGenerator.generate_trace_id" @@ -274,13 +268,13 @@ def test_invalid_trace_id( mock_generate_span_id.configure_mock(return_value=2) carrier = { - format_.TRACE_ID_KEY: "abc123", - format_.SPAN_ID_KEY: self.serialized_span_id, - format_.FLAGS_KEY: "1", + FORMAT.TRACE_ID_KEY: "abc123", + FORMAT.SPAN_ID_KEY: self.serialized_span_id, + FORMAT.FLAGS_KEY: "1", } - ctx = format_.extract(carrier) - span_context = get_current_span(ctx).get_span_context() + ctx = FORMAT.extract(carrier) + span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, 1) self.assertEqual(span_context.span_id, 2) @@ -300,13 +294,13 @@ def test_invalid_span_id( mock_generate_span_id.configure_mock(return_value=2) carrier = { - format_.TRACE_ID_KEY: self.serialized_trace_id, - format_.SPAN_ID_KEY: "abc123", - format_.FLAGS_KEY: "1", + FORMAT.TRACE_ID_KEY: self.serialized_trace_id, + FORMAT.SPAN_ID_KEY: "abc123", + FORMAT.FLAGS_KEY: "1", } - ctx = format_.extract(carrier) - span_context = get_current_span(ctx).get_span_context() + ctx = FORMAT.extract(carrier) + span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, 1) self.assertEqual(span_context.span_id, 2) @@ -314,18 +308,18 @@ def test_invalid_span_id( def test_missing_span_id(self): """If a trace id is missing, populate an invalid trace id.""" carrier = { - format_.TRACE_ID_KEY: self.serialized_trace_id, - format_.FLAGS_KEY: "1", + FORMAT.TRACE_ID_KEY: self.serialized_trace_id, + FORMAT.FLAGS_KEY: "1", } - ctx = format_.extract(carrier) - span_context = get_current_span(ctx).get_span_context() - self.assertEqual(span_context.span_id, INVALID_SPAN_ID) + ctx = FORMAT.extract(carrier) + span_context = trace_api.get_current_span(ctx).get_span_context() + self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) def test_inject_empty_context(self): """If the current context has no span, don't add headers""" new_carrier = {} - format_.inject(new_carrier, get_current()) + FORMAT.inject(new_carrier, get_current()) self.assertEqual(len(new_carrier), 0) def test_default_span(self): @@ -333,19 +327,19 @@ def test_default_span(self): NonRecordingSpan""" try: - format_.inject({}, format_.extract({})) + FORMAT.inject({}, FORMAT.extract({})) except Exception: # pylint: disable=broad-except self.fail("propagator crashed when working with NonRecordingSpan") def test_fields(self): """Make sure the fields attribute returns the fields used in inject""" - tracer = TracerProvider().get_tracer("sdk_tracer_provider") + tracer = trace.TracerProvider().get_tracer("sdk_tracer_provider") carrier = {} with tracer.start_as_current_span("parent"): with tracer.start_as_current_span("child"): - format_.inject(carrier) + FORMAT.inject(carrier) - self.assertEqual(format_.fields, carrier.keys()) + self.assertEqual(FORMAT.fields, carrier.keys()) diff --git a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py index 3bda496db6f..2908f0697c8 100644 --- a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py +++ b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py @@ -12,25 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, Optional, Set -from urllib.parse import quote, unquote +import typing +import urllib.parse +import opentelemetry.trace as trace from opentelemetry import baggage from opentelemetry.context import Context, get_current from opentelemetry.propagators.textmap import TextMapPropagator -from opentelemetry.trace import ( - INVALID_SPAN, - INVALID_SPAN_CONTEXT, - INVALID_SPAN_ID, - INVALID_TRACE_ID, - NonRecordingSpan, - SpanContext, - TraceFlags, - format_span_id, - format_trace_id, - get_current_span, - set_span_in_context, -) +from opentelemetry.trace import format_span_id, format_trace_id class JaegerPropagator(TextMapPropagator): @@ -39,64 +28,73 @@ class JaegerPropagator(TextMapPropagator): See: https://www.jaegertracing.io/docs/1.19/client-libraries/#propagation-format """ - _trace_id_key = "uber-trace-id" - _baggage_prefix = "uberctx-" - _debug_flag = 0x02 + TRACE_ID_KEY = "uber-trace-id" + BAGGAGE_PREFIX = "uberctx-" + DEBUG_FLAG = 0x02 def extract( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> Context: if context is None: context = get_current() - header = carrier.get(self._trace_id_key) + header = carrier.get(self.TRACE_ID_KEY) if header is None: - return set_span_in_context(INVALID_SPAN, context) + return trace.set_span_in_context(trace.INVALID_SPAN, context) fields = header.split(":") for key in [ key for key in carrier.keys() - if key.startswith(self._baggage_prefix) + if key.startswith(self.BAGGAGE_PREFIX) ]: context = baggage.set_baggage( - key.replace(self._baggage_prefix, ""), - unquote(carrier[key]).strip(), + key.replace(self.BAGGAGE_PREFIX, ""), + urllib.parse.quote(carrier[key]).strip(), context=context, ) if len(fields) != 4: - return set_span_in_context(INVALID_SPAN, context) + return trace.set_span_in_context(trace.INVALID_SPAN, context) trace_id, span_id, _parent_id, flags = fields - if trace_id == INVALID_TRACE_ID or span_id == INVALID_SPAN_ID: - return set_span_in_context(INVALID_SPAN, context) - - span = NonRecordingSpan( - SpanContext( + if ( + trace_id == trace.INVALID_TRACE_ID + or span_id == trace.INVALID_SPAN_ID + ): + return trace.set_span_in_context(trace.INVALID_SPAN, context) + + span = trace.NonRecordingSpan( + trace.SpanContext( trace_id=int(trace_id, 16), span_id=int(span_id, 16), is_remote=True, - trace_flags=TraceFlags(int(flags, 16) & TraceFlags.SAMPLED), + trace_flags=trace.TraceFlags( + int(flags, 16) & trace.TraceFlags.SAMPLED + ), ) ) - return set_span_in_context(span, context) + return trace.set_span_in_context(span, context) def inject( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> None: - span = get_current_span(context=context) + span = trace.get_current_span(context=context) span_context = span.get_span_context() - if span_context == INVALID_SPAN_CONTEXT: + if span_context == trace.INVALID_SPAN_CONTEXT: return span_parent_id = span.parent.span_id if span.parent else 0 trace_flags = span_context.trace_flags if trace_flags.sampled: - trace_flags |= self._debug_flag + trace_flags |= self.DEBUG_FLAG # set span identity - carrier[self._trace_id_key] = _format_uber_trace_id( + carrier[self.TRACE_ID_KEY] = _format_uber_trace_id( span_context.trace_id, span_context.span_id, span_parent_id, @@ -108,18 +106,33 @@ def inject( if not baggage_entries: return for key, value in baggage_entries.items(): - baggage_key = self._baggage_prefix + key - carrier[baggage_key] = quote(str(value)) + baggage_key = self.BAGGAGE_PREFIX + key + carrier[baggage_key] = urllib.parse.quote(str(value)) @property - def fields(self) -> Set[str]: - return {self._trace_id_key} + def fields(self) -> typing.Set[str]: + return {self.TRACE_ID_KEY} + + def _extract_baggage(self, getter, carrier, context): + baggage_keys = [ + key + for key in getter.keys(carrier) + if key.startswith(self.BAGGAGE_PREFIX) + ] + for key in baggage_keys: + value = carrier.get(key) + context = baggage.set_baggage( + key.replace(self.BAGGAGE_PREFIX, ""), + urllib.parse.quote(value).strip(), + context=context, + ) + return context def _format_uber_trace_id(trace_id, span_id, parent_span_id, flags): - return "{trace_id}:{span_id}:{parent_id}:{flags:02x}".format( + return "{trace_id}:{span_id}:{parent_id}:{:02x}".format( + flags, trace_id=format_trace_id(trace_id), span_id=format_span_id(span_id), parent_id=format_span_id(parent_span_id), - flags=flags, ) diff --git a/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py b/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py index c5f4f150cd5..620d7ebc45a 100644 --- a/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py +++ b/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py @@ -12,23 +12,22 @@ # See the License for the specific language governing permissions and # limitations under the License. -from unittest import TestCase +import unittest import opentelemetry.sdk.trace as trace import opentelemetry.sdk.trace.id_generator as id_generator import opentelemetry.trace as trace_api from opentelemetry import baggage -from opentelemetry.propagators.jaeger import ( # pylint: disable=no-name-in-module - JaegerPropagator, - _format_uber_trace_id, +from opentelemetry.propagators import ( # pylint: disable=no-name-in-module + jaeger, ) -format_ = JaegerPropagator() +FORMAT = jaeger.JaegerPropagator() def get_context_new_carrier(old_carrier, carrier_baggage=None): - ctx = format_.extract(old_carrier) + ctx = FORMAT.extract(old_carrier) if carrier_baggage: for key, value in carrier_baggage.items(): ctx = baggage.set_baggage(key, value, ctx) @@ -50,94 +49,94 @@ def get_context_new_carrier(old_carrier, carrier_baggage=None): new_carrier = {} ctx = trace_api.set_span_in_context(child, ctx) - format_.inject(new_carrier, context=ctx) + FORMAT.inject(new_carrier, context=ctx) return ctx, new_carrier -class TestJaegerPropagator(TestCase): - # pylint: disable=protected-access +class TestJaegerPropagator(unittest.TestCase): @classmethod def setUpClass(cls): generator = id_generator.RandomIdGenerator() cls.trace_id = generator.generate_trace_id() cls.span_id = generator.generate_span_id() cls.parent_span_id = generator.generate_span_id() - cls.serialized_uber_trace_id = _format_uber_trace_id( + cls.serialized_uber_trace_id = jaeger._format_uber_trace_id( # pylint: disable=protected-access cls.trace_id, cls.span_id, cls.parent_span_id, 11 ) def test_extract_valid_span(self): - old_carrier = {format_._trace_id_key: self.serialized_uber_trace_id} - ctx = format_.extract(old_carrier) + old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} + ctx = FORMAT.extract(old_carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, self.trace_id) self.assertEqual(span_context.span_id, self.span_id) def test_missing_carrier(self): old_carrier = {} - ctx = format_.extract(old_carrier) + ctx = FORMAT.extract(old_carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) def test_trace_id(self): - old_carrier = {format_._trace_id_key: self.serialized_uber_trace_id} + old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} _, new_carrier = get_context_new_carrier(old_carrier) self.assertEqual( self.serialized_uber_trace_id.split(":")[0], - new_carrier[format_._trace_id_key].split(":")[0], + new_carrier[FORMAT.TRACE_ID_KEY].split(":")[0], ) def test_parent_span_id(self): - old_carrier = {format_._trace_id_key: self.serialized_uber_trace_id} + old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} _, new_carrier = get_context_new_carrier(old_carrier) span_id = self.serialized_uber_trace_id.split(":")[1] - parent_span_id = new_carrier[format_._trace_id_key].split(":")[2] + parent_span_id = new_carrier[FORMAT.TRACE_ID_KEY].split(":")[2] self.assertEqual(span_id, parent_span_id) def test_sampled_flag_set(self): - old_carrier = {format_._trace_id_key: self.serialized_uber_trace_id} + old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} _, new_carrier = get_context_new_carrier(old_carrier) sample_flag_value = ( - int(new_carrier[format_._trace_id_key].split(":")[3]) & 0x01 + int(new_carrier[FORMAT.TRACE_ID_KEY].split(":")[3]) & 0x01 ) self.assertEqual(1, sample_flag_value) def test_debug_flag_set(self): - old_carrier = {format_._trace_id_key: self.serialized_uber_trace_id} + old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} _, new_carrier = get_context_new_carrier(old_carrier) debug_flag_value = ( - int(new_carrier[format_._trace_id_key].split(":")[3]) - & format_._debug_flag + int(new_carrier[FORMAT.TRACE_ID_KEY].split(":")[3]) + & FORMAT.DEBUG_FLAG ) - self.assertEqual(format_._debug_flag, debug_flag_value) + self.assertEqual(FORMAT.DEBUG_FLAG, debug_flag_value) def test_sample_debug_flags_unset(self): - uber_trace_id = _format_uber_trace_id( + # pylint: disable=protected-access + uber_trace_id = jaeger._format_uber_trace_id( self.trace_id, self.span_id, self.parent_span_id, 0 ) - old_carrier = {format_._trace_id_key: uber_trace_id} + old_carrier = {FORMAT.TRACE_ID_KEY: uber_trace_id} _, new_carrier = get_context_new_carrier(old_carrier) - flags = int(new_carrier[format_._trace_id_key].split(":")[3]) + flags = int(new_carrier[FORMAT.TRACE_ID_KEY].split(":")[3]) sample_flag_value = flags & 0x01 - debug_flag_value = flags & format_._debug_flag + debug_flag_value = flags & FORMAT.DEBUG_FLAG self.assertEqual(0, sample_flag_value) self.assertEqual(0, debug_flag_value) def test_baggage(self): - old_carrier = {format_._trace_id_key: self.serialized_uber_trace_id} + old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} input_baggage = {"key1": "value1"} _, new_carrier = get_context_new_carrier(old_carrier, input_baggage) - ctx = format_.extract(new_carrier) + ctx = FORMAT.extract(new_carrier) self.assertDictEqual(input_baggage, ctx["baggage"]) def test_non_string_baggage(self): - old_carrier = {format_._trace_id_key: self.serialized_uber_trace_id} + old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} input_baggage = {"key1": 1, "key2": True} formatted_baggage = {"key1": "1", "key2": "True"} _, new_carrier = get_context_new_carrier(old_carrier, input_baggage) - ctx = format_.extract(new_carrier) + ctx = FORMAT.extract(new_carrier) self.assertDictEqual(formatted_baggage, ctx["baggage"]) def test_extract_invalid_uber_trace_id(self): @@ -146,7 +145,7 @@ def test_extract_invalid_uber_trace_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = format_.extract(old_carrier) + context = FORMAT.extract(old_carrier) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) @@ -157,7 +156,7 @@ def test_extract_invalid_trace_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = format_.extract(old_carrier) + context = FORMAT.extract(old_carrier) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) @@ -168,7 +167,7 @@ def test_extract_invalid_span_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = format_.extract(old_carrier) + context = FORMAT.extract(old_carrier) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) @@ -180,6 +179,6 @@ def test_fields(self): with tracer.start_as_current_span("parent"): with tracer.start_as_current_span("child"): - format_.inject(carrier) + FORMAT.inject(carrier) - self.assertEqual(format_.fields, carrier.keys()) + self.assertEqual(FORMAT.fields, carrier.keys()) diff --git a/shim/opentelemetry-opentracing-shim/tests/test_shim.py b/shim/opentelemetry-opentracing-shim/tests/test_shim.py index ef73843073f..a27d30de718 100644 --- a/shim/opentelemetry-opentracing-shim/tests/test_shim.py +++ b/shim/opentelemetry-opentracing-shim/tests/test_shim.py @@ -493,9 +493,9 @@ def test_inject_http_headers(self): headers = {} self.shim.inject(context, opentracing.Format.HTTP_HEADERS, headers) self.assertEqual( - headers[MockTextMapPropagator.trace_id_key], str(1220) + headers[MockTextMapPropagator.TRACE_ID_KEY], str(1220) ) - self.assertEqual(headers[MockTextMapPropagator.span_id_key], str(7478)) + self.assertEqual(headers[MockTextMapPropagator.SPAN_ID_KEY], str(7478)) def test_inject_text_map(self): """Test `inject()` method for Format.TEXT_MAP.""" @@ -509,10 +509,10 @@ def test_inject_text_map(self): text_map = {} self.shim.inject(context, opentracing.Format.TEXT_MAP, text_map) self.assertEqual( - text_map[MockTextMapPropagator.trace_id_key], str(1220) + text_map[MockTextMapPropagator.TRACE_ID_KEY], str(1220) ) self.assertEqual( - text_map[MockTextMapPropagator.span_id_key], str(7478) + text_map[MockTextMapPropagator.SPAN_ID_KEY], str(7478) ) def test_inject_binary(self): @@ -531,8 +531,8 @@ def test_extract_http_headers(self): """Test `extract()` method for Format.HTTP_HEADERS.""" carrier = { - MockTextMapPropagator.trace_id_key: 1220, - MockTextMapPropagator.span_id_key: 7478, + MockTextMapPropagator.TRACE_ID_KEY: 1220, + MockTextMapPropagator.SPAN_ID_KEY: 7478, } ctx = self.shim.extract(opentracing.Format.HTTP_HEADERS, carrier) @@ -557,8 +557,8 @@ def test_extract_text_map(self): """Test `extract()` method for Format.TEXT_MAP.""" carrier = { - MockTextMapPropagator.trace_id_key: 1220, - MockTextMapPropagator.span_id_key: 7478, + MockTextMapPropagator.TRACE_ID_KEY: 1220, + MockTextMapPropagator.SPAN_ID_KEY: 7478, } ctx = self.shim.extract(opentracing.Format.TEXT_MAP, carrier) diff --git a/tests/util/src/opentelemetry/test/mock_textmap.py b/tests/util/src/opentelemetry/test/mock_textmap.py index 82cbbfd8a60..4028a1a2647 100644 --- a/tests/util/src/opentelemetry/test/mock_textmap.py +++ b/tests/util/src/opentelemetry/test/mock_textmap.py @@ -12,17 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, Optional +import typing +from opentelemetry import trace from opentelemetry.context import Context, get_current from opentelemetry.propagators.textmap import TextMapPropagator -from opentelemetry.trace import ( - INVALID_SPAN, - NonRecordingSpan, - SpanContext, - get_current_span, - set_span_in_context, -) class NOOPTextMapPropagator(TextMapPropagator): @@ -33,12 +27,16 @@ class NOOPTextMapPropagator(TextMapPropagator): """ def extract( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> Context: return get_current() def inject( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> None: return None @@ -50,33 +48,37 @@ def fields(self): class MockTextMapPropagator(TextMapPropagator): """Mock propagator for testing purposes.""" - trace_id_key = "mock-traceid" - span_id_key = "mock-spanid" + TRACE_ID_KEY = "mock-traceid" + SPAN_ID_KEY = "mock-spanid" def extract( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> Context: - trace_id = carrier.get(self.trace_id_key) - span_id = carrier.get(self.span_id_key) + trace_id = carrier.get(self.TRACE_ID_KEY) + span_id = carrier.get(self.SPAN_ID_KEY) if trace_id is None or span_id is None: - return set_span_in_context(INVALID_SPAN) + return trace.set_span_in_context(trace.INVALID_SPAN) - return set_span_in_context( - NonRecordingSpan( - SpanContext( + return trace.set_span_in_context( + trace.NonRecordingSpan( + trace.SpanContext( trace_id=trace_id, span_id=span_id, is_remote=True, ) ) ) def inject( - self, carrier: Dict[str, str], context: Optional[Context] = None, + self, + carrier: typing.Dict[str, str], + context: typing.Optional[Context] = None, ) -> None: - span = get_current_span(context) - carrier[self.trace_id_key] = str(span.get_span_context().trace_id) - carrier[self.span_id_key] = str(span.get_span_context().span_id) + span = trace.get_current_span(context) + carrier[self.TRACE_ID_KEY] = str(span.get_span_context().trace_id) + carrier[self.SPAN_ID_KEY] = str(span.get_span_context().span_id) @property def fields(self): - return {self.trace_id_key, self.span_id_key} + return {self.TRACE_ID_KEY, self.SPAN_ID_KEY} From e00ef20189d0b59ac91487ca4b44e93bac4183f7 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Tue, 23 Mar 2021 16:57:42 -0600 Subject: [PATCH 03/28] Revert "Remove code cleanup" and "Remove setters and getters" This reverts commit cfd4dc7f683792743c41a7e501becce8779d212a. This reverts commit 8ec609f966c5853a8b51475807940fa77faf7251. --- .github/workflows/test.yml | 2 +- CHANGELOG.md | 3 - docs/conf.py | 1 + docs/examples/auto-instrumentation/README.rst | 2 +- docs/examples/auto-instrumentation/client.py | 2 +- .../server_instrumented.py | 3 +- docs/examples/datadog_exporter/client.py | 2 +- docs/examples/django/client.py | 2 +- .../baggage/propagation/__init__.py | 48 +++++--- .../src/opentelemetry/propagate/__init__.py | 32 +++-- .../opentelemetry/propagators/composite.py | 10 +- .../src/opentelemetry/propagators/textmap.py | 109 +++++++++++++++--- .../trace/propagation/tracecontext.py | 24 ++-- .../src/opentelemetry/trace/span.py | 38 +++--- .../tests/baggage/test_baggage_propagation.py | 33 +++--- .../tests/propagators/test_composite.py | 54 +++++---- .../propagators/test_global_httptextformat.py | 26 +++-- .../tests/trace/propagation/test_textmap.py | 44 +++++++ .../test_tracecontexthttptextformat.py | 85 ++++++++------ .../tests/trace/test_tracestate.py | 4 +- .../opentelemetry/propagators/b3/__init__.py | 66 ++++++++--- .../propagation/test_benchmark_b3_format.py | 3 + .../tests/test_b3_format.py | 61 ++++++---- .../propagators/jaeger/__init__.py | 61 ++++++---- .../tests/test_jaeger_propagator.py | 38 +++--- .../shim/opentracing_shim/__init__.py | 6 +- .../src/opentelemetry/test/mock_textmap.py | 37 ++++-- 27 files changed, 538 insertions(+), 258 deletions(-) create mode 100644 opentelemetry-api/tests/trace/propagation/test_textmap.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e3174a5f641..908cf71caa3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: a1bda203e3d84acf95641fe97e8c080361c8528e + CONTRIB_REPO_SHA: 5bc0fa1611502be47a1f4eb550fe255e4b707ba1 jobs: build: diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b13214748e..7a8e24366d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v0.18b0...HEAD) -- Remove setters and getters - ([#1690](https://github.com/open-telemetry/opentelemetry-python/pull/1690)) - ### Added - Document how to work with fork process web server models(Gunicorn, uWSGI etc...) ([#1609](https://github.com/open-telemetry/opentelemetry-python/pull/1609)) diff --git a/docs/conf.py b/docs/conf.py index 5d44c24dd22..d23cebfe96c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -104,6 +104,7 @@ ("py:class", "opentelemetry.trace._LinkBase",), # TODO: Understand why sphinx is not able to find this local class ("py:class", "opentelemetry.propagators.textmap.TextMapPropagator",), + ("py:class", "opentelemetry.propagators.textmap.DictGetter",), ("any", "opentelemetry.propagators.textmap.TextMapPropagator.extract",), ("any", "opentelemetry.propagators.textmap.TextMapPropagator.inject",), ] diff --git a/docs/examples/auto-instrumentation/README.rst b/docs/examples/auto-instrumentation/README.rst index 0a6c07bb408..607aa1b44b7 100644 --- a/docs/examples/auto-instrumentation/README.rst +++ b/docs/examples/auto-instrumentation/README.rst @@ -37,7 +37,7 @@ Manually instrumented server def server_request(): with tracer.start_as_current_span( "server_request", - context=propagators.extract(request.headers + context=propagators.extract(DictGetter(), request.headers ), ): print(request.args.get("param")) diff --git a/docs/examples/auto-instrumentation/client.py b/docs/examples/auto-instrumentation/client.py index cc948cc54b8..fefc1f67b98 100644 --- a/docs/examples/auto-instrumentation/client.py +++ b/docs/examples/auto-instrumentation/client.py @@ -37,7 +37,7 @@ with tracer.start_as_current_span("client-server"): headers = {} - propagators.inject(headers) + propagators.inject(dict.__setitem__, headers) requested = get( "http://localhost:8082/server_request", params={"param": argv[1]}, diff --git a/docs/examples/auto-instrumentation/server_instrumented.py b/docs/examples/auto-instrumentation/server_instrumented.py index 652358e3a2e..1ac1bd6b71b 100644 --- a/docs/examples/auto-instrumentation/server_instrumented.py +++ b/docs/examples/auto-instrumentation/server_instrumented.py @@ -17,6 +17,7 @@ from opentelemetry import trace from opentelemetry.instrumentation.wsgi import collect_request_attributes from opentelemetry.propagate import extract +from opentelemetry.propagators.textmap import DictGetter from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( ConsoleSpanExporter, @@ -37,7 +38,7 @@ def server_request(): with tracer.start_as_current_span( "server_request", - context=extract(request.headers), + context=extract(DictGetter(), request.headers), kind=trace.SpanKind.SERVER, attributes=collect_request_attributes(request.environ), ): diff --git a/docs/examples/datadog_exporter/client.py b/docs/examples/datadog_exporter/client.py index 7c6196ad4ab..6b4b5d00ec1 100644 --- a/docs/examples/datadog_exporter/client.py +++ b/docs/examples/datadog_exporter/client.py @@ -47,7 +47,7 @@ with tracer.start_as_current_span("client-server"): headers = {} - inject(headers) + inject(dict.__setitem__, headers) requested = get( "http://localhost:8082/server_request", params={"param": argv[1]}, diff --git a/docs/examples/django/client.py b/docs/examples/django/client.py index 3ae0cb6e1cf..bc3606cbe76 100644 --- a/docs/examples/django/client.py +++ b/docs/examples/django/client.py @@ -36,7 +36,7 @@ with tracer.start_as_current_span("client-server"): headers = {} - inject(headers) + inject(dict.__setitem__, headers) requested = get( "http://localhost:8000", params={"param": argv[1]}, diff --git a/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py b/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py index 0c0dc25663e..e6d1c4207bc 100644 --- a/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py +++ b/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py @@ -31,7 +31,8 @@ class W3CBaggagePropagator(textmap.TextMapPropagator): def extract( self, - carrier: typing.Dict[str, str], + getter: textmap.Getter[textmap.TextMapPropagatorT], + carrier: textmap.TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> Context: """Extract Baggage from the carrier. @@ -43,7 +44,9 @@ def extract( if context is None: context = get_current() - header = carrier.get(self._BAGGAGE_HEADER_NAME) + header = _extract_first_element( + getter.get(carrier, self._BAGGAGE_HEADER_NAME) + ) if not header or len(header) > self._MAX_HEADER_LENGTH: return context @@ -56,19 +59,22 @@ def extract( total_baggage_entries -= 1 if len(entry) > self._MAX_PAIR_LENGTH: continue - if "=" in entry: + try: name, value = entry.split("=", 1) - context = baggage.set_baggage( - urllib.parse.unquote(name).strip(), - urllib.parse.unquote(value).strip(), - context=context, - ) + except Exception: # pylint: disable=broad-except + continue + context = baggage.set_baggage( + urllib.parse.unquote(name).strip(), + urllib.parse.unquote(value).strip(), + context=context, + ) return context def inject( self, - carrier: typing.Dict[str, str], + set_in_carrier: textmap.Setter[textmap.TextMapPropagatorT], + carrier: textmap.TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> None: """Injects Baggage into the carrier. @@ -77,14 +83,28 @@ def inject( `opentelemetry.propagators.textmap.TextMapPropagator.inject` """ baggage_entries = baggage.get_all(context=context) + if not baggage_entries: + return - if baggage_entries: - carrier[self._BAGGAGE_HEADER_NAME] = ",".join( - key + "=" + urllib.parse.quote_plus(str(value)) - for key, value in baggage_entries.items() - ) + baggage_string = _format_baggage(baggage_entries) + set_in_carrier(carrier, self._BAGGAGE_HEADER_NAME, baggage_string) @property def fields(self) -> typing.Set[str]: """Returns a set with the fields set in `inject`.""" return {self._BAGGAGE_HEADER_NAME} + + +def _format_baggage(baggage_entries: typing.Mapping[str, object]) -> str: + return ",".join( + key + "=" + urllib.parse.quote_plus(str(value)) + for key, value in baggage_entries.items() + ) + + +def _extract_first_element( + items: typing.Optional[typing.Iterable[textmap.TextMapPropagatorT]], +) -> typing.Optional[textmap.TextMapPropagatorT]: + if items is None: + return None + return next(iter(items), None) diff --git a/opentelemetry-api/src/opentelemetry/propagate/__init__.py b/opentelemetry-api/src/opentelemetry/propagate/__init__.py index 02fb165271a..44f9897a532 100644 --- a/opentelemetry-api/src/opentelemetry/propagate/__init__.py +++ b/opentelemetry-api/src/opentelemetry/propagate/__init__.py @@ -40,12 +40,23 @@ PROPAGATOR = propagators.get_global_textmap() + def get_header_from_flask_request(request, key): + return request.headers.get_all(key) + + def set_header_into_requests_request(request: requests.Request, + key: str, value: str): + request.headers[key] = value + def example_route(): - context = PROPAGATOR.extract(flask.request) + context = PROPAGATOR.extract( + get_header_from_flask_request, + flask.request + ) request_to_downstream = requests.Request( "GET", "http://httpbin.org/get" ) PROPAGATOR.inject( + set_header_into_requests_request, request_to_downstream, context=context ) @@ -71,7 +82,9 @@ def example_route(): def extract( - carrier: typing.Dict[str, str], context: typing.Optional[Context] = None, + getter: textmap.Getter[textmap.TextMapPropagatorT], + carrier: textmap.TextMapPropagatorT, + context: typing.Optional[Context] = None, ) -> Context: """Uses the configured propagator to extract a Context from the carrier. @@ -86,21 +99,26 @@ def extract( context: an optional Context to use. Defaults to current context if not set. """ - return get_global_textmap().extract(carrier, context) + return get_global_textmap().extract(getter, carrier, context) def inject( - carrier: typing.Dict[str, str], context: typing.Optional[Context] = None, + set_in_carrier: textmap.Setter[textmap.TextMapPropagatorT], + carrier: textmap.TextMapPropagatorT, + context: typing.Optional[Context] = None, ) -> None: """Uses the configured propagator to inject a Context into the carrier. Args: - carrier: A dict-like object that contains a representation of HTTP - headers. + set_in_carrier: A setter function that can set values + on the carrier. + carrier: An object that contains a representation of HTTP + headers. Should be paired with set_in_carrier, which + should know how to set header values on the carrier. context: an optional Context to use. Defaults to current context if not set. """ - get_global_textmap().inject(carrier, context) + get_global_textmap().inject(set_in_carrier, carrier, context) try: diff --git a/opentelemetry-api/src/opentelemetry/propagators/composite.py b/opentelemetry-api/src/opentelemetry/propagators/composite.py index 82f5c3fc46b..92dc6b8a380 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/composite.py +++ b/opentelemetry-api/src/opentelemetry/propagators/composite.py @@ -35,7 +35,8 @@ def __init__( def extract( self, - carrier: typing.Dict[str, str], + getter: textmap.Getter[textmap.TextMapPropagatorT], + carrier: textmap.TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> Context: """Run each of the configured propagators with the given context and carrier. @@ -46,12 +47,13 @@ def extract( See `opentelemetry.propagators.textmap.TextMapPropagator.extract` """ for propagator in self._propagators: - context = propagator.extract(carrier, context) + context = propagator.extract(getter, carrier, context) return context # type: ignore def inject( self, - carrier: typing.Dict[str, str], + set_in_carrier: textmap.Setter[textmap.TextMapPropagatorT], + carrier: textmap.TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> None: """Run each of the configured propagators with the given context and carrier. @@ -62,7 +64,7 @@ def inject( See `opentelemetry.propagators.textmap.TextMapPropagator.inject` """ for propagator in self._propagators: - propagator.inject(carrier, context) + propagator.inject(set_in_carrier, carrier, context) @property def fields(self) -> typing.Set[str]: diff --git a/opentelemetry-api/src/opentelemetry/propagators/textmap.py b/opentelemetry-api/src/opentelemetry/propagators/textmap.py index aa4a4589f20..cf93d1d6319 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/textmap.py +++ b/opentelemetry-api/src/opentelemetry/propagators/textmap.py @@ -17,47 +17,126 @@ from opentelemetry.context.context import Context +TextMapPropagatorT = typing.TypeVar("TextMapPropagatorT") +CarrierValT = typing.Union[typing.List[str], str] + +Setter = typing.Callable[[TextMapPropagatorT, str, str], None] + + +class Getter(typing.Generic[TextMapPropagatorT]): + """This class implements a Getter that enables extracting propagated + fields from a carrier. + """ + + def get( + self, carrier: TextMapPropagatorT, key: str + ) -> typing.Optional[typing.List[str]]: + """Function that can retrieve zero + or more values from the carrier. In the case that + the value does not exist, returns None. + + Args: + carrier: An object which contains values that are used to + construct a Context. + key: key of a field in carrier. + Returns: first value of the propagation key or None if the key doesn't + exist. + """ + raise NotImplementedError() + + def keys(self, carrier: TextMapPropagatorT) -> typing.List[str]: + """Function that can retrieve all the keys in a carrier object. + + Args: + carrier: An object which contains values that are + used to construct a Context. + Returns: + list of keys from the carrier. + """ + raise NotImplementedError() + + +class DictGetter(Getter[typing.Dict[str, CarrierValT]]): + def get( + self, carrier: typing.Dict[str, CarrierValT], key: str + ) -> typing.Optional[typing.List[str]]: + """Getter implementation to retrieve a value from a dictionary. + + Args: + carrier: dictionary in which header + key: the key used to get the value + Returns: + A list with a single string with the value if it exists, else None. + """ + val = carrier.get(key, None) + if val is None: + return None + if isinstance(val, typing.Iterable) and not isinstance(val, str): + return list(val) + return [val] + + def keys(self, carrier: typing.Dict[str, CarrierValT]) -> typing.List[str]: + """Keys implementation that returns all keys from a dictionary.""" + return list(carrier.keys()) + class TextMapPropagator(abc.ABC): """This class provides an interface that enables extracting and injecting - context into headers of HTTP requests. HTTP frameworks and clients can - integrate with TextMapPropagator by providing the object containing the - headers. + context into headers of HTTP requests. HTTP frameworks and clients + can integrate with TextMapPropagator by providing the object containing the + headers, and a getter and setter function for the extraction and + injection of values, respectively. + """ @abc.abstractmethod def extract( self, - carrier: typing.Dict[str, str], + getter: Getter[TextMapPropagatorT], + carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> Context: """Create a Context from values in the carrier. - Retrieves values from the carrier object and uses them to populate a - context and returns it afterwards. + The extract function should retrieve values from the carrier + object using getter, and use values to populate a + Context value and return it. Args: - carrier: and object which contains values that are used to - construct a Context. - context: an optional Context to use. Defaults to current context if - not set. + getter: 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 Context. This object + must be paired with an appropriate getter + which understands how to extract a value from it. + context: an optional Context to use. Defaults to current + context if not set. Returns: - A Context with the configuration found in the carrier. + A Context with configuration found in the carrier. + """ @abc.abstractmethod def inject( self, - carrier: typing.Dict[str, str], + set_in_carrier: Setter[TextMapPropagatorT], + carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> None: """Inject values from a Context into a carrier. - Enables the propagation of values into HTTP clients or other objects - which perform an HTTP request. + 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: - carrier: An dict-like object where to store HTTP headers. + 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. context: an optional Context to use. Defaults to current context if not set. diff --git a/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py b/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py index 11248025c0b..480e716bf78 100644 --- a/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py +++ b/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py @@ -35,19 +35,20 @@ class TraceContextTextMapPropagator(textmap.TextMapPropagator): def extract( self, - carrier: typing.Dict[str, str], + getter: textmap.Getter[textmap.TextMapPropagatorT], + carrier: textmap.TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> Context: """Extracts SpanContext from the carrier. See `opentelemetry.propagators.textmap.TextMapPropagator.extract` """ - header = carrier.get(self._TRACEPARENT_HEADER_NAME) + header = getter.get(carrier, self._TRACEPARENT_HEADER_NAME) if not header: return trace.set_span_in_context(trace.INVALID_SPAN, context) - match = re.search(self._TRACEPARENT_HEADER_FORMAT_RE, header) + match = re.search(self._TRACEPARENT_HEADER_FORMAT_RE, header[0]) if not match: return trace.set_span_in_context(trace.INVALID_SPAN, context) @@ -65,7 +66,7 @@ def extract( if version == "ff": return trace.set_span_in_context(trace.INVALID_SPAN, context) - tracestate_headers = carrier.get(self._TRACESTATE_HEADER_NAME) + tracestate_headers = getter.get(carrier, self._TRACESTATE_HEADER_NAME) if tracestate_headers is None: tracestate = None else: @@ -84,7 +85,8 @@ def extract( def inject( self, - carrier: typing.Dict[str, str], + set_in_carrier: textmap.Setter[textmap.TextMapPropagatorT], + carrier: textmap.TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> None: """Injects SpanContext into the carrier. @@ -95,17 +97,19 @@ def inject( span_context = span.get_span_context() if span_context == trace.INVALID_SPAN_CONTEXT: return - carrier[ - self._TRACEPARENT_HEADER_NAME - ] = "00-{trace_id}-{span_id}-{:02x}".format( + traceparent_string = "00-{trace_id}-{span_id}-{:02x}".format( span_context.trace_flags, trace_id=format_trace_id(span_context.trace_id), span_id=format_span_id(span_context.span_id), ) - + set_in_carrier( + carrier, self._TRACEPARENT_HEADER_NAME, traceparent_string + ) if span_context.trace_state: tracestate_string = span_context.trace_state.to_header() - carrier[self._TRACESTATE_HEADER_NAME] = tracestate_string + set_in_carrier( + carrier, self._TRACESTATE_HEADER_NAME, tracestate_string + ) @property def fields(self) -> typing.Set[str]: diff --git a/opentelemetry-api/src/opentelemetry/trace/span.py b/opentelemetry-api/src/opentelemetry/trace/span.py index 095811b0df2..d04cdfa49dd 100644 --- a/opentelemetry-api/src/opentelemetry/trace/span.py +++ b/opentelemetry-api/src/opentelemetry/trace/span.py @@ -335,11 +335,11 @@ def to_header(self) -> str: return ",".join(key + "=" + value for key, value in self._dict.items()) @classmethod - def from_header(cls, header: str) -> "TraceState": + def from_header(cls, header_list: typing.List[str]) -> "TraceState": """Parses one or more w3c tracestate header into a TraceState. Args: - header: one W3C tracestate headers. + header_list: one or more w3c tracestate headers. Returns: A valid TraceState that contains values extracted from @@ -351,24 +351,24 @@ def from_header(cls, header: str) -> "TraceState": If the number of keys is beyond the maximum, all values will be discarded and an empty tracestate will be returned. """ - pairs = OrderedDict() - for member in re.split(_delimiter_pattern, header): - # empty members are valid, but no need to process further. - if not member: - continue - match = _member_pattern.fullmatch(member) - if not match: - _logger.warning( - "Member doesn't match the w3c identifiers format %s", - member, - ) - return cls() - key, _eq, value = match.groups() - # duplicate keys are not legal in header - if key in pairs: - return cls() - pairs[key] = value + for header in header_list: + for member in re.split(_delimiter_pattern, header): + # empty members are valid, but no need to process further. + if not member: + continue + match = _member_pattern.fullmatch(member) + if not match: + _logger.warning( + "Member doesn't match the w3c identifiers format %s", + member, + ) + return cls() + key, _eq, value = match.groups() + # duplicate keys are not legal in header + if key in pairs: + return cls() + pairs[key] = value return cls(list(pairs.items())) @classmethod diff --git a/opentelemetry-api/tests/baggage/test_baggage_propagation.py b/opentelemetry-api/tests/baggage/test_baggage_propagation.py index 11bdc2429af..3047ddbbe46 100644 --- a/opentelemetry-api/tests/baggage/test_baggage_propagation.py +++ b/opentelemetry-api/tests/baggage/test_baggage_propagation.py @@ -15,11 +15,14 @@ # type: ignore import unittest -from unittest.mock import patch +from unittest.mock import Mock, patch from opentelemetry import baggage from opentelemetry.baggage.propagation import W3CBaggagePropagator from opentelemetry.context import get_current +from opentelemetry.propagators.textmap import DictGetter + +carrier_getter = DictGetter() class TestBaggagePropagation(unittest.TestCase): @@ -28,9 +31,8 @@ def setUp(self): def _extract(self, header_value): """Test helper""" - return baggage.get_all( - self.propagator.extract({"baggage": header_value}) - ) + header = {"baggage": [header_value]} + return baggage.get_all(self.propagator.extract(carrier_getter, header)) def _inject(self, values): """Test helper""" @@ -38,11 +40,14 @@ def _inject(self, values): for k, v in values.items(): ctx = baggage.set_baggage(k, v, context=ctx) output = {} - self.propagator.inject(output, context=ctx) + self.propagator.inject(dict.__setitem__, output, context=ctx) return output.get("baggage") def test_no_context_header(self): - self.assertEqual(baggage.get_all(self.propagator.extract({})), {}) + baggage_entries = baggage.get_all( + self.propagator.extract(carrier_getter, {}) + ) + self.assertEqual(baggage_entries, {}) def test_empty_context_header(self): header = "" @@ -141,14 +146,16 @@ def test_inject_non_string_values(self): self.assertIn("key3=123.567", output) @patch("opentelemetry.baggage.propagation.baggage") - def test_fields(self, mock_baggage): + @patch("opentelemetry.baggage.propagation._format_baggage") + def test_fields(self, mock_format_baggage, mock_baggage): - mock_baggage.configure_mock( - **{"get_all.return_value": {"a": "b", "c": "d"}} - ) + mock_set_in_carrier = Mock() + + self.propagator.inject(mock_set_in_carrier, {}) - carrier = {} + inject_fields = set() - self.propagator.inject(carrier) + for mock_call in mock_set_in_carrier.mock_calls: + inject_fields.add(mock_call[1][1]) - self.assertEqual(carrier.keys(), self.propagator.fields) + self.assertEqual(inject_fields, self.propagator.fields) diff --git a/opentelemetry-api/tests/propagators/test_composite.py b/opentelemetry-api/tests/propagators/test_composite.py index f898b65a2df..e33649bbdd8 100644 --- a/opentelemetry-api/tests/propagators/test_composite.py +++ b/opentelemetry-api/tests/propagators/test_composite.py @@ -20,15 +20,22 @@ from opentelemetry.propagators.composite import CompositeHTTPPropagator +def get_as_list(dict_object, key): + value = dict_object.get(key) + return [value] if value is not None else [] + + def mock_inject(name, value="data"): - def wrapped(carrier=None, context=None): + def wrapped(setter, carrier=None, context=None): carrier[name] = value + setter({}, "inject_field_{}_0".format(name), None) + setter({}, "inject_field_{}_1".format(name), None) return wrapped def mock_extract(name, value="context"): - def wrapped(carrier=None, context=None): + def wrapped(getter, carrier=None, context=None): new_context = context.copy() new_context[name] = value return new_context @@ -62,20 +69,24 @@ def setUpClass(cls): def test_no_propagators(self): propagator = CompositeHTTPPropagator([]) new_carrier = {} - propagator.inject(carrier=new_carrier) + propagator.inject(dict.__setitem__, carrier=new_carrier) self.assertEqual(new_carrier, {}) - context = propagator.extract(carrier=new_carrier, context={}) + context = propagator.extract( + get_as_list, carrier=new_carrier, context={} + ) self.assertEqual(context, {}) def test_single_propagator(self): propagator = CompositeHTTPPropagator([self.mock_propagator_0]) new_carrier = {} - propagator.inject(carrier=new_carrier) + propagator.inject(dict.__setitem__, carrier=new_carrier) self.assertEqual(new_carrier, {"mock-0": "data"}) - context = propagator.extract(carrier=new_carrier, context={}) + context = propagator.extract( + get_as_list, carrier=new_carrier, context={} + ) self.assertEqual(context, {"mock-0": "context"}) def test_multiple_propagators(self): @@ -84,10 +95,12 @@ def test_multiple_propagators(self): ) new_carrier = {} - propagator.inject(carrier=new_carrier) + propagator.inject(dict.__setitem__, carrier=new_carrier) self.assertEqual(new_carrier, {"mock-0": "data", "mock-1": "data"}) - context = propagator.extract(carrier=new_carrier, context={}) + context = propagator.extract( + get_as_list, carrier=new_carrier, context={} + ) self.assertEqual(context, {"mock-0": "context", "mock-1": "context"}) def test_multiple_propagators_same_key(self): @@ -98,10 +111,12 @@ def test_multiple_propagators_same_key(self): ) new_carrier = {} - propagator.inject(carrier=new_carrier) + propagator.inject(dict.__setitem__, carrier=new_carrier) self.assertEqual(new_carrier, {"mock-0": "data2"}) - context = propagator.extract(carrier=new_carrier, context={}) + context = propagator.extract( + get_as_list, carrier=new_carrier, context={} + ) self.assertEqual(context, {"mock-0": "context2"}) def test_fields(self): @@ -113,14 +128,13 @@ def test_fields(self): ] ) - propagator.inject({}) + mock_set_in_carrier = Mock() - self.assertEqual( - { - "inject_field_mock-0_0", - "inject_field_mock-0_1", - "inject_field_mock-1_0", - "inject_field_mock-1_1", - }, - propagator.fields, - ) + propagator.inject(mock_set_in_carrier, {}) + + inject_fields = set() + + for mock_call in mock_set_in_carrier.mock_calls: + inject_fields.add(mock_call[1][1]) + + self.assertEqual(inject_fields, propagator.fields) diff --git a/opentelemetry-api/tests/propagators/test_global_httptextformat.py b/opentelemetry-api/tests/propagators/test_global_httptextformat.py index 30e39f11865..6ba32e46183 100644 --- a/opentelemetry-api/tests/propagators/test_global_httptextformat.py +++ b/opentelemetry-api/tests/propagators/test_global_httptextformat.py @@ -18,9 +18,12 @@ from opentelemetry import baggage, trace from opentelemetry.propagate import extract, inject +from opentelemetry.propagators.textmap import DictGetter from opentelemetry.trace import get_current_span, set_span_in_context from opentelemetry.trace.span import format_span_id, format_trace_id +carrier_getter = DictGetter() + class TestDefaultGlobalPropagator(unittest.TestCase): """Test ensures the default global composite propagator works as intended""" @@ -33,17 +36,16 @@ def test_propagation(self): trace_id=format_trace_id(self.TRACE_ID), span_id=format_span_id(self.SPAN_ID), ) - - ctx = extract( - { - "baggage": "key1=val1,key2=val2", - "traceparent": traceparent_value, - "tracestate": "foo=1,bar=2,baz=3", - } - ) - self.assertEqual( - baggage.get_all(context=ctx), {"key1": "val1", "key2": "val2"} - ) + tracestate_value = "foo=1,bar=2,baz=3" + headers = { + "baggage": ["key1=val1,key2=val2"], + "traceparent": [traceparent_value], + "tracestate": [tracestate_value], + } + ctx = extract(carrier_getter, headers) + baggage_entries = baggage.get_all(context=ctx) + expected = {"key1": "val1", "key2": "val2"} + self.assertEqual(baggage_entries, expected) span_context = get_current_span(context=ctx).get_span_context() self.assertEqual(span_context.trace_id, self.TRACE_ID) @@ -54,7 +56,7 @@ def test_propagation(self): ctx = baggage.set_baggage("key4", "val4", context=ctx) ctx = set_span_in_context(span, context=ctx) output = {} - inject(output, context=ctx) + inject(dict.__setitem__, output, context=ctx) self.assertEqual(traceparent_value, output["traceparent"]) self.assertIn("key3=val3", output["baggage"]) self.assertIn("key4=val4", output["baggage"]) diff --git a/opentelemetry-api/tests/trace/propagation/test_textmap.py b/opentelemetry-api/tests/trace/propagation/test_textmap.py new file mode 100644 index 00000000000..e47a0d22cb4 --- /dev/null +++ b/opentelemetry-api/tests/trace/propagation/test_textmap.py @@ -0,0 +1,44 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# type: ignore + +import unittest + +from opentelemetry.propagators.textmap import DictGetter + + +class TestDictGetter(unittest.TestCase): + def test_get_none(self): + getter = DictGetter() + carrier = {} + val = getter.get(carrier, "test") + self.assertIsNone(val) + + def test_get_str(self): + getter = DictGetter() + carrier = {"test": "val"} + val = getter.get(carrier, "test") + self.assertEqual(val, ["val"]) + + def test_get_iter(self): + getter = DictGetter() + carrier = {"test": ["val"]} + val = getter.get(carrier, "test") + self.assertEqual(val, ["val"]) + + def test_keys(self): + getter = DictGetter() + keys = getter.keys({"test": "val"}) + self.assertEqual(keys, ["test"]) diff --git a/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py b/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py index 916417096d2..79683d43d94 100644 --- a/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py +++ b/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py @@ -19,11 +19,14 @@ from unittest.mock import Mock, patch from opentelemetry import trace +from opentelemetry.propagators.textmap import DictGetter from opentelemetry.trace.propagation import tracecontext from opentelemetry.trace.span import TraceState FORMAT = tracecontext.TraceContextTextMapPropagator() +carrier_getter = DictGetter() + class TestTraceContextFormat(unittest.TestCase): TRACE_ID = int("12345678901234567890123456789012", 16) # type:int @@ -39,7 +42,7 @@ def test_no_traceparent_header(self): trace-id and parent-id that represents the current request. """ output = {} # type:typing.Dict[str, typing.List[str]] - span = trace.get_current_span(FORMAT.extract(output)) + span = trace.get_current_span(FORMAT.extract(carrier_getter, output)) self.assertIsInstance(span.get_span_context(), trace.SpanContext) def test_headers_with_tracestate(self): @@ -53,9 +56,10 @@ def test_headers_with_tracestate(self): tracestate_value = "foo=1,bar=2,baz=3" span_context = trace.get_current_span( FORMAT.extract( + carrier_getter, { - "traceparent": traceparent_value, - "tracestate": tracestate_value, + "traceparent": [traceparent_value], + "tracestate": [tracestate_value], }, ) ).get_span_context() @@ -69,7 +73,7 @@ def test_headers_with_tracestate(self): span = trace.NonRecordingSpan(span_context) ctx = trace.set_span_in_context(span) - FORMAT.inject(output, ctx) + FORMAT.inject(dict.__setitem__, output, ctx) self.assertEqual(output["traceparent"], traceparent_value) for pair in ["foo=1", "bar=2", "baz=3"]: self.assertIn(pair, output["tracestate"]) @@ -96,12 +100,12 @@ def test_invalid_trace_id(self): """ span = trace.get_current_span( FORMAT.extract( + carrier_getter, { - "traceparent": ( - "00-00000000000000000000000000000000-" - "1234567890123456-00" - ), - "tracestate": "foo=1,bar=2,foo=3", + "traceparent": [ + "00-00000000000000000000000000000000-1234567890123456-00" + ], + "tracestate": ["foo=1,bar=2,foo=3"], }, ) ) @@ -127,12 +131,12 @@ def test_invalid_parent_id(self): """ span = trace.get_current_span( FORMAT.extract( + carrier_getter, { - "traceparent": ( - "00-00000000000000000000000000000000-" - "0000000000000000-00" - ), - "tracestate": "foo=1,bar=2,foo=3", + "traceparent": [ + "00-00000000000000000000000000000000-0000000000000000-00" + ], + "tracestate": ["foo=1,bar=2,foo=3"], }, ) ) @@ -151,8 +155,7 @@ def test_no_send_empty_tracestate(self): trace.SpanContext(self.TRACE_ID, self.SPAN_ID, is_remote=False) ) ctx = trace.set_span_in_context(span) - - FORMAT.inject(output, ctx) + FORMAT.inject(dict.__setitem__, output, ctx) self.assertTrue("traceparent" in output) self.assertFalse("tracestate" in output) @@ -166,12 +169,13 @@ def test_format_not_supported(self): """ span = trace.get_current_span( FORMAT.extract( + carrier_getter, { - "traceparent": ( + "traceparent": [ "00-12345678901234567890123456789012-" "1234567890123456-00-residue" - ), - "tracestate": "foo=1,bar=2,foo=3", + ], + "tracestate": ["foo=1,bar=2,foo=3"], }, ) ) @@ -181,19 +185,19 @@ def test_propagate_invalid_context(self): """Do not propagate invalid trace context.""" output = {} # type:typing.Dict[str, str] ctx = trace.set_span_in_context(trace.INVALID_SPAN) - FORMAT.inject(output, context=ctx) + FORMAT.inject(dict.__setitem__, output, context=ctx) self.assertFalse("traceparent" in output) def test_tracestate_empty_header(self): """Test tracestate with an additional empty header (should be ignored)""" span = trace.get_current_span( FORMAT.extract( + carrier_getter, { - "traceparent": ( - "00-12345678901234567890123456789012-" - "1234567890123456-00" - ), - "tracestate": "foo=1, ", + "traceparent": [ + "00-12345678901234567890123456789012-1234567890123456-00" + ], + "tracestate": ["foo=1", ""], }, ) ) @@ -203,12 +207,12 @@ def test_tracestate_header_with_trailing_comma(self): """Do not propagate invalid trace context.""" span = trace.get_current_span( FORMAT.extract( + carrier_getter, { - "traceparent": ( - "00-12345678901234567890123456789012-" - "1234567890123456-00" - ), - "tracestate": "foo=1,", + "traceparent": [ + "00-12345678901234567890123456789012-1234567890123456-00" + ], + "tracestate": ["foo=1,"], }, ) ) @@ -226,12 +230,13 @@ def test_tracestate_keys(self): ) span = trace.get_current_span( FORMAT.extract( + carrier_getter, { - "traceparent": ( + "traceparent": [ "00-12345678901234567890123456789012-" "1234567890123456-00" - ), - "tracestate": tracestate_value, + ], + "tracestate": [tracestate_value], }, ) ) @@ -246,8 +251,9 @@ def test_tracestate_keys(self): span.get_span_context().trace_state["foo-_*/bar"], "bar4" ) + @patch("opentelemetry.trace.INVALID_SPAN_CONTEXT") @patch("opentelemetry.trace.get_current_span") - def test_fields(self, mock_get_current_span): + def test_fields(self, mock_get_current_span, mock_invalid_span_context): mock_get_current_span.configure_mock( return_value=Mock( @@ -264,8 +270,13 @@ def test_fields(self, mock_get_current_span): ) ) - carrier = {} + mock_set_in_carrier = Mock() + + FORMAT.inject(mock_set_in_carrier, {}) + + inject_fields = set() - FORMAT.inject(carrier) + for mock_call in mock_set_in_carrier.mock_calls: + inject_fields.add(mock_call[1][1]) - self.assertEqual(carrier.keys(), {"traceparent", "tracestate"}) + self.assertEqual(inject_fields, FORMAT.fields) diff --git a/opentelemetry-api/tests/trace/test_tracestate.py b/opentelemetry-api/tests/trace/test_tracestate.py index 9126ceabd75..6665dd612dd 100644 --- a/opentelemetry-api/tests/trace/test_tracestate.py +++ b/opentelemetry-api/tests/trace/test_tracestate.py @@ -78,7 +78,7 @@ def test_tracestate_from_header(self): "foo=bar3", "foo-_*/bar=bar4", ] - header_list = ",".join(entries) + header_list = [",".join(entries)] state = TraceState.from_header(header_list) self.assertEqual(state.to_header(), ",".join(entries)) @@ -89,7 +89,7 @@ def test_tracestate_order_changed(self): "foo=bar3", "foo-_*/bar=bar4", ] - header_list = ",".join(entries) + header_list = [",".join(entries)] state = TraceState.from_header(header_list) new_state = state.update("foo", "bar33") entries = list(new_state.items()) # type: ignore diff --git a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py index 9527ff4b471..01abcc7c879 100644 --- a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py +++ b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py @@ -17,7 +17,12 @@ import opentelemetry.trace as trace from opentelemetry.context import Context -from opentelemetry.propagators.textmap import TextMapPropagator +from opentelemetry.propagators.textmap import ( + Getter, + Setter, + TextMapPropagator, + TextMapPropagatorT, +) from opentelemetry.trace import format_span_id, format_trace_id @@ -39,18 +44,19 @@ class B3Format(TextMapPropagator): def extract( self, - carrier: typing.Dict[str, str], + getter: Getter[TextMapPropagatorT], + carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> Context: - trace_id = format_trace_id(trace.INVALID_TRACE_ID) span_id = format_span_id(trace.INVALID_SPAN_ID) sampled = "0" flags = None - single_header = carrier.get(self.SINGLE_HEADER_KEY) - - if single_header is not None: + single_header = _extract_first_element( + getter.get(carrier, self.SINGLE_HEADER_KEY) + ) + if single_header: # The b3 spec calls for the sampling state to be # "deferred", which is unspecified. This concept does not # translate to SpanContext, so we set it as recorded. @@ -68,10 +74,22 @@ def extract( else: return trace.set_span_in_context(trace.INVALID_SPAN) else: - trace_id = carrier.get(self.TRACE_ID_KEY, False) or trace_id - span_id = carrier.get(self.SPAN_ID_KEY, False) or span_id - sampled = carrier.get(self.SAMPLED_KEY, False) or sampled - flags = carrier.get(self.FLAGS_KEY, False) or flags + trace_id = ( + _extract_first_element(getter.get(carrier, self.TRACE_ID_KEY)) + or trace_id + ) + span_id = ( + _extract_first_element(getter.get(carrier, self.SPAN_ID_KEY)) + or span_id + ) + sampled = ( + _extract_first_element(getter.get(carrier, self.SAMPLED_KEY)) + or sampled + ) + flags = ( + _extract_first_element(getter.get(carrier, self.FLAGS_KEY)) + or flags + ) if ( self._trace_id_regex.fullmatch(trace_id) is None @@ -109,10 +127,10 @@ def extract( def inject( self, - carrier: typing.Dict[str, str], + set_in_carrier: Setter[TextMapPropagatorT], + carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> None: - span = trace.get_current_span(context=context) span_context = span.get_span_context() @@ -120,14 +138,20 @@ def inject( return sampled = (trace.TraceFlags.SAMPLED & span_context.trace_flags) != 0 - carrier[self.TRACE_ID_KEY] = format_trace_id(span_context.trace_id) - carrier[self.SPAN_ID_KEY] = format_span_id(span_context.span_id) + set_in_carrier( + carrier, self.TRACE_ID_KEY, format_trace_id(span_context.trace_id), + ) + set_in_carrier( + carrier, self.SPAN_ID_KEY, format_span_id(span_context.span_id) + ) span_parent = getattr(span, "parent", None) if span_parent is not None: - carrier[self.PARENT_SPAN_ID_KEY] = format_span_id( - span_parent.span_id + set_in_carrier( + carrier, + self.PARENT_SPAN_ID_KEY, + format_span_id(span_parent.span_id), ) - carrier[self.SAMPLED_KEY] = "1" if sampled else "0" + set_in_carrier(carrier, self.SAMPLED_KEY, "1" if sampled else "0") @property def fields(self) -> typing.Set[str]: @@ -137,3 +161,11 @@ def fields(self) -> typing.Set[str]: self.PARENT_SPAN_ID_KEY, self.SAMPLED_KEY, } + + +def _extract_first_element( + items: typing.Iterable[TextMapPropagatorT], +) -> typing.Optional[TextMapPropagatorT]: + if items is None: + return None + return next(iter(items), None) diff --git a/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py b/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py index 3a7a251ad88..5048f495f06 100644 --- a/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py +++ b/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py @@ -14,6 +14,7 @@ import opentelemetry.propagators.b3 as b3_format import opentelemetry.sdk.trace as trace +from opentelemetry.propagators.textmap import DictGetter FORMAT = b3_format.B3Format() @@ -21,6 +22,7 @@ def test_extract_single_header(benchmark): benchmark( FORMAT.extract, + DictGetter(), { FORMAT.SINGLE_HEADER_KEY: "bdb5b63237ed38aea578af665aa5aa60-c32d953d73ad2251-1-11fd79a30b0896cd285b396ae102dd76" }, @@ -33,6 +35,7 @@ def test_inject_empty_context(benchmark): with tracer.start_as_current_span("Child Span"): benchmark( FORMAT.inject, + dict.__setitem__, { FORMAT.TRACE_ID_KEY: "bdb5b63237ed38aea578af665aa5aa60", FORMAT.SPAN_ID_KEY: "00000000000000000c32d953d73ad225", diff --git a/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py b/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py index 3343ac0f5c4..f9d3bce1adb 100644 --- a/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py +++ b/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py @@ -13,20 +13,24 @@ # limitations under the License. import unittest -from unittest.mock import patch +from unittest.mock import Mock, patch import opentelemetry.propagators.b3 as b3_format # pylint: disable=no-name-in-module,import-error import opentelemetry.sdk.trace as trace import opentelemetry.sdk.trace.id_generator as id_generator import opentelemetry.trace as trace_api from opentelemetry.context import get_current +from opentelemetry.propagators.textmap import DictGetter FORMAT = b3_format.B3Format() +carrier_getter = DictGetter() + + def get_child_parent_new_carrier(old_carrier): - ctx = FORMAT.extract(old_carrier) + ctx = FORMAT.extract(carrier_getter, old_carrier) parent_span_context = trace_api.get_current_span(ctx).get_span_context() parent = trace._Span("parent", parent_span_context) @@ -44,8 +48,7 @@ def get_child_parent_new_carrier(old_carrier): new_carrier = {} ctx = trace_api.set_span_in_context(child) - - FORMAT.inject(new_carrier, context=ctx) + FORMAT.inject(dict.__setitem__, new_carrier, context=ctx) return child, parent, new_carrier @@ -91,7 +94,6 @@ def test_extract_multi_header(self): new_carrier[FORMAT.SPAN_ID_KEY], b3_format.format_span_id(child.context.span_id), ) - self.assertEqual( new_carrier[FORMAT.PARENT_SPAN_ID_KEY], b3_format.format_span_id(parent.context.span_id), @@ -234,10 +236,10 @@ def test_64bit_trace_id(self): def test_invalid_single_header(self): """If an invalid single header is passed, return an - invalid trace_api.SpanContext. + invalid SpanContext. """ carrier = {FORMAT.SINGLE_HEADER_KEY: "0-1-2-3-4-5-6-7"} - ctx = FORMAT.extract(carrier) + ctx = FORMAT.extract(carrier_getter, carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) @@ -249,7 +251,7 @@ def test_missing_trace_id(self): FORMAT.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier) + ctx = FORMAT.extract(carrier_getter, carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) @@ -273,7 +275,7 @@ def test_invalid_trace_id( FORMAT.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier) + ctx = FORMAT.extract(carrier_getter, carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, 1) @@ -299,7 +301,7 @@ def test_invalid_span_id( FORMAT.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier) + ctx = FORMAT.extract(carrier_getter, carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, 1) @@ -312,34 +314,45 @@ def test_missing_span_id(self): FORMAT.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier) + ctx = FORMAT.extract(carrier_getter, carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) - def test_inject_empty_context(self): + @staticmethod + def test_inject_empty_context(): """If the current context has no span, don't add headers""" new_carrier = {} - FORMAT.inject(new_carrier, get_current()) - self.assertEqual(len(new_carrier), 0) + FORMAT.inject(dict.__setitem__, new_carrier, get_current()) + assert len(new_carrier) == 0 - def test_default_span(self): - """Make sure propagator does not crash when working with - NonRecordingSpan""" + @staticmethod + def test_default_span(): + """Make sure propagator does not crash when working with NonRecordingSpan""" - try: - FORMAT.inject({}, FORMAT.extract({})) - except Exception: # pylint: disable=broad-except - self.fail("propagator crashed when working with NonRecordingSpan") + class CarrierGetter(DictGetter): + def get(self, carrier, key): + return carrier.get(key, None) + + def setter(carrier, key, value): + carrier[key] = value + + ctx = FORMAT.extract(CarrierGetter(), {}) + FORMAT.inject(setter, {}, ctx) def test_fields(self): """Make sure the fields attribute returns the fields used in inject""" tracer = trace.TracerProvider().get_tracer("sdk_tracer_provider") - carrier = {} + mock_set_in_carrier = Mock() with tracer.start_as_current_span("parent"): with tracer.start_as_current_span("child"): - FORMAT.inject(carrier) + FORMAT.inject(mock_set_in_carrier, {}) + + inject_fields = set() + + for call in mock_set_in_carrier.mock_calls: + inject_fields.add(call[1][1]) - self.assertEqual(FORMAT.fields, carrier.keys()) + self.assertEqual(FORMAT.fields, inject_fields) diff --git a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py index 2908f0697c8..8e7fe5f69ff 100644 --- a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py +++ b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py @@ -18,7 +18,12 @@ import opentelemetry.trace as trace from opentelemetry import baggage from opentelemetry.context import Context, get_current -from opentelemetry.propagators.textmap import TextMapPropagator +from opentelemetry.propagators.textmap import ( + Getter, + Setter, + TextMapPropagator, + TextMapPropagatorT, +) from opentelemetry.trace import format_span_id, format_trace_id @@ -34,28 +39,19 @@ class JaegerPropagator(TextMapPropagator): def extract( self, - carrier: typing.Dict[str, str], + getter: Getter[TextMapPropagatorT], + carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> Context: if context is None: context = get_current() - header = carrier.get(self.TRACE_ID_KEY) - if header is None: + header = getter.get(carrier, self.TRACE_ID_KEY) + if not header: return trace.set_span_in_context(trace.INVALID_SPAN, context) - fields = header.split(":") - - for key in [ - key - for key in carrier.keys() - if key.startswith(self.BAGGAGE_PREFIX) - ]: - context = baggage.set_baggage( - key.replace(self.BAGGAGE_PREFIX, ""), - urllib.parse.quote(carrier[key]).strip(), - context=context, - ) + fields = _extract_first_element(header).split(":") + context = self._extract_baggage(getter, carrier, context) if len(fields) != 4: return trace.set_span_in_context(trace.INVALID_SPAN, context) @@ -80,7 +76,8 @@ def extract( def inject( self, - carrier: typing.Dict[str, str], + set_in_carrier: Setter[TextMapPropagatorT], + carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> None: span = trace.get_current_span(context=context) @@ -94,11 +91,15 @@ def inject( trace_flags |= self.DEBUG_FLAG # set span identity - carrier[self.TRACE_ID_KEY] = _format_uber_trace_id( - span_context.trace_id, - span_context.span_id, - span_parent_id, - trace_flags, + set_in_carrier( + carrier, + self.TRACE_ID_KEY, + _format_uber_trace_id( + span_context.trace_id, + span_context.span_id, + span_parent_id, + trace_flags, + ), ) # set span baggage, if any @@ -107,7 +108,9 @@ def inject( return for key, value in baggage_entries.items(): baggage_key = self.BAGGAGE_PREFIX + key - carrier[baggage_key] = urllib.parse.quote(str(value)) + set_in_carrier( + carrier, baggage_key, urllib.parse.quote(str(value)) + ) @property def fields(self) -> typing.Set[str]: @@ -120,10 +123,10 @@ def _extract_baggage(self, getter, carrier, context): if key.startswith(self.BAGGAGE_PREFIX) ] for key in baggage_keys: - value = carrier.get(key) + value = _extract_first_element(getter.get(carrier, key)) context = baggage.set_baggage( key.replace(self.BAGGAGE_PREFIX, ""), - urllib.parse.quote(value).strip(), + urllib.parse.unquote(value).strip(), context=context, ) return context @@ -136,3 +139,11 @@ def _format_uber_trace_id(trace_id, span_id, parent_span_id, flags): span_id=format_span_id(span_id), parent_id=format_span_id(parent_span_id), ) + + +def _extract_first_element( + items: typing.Iterable[TextMapPropagatorT], +) -> typing.Optional[TextMapPropagatorT]: + if items is None: + return None + return next(iter(items), None) diff --git a/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py b/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py index 620d7ebc45a..da8a855edbe 100644 --- a/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py +++ b/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py @@ -13,6 +13,7 @@ # limitations under the License. import unittest +from unittest.mock import Mock import opentelemetry.sdk.trace as trace import opentelemetry.sdk.trace.id_generator as id_generator @@ -21,13 +22,17 @@ from opentelemetry.propagators import ( # pylint: disable=no-name-in-module jaeger, ) +from opentelemetry.propagators.textmap import DictGetter FORMAT = jaeger.JaegerPropagator() +carrier_getter = DictGetter() + + def get_context_new_carrier(old_carrier, carrier_baggage=None): - ctx = FORMAT.extract(old_carrier) + ctx = FORMAT.extract(carrier_getter, old_carrier) if carrier_baggage: for key, value in carrier_baggage.items(): ctx = baggage.set_baggage(key, value, ctx) @@ -49,7 +54,7 @@ def get_context_new_carrier(old_carrier, carrier_baggage=None): new_carrier = {} ctx = trace_api.set_span_in_context(child, ctx) - FORMAT.inject(new_carrier, context=ctx) + FORMAT.inject(dict.__setitem__, new_carrier, context=ctx) return ctx, new_carrier @@ -67,14 +72,14 @@ def setUpClass(cls): def test_extract_valid_span(self): old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} - ctx = FORMAT.extract(old_carrier) + ctx = FORMAT.extract(carrier_getter, old_carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, self.trace_id) self.assertEqual(span_context.span_id, self.span_id) def test_missing_carrier(self): old_carrier = {} - ctx = FORMAT.extract(old_carrier) + ctx = FORMAT.extract(carrier_getter, old_carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) @@ -112,8 +117,7 @@ def test_debug_flag_set(self): self.assertEqual(FORMAT.DEBUG_FLAG, debug_flag_value) def test_sample_debug_flags_unset(self): - # pylint: disable=protected-access - uber_trace_id = jaeger._format_uber_trace_id( + uber_trace_id = jaeger._format_uber_trace_id( # pylint: disable=protected-access self.trace_id, self.span_id, self.parent_span_id, 0 ) old_carrier = {FORMAT.TRACE_ID_KEY: uber_trace_id} @@ -128,7 +132,7 @@ def test_baggage(self): old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} input_baggage = {"key1": "value1"} _, new_carrier = get_context_new_carrier(old_carrier, input_baggage) - ctx = FORMAT.extract(new_carrier) + ctx = FORMAT.extract(carrier_getter, new_carrier) self.assertDictEqual(input_baggage, ctx["baggage"]) def test_non_string_baggage(self): @@ -136,7 +140,7 @@ def test_non_string_baggage(self): input_baggage = {"key1": 1, "key2": True} formatted_baggage = {"key1": "1", "key2": "True"} _, new_carrier = get_context_new_carrier(old_carrier, input_baggage) - ctx = FORMAT.extract(new_carrier) + ctx = FORMAT.extract(carrier_getter, new_carrier) self.assertDictEqual(formatted_baggage, ctx["baggage"]) def test_extract_invalid_uber_trace_id(self): @@ -145,7 +149,7 @@ def test_extract_invalid_uber_trace_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = FORMAT.extract(old_carrier) + context = FORMAT.extract(carrier_getter, old_carrier) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) @@ -156,7 +160,7 @@ def test_extract_invalid_trace_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = FORMAT.extract(old_carrier) + context = FORMAT.extract(carrier_getter, old_carrier) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) @@ -167,18 +171,18 @@ def test_extract_invalid_span_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = FORMAT.extract(old_carrier) + context = FORMAT.extract(carrier_getter, old_carrier) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) def test_fields(self): tracer = trace.TracerProvider().get_tracer("sdk_tracer_provider") - - carrier = {} - + mock_set_in_carrier = Mock() with tracer.start_as_current_span("parent"): with tracer.start_as_current_span("child"): - FORMAT.inject(carrier) - - self.assertEqual(FORMAT.fields, carrier.keys()) + FORMAT.inject(mock_set_in_carrier, {}) + inject_fields = set() + for call in mock_set_in_carrier.mock_calls: + inject_fields.add(call[1][1]) + self.assertEqual(FORMAT.fields, inject_fields) diff --git a/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py b/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py index 2327abbfae1..b7a365302f9 100644 --- a/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py +++ b/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py @@ -102,6 +102,7 @@ from opentelemetry.baggage import get_baggage, set_baggage from opentelemetry.context import Context, attach, detach, get_value, set_value from opentelemetry.propagate import get_global_textmap +from opentelemetry.propagators.textmap import DictGetter from opentelemetry.shim.opentracing_shim import util from opentelemetry.shim.opentracing_shim.version import __version__ from opentelemetry.trace import INVALID_SPAN_CONTEXT, Link, NonRecordingSpan @@ -526,6 +527,7 @@ def __init__(self, tracer: OtelTracer): Format.TEXT_MAP, Format.HTTP_HEADERS, ) + self._carrier_getter = DictGetter() def unwrap(self): """Returns the :class:`opentelemetry.trace.Tracer` object that is @@ -682,7 +684,7 @@ def inject(self, span_context, format: object, carrier: object): propagator = get_global_textmap() ctx = set_span_in_context(NonRecordingSpan(span_context.unwrap())) - propagator.inject(carrier, context=ctx) + propagator.inject(type(carrier).__setitem__, carrier, context=ctx) def extract(self, format: object, carrier: object): """Returns an ``opentracing.SpanContext`` instance extracted from a @@ -710,7 +712,7 @@ def extract(self, format: object, carrier: object): raise UnsupportedFormatException propagator = get_global_textmap() - ctx = propagator.extract(carrier) + ctx = propagator.extract(self._carrier_getter, carrier) span = get_current_span(ctx) if span is not None: otel_context = span.get_span_context() diff --git a/tests/util/src/opentelemetry/test/mock_textmap.py b/tests/util/src/opentelemetry/test/mock_textmap.py index 4028a1a2647..1edd079042f 100644 --- a/tests/util/src/opentelemetry/test/mock_textmap.py +++ b/tests/util/src/opentelemetry/test/mock_textmap.py @@ -16,7 +16,12 @@ from opentelemetry import trace from opentelemetry.context import Context, get_current -from opentelemetry.propagators.textmap import TextMapPropagator +from opentelemetry.propagators.textmap import ( + Getter, + Setter, + TextMapPropagator, + TextMapPropagatorT, +) class NOOPTextMapPropagator(TextMapPropagator): @@ -28,14 +33,16 @@ class NOOPTextMapPropagator(TextMapPropagator): def extract( self, - carrier: typing.Dict[str, str], + getter: Getter[TextMapPropagatorT], + carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> Context: return get_current() def inject( self, - carrier: typing.Dict[str, str], + set_in_carrier: Setter[TextMapPropagatorT], + carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> None: return None @@ -53,31 +60,39 @@ class MockTextMapPropagator(TextMapPropagator): def extract( self, - carrier: typing.Dict[str, str], + getter: Getter[TextMapPropagatorT], + carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> Context: - trace_id = carrier.get(self.TRACE_ID_KEY) - span_id = carrier.get(self.SPAN_ID_KEY) + trace_id_list = getter.get(carrier, self.TRACE_ID_KEY) + span_id_list = getter.get(carrier, self.SPAN_ID_KEY) - if trace_id is None or span_id is None: + if not trace_id_list or not span_id_list: return trace.set_span_in_context(trace.INVALID_SPAN) return trace.set_span_in_context( trace.NonRecordingSpan( trace.SpanContext( - trace_id=trace_id, span_id=span_id, is_remote=True, + trace_id=int(trace_id_list[0]), + span_id=int(span_id_list[0]), + is_remote=True, ) ) ) def inject( self, - carrier: typing.Dict[str, str], + set_in_carrier: Setter[TextMapPropagatorT], + carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, ) -> None: span = trace.get_current_span(context) - carrier[self.TRACE_ID_KEY] = str(span.get_span_context().trace_id) - carrier[self.SPAN_ID_KEY] = str(span.get_span_context().span_id) + set_in_carrier( + carrier, self.TRACE_ID_KEY, str(span.get_span_context().trace_id) + ) + set_in_carrier( + carrier, self.SPAN_ID_KEY, str(span.get_span_context().span_id) + ) @property def fields(self): From 973ac4b0c5fb57a0982c77e3da780f307f53b3b5 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Tue, 23 Mar 2021 17:50:45 -0600 Subject: [PATCH 04/28] Try to implement with default getters and setters Just for the record, I object this approach. I'll explain why in the corresponding PR. --- docs/examples/auto-instrumentation/README.rst | 3 +- docs/examples/auto-instrumentation/client.py | 2 +- .../baggage/propagation/__init__.py | 6 +-- .../src/opentelemetry/propagate/__init__.py | 10 ++-- .../opentelemetry/propagators/composite.py | 8 +-- .../src/opentelemetry/propagators/textmap.py | 50 ++++++++++++++++--- .../trace/propagation/tracecontext.py | 8 +-- .../tests/baggage/test_baggage_propagation.py | 10 ++-- .../tests/propagators/test_composite.py | 26 +++++----- .../propagators/test_global_httptextformat.py | 4 +- .../test_tracecontexthttptextformat.py | 26 +++++----- .../opentelemetry/propagators/b3/__init__.py | 14 +++--- .../propagation/test_benchmark_b3_format.py | 4 +- .../tests/test_b3_format.py | 27 +++++----- .../propagators/jaeger/__init__.py | 10 ++-- .../tests/test_jaeger_propagator.py | 20 ++++---- .../shim/opentracing_shim/__init__.py | 4 +- .../src/opentelemetry/test/mock_textmap.py | 14 +++--- 18 files changed, 144 insertions(+), 102 deletions(-) diff --git a/docs/examples/auto-instrumentation/README.rst b/docs/examples/auto-instrumentation/README.rst index 607aa1b44b7..48c59951b4b 100644 --- a/docs/examples/auto-instrumentation/README.rst +++ b/docs/examples/auto-instrumentation/README.rst @@ -37,8 +37,7 @@ Manually instrumented server def server_request(): with tracer.start_as_current_span( "server_request", - context=propagators.extract(DictGetter(), request.headers - ), + context=propagators.extract(request.headers), ): print(request.args.get("param")) return "served" diff --git a/docs/examples/auto-instrumentation/client.py b/docs/examples/auto-instrumentation/client.py index fefc1f67b98..cc948cc54b8 100644 --- a/docs/examples/auto-instrumentation/client.py +++ b/docs/examples/auto-instrumentation/client.py @@ -37,7 +37,7 @@ with tracer.start_as_current_span("client-server"): headers = {} - propagators.inject(dict.__setitem__, headers) + propagators.inject(headers) requested = get( "http://localhost:8082/server_request", params={"param": argv[1]}, diff --git a/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py b/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py index e6d1c4207bc..d3090a1809c 100644 --- a/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py +++ b/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py @@ -31,9 +31,9 @@ class W3CBaggagePropagator(textmap.TextMapPropagator): def extract( self, - getter: textmap.Getter[textmap.TextMapPropagatorT], carrier: textmap.TextMapPropagatorT, context: typing.Optional[Context] = None, + getter: textmap.Getter = textmap.default_getter, ) -> Context: """Extract Baggage from the carrier. @@ -73,9 +73,9 @@ def extract( def inject( self, - set_in_carrier: textmap.Setter[textmap.TextMapPropagatorT], carrier: textmap.TextMapPropagatorT, context: typing.Optional[Context] = None, + set_in_carrier: textmap.Setter = textmap.default_setter, ) -> None: """Injects Baggage into the carrier. @@ -87,7 +87,7 @@ def inject( return baggage_string = _format_baggage(baggage_entries) - set_in_carrier(carrier, self._BAGGAGE_HEADER_NAME, baggage_string) + set_in_carrier.set(carrier, self._BAGGAGE_HEADER_NAME, baggage_string) @property def fields(self) -> typing.Set[str]: diff --git a/opentelemetry-api/src/opentelemetry/propagate/__init__.py b/opentelemetry-api/src/opentelemetry/propagate/__init__.py index 44f9897a532..7fc6a5276fb 100644 --- a/opentelemetry-api/src/opentelemetry/propagate/__init__.py +++ b/opentelemetry-api/src/opentelemetry/propagate/__init__.py @@ -82,9 +82,9 @@ def example_route(): def extract( - getter: textmap.Getter[textmap.TextMapPropagatorT], carrier: textmap.TextMapPropagatorT, context: typing.Optional[Context] = None, + getter: textmap.Getter = textmap.default_getter, ) -> Context: """Uses the configured propagator to extract a Context from the carrier. @@ -99,13 +99,13 @@ def extract( context: an optional Context to use. Defaults to current context if not set. """ - return get_global_textmap().extract(getter, carrier, context) + return get_global_textmap().extract(carrier, context, getter=getter) def inject( - set_in_carrier: textmap.Setter[textmap.TextMapPropagatorT], carrier: textmap.TextMapPropagatorT, context: typing.Optional[Context] = None, + set_in_carrier: textmap.Setter = textmap.default_setter, ) -> None: """Uses the configured propagator to inject a Context into the carrier. @@ -118,7 +118,9 @@ def inject( context: an optional Context to use. Defaults to current context if not set. """ - get_global_textmap().inject(set_in_carrier, carrier, context) + get_global_textmap().inject( + carrier, context=context, set_in_carrier=set_in_carrier + ) try: diff --git a/opentelemetry-api/src/opentelemetry/propagators/composite.py b/opentelemetry-api/src/opentelemetry/propagators/composite.py index 92dc6b8a380..8fcfd84aa19 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/composite.py +++ b/opentelemetry-api/src/opentelemetry/propagators/composite.py @@ -35,9 +35,9 @@ def __init__( def extract( self, - getter: textmap.Getter[textmap.TextMapPropagatorT], carrier: textmap.TextMapPropagatorT, context: typing.Optional[Context] = None, + getter: textmap.Getter = textmap.default_getter, ) -> Context: """Run each of the configured propagators with the given context and carrier. Propagators are run in the order they are configured, if multiple @@ -47,14 +47,14 @@ def extract( See `opentelemetry.propagators.textmap.TextMapPropagator.extract` """ for propagator in self._propagators: - context = propagator.extract(getter, carrier, context) + context = propagator.extract(carrier, context, getter=getter) return context # type: ignore def inject( self, - set_in_carrier: textmap.Setter[textmap.TextMapPropagatorT], carrier: textmap.TextMapPropagatorT, context: typing.Optional[Context] = None, + set_in_carrier: textmap.Setter = textmap.default_setter, ) -> None: """Run each of the configured propagators with the given context and carrier. Propagators are run in the order they are configured, if multiple @@ -64,7 +64,7 @@ def inject( See `opentelemetry.propagators.textmap.TextMapPropagator.inject` """ for propagator in self._propagators: - propagator.inject(set_in_carrier, carrier, context) + propagator.inject(carrier, context, set_in_carrier=set_in_carrier) @property def fields(self) -> typing.Set[str]: diff --git a/opentelemetry-api/src/opentelemetry/propagators/textmap.py b/opentelemetry-api/src/opentelemetry/propagators/textmap.py index cf93d1d6319..151da781b01 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/textmap.py +++ b/opentelemetry-api/src/opentelemetry/propagators/textmap.py @@ -20,14 +20,13 @@ TextMapPropagatorT = typing.TypeVar("TextMapPropagatorT") CarrierValT = typing.Union[typing.List[str], str] -Setter = typing.Callable[[TextMapPropagatorT, str, str], None] - -class Getter(typing.Generic[TextMapPropagatorT]): +class Getter(abc.ABC): """This class implements a Getter that enables extracting propagated fields from a carrier. """ + @abc.abstractmethod def get( self, carrier: TextMapPropagatorT, key: str ) -> typing.Optional[typing.List[str]]: @@ -42,8 +41,8 @@ def get( Returns: first value of the propagation key or None if the key doesn't exist. """ - raise NotImplementedError() + @abc.abstractmethod def keys(self, carrier: TextMapPropagatorT) -> typing.List[str]: """Function that can retrieve all the keys in a carrier object. @@ -53,10 +52,26 @@ def keys(self, carrier: TextMapPropagatorT) -> typing.List[str]: Returns: list of keys from the carrier. """ - raise NotImplementedError() -class DictGetter(Getter[typing.Dict[str, CarrierValT]]): +class Setter(abc.ABC): + """This class implements a Setter that enables injecting propagated + fields into a carrier. + """ + + @abc.abstractmethod + def set(self, carrier: TextMapPropagatorT, key: str, value: str) -> None: + """Function that can set a value into a carrier"" + + Args: + carrier: An object which contains values that are used to + construct a Context. + key: key of a field in carrier. + value: value for a field in carrier. + """ + + +class DictGetter(Getter): def get( self, carrier: typing.Dict[str, CarrierValT], key: str ) -> typing.Optional[typing.List[str]]: @@ -80,6 +95,25 @@ def keys(self, carrier: typing.Dict[str, CarrierValT]) -> typing.List[str]: return list(carrier.keys()) +default_getter = DictGetter() + + +class DictSetter(Setter): + def set( + self, carrier: typing.Dict[str, CarrierValT], key: str, value: str + ) -> None: + """Setter implementation to set a value into a dictionary. + + Args: + carrier: dictionary in which header + key: the key used to set the value + """ + carrier[key] = value + + +default_setter = DictSetter() + + class TextMapPropagator(abc.ABC): """This class provides an interface that enables extracting and injecting context into headers of HTTP requests. HTTP frameworks and clients @@ -92,9 +126,9 @@ class TextMapPropagator(abc.ABC): @abc.abstractmethod def extract( self, - getter: Getter[TextMapPropagatorT], carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, + getter: Getter = default_getter, ) -> Context: """Create a Context from values in the carrier. @@ -120,9 +154,9 @@ def extract( @abc.abstractmethod def inject( self, - set_in_carrier: Setter[TextMapPropagatorT], carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, + set_in_carrier: Setter = default_setter, ) -> None: """Inject values from a Context into a carrier. diff --git a/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py b/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py index 480e716bf78..90b80133785 100644 --- a/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py +++ b/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py @@ -35,9 +35,9 @@ class TraceContextTextMapPropagator(textmap.TextMapPropagator): def extract( self, - getter: textmap.Getter[textmap.TextMapPropagatorT], carrier: textmap.TextMapPropagatorT, context: typing.Optional[Context] = None, + getter: textmap.Getter = textmap.default_getter, ) -> Context: """Extracts SpanContext from the carrier. @@ -85,9 +85,9 @@ def extract( def inject( self, - set_in_carrier: textmap.Setter[textmap.TextMapPropagatorT], carrier: textmap.TextMapPropagatorT, context: typing.Optional[Context] = None, + set_in_carrier: textmap.Setter = textmap.default_setter, ) -> None: """Injects SpanContext into the carrier. @@ -102,12 +102,12 @@ def inject( trace_id=format_trace_id(span_context.trace_id), span_id=format_span_id(span_context.span_id), ) - set_in_carrier( + set_in_carrier.set( carrier, self._TRACEPARENT_HEADER_NAME, traceparent_string ) if span_context.trace_state: tracestate_string = span_context.trace_state.to_header() - set_in_carrier( + set_in_carrier.set( carrier, self._TRACESTATE_HEADER_NAME, tracestate_string ) diff --git a/opentelemetry-api/tests/baggage/test_baggage_propagation.py b/opentelemetry-api/tests/baggage/test_baggage_propagation.py index 3047ddbbe46..79c52b8a354 100644 --- a/opentelemetry-api/tests/baggage/test_baggage_propagation.py +++ b/opentelemetry-api/tests/baggage/test_baggage_propagation.py @@ -32,7 +32,9 @@ def setUp(self): def _extract(self, header_value): """Test helper""" header = {"baggage": [header_value]} - return baggage.get_all(self.propagator.extract(carrier_getter, header)) + return baggage.get_all( + self.propagator.extract(header, getter=carrier_getter) + ) def _inject(self, values): """Test helper""" @@ -40,12 +42,12 @@ def _inject(self, values): for k, v in values.items(): ctx = baggage.set_baggage(k, v, context=ctx) output = {} - self.propagator.inject(dict.__setitem__, output, context=ctx) + self.propagator.inject(output, context=ctx) return output.get("baggage") def test_no_context_header(self): baggage_entries = baggage.get_all( - self.propagator.extract(carrier_getter, {}) + self.propagator.extract({}, getter=carrier_getter) ) self.assertEqual(baggage_entries, {}) @@ -151,7 +153,7 @@ def test_fields(self, mock_format_baggage, mock_baggage): mock_set_in_carrier = Mock() - self.propagator.inject(mock_set_in_carrier, {}) + self.propagator.inject({}, set_in_carrier=mock_set_in_carrier) inject_fields = set() diff --git a/opentelemetry-api/tests/propagators/test_composite.py b/opentelemetry-api/tests/propagators/test_composite.py index e33649bbdd8..4713b76ebeb 100644 --- a/opentelemetry-api/tests/propagators/test_composite.py +++ b/opentelemetry-api/tests/propagators/test_composite.py @@ -26,16 +26,16 @@ def get_as_list(dict_object, key): def mock_inject(name, value="data"): - def wrapped(setter, carrier=None, context=None): + def wrapped(carrier=None, context=None, set_in_carrier=None): carrier[name] = value - setter({}, "inject_field_{}_0".format(name), None) - setter({}, "inject_field_{}_1".format(name), None) + set_in_carrier.set({}, "inject_field_{}_0".format(name), None) + set_in_carrier.set({}, "inject_field_{}_1".format(name), None) return wrapped def mock_extract(name, value="context"): - def wrapped(getter, carrier=None, context=None): + def wrapped(carrier=None, context=None, getter=None): new_context = context.copy() new_context[name] = value return new_context @@ -69,11 +69,11 @@ def setUpClass(cls): def test_no_propagators(self): propagator = CompositeHTTPPropagator([]) new_carrier = {} - propagator.inject(dict.__setitem__, carrier=new_carrier) + propagator.inject(new_carrier) self.assertEqual(new_carrier, {}) context = propagator.extract( - get_as_list, carrier=new_carrier, context={} + carrier=new_carrier, context={}, getter=get_as_list ) self.assertEqual(context, {}) @@ -81,11 +81,11 @@ def test_single_propagator(self): propagator = CompositeHTTPPropagator([self.mock_propagator_0]) new_carrier = {} - propagator.inject(dict.__setitem__, carrier=new_carrier) + propagator.inject(new_carrier) self.assertEqual(new_carrier, {"mock-0": "data"}) context = propagator.extract( - get_as_list, carrier=new_carrier, context={} + carrier=new_carrier, context={}, getter=get_as_list ) self.assertEqual(context, {"mock-0": "context"}) @@ -95,11 +95,11 @@ def test_multiple_propagators(self): ) new_carrier = {} - propagator.inject(dict.__setitem__, carrier=new_carrier) + propagator.inject(new_carrier) self.assertEqual(new_carrier, {"mock-0": "data", "mock-1": "data"}) context = propagator.extract( - get_as_list, carrier=new_carrier, context={} + carrier=new_carrier, context={}, getter=get_as_list ) self.assertEqual(context, {"mock-0": "context", "mock-1": "context"}) @@ -111,11 +111,11 @@ def test_multiple_propagators_same_key(self): ) new_carrier = {} - propagator.inject(dict.__setitem__, carrier=new_carrier) + propagator.inject(new_carrier) self.assertEqual(new_carrier, {"mock-0": "data2"}) context = propagator.extract( - get_as_list, carrier=new_carrier, context={} + carrier=new_carrier, context={}, getter=get_as_list ) self.assertEqual(context, {"mock-0": "context2"}) @@ -130,7 +130,7 @@ def test_fields(self): mock_set_in_carrier = Mock() - propagator.inject(mock_set_in_carrier, {}) + propagator.inject({}, set_in_carrier=mock_set_in_carrier) inject_fields = set() diff --git a/opentelemetry-api/tests/propagators/test_global_httptextformat.py b/opentelemetry-api/tests/propagators/test_global_httptextformat.py index 6ba32e46183..0d36482fe11 100644 --- a/opentelemetry-api/tests/propagators/test_global_httptextformat.py +++ b/opentelemetry-api/tests/propagators/test_global_httptextformat.py @@ -42,7 +42,7 @@ def test_propagation(self): "traceparent": [traceparent_value], "tracestate": [tracestate_value], } - ctx = extract(carrier_getter, headers) + ctx = extract(headers, getter=carrier_getter) baggage_entries = baggage.get_all(context=ctx) expected = {"key1": "val1", "key2": "val2"} self.assertEqual(baggage_entries, expected) @@ -56,7 +56,7 @@ def test_propagation(self): ctx = baggage.set_baggage("key4", "val4", context=ctx) ctx = set_span_in_context(span, context=ctx) output = {} - inject(dict.__setitem__, output, context=ctx) + inject(output, context=ctx) self.assertEqual(traceparent_value, output["traceparent"]) self.assertIn("key3=val3", output["baggage"]) self.assertIn("key4=val4", output["baggage"]) diff --git a/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py b/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py index 79683d43d94..4f2c3dae408 100644 --- a/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py +++ b/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py @@ -42,7 +42,9 @@ def test_no_traceparent_header(self): trace-id and parent-id that represents the current request. """ output = {} # type:typing.Dict[str, typing.List[str]] - span = trace.get_current_span(FORMAT.extract(carrier_getter, output)) + span = trace.get_current_span( + FORMAT.extract(output, getter=carrier_getter) + ) self.assertIsInstance(span.get_span_context(), trace.SpanContext) def test_headers_with_tracestate(self): @@ -56,11 +58,11 @@ def test_headers_with_tracestate(self): tracestate_value = "foo=1,bar=2,baz=3" span_context = trace.get_current_span( FORMAT.extract( - carrier_getter, { "traceparent": [traceparent_value], "tracestate": [tracestate_value], }, + getter=carrier_getter, ) ).get_span_context() self.assertEqual(span_context.trace_id, self.TRACE_ID) @@ -73,7 +75,7 @@ def test_headers_with_tracestate(self): span = trace.NonRecordingSpan(span_context) ctx = trace.set_span_in_context(span) - FORMAT.inject(dict.__setitem__, output, ctx) + FORMAT.inject(output, context=ctx) self.assertEqual(output["traceparent"], traceparent_value) for pair in ["foo=1", "bar=2", "baz=3"]: self.assertIn(pair, output["tracestate"]) @@ -100,13 +102,13 @@ def test_invalid_trace_id(self): """ span = trace.get_current_span( FORMAT.extract( - carrier_getter, { "traceparent": [ "00-00000000000000000000000000000000-1234567890123456-00" ], "tracestate": ["foo=1,bar=2,foo=3"], }, + getter=carrier_getter, ) ) self.assertEqual(span.get_span_context(), trace.INVALID_SPAN_CONTEXT) @@ -131,13 +133,13 @@ def test_invalid_parent_id(self): """ span = trace.get_current_span( FORMAT.extract( - carrier_getter, { "traceparent": [ "00-00000000000000000000000000000000-0000000000000000-00" ], "tracestate": ["foo=1,bar=2,foo=3"], }, + getter=carrier_getter, ) ) self.assertEqual(span.get_span_context(), trace.INVALID_SPAN_CONTEXT) @@ -155,7 +157,7 @@ def test_no_send_empty_tracestate(self): trace.SpanContext(self.TRACE_ID, self.SPAN_ID, is_remote=False) ) ctx = trace.set_span_in_context(span) - FORMAT.inject(dict.__setitem__, output, ctx) + FORMAT.inject(output, context=ctx) self.assertTrue("traceparent" in output) self.assertFalse("tracestate" in output) @@ -169,7 +171,6 @@ def test_format_not_supported(self): """ span = trace.get_current_span( FORMAT.extract( - carrier_getter, { "traceparent": [ "00-12345678901234567890123456789012-" @@ -177,6 +178,7 @@ def test_format_not_supported(self): ], "tracestate": ["foo=1,bar=2,foo=3"], }, + getter=carrier_getter, ) ) self.assertEqual(span.get_span_context(), trace.INVALID_SPAN_CONTEXT) @@ -185,20 +187,20 @@ def test_propagate_invalid_context(self): """Do not propagate invalid trace context.""" output = {} # type:typing.Dict[str, str] ctx = trace.set_span_in_context(trace.INVALID_SPAN) - FORMAT.inject(dict.__setitem__, output, context=ctx) + FORMAT.inject(output, context=ctx) self.assertFalse("traceparent" in output) def test_tracestate_empty_header(self): """Test tracestate with an additional empty header (should be ignored)""" span = trace.get_current_span( FORMAT.extract( - carrier_getter, { "traceparent": [ "00-12345678901234567890123456789012-1234567890123456-00" ], "tracestate": ["foo=1", ""], }, + getter=carrier_getter, ) ) self.assertEqual(span.get_span_context().trace_state["foo"], "1") @@ -207,13 +209,13 @@ def test_tracestate_header_with_trailing_comma(self): """Do not propagate invalid trace context.""" span = trace.get_current_span( FORMAT.extract( - carrier_getter, { "traceparent": [ "00-12345678901234567890123456789012-1234567890123456-00" ], "tracestate": ["foo=1,"], }, + getter=carrier_getter, ) ) self.assertEqual(span.get_span_context().trace_state["foo"], "1") @@ -230,7 +232,6 @@ def test_tracestate_keys(self): ) span = trace.get_current_span( FORMAT.extract( - carrier_getter, { "traceparent": [ "00-12345678901234567890123456789012-" @@ -238,6 +239,7 @@ def test_tracestate_keys(self): ], "tracestate": [tracestate_value], }, + getter=carrier_getter, ) ) self.assertEqual( @@ -272,7 +274,7 @@ def test_fields(self, mock_get_current_span, mock_invalid_span_context): mock_set_in_carrier = Mock() - FORMAT.inject(mock_set_in_carrier, {}) + FORMAT.inject({}, set_in_carrier=mock_set_in_carrier) inject_fields = set() diff --git a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py index 01abcc7c879..9f2e39cee09 100644 --- a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py +++ b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py @@ -22,6 +22,8 @@ Setter, TextMapPropagator, TextMapPropagatorT, + default_getter, + default_setter, ) from opentelemetry.trace import format_span_id, format_trace_id @@ -44,9 +46,9 @@ class B3Format(TextMapPropagator): def extract( self, - getter: Getter[TextMapPropagatorT], carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, + getter: Getter = default_getter, ) -> Context: trace_id = format_trace_id(trace.INVALID_TRACE_ID) span_id = format_span_id(trace.INVALID_SPAN_ID) @@ -127,9 +129,9 @@ def extract( def inject( self, - set_in_carrier: Setter[TextMapPropagatorT], carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, + set_in_carrier: Setter = default_setter, ) -> None: span = trace.get_current_span(context=context) @@ -138,20 +140,20 @@ def inject( return sampled = (trace.TraceFlags.SAMPLED & span_context.trace_flags) != 0 - set_in_carrier( + set_in_carrier.set( carrier, self.TRACE_ID_KEY, format_trace_id(span_context.trace_id), ) - set_in_carrier( + set_in_carrier.set( carrier, self.SPAN_ID_KEY, format_span_id(span_context.span_id) ) span_parent = getattr(span, "parent", None) if span_parent is not None: - set_in_carrier( + set_in_carrier.set( carrier, self.PARENT_SPAN_ID_KEY, format_span_id(span_parent.span_id), ) - set_in_carrier(carrier, self.SAMPLED_KEY, "1" if sampled else "0") + set_in_carrier.set(carrier, self.SAMPLED_KEY, "1" if sampled else "0") @property def fields(self) -> typing.Set[str]: diff --git a/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py b/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py index 5048f495f06..1a40b7d697e 100644 --- a/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py +++ b/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py @@ -14,7 +14,7 @@ import opentelemetry.propagators.b3 as b3_format import opentelemetry.sdk.trace as trace -from opentelemetry.propagators.textmap import DictGetter +from opentelemetry.propagators.textmap import default_getter FORMAT = b3_format.B3Format() @@ -22,10 +22,10 @@ def test_extract_single_header(benchmark): benchmark( FORMAT.extract, - DictGetter(), { FORMAT.SINGLE_HEADER_KEY: "bdb5b63237ed38aea578af665aa5aa60-c32d953d73ad2251-1-11fd79a30b0896cd285b396ae102dd76" }, + getter=default_getter, ) diff --git a/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py b/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py index f9d3bce1adb..d696f4ea33d 100644 --- a/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py +++ b/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py @@ -20,7 +20,7 @@ import opentelemetry.sdk.trace.id_generator as id_generator import opentelemetry.trace as trace_api from opentelemetry.context import get_current -from opentelemetry.propagators.textmap import DictGetter +from opentelemetry.propagators.textmap import DictGetter, default_setter FORMAT = b3_format.B3Format() @@ -30,7 +30,7 @@ def get_child_parent_new_carrier(old_carrier): - ctx = FORMAT.extract(carrier_getter, old_carrier) + ctx = FORMAT.extract(old_carrier, getter=carrier_getter) parent_span_context = trace_api.get_current_span(ctx).get_span_context() parent = trace._Span("parent", parent_span_context) @@ -48,7 +48,7 @@ def get_child_parent_new_carrier(old_carrier): new_carrier = {} ctx = trace_api.set_span_in_context(child) - FORMAT.inject(dict.__setitem__, new_carrier, context=ctx) + FORMAT.inject(new_carrier, context=ctx) return child, parent, new_carrier @@ -239,7 +239,7 @@ def test_invalid_single_header(self): invalid SpanContext. """ carrier = {FORMAT.SINGLE_HEADER_KEY: "0-1-2-3-4-5-6-7"} - ctx = FORMAT.extract(carrier_getter, carrier) + ctx = FORMAT.extract(carrier, getter=carrier_getter) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) @@ -251,7 +251,7 @@ def test_missing_trace_id(self): FORMAT.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier_getter, carrier) + ctx = FORMAT.extract(carrier, getter=carrier_getter) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) @@ -275,7 +275,7 @@ def test_invalid_trace_id( FORMAT.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier_getter, carrier) + ctx = FORMAT.extract(carrier, getter=carrier_getter) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, 1) @@ -301,7 +301,7 @@ def test_invalid_span_id( FORMAT.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier_getter, carrier) + ctx = FORMAT.extract(carrier, getter=carrier_getter) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, 1) @@ -314,7 +314,7 @@ def test_missing_span_id(self): FORMAT.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier_getter, carrier) + ctx = FORMAT.extract(carrier, getter=carrier_getter) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) @@ -322,7 +322,7 @@ def test_missing_span_id(self): def test_inject_empty_context(): """If the current context has no span, don't add headers""" new_carrier = {} - FORMAT.inject(dict.__setitem__, new_carrier, get_current()) + FORMAT.inject(new_carrier, get_current()) assert len(new_carrier) == 0 @staticmethod @@ -333,11 +333,8 @@ class CarrierGetter(DictGetter): def get(self, carrier, key): return carrier.get(key, None) - def setter(carrier, key, value): - carrier[key] = value - - ctx = FORMAT.extract(CarrierGetter(), {}) - FORMAT.inject(setter, {}, ctx) + ctx = FORMAT.extract({}, getter=CarrierGetter()) + FORMAT.inject({}, context=ctx, set_in_carrier=default_setter) def test_fields(self): """Make sure the fields attribute returns the fields used in inject""" @@ -348,7 +345,7 @@ def test_fields(self): with tracer.start_as_current_span("parent"): with tracer.start_as_current_span("child"): - FORMAT.inject(mock_set_in_carrier, {}) + FORMAT.inject({}, set_in_carrier=mock_set_in_carrier) inject_fields = set() diff --git a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py index 8e7fe5f69ff..13af155fd10 100644 --- a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py +++ b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py @@ -23,6 +23,8 @@ Setter, TextMapPropagator, TextMapPropagatorT, + default_getter, + default_setter, ) from opentelemetry.trace import format_span_id, format_trace_id @@ -39,9 +41,9 @@ class JaegerPropagator(TextMapPropagator): def extract( self, - getter: Getter[TextMapPropagatorT], carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, + getter: Getter = default_getter, ) -> Context: if context is None: @@ -76,9 +78,9 @@ def extract( def inject( self, - set_in_carrier: Setter[TextMapPropagatorT], carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, + set_in_carrier: Setter = default_setter, ) -> None: span = trace.get_current_span(context=context) span_context = span.get_span_context() @@ -91,7 +93,7 @@ def inject( trace_flags |= self.DEBUG_FLAG # set span identity - set_in_carrier( + set_in_carrier.set( carrier, self.TRACE_ID_KEY, _format_uber_trace_id( @@ -108,7 +110,7 @@ def inject( return for key, value in baggage_entries.items(): baggage_key = self.BAGGAGE_PREFIX + key - set_in_carrier( + set_in_carrier.set( carrier, baggage_key, urllib.parse.quote(str(value)) ) diff --git a/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py b/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py index da8a855edbe..3360b9ae47b 100644 --- a/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py +++ b/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py @@ -32,7 +32,7 @@ def get_context_new_carrier(old_carrier, carrier_baggage=None): - ctx = FORMAT.extract(carrier_getter, old_carrier) + ctx = FORMAT.extract(old_carrier, getter=carrier_getter) if carrier_baggage: for key, value in carrier_baggage.items(): ctx = baggage.set_baggage(key, value, ctx) @@ -54,7 +54,7 @@ def get_context_new_carrier(old_carrier, carrier_baggage=None): new_carrier = {} ctx = trace_api.set_span_in_context(child, ctx) - FORMAT.inject(dict.__setitem__, new_carrier, context=ctx) + FORMAT.inject(new_carrier, context=ctx) return ctx, new_carrier @@ -72,14 +72,14 @@ def setUpClass(cls): def test_extract_valid_span(self): old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} - ctx = FORMAT.extract(carrier_getter, old_carrier) + ctx = FORMAT.extract(old_carrier, getter=carrier_getter) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, self.trace_id) self.assertEqual(span_context.span_id, self.span_id) def test_missing_carrier(self): old_carrier = {} - ctx = FORMAT.extract(carrier_getter, old_carrier) + ctx = FORMAT.extract(old_carrier, getter=carrier_getter) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) @@ -132,7 +132,7 @@ def test_baggage(self): old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} input_baggage = {"key1": "value1"} _, new_carrier = get_context_new_carrier(old_carrier, input_baggage) - ctx = FORMAT.extract(carrier_getter, new_carrier) + ctx = FORMAT.extract(new_carrier, getter=carrier_getter) self.assertDictEqual(input_baggage, ctx["baggage"]) def test_non_string_baggage(self): @@ -140,7 +140,7 @@ def test_non_string_baggage(self): input_baggage = {"key1": 1, "key2": True} formatted_baggage = {"key1": "1", "key2": "True"} _, new_carrier = get_context_new_carrier(old_carrier, input_baggage) - ctx = FORMAT.extract(carrier_getter, new_carrier) + ctx = FORMAT.extract(new_carrier, getter=carrier_getter) self.assertDictEqual(formatted_baggage, ctx["baggage"]) def test_extract_invalid_uber_trace_id(self): @@ -149,7 +149,7 @@ def test_extract_invalid_uber_trace_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = FORMAT.extract(carrier_getter, old_carrier) + context = FORMAT.extract(old_carrier, getter=carrier_getter) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) @@ -160,7 +160,7 @@ def test_extract_invalid_trace_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = FORMAT.extract(carrier_getter, old_carrier) + context = FORMAT.extract(old_carrier, getter=carrier_getter) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) @@ -171,7 +171,7 @@ def test_extract_invalid_span_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = FORMAT.extract(carrier_getter, old_carrier) + context = FORMAT.extract(old_carrier, getter=carrier_getter) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) @@ -181,7 +181,7 @@ def test_fields(self): mock_set_in_carrier = Mock() with tracer.start_as_current_span("parent"): with tracer.start_as_current_span("child"): - FORMAT.inject(mock_set_in_carrier, {}) + FORMAT.inject({}, set_in_carrier=mock_set_in_carrier) inject_fields = set() for call in mock_set_in_carrier.mock_calls: inject_fields.add(call[1][1]) diff --git a/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py b/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py index b7a365302f9..cc3a1d14be9 100644 --- a/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py +++ b/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py @@ -684,7 +684,7 @@ def inject(self, span_context, format: object, carrier: object): propagator = get_global_textmap() ctx = set_span_in_context(NonRecordingSpan(span_context.unwrap())) - propagator.inject(type(carrier).__setitem__, carrier, context=ctx) + propagator.inject(carrier, context=ctx) def extract(self, format: object, carrier: object): """Returns an ``opentracing.SpanContext`` instance extracted from a @@ -712,7 +712,7 @@ def extract(self, format: object, carrier: object): raise UnsupportedFormatException propagator = get_global_textmap() - ctx = propagator.extract(self._carrier_getter, carrier) + ctx = propagator.extract(carrier, getter=self._carrier_getter) span = get_current_span(ctx) if span is not None: otel_context = span.get_span_context() diff --git a/tests/util/src/opentelemetry/test/mock_textmap.py b/tests/util/src/opentelemetry/test/mock_textmap.py index 1edd079042f..953b8adcf97 100644 --- a/tests/util/src/opentelemetry/test/mock_textmap.py +++ b/tests/util/src/opentelemetry/test/mock_textmap.py @@ -21,6 +21,8 @@ Setter, TextMapPropagator, TextMapPropagatorT, + default_getter, + default_setter, ) @@ -33,17 +35,17 @@ class NOOPTextMapPropagator(TextMapPropagator): def extract( self, - getter: Getter[TextMapPropagatorT], carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, + getter: Getter = default_getter, ) -> Context: return get_current() def inject( self, - set_in_carrier: Setter[TextMapPropagatorT], carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, + set_in_carrier: Setter = default_setter, ) -> None: return None @@ -60,9 +62,9 @@ class MockTextMapPropagator(TextMapPropagator): def extract( self, - getter: Getter[TextMapPropagatorT], carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, + getter: Getter = default_getter, ) -> Context: trace_id_list = getter.get(carrier, self.TRACE_ID_KEY) span_id_list = getter.get(carrier, self.SPAN_ID_KEY) @@ -82,15 +84,15 @@ def extract( def inject( self, - set_in_carrier: Setter[TextMapPropagatorT], carrier: TextMapPropagatorT, context: typing.Optional[Context] = None, + set_in_carrier: Setter = default_setter, ) -> None: span = trace.get_current_span(context) - set_in_carrier( + set_in_carrier.set( carrier, self.TRACE_ID_KEY, str(span.get_span_context().trace_id) ) - set_in_carrier( + set_in_carrier.set( carrier, self.SPAN_ID_KEY, str(span.get_span_context().span_id) ) From b4ec107977534b75bd1679a470ec1cf50abac240 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 13:45:17 -0600 Subject: [PATCH 05/28] Fix mypy --- .../src/opentelemetry/propagators/textmap.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/propagators/textmap.py b/opentelemetry-api/src/opentelemetry/propagators/textmap.py index 151da781b01..fc700473435 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/textmap.py +++ b/opentelemetry-api/src/opentelemetry/propagators/textmap.py @@ -72,7 +72,7 @@ def set(self, carrier: TextMapPropagatorT, key: str, value: str) -> None: class DictGetter(Getter): - def get( + def get( # type: ignore self, carrier: typing.Dict[str, CarrierValT], key: str ) -> typing.Optional[typing.List[str]]: """Getter implementation to retrieve a value from a dictionary. @@ -90,7 +90,9 @@ def get( return list(val) return [val] - def keys(self, carrier: typing.Dict[str, CarrierValT]) -> typing.List[str]: + def keys( # type: ignore + self, carrier: typing.Dict[str, CarrierValT] + ) -> typing.List[str]: """Keys implementation that returns all keys from a dictionary.""" return list(carrier.keys()) @@ -99,7 +101,7 @@ def keys(self, carrier: typing.Dict[str, CarrierValT]) -> typing.List[str]: class DictSetter(Setter): - def set( + def set( # type: ignore self, carrier: typing.Dict[str, CarrierValT], key: str, value: str ) -> None: """Setter implementation to set a value into a dictionary. From e4d16989fc983fb95353b84918e899e7936d8163 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 13:46:06 -0600 Subject: [PATCH 06/28] Fix changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a8e24366d1..4e7cbc03257 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v0.18b0...HEAD) +- Make setters and getters optional + ([#1690](https://github.com/open-telemetry/opentelemetry-python/pull/1690)) ### Added - Document how to work with fork process web server models(Gunicorn, uWSGI etc...) From 1586653249074fd147b8ea3a4c106a8da1d2c8c6 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 13:47:31 -0600 Subject: [PATCH 07/28] Rename to CarrierT --- .../opentelemetry/baggage/propagation/__init__.py | 8 ++++---- .../src/opentelemetry/propagate/__init__.py | 4 ++-- .../src/opentelemetry/propagators/composite.py | 4 ++-- .../src/opentelemetry/propagators/textmap.py | 12 ++++++------ .../opentelemetry/trace/propagation/tracecontext.py | 4 ++-- .../src/opentelemetry/propagators/b3/__init__.py | 10 +++++----- .../src/opentelemetry/propagators/jaeger/__init__.py | 10 +++++----- tests/util/src/opentelemetry/test/mock_textmap.py | 10 +++++----- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py b/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py index d3090a1809c..e5ea9ded123 100644 --- a/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py +++ b/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py @@ -31,7 +31,7 @@ class W3CBaggagePropagator(textmap.TextMapPropagator): def extract( self, - carrier: textmap.TextMapPropagatorT, + carrier: textmap.CarrierT, context: typing.Optional[Context] = None, getter: textmap.Getter = textmap.default_getter, ) -> Context: @@ -73,7 +73,7 @@ def extract( def inject( self, - carrier: textmap.TextMapPropagatorT, + carrier: textmap.CarrierT, context: typing.Optional[Context] = None, set_in_carrier: textmap.Setter = textmap.default_setter, ) -> None: @@ -103,8 +103,8 @@ def _format_baggage(baggage_entries: typing.Mapping[str, object]) -> str: def _extract_first_element( - items: typing.Optional[typing.Iterable[textmap.TextMapPropagatorT]], -) -> typing.Optional[textmap.TextMapPropagatorT]: + items: typing.Optional[typing.Iterable[textmap.CarrierT]], +) -> typing.Optional[textmap.CarrierT]: if items is None: return None return next(iter(items), None) diff --git a/opentelemetry-api/src/opentelemetry/propagate/__init__.py b/opentelemetry-api/src/opentelemetry/propagate/__init__.py index 7fc6a5276fb..f13b04f9e81 100644 --- a/opentelemetry-api/src/opentelemetry/propagate/__init__.py +++ b/opentelemetry-api/src/opentelemetry/propagate/__init__.py @@ -82,7 +82,7 @@ def example_route(): def extract( - carrier: textmap.TextMapPropagatorT, + carrier: textmap.CarrierT, context: typing.Optional[Context] = None, getter: textmap.Getter = textmap.default_getter, ) -> Context: @@ -103,7 +103,7 @@ def extract( def inject( - carrier: textmap.TextMapPropagatorT, + carrier: textmap.CarrierT, context: typing.Optional[Context] = None, set_in_carrier: textmap.Setter = textmap.default_setter, ) -> None: diff --git a/opentelemetry-api/src/opentelemetry/propagators/composite.py b/opentelemetry-api/src/opentelemetry/propagators/composite.py index 8fcfd84aa19..73853f0c2cb 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/composite.py +++ b/opentelemetry-api/src/opentelemetry/propagators/composite.py @@ -35,7 +35,7 @@ def __init__( def extract( self, - carrier: textmap.TextMapPropagatorT, + carrier: textmap.CarrierT, context: typing.Optional[Context] = None, getter: textmap.Getter = textmap.default_getter, ) -> Context: @@ -52,7 +52,7 @@ def extract( def inject( self, - carrier: textmap.TextMapPropagatorT, + carrier: textmap.CarrierT, context: typing.Optional[Context] = None, set_in_carrier: textmap.Setter = textmap.default_setter, ) -> None: diff --git a/opentelemetry-api/src/opentelemetry/propagators/textmap.py b/opentelemetry-api/src/opentelemetry/propagators/textmap.py index fc700473435..19fe86e62c6 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/textmap.py +++ b/opentelemetry-api/src/opentelemetry/propagators/textmap.py @@ -17,7 +17,7 @@ from opentelemetry.context.context import Context -TextMapPropagatorT = typing.TypeVar("TextMapPropagatorT") +CarrierT = typing.TypeVar("CarrierT") CarrierValT = typing.Union[typing.List[str], str] @@ -28,7 +28,7 @@ class Getter(abc.ABC): @abc.abstractmethod def get( - self, carrier: TextMapPropagatorT, key: str + self, carrier: CarrierT, key: str ) -> typing.Optional[typing.List[str]]: """Function that can retrieve zero or more values from the carrier. In the case that @@ -43,7 +43,7 @@ def get( """ @abc.abstractmethod - def keys(self, carrier: TextMapPropagatorT) -> typing.List[str]: + def keys(self, carrier: CarrierT) -> typing.List[str]: """Function that can retrieve all the keys in a carrier object. Args: @@ -60,7 +60,7 @@ class Setter(abc.ABC): """ @abc.abstractmethod - def set(self, carrier: TextMapPropagatorT, key: str, value: str) -> None: + def set(self, carrier: CarrierT, key: str, value: str) -> None: """Function that can set a value into a carrier"" Args: @@ -128,7 +128,7 @@ class TextMapPropagator(abc.ABC): @abc.abstractmethod def extract( self, - carrier: TextMapPropagatorT, + carrier: CarrierT, context: typing.Optional[Context] = None, getter: Getter = default_getter, ) -> Context: @@ -156,7 +156,7 @@ def extract( @abc.abstractmethod def inject( self, - carrier: TextMapPropagatorT, + carrier: CarrierT, context: typing.Optional[Context] = None, set_in_carrier: Setter = default_setter, ) -> None: diff --git a/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py b/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py index 90b80133785..6b59d65babe 100644 --- a/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py +++ b/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py @@ -35,7 +35,7 @@ class TraceContextTextMapPropagator(textmap.TextMapPropagator): def extract( self, - carrier: textmap.TextMapPropagatorT, + carrier: textmap.CarrierT, context: typing.Optional[Context] = None, getter: textmap.Getter = textmap.default_getter, ) -> Context: @@ -85,7 +85,7 @@ def extract( def inject( self, - carrier: textmap.TextMapPropagatorT, + carrier: textmap.CarrierT, context: typing.Optional[Context] = None, set_in_carrier: textmap.Setter = textmap.default_setter, ) -> None: diff --git a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py index 9f2e39cee09..ece65dea078 100644 --- a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py +++ b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py @@ -21,7 +21,7 @@ Getter, Setter, TextMapPropagator, - TextMapPropagatorT, + CarrierT, default_getter, default_setter, ) @@ -46,7 +46,7 @@ class B3Format(TextMapPropagator): def extract( self, - carrier: TextMapPropagatorT, + carrier: CarrierT, context: typing.Optional[Context] = None, getter: Getter = default_getter, ) -> Context: @@ -129,7 +129,7 @@ def extract( def inject( self, - carrier: TextMapPropagatorT, + carrier: CarrierT, context: typing.Optional[Context] = None, set_in_carrier: Setter = default_setter, ) -> None: @@ -166,8 +166,8 @@ def fields(self) -> typing.Set[str]: def _extract_first_element( - items: typing.Iterable[TextMapPropagatorT], -) -> typing.Optional[TextMapPropagatorT]: + items: typing.Iterable[CarrierT], +) -> typing.Optional[CarrierT]: if items is None: return None return next(iter(items), None) diff --git a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py index 13af155fd10..d56cc76066a 100644 --- a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py +++ b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py @@ -22,7 +22,7 @@ Getter, Setter, TextMapPropagator, - TextMapPropagatorT, + CarrierT, default_getter, default_setter, ) @@ -41,7 +41,7 @@ class JaegerPropagator(TextMapPropagator): def extract( self, - carrier: TextMapPropagatorT, + carrier: CarrierT, context: typing.Optional[Context] = None, getter: Getter = default_getter, ) -> Context: @@ -78,7 +78,7 @@ def extract( def inject( self, - carrier: TextMapPropagatorT, + carrier: CarrierT, context: typing.Optional[Context] = None, set_in_carrier: Setter = default_setter, ) -> None: @@ -144,8 +144,8 @@ def _format_uber_trace_id(trace_id, span_id, parent_span_id, flags): def _extract_first_element( - items: typing.Iterable[TextMapPropagatorT], -) -> typing.Optional[TextMapPropagatorT]: + items: typing.Iterable[CarrierT], +) -> typing.Optional[CarrierT]: if items is None: return None return next(iter(items), None) diff --git a/tests/util/src/opentelemetry/test/mock_textmap.py b/tests/util/src/opentelemetry/test/mock_textmap.py index 953b8adcf97..7994697a2eb 100644 --- a/tests/util/src/opentelemetry/test/mock_textmap.py +++ b/tests/util/src/opentelemetry/test/mock_textmap.py @@ -20,7 +20,7 @@ Getter, Setter, TextMapPropagator, - TextMapPropagatorT, + CarrierT, default_getter, default_setter, ) @@ -35,7 +35,7 @@ class NOOPTextMapPropagator(TextMapPropagator): def extract( self, - carrier: TextMapPropagatorT, + carrier: CarrierT, context: typing.Optional[Context] = None, getter: Getter = default_getter, ) -> Context: @@ -43,7 +43,7 @@ def extract( def inject( self, - carrier: TextMapPropagatorT, + carrier: CarrierT, context: typing.Optional[Context] = None, set_in_carrier: Setter = default_setter, ) -> None: @@ -62,7 +62,7 @@ class MockTextMapPropagator(TextMapPropagator): def extract( self, - carrier: TextMapPropagatorT, + carrier: CarrierT, context: typing.Optional[Context] = None, getter: Getter = default_getter, ) -> Context: @@ -84,7 +84,7 @@ def extract( def inject( self, - carrier: TextMapPropagatorT, + carrier: CarrierT, context: typing.Optional[Context] = None, set_in_carrier: Setter = default_setter, ) -> None: From 017be2c211678745a0436bb340e639443de97f83 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 14:58:40 -0600 Subject: [PATCH 08/28] Rename set_in_carrier to setter --- .../opentelemetry/baggage/propagation/__init__.py | 4 ++-- .../src/opentelemetry/propagate/__init__.py | 8 ++++---- .../src/opentelemetry/propagators/composite.py | 4 ++-- .../src/opentelemetry/propagators/textmap.py | 8 ++++---- .../opentelemetry/trace/propagation/tracecontext.py | 6 +++--- .../tests/baggage/test_baggage_propagation.py | 6 +++--- .../tests/propagators/test_composite.py | 12 ++++++------ .../propagation/test_tracecontexthttptextformat.py | 6 +++--- .../src/opentelemetry/propagators/b3/__init__.py | 10 +++++----- .../tests/test_b3_format.py | 8 ++++---- .../src/opentelemetry/propagators/jaeger/__init__.py | 6 +++--- .../tests/test_jaeger_propagator.py | 6 +++--- tests/util/src/opentelemetry/test/mock_textmap.py | 8 ++++---- 13 files changed, 46 insertions(+), 46 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py b/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py index e5ea9ded123..04d896baa36 100644 --- a/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py +++ b/opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py @@ -75,7 +75,7 @@ def inject( self, carrier: textmap.CarrierT, context: typing.Optional[Context] = None, - set_in_carrier: textmap.Setter = textmap.default_setter, + setter: textmap.Setter = textmap.default_setter, ) -> None: """Injects Baggage into the carrier. @@ -87,7 +87,7 @@ def inject( return baggage_string = _format_baggage(baggage_entries) - set_in_carrier.set(carrier, self._BAGGAGE_HEADER_NAME, baggage_string) + setter.set(carrier, self._BAGGAGE_HEADER_NAME, baggage_string) @property def fields(self) -> typing.Set[str]: diff --git a/opentelemetry-api/src/opentelemetry/propagate/__init__.py b/opentelemetry-api/src/opentelemetry/propagate/__init__.py index f13b04f9e81..dd19b2edd71 100644 --- a/opentelemetry-api/src/opentelemetry/propagate/__init__.py +++ b/opentelemetry-api/src/opentelemetry/propagate/__init__.py @@ -105,21 +105,21 @@ def extract( def inject( carrier: textmap.CarrierT, context: typing.Optional[Context] = None, - set_in_carrier: textmap.Setter = textmap.default_setter, + setter: textmap.Setter = textmap.default_setter, ) -> None: """Uses the configured propagator to inject a Context into the carrier. Args: - set_in_carrier: A setter function that can set values + setter: A setter function that can set values on the carrier. carrier: An object that contains a representation of HTTP - headers. Should be paired with set_in_carrier, which + headers. Should be paired with setter, which should know how to set header values on the carrier. context: an optional Context to use. Defaults to current context if not set. """ get_global_textmap().inject( - carrier, context=context, set_in_carrier=set_in_carrier + carrier, context=context, setter=setter ) diff --git a/opentelemetry-api/src/opentelemetry/propagators/composite.py b/opentelemetry-api/src/opentelemetry/propagators/composite.py index 73853f0c2cb..c027f638dcd 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/composite.py +++ b/opentelemetry-api/src/opentelemetry/propagators/composite.py @@ -54,7 +54,7 @@ def inject( self, carrier: textmap.CarrierT, context: typing.Optional[Context] = None, - set_in_carrier: textmap.Setter = textmap.default_setter, + setter: textmap.Setter = textmap.default_setter, ) -> None: """Run each of the configured propagators with the given context and carrier. Propagators are run in the order they are configured, if multiple @@ -64,7 +64,7 @@ def inject( See `opentelemetry.propagators.textmap.TextMapPropagator.inject` """ for propagator in self._propagators: - propagator.inject(carrier, context, set_in_carrier=set_in_carrier) + propagator.inject(carrier, context, setter=setter) @property def fields(self) -> typing.Set[str]: diff --git a/opentelemetry-api/src/opentelemetry/propagators/textmap.py b/opentelemetry-api/src/opentelemetry/propagators/textmap.py index 19fe86e62c6..0c88655473c 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/textmap.py +++ b/opentelemetry-api/src/opentelemetry/propagators/textmap.py @@ -158,20 +158,20 @@ def inject( self, carrier: CarrierT, context: typing.Optional[Context] = None, - set_in_carrier: Setter = default_setter, + setter: Setter = default_setter, ) -> None: """Inject values from a Context into a 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 + should use the setter method to set values on the carrier. Args: - set_in_carrier: A setter function that can set values + setter: 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 + Should be paired with setter, which should know how to set header values on the carrier. context: an optional Context to use. Defaults to current context if not set. diff --git a/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py b/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py index 6b59d65babe..1e269e82538 100644 --- a/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py +++ b/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py @@ -87,7 +87,7 @@ def inject( self, carrier: textmap.CarrierT, context: typing.Optional[Context] = None, - set_in_carrier: textmap.Setter = textmap.default_setter, + setter: textmap.Setter = textmap.default_setter, ) -> None: """Injects SpanContext into the carrier. @@ -102,12 +102,12 @@ def inject( trace_id=format_trace_id(span_context.trace_id), span_id=format_span_id(span_context.span_id), ) - set_in_carrier.set( + setter.set( carrier, self._TRACEPARENT_HEADER_NAME, traceparent_string ) if span_context.trace_state: tracestate_string = span_context.trace_state.to_header() - set_in_carrier.set( + setter.set( carrier, self._TRACESTATE_HEADER_NAME, tracestate_string ) diff --git a/opentelemetry-api/tests/baggage/test_baggage_propagation.py b/opentelemetry-api/tests/baggage/test_baggage_propagation.py index 79c52b8a354..f9a28736007 100644 --- a/opentelemetry-api/tests/baggage/test_baggage_propagation.py +++ b/opentelemetry-api/tests/baggage/test_baggage_propagation.py @@ -151,13 +151,13 @@ def test_inject_non_string_values(self): @patch("opentelemetry.baggage.propagation._format_baggage") def test_fields(self, mock_format_baggage, mock_baggage): - mock_set_in_carrier = Mock() + mock_setter = Mock() - self.propagator.inject({}, set_in_carrier=mock_set_in_carrier) + self.propagator.inject({}, setter=mock_setter) inject_fields = set() - for mock_call in mock_set_in_carrier.mock_calls: + for mock_call in mock_setter.mock_calls: inject_fields.add(mock_call[1][1]) self.assertEqual(inject_fields, self.propagator.fields) diff --git a/opentelemetry-api/tests/propagators/test_composite.py b/opentelemetry-api/tests/propagators/test_composite.py index 4713b76ebeb..ef9fae2a1ac 100644 --- a/opentelemetry-api/tests/propagators/test_composite.py +++ b/opentelemetry-api/tests/propagators/test_composite.py @@ -26,10 +26,10 @@ def get_as_list(dict_object, key): def mock_inject(name, value="data"): - def wrapped(carrier=None, context=None, set_in_carrier=None): + def wrapped(carrier=None, context=None, setter=None): carrier[name] = value - set_in_carrier.set({}, "inject_field_{}_0".format(name), None) - set_in_carrier.set({}, "inject_field_{}_1".format(name), None) + setter.set({}, "inject_field_{}_0".format(name), None) + setter.set({}, "inject_field_{}_1".format(name), None) return wrapped @@ -128,13 +128,13 @@ def test_fields(self): ] ) - mock_set_in_carrier = Mock() + mock_setter = Mock() - propagator.inject({}, set_in_carrier=mock_set_in_carrier) + propagator.inject({}, setter=mock_setter) inject_fields = set() - for mock_call in mock_set_in_carrier.mock_calls: + for mock_call in mock_setter.mock_calls: inject_fields.add(mock_call[1][1]) self.assertEqual(inject_fields, propagator.fields) diff --git a/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py b/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py index 4f2c3dae408..cea62382996 100644 --- a/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py +++ b/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py @@ -272,13 +272,13 @@ def test_fields(self, mock_get_current_span, mock_invalid_span_context): ) ) - mock_set_in_carrier = Mock() + mock_setter = Mock() - FORMAT.inject({}, set_in_carrier=mock_set_in_carrier) + FORMAT.inject({}, setter=mock_setter) inject_fields = set() - for mock_call in mock_set_in_carrier.mock_calls: + for mock_call in mock_setter.mock_calls: inject_fields.add(mock_call[1][1]) self.assertEqual(inject_fields, FORMAT.fields) diff --git a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py index ece65dea078..25ec2347184 100644 --- a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py +++ b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py @@ -131,7 +131,7 @@ def inject( self, carrier: CarrierT, context: typing.Optional[Context] = None, - set_in_carrier: Setter = default_setter, + setter: Setter = default_setter, ) -> None: span = trace.get_current_span(context=context) @@ -140,20 +140,20 @@ def inject( return sampled = (trace.TraceFlags.SAMPLED & span_context.trace_flags) != 0 - set_in_carrier.set( + setter.set( carrier, self.TRACE_ID_KEY, format_trace_id(span_context.trace_id), ) - set_in_carrier.set( + setter.set( carrier, self.SPAN_ID_KEY, format_span_id(span_context.span_id) ) span_parent = getattr(span, "parent", None) if span_parent is not None: - set_in_carrier.set( + setter.set( carrier, self.PARENT_SPAN_ID_KEY, format_span_id(span_parent.span_id), ) - set_in_carrier.set(carrier, self.SAMPLED_KEY, "1" if sampled else "0") + setter.set(carrier, self.SAMPLED_KEY, "1" if sampled else "0") @property def fields(self) -> typing.Set[str]: diff --git a/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py b/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py index d696f4ea33d..8d624abc0b0 100644 --- a/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py +++ b/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py @@ -334,22 +334,22 @@ def get(self, carrier, key): return carrier.get(key, None) ctx = FORMAT.extract({}, getter=CarrierGetter()) - FORMAT.inject({}, context=ctx, set_in_carrier=default_setter) + FORMAT.inject({}, context=ctx, setter=default_setter) def test_fields(self): """Make sure the fields attribute returns the fields used in inject""" tracer = trace.TracerProvider().get_tracer("sdk_tracer_provider") - mock_set_in_carrier = Mock() + mock_setter = Mock() with tracer.start_as_current_span("parent"): with tracer.start_as_current_span("child"): - FORMAT.inject({}, set_in_carrier=mock_set_in_carrier) + FORMAT.inject({}, setter=mock_setter) inject_fields = set() - for call in mock_set_in_carrier.mock_calls: + for call in mock_setter.mock_calls: inject_fields.add(call[1][1]) self.assertEqual(FORMAT.fields, inject_fields) diff --git a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py index d56cc76066a..a8eed85e0aa 100644 --- a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py +++ b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py @@ -80,7 +80,7 @@ def inject( self, carrier: CarrierT, context: typing.Optional[Context] = None, - set_in_carrier: Setter = default_setter, + setter: Setter = default_setter, ) -> None: span = trace.get_current_span(context=context) span_context = span.get_span_context() @@ -93,7 +93,7 @@ def inject( trace_flags |= self.DEBUG_FLAG # set span identity - set_in_carrier.set( + setter.set( carrier, self.TRACE_ID_KEY, _format_uber_trace_id( @@ -110,7 +110,7 @@ def inject( return for key, value in baggage_entries.items(): baggage_key = self.BAGGAGE_PREFIX + key - set_in_carrier.set( + setter.set( carrier, baggage_key, urllib.parse.quote(str(value)) ) diff --git a/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py b/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py index 3360b9ae47b..604c9789f8b 100644 --- a/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py +++ b/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py @@ -178,11 +178,11 @@ def test_extract_invalid_span_id(self): def test_fields(self): tracer = trace.TracerProvider().get_tracer("sdk_tracer_provider") - mock_set_in_carrier = Mock() + mock_setter = Mock() with tracer.start_as_current_span("parent"): with tracer.start_as_current_span("child"): - FORMAT.inject({}, set_in_carrier=mock_set_in_carrier) + FORMAT.inject({}, setter=mock_setter) inject_fields = set() - for call in mock_set_in_carrier.mock_calls: + for call in mock_setter.mock_calls: inject_fields.add(call[1][1]) self.assertEqual(FORMAT.fields, inject_fields) diff --git a/tests/util/src/opentelemetry/test/mock_textmap.py b/tests/util/src/opentelemetry/test/mock_textmap.py index 7994697a2eb..543708907c9 100644 --- a/tests/util/src/opentelemetry/test/mock_textmap.py +++ b/tests/util/src/opentelemetry/test/mock_textmap.py @@ -45,7 +45,7 @@ def inject( self, carrier: CarrierT, context: typing.Optional[Context] = None, - set_in_carrier: Setter = default_setter, + setter: Setter = default_setter, ) -> None: return None @@ -86,13 +86,13 @@ def inject( self, carrier: CarrierT, context: typing.Optional[Context] = None, - set_in_carrier: Setter = default_setter, + setter: Setter = default_setter, ) -> None: span = trace.get_current_span(context) - set_in_carrier.set( + setter.set( carrier, self.TRACE_ID_KEY, str(span.get_span_context().trace_id) ) - set_in_carrier.set( + setter.set( carrier, self.SPAN_ID_KEY, str(span.get_span_context().span_id) ) From 2ca12cb95c0cff963138ca50cbba9bc22e894798 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 15:35:11 -0600 Subject: [PATCH 09/28] Remove unnecessary arguments, rename to Default --- docs/conf.py | 2 +- .../server_instrumented.py | 3 +-- .../src/opentelemetry/propagators/textmap.py | 8 +++---- .../tests/baggage/test_baggage_propagation.py | 7 ++----- .../propagators/test_global_httptextformat.py | 5 +---- .../tests/trace/propagation/test_textmap.py | 12 +++++------ .../test_tracecontexthttptextformat.py | 12 +---------- .../propagation/test_benchmark_b3_format.py | 2 -- .../tests/test_b3_format.py | 21 ++++++++----------- .../tests/test_jaeger_propagator.py | 20 +++++++----------- .../shim/opentracing_shim/__init__.py | 4 +--- 11 files changed, 34 insertions(+), 62 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index d23cebfe96c..61dc1a82540 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -104,7 +104,7 @@ ("py:class", "opentelemetry.trace._LinkBase",), # TODO: Understand why sphinx is not able to find this local class ("py:class", "opentelemetry.propagators.textmap.TextMapPropagator",), - ("py:class", "opentelemetry.propagators.textmap.DictGetter",), + ("py:class", "opentelemetry.propagators.textmap.DefaultGetter",), ("any", "opentelemetry.propagators.textmap.TextMapPropagator.extract",), ("any", "opentelemetry.propagators.textmap.TextMapPropagator.inject",), ] diff --git a/docs/examples/auto-instrumentation/server_instrumented.py b/docs/examples/auto-instrumentation/server_instrumented.py index 1ac1bd6b71b..652358e3a2e 100644 --- a/docs/examples/auto-instrumentation/server_instrumented.py +++ b/docs/examples/auto-instrumentation/server_instrumented.py @@ -17,7 +17,6 @@ from opentelemetry import trace from opentelemetry.instrumentation.wsgi import collect_request_attributes from opentelemetry.propagate import extract -from opentelemetry.propagators.textmap import DictGetter from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( ConsoleSpanExporter, @@ -38,7 +37,7 @@ def server_request(): with tracer.start_as_current_span( "server_request", - context=extract(DictGetter(), request.headers), + context=extract(request.headers), kind=trace.SpanKind.SERVER, attributes=collect_request_attributes(request.environ), ): diff --git a/opentelemetry-api/src/opentelemetry/propagators/textmap.py b/opentelemetry-api/src/opentelemetry/propagators/textmap.py index 0c88655473c..39d1b122444 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/textmap.py +++ b/opentelemetry-api/src/opentelemetry/propagators/textmap.py @@ -71,7 +71,7 @@ def set(self, carrier: CarrierT, key: str, value: str) -> None: """ -class DictGetter(Getter): +class DefaultGetter(Getter): def get( # type: ignore self, carrier: typing.Dict[str, CarrierValT], key: str ) -> typing.Optional[typing.List[str]]: @@ -97,10 +97,10 @@ def keys( # type: ignore return list(carrier.keys()) -default_getter = DictGetter() +default_getter = DefaultGetter() -class DictSetter(Setter): +class DefaultSetter(Setter): def set( # type: ignore self, carrier: typing.Dict[str, CarrierValT], key: str, value: str ) -> None: @@ -113,7 +113,7 @@ def set( # type: ignore carrier[key] = value -default_setter = DictSetter() +default_setter = DefaultSetter() class TextMapPropagator(abc.ABC): diff --git a/opentelemetry-api/tests/baggage/test_baggage_propagation.py b/opentelemetry-api/tests/baggage/test_baggage_propagation.py index f9a28736007..6d8acebcf54 100644 --- a/opentelemetry-api/tests/baggage/test_baggage_propagation.py +++ b/opentelemetry-api/tests/baggage/test_baggage_propagation.py @@ -20,9 +20,6 @@ from opentelemetry import baggage from opentelemetry.baggage.propagation import W3CBaggagePropagator from opentelemetry.context import get_current -from opentelemetry.propagators.textmap import DictGetter - -carrier_getter = DictGetter() class TestBaggagePropagation(unittest.TestCase): @@ -33,7 +30,7 @@ def _extract(self, header_value): """Test helper""" header = {"baggage": [header_value]} return baggage.get_all( - self.propagator.extract(header, getter=carrier_getter) + self.propagator.extract(header) ) def _inject(self, values): @@ -47,7 +44,7 @@ def _inject(self, values): def test_no_context_header(self): baggage_entries = baggage.get_all( - self.propagator.extract({}, getter=carrier_getter) + self.propagator.extract({}) ) self.assertEqual(baggage_entries, {}) diff --git a/opentelemetry-api/tests/propagators/test_global_httptextformat.py b/opentelemetry-api/tests/propagators/test_global_httptextformat.py index 0d36482fe11..466ce6895f8 100644 --- a/opentelemetry-api/tests/propagators/test_global_httptextformat.py +++ b/opentelemetry-api/tests/propagators/test_global_httptextformat.py @@ -18,12 +18,9 @@ from opentelemetry import baggage, trace from opentelemetry.propagate import extract, inject -from opentelemetry.propagators.textmap import DictGetter from opentelemetry.trace import get_current_span, set_span_in_context from opentelemetry.trace.span import format_span_id, format_trace_id -carrier_getter = DictGetter() - class TestDefaultGlobalPropagator(unittest.TestCase): """Test ensures the default global composite propagator works as intended""" @@ -42,7 +39,7 @@ def test_propagation(self): "traceparent": [traceparent_value], "tracestate": [tracestate_value], } - ctx = extract(headers, getter=carrier_getter) + ctx = extract(headers) baggage_entries = baggage.get_all(context=ctx) expected = {"key1": "val1", "key2": "val2"} self.assertEqual(baggage_entries, expected) diff --git a/opentelemetry-api/tests/trace/propagation/test_textmap.py b/opentelemetry-api/tests/trace/propagation/test_textmap.py index e47a0d22cb4..6b22d46f88e 100644 --- a/opentelemetry-api/tests/trace/propagation/test_textmap.py +++ b/opentelemetry-api/tests/trace/propagation/test_textmap.py @@ -16,29 +16,29 @@ import unittest -from opentelemetry.propagators.textmap import DictGetter +from opentelemetry.propagators.textmap import DefaultGetter -class TestDictGetter(unittest.TestCase): +class TestDefaultGetter(unittest.TestCase): def test_get_none(self): - getter = DictGetter() + getter = DefaultGetter() carrier = {} val = getter.get(carrier, "test") self.assertIsNone(val) def test_get_str(self): - getter = DictGetter() + getter = DefaultGetter() carrier = {"test": "val"} val = getter.get(carrier, "test") self.assertEqual(val, ["val"]) def test_get_iter(self): - getter = DictGetter() + getter = DefaultGetter() carrier = {"test": ["val"]} val = getter.get(carrier, "test") self.assertEqual(val, ["val"]) def test_keys(self): - getter = DictGetter() + getter = DefaultGetter() keys = getter.keys({"test": "val"}) self.assertEqual(keys, ["test"]) diff --git a/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py b/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py index cea62382996..cb7f07c0157 100644 --- a/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py +++ b/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py @@ -19,14 +19,11 @@ from unittest.mock import Mock, patch from opentelemetry import trace -from opentelemetry.propagators.textmap import DictGetter from opentelemetry.trace.propagation import tracecontext from opentelemetry.trace.span import TraceState FORMAT = tracecontext.TraceContextTextMapPropagator() -carrier_getter = DictGetter() - class TestTraceContextFormat(unittest.TestCase): TRACE_ID = int("12345678901234567890123456789012", 16) # type:int @@ -43,7 +40,7 @@ def test_no_traceparent_header(self): """ output = {} # type:typing.Dict[str, typing.List[str]] span = trace.get_current_span( - FORMAT.extract(output, getter=carrier_getter) + FORMAT.extract(output) ) self.assertIsInstance(span.get_span_context(), trace.SpanContext) @@ -62,7 +59,6 @@ def test_headers_with_tracestate(self): "traceparent": [traceparent_value], "tracestate": [tracestate_value], }, - getter=carrier_getter, ) ).get_span_context() self.assertEqual(span_context.trace_id, self.TRACE_ID) @@ -108,7 +104,6 @@ def test_invalid_trace_id(self): ], "tracestate": ["foo=1,bar=2,foo=3"], }, - getter=carrier_getter, ) ) self.assertEqual(span.get_span_context(), trace.INVALID_SPAN_CONTEXT) @@ -139,7 +134,6 @@ def test_invalid_parent_id(self): ], "tracestate": ["foo=1,bar=2,foo=3"], }, - getter=carrier_getter, ) ) self.assertEqual(span.get_span_context(), trace.INVALID_SPAN_CONTEXT) @@ -178,7 +172,6 @@ def test_format_not_supported(self): ], "tracestate": ["foo=1,bar=2,foo=3"], }, - getter=carrier_getter, ) ) self.assertEqual(span.get_span_context(), trace.INVALID_SPAN_CONTEXT) @@ -200,7 +193,6 @@ def test_tracestate_empty_header(self): ], "tracestate": ["foo=1", ""], }, - getter=carrier_getter, ) ) self.assertEqual(span.get_span_context().trace_state["foo"], "1") @@ -215,7 +207,6 @@ def test_tracestate_header_with_trailing_comma(self): ], "tracestate": ["foo=1,"], }, - getter=carrier_getter, ) ) self.assertEqual(span.get_span_context().trace_state["foo"], "1") @@ -239,7 +230,6 @@ def test_tracestate_keys(self): ], "tracestate": [tracestate_value], }, - getter=carrier_getter, ) ) self.assertEqual( diff --git a/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py b/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py index 1a40b7d697e..ee870135875 100644 --- a/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py +++ b/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py @@ -14,7 +14,6 @@ import opentelemetry.propagators.b3 as b3_format import opentelemetry.sdk.trace as trace -from opentelemetry.propagators.textmap import default_getter FORMAT = b3_format.B3Format() @@ -25,7 +24,6 @@ def test_extract_single_header(benchmark): { FORMAT.SINGLE_HEADER_KEY: "bdb5b63237ed38aea578af665aa5aa60-c32d953d73ad2251-1-11fd79a30b0896cd285b396ae102dd76" }, - getter=default_getter, ) diff --git a/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py b/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py index 8d624abc0b0..d1d96a269f0 100644 --- a/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py +++ b/propagator/opentelemetry-propagator-b3/tests/test_b3_format.py @@ -20,17 +20,14 @@ import opentelemetry.sdk.trace.id_generator as id_generator import opentelemetry.trace as trace_api from opentelemetry.context import get_current -from opentelemetry.propagators.textmap import DictGetter, default_setter +from opentelemetry.propagators.textmap import DefaultGetter FORMAT = b3_format.B3Format() -carrier_getter = DictGetter() - - def get_child_parent_new_carrier(old_carrier): - ctx = FORMAT.extract(old_carrier, getter=carrier_getter) + ctx = FORMAT.extract(old_carrier) parent_span_context = trace_api.get_current_span(ctx).get_span_context() parent = trace._Span("parent", parent_span_context) @@ -239,7 +236,7 @@ def test_invalid_single_header(self): invalid SpanContext. """ carrier = {FORMAT.SINGLE_HEADER_KEY: "0-1-2-3-4-5-6-7"} - ctx = FORMAT.extract(carrier, getter=carrier_getter) + ctx = FORMAT.extract(carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) @@ -251,7 +248,7 @@ def test_missing_trace_id(self): FORMAT.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier, getter=carrier_getter) + ctx = FORMAT.extract(carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) @@ -275,7 +272,7 @@ def test_invalid_trace_id( FORMAT.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier, getter=carrier_getter) + ctx = FORMAT.extract(carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, 1) @@ -301,7 +298,7 @@ def test_invalid_span_id( FORMAT.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier, getter=carrier_getter) + ctx = FORMAT.extract(carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, 1) @@ -314,7 +311,7 @@ def test_missing_span_id(self): FORMAT.FLAGS_KEY: "1", } - ctx = FORMAT.extract(carrier, getter=carrier_getter) + ctx = FORMAT.extract(carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) @@ -329,12 +326,12 @@ def test_inject_empty_context(): def test_default_span(): """Make sure propagator does not crash when working with NonRecordingSpan""" - class CarrierGetter(DictGetter): + class CarrierGetter(DefaultGetter): def get(self, carrier, key): return carrier.get(key, None) ctx = FORMAT.extract({}, getter=CarrierGetter()) - FORMAT.inject({}, context=ctx, setter=default_setter) + FORMAT.inject({}, context=ctx) def test_fields(self): """Make sure the fields attribute returns the fields used in inject""" diff --git a/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py b/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py index 604c9789f8b..003bbfeb49d 100644 --- a/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py +++ b/propagator/opentelemetry-propagator-jaeger/tests/test_jaeger_propagator.py @@ -22,17 +22,13 @@ from opentelemetry.propagators import ( # pylint: disable=no-name-in-module jaeger, ) -from opentelemetry.propagators.textmap import DictGetter FORMAT = jaeger.JaegerPropagator() -carrier_getter = DictGetter() - - def get_context_new_carrier(old_carrier, carrier_baggage=None): - ctx = FORMAT.extract(old_carrier, getter=carrier_getter) + ctx = FORMAT.extract(old_carrier) if carrier_baggage: for key, value in carrier_baggage.items(): ctx = baggage.set_baggage(key, value, ctx) @@ -72,14 +68,14 @@ def setUpClass(cls): def test_extract_valid_span(self): old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} - ctx = FORMAT.extract(old_carrier, getter=carrier_getter) + ctx = FORMAT.extract(old_carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, self.trace_id) self.assertEqual(span_context.span_id, self.span_id) def test_missing_carrier(self): old_carrier = {} - ctx = FORMAT.extract(old_carrier, getter=carrier_getter) + ctx = FORMAT.extract(old_carrier) span_context = trace_api.get_current_span(ctx).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) @@ -132,7 +128,7 @@ def test_baggage(self): old_carrier = {FORMAT.TRACE_ID_KEY: self.serialized_uber_trace_id} input_baggage = {"key1": "value1"} _, new_carrier = get_context_new_carrier(old_carrier, input_baggage) - ctx = FORMAT.extract(new_carrier, getter=carrier_getter) + ctx = FORMAT.extract(new_carrier) self.assertDictEqual(input_baggage, ctx["baggage"]) def test_non_string_baggage(self): @@ -140,7 +136,7 @@ def test_non_string_baggage(self): input_baggage = {"key1": 1, "key2": True} formatted_baggage = {"key1": "1", "key2": "True"} _, new_carrier = get_context_new_carrier(old_carrier, input_baggage) - ctx = FORMAT.extract(new_carrier, getter=carrier_getter) + ctx = FORMAT.extract(new_carrier) self.assertDictEqual(formatted_baggage, ctx["baggage"]) def test_extract_invalid_uber_trace_id(self): @@ -149,7 +145,7 @@ def test_extract_invalid_uber_trace_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = FORMAT.extract(old_carrier, getter=carrier_getter) + context = FORMAT.extract(old_carrier) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) @@ -160,7 +156,7 @@ def test_extract_invalid_trace_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = FORMAT.extract(old_carrier, getter=carrier_getter) + context = FORMAT.extract(old_carrier) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.trace_id, trace_api.INVALID_TRACE_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) @@ -171,7 +167,7 @@ def test_extract_invalid_span_id(self): "uberctx-key1": "value1", } formatted_baggage = {"key1": "value1"} - context = FORMAT.extract(old_carrier, getter=carrier_getter) + context = FORMAT.extract(old_carrier) span_context = trace_api.get_current_span(context).get_span_context() self.assertEqual(span_context.span_id, trace_api.INVALID_SPAN_ID) self.assertDictEqual(formatted_baggage, context["baggage"]) diff --git a/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py b/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py index cc3a1d14be9..2327abbfae1 100644 --- a/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py +++ b/shim/opentelemetry-opentracing-shim/src/opentelemetry/shim/opentracing_shim/__init__.py @@ -102,7 +102,6 @@ from opentelemetry.baggage import get_baggage, set_baggage from opentelemetry.context import Context, attach, detach, get_value, set_value from opentelemetry.propagate import get_global_textmap -from opentelemetry.propagators.textmap import DictGetter from opentelemetry.shim.opentracing_shim import util from opentelemetry.shim.opentracing_shim.version import __version__ from opentelemetry.trace import INVALID_SPAN_CONTEXT, Link, NonRecordingSpan @@ -527,7 +526,6 @@ def __init__(self, tracer: OtelTracer): Format.TEXT_MAP, Format.HTTP_HEADERS, ) - self._carrier_getter = DictGetter() def unwrap(self): """Returns the :class:`opentelemetry.trace.Tracer` object that is @@ -712,7 +710,7 @@ def extract(self, format: object, carrier: object): raise UnsupportedFormatException propagator = get_global_textmap() - ctx = propagator.extract(carrier, getter=self._carrier_getter) + ctx = propagator.extract(carrier) span = get_current_span(ctx) if span is not None: otel_context = span.get_span_context() From e131478ea9f7b08e1f3f09e2352ec1d58f43bff3 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 15:39:21 -0600 Subject: [PATCH 10/28] Update SHA --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 908cf71caa3..0925de313cd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: 5bc0fa1611502be47a1f4eb550fe255e4b707ba1 + CONTRIB_REPO_SHA: 849a781fef10bcf520eefb03a6dae52d523dc703 jobs: build: From b298b5627602da59ca2f007aa2e0a0488033ba22 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 15:45:40 -0600 Subject: [PATCH 11/28] Fix lint --- opentelemetry-api/src/opentelemetry/propagate/__init__.py | 4 +--- .../src/opentelemetry/trace/propagation/tracecontext.py | 4 +--- .../tests/baggage/test_baggage_propagation.py | 8 ++------ .../trace/propagation/test_tracecontexthttptextformat.py | 4 +--- .../src/opentelemetry/propagators/b3/__init__.py | 2 +- .../src/opentelemetry/propagators/jaeger/__init__.py | 6 ++---- tests/util/src/opentelemetry/test/mock_textmap.py | 2 +- 7 files changed, 9 insertions(+), 21 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/propagate/__init__.py b/opentelemetry-api/src/opentelemetry/propagate/__init__.py index dd19b2edd71..b58bf567050 100644 --- a/opentelemetry-api/src/opentelemetry/propagate/__init__.py +++ b/opentelemetry-api/src/opentelemetry/propagate/__init__.py @@ -118,9 +118,7 @@ def inject( context: an optional Context to use. Defaults to current context if not set. """ - get_global_textmap().inject( - carrier, context=context, setter=setter - ) + get_global_textmap().inject(carrier, context=context, setter=setter) try: diff --git a/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py b/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py index 1e269e82538..9fc5cfed242 100644 --- a/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py +++ b/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py @@ -102,9 +102,7 @@ def inject( trace_id=format_trace_id(span_context.trace_id), span_id=format_span_id(span_context.span_id), ) - setter.set( - carrier, self._TRACEPARENT_HEADER_NAME, traceparent_string - ) + setter.set(carrier, self._TRACEPARENT_HEADER_NAME, traceparent_string) if span_context.trace_state: tracestate_string = span_context.trace_state.to_header() setter.set( diff --git a/opentelemetry-api/tests/baggage/test_baggage_propagation.py b/opentelemetry-api/tests/baggage/test_baggage_propagation.py index 6d8acebcf54..9084bb778e0 100644 --- a/opentelemetry-api/tests/baggage/test_baggage_propagation.py +++ b/opentelemetry-api/tests/baggage/test_baggage_propagation.py @@ -29,9 +29,7 @@ def setUp(self): def _extract(self, header_value): """Test helper""" header = {"baggage": [header_value]} - return baggage.get_all( - self.propagator.extract(header) - ) + return baggage.get_all(self.propagator.extract(header)) def _inject(self, values): """Test helper""" @@ -43,9 +41,7 @@ def _inject(self, values): return output.get("baggage") def test_no_context_header(self): - baggage_entries = baggage.get_all( - self.propagator.extract({}) - ) + baggage_entries = baggage.get_all(self.propagator.extract({})) self.assertEqual(baggage_entries, {}) def test_empty_context_header(self): diff --git a/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py b/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py index cb7f07c0157..98ca50610b9 100644 --- a/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py +++ b/opentelemetry-api/tests/trace/propagation/test_tracecontexthttptextformat.py @@ -39,9 +39,7 @@ def test_no_traceparent_header(self): trace-id and parent-id that represents the current request. """ output = {} # type:typing.Dict[str, typing.List[str]] - span = trace.get_current_span( - FORMAT.extract(output) - ) + span = trace.get_current_span(FORMAT.extract(output)) self.assertIsInstance(span.get_span_context(), trace.SpanContext) def test_headers_with_tracestate(self): diff --git a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py index 25ec2347184..be478b05ec0 100644 --- a/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py +++ b/propagator/opentelemetry-propagator-b3/src/opentelemetry/propagators/b3/__init__.py @@ -18,10 +18,10 @@ import opentelemetry.trace as trace from opentelemetry.context import Context from opentelemetry.propagators.textmap import ( + CarrierT, Getter, Setter, TextMapPropagator, - CarrierT, default_getter, default_setter, ) diff --git a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py index a8eed85e0aa..47f438531fb 100644 --- a/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py +++ b/propagator/opentelemetry-propagator-jaeger/src/opentelemetry/propagators/jaeger/__init__.py @@ -19,10 +19,10 @@ from opentelemetry import baggage from opentelemetry.context import Context, get_current from opentelemetry.propagators.textmap import ( + CarrierT, Getter, Setter, TextMapPropagator, - CarrierT, default_getter, default_setter, ) @@ -110,9 +110,7 @@ def inject( return for key, value in baggage_entries.items(): baggage_key = self.BAGGAGE_PREFIX + key - setter.set( - carrier, baggage_key, urllib.parse.quote(str(value)) - ) + setter.set(carrier, baggage_key, urllib.parse.quote(str(value))) @property def fields(self) -> typing.Set[str]: diff --git a/tests/util/src/opentelemetry/test/mock_textmap.py b/tests/util/src/opentelemetry/test/mock_textmap.py index 543708907c9..4cdef447d6a 100644 --- a/tests/util/src/opentelemetry/test/mock_textmap.py +++ b/tests/util/src/opentelemetry/test/mock_textmap.py @@ -17,10 +17,10 @@ from opentelemetry import trace from opentelemetry.context import Context, get_current from opentelemetry.propagators.textmap import ( + CarrierT, Getter, Setter, TextMapPropagator, - CarrierT, default_getter, default_setter, ) From 0cec680929f9cc53b7e7dc8e762a1e389c3dee55 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 15:46:04 -0600 Subject: [PATCH 12/28] Update SHA --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0925de313cd..abc7988e186 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: 849a781fef10bcf520eefb03a6dae52d523dc703 + CONTRIB_REPO_SHA: b3ffa09d9e757bad3e26ac9d8e9da4fb57a8875b jobs: build: From 817599e500d5639485085665c246b2bbfdb6f521 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 15:54:29 -0600 Subject: [PATCH 13/28] Update SHA --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index abc7988e186..4d94ae5a31c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: b3ffa09d9e757bad3e26ac9d8e9da4fb57a8875b + CONTRIB_REPO_SHA: 04a2c65de3391752d718eb2d2c8d096bff04280b jobs: build: From df649ea04a245ff8c3d56716b663ca32763f973a Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 15:58:58 -0600 Subject: [PATCH 14/28] Update SHA --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4d94ae5a31c..9151bfb4664 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: 04a2c65de3391752d718eb2d2c8d096bff04280b + CONTRIB_REPO_SHA: e38a8be7d4fe807a9a985fd8fb2b16c45171f7d3 jobs: build: From f946e75ac3a7ff7582c619df00b06a9881532a45 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 16:07:38 -0600 Subject: [PATCH 15/28] Update SHA --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9151bfb4664..04edd20058c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: e38a8be7d4fe807a9a985fd8fb2b16c45171f7d3 + CONTRIB_REPO_SHA: 5797fee6ebbbcff3da6e80efabb162aba455d0b7 jobs: build: From f4ba4c5a48fbd12c9f6a736899433ba2ab2dcaf9 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 16:20:17 -0600 Subject: [PATCH 16/28] Update SHA --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 04edd20058c..7e5c097eda3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: 5797fee6ebbbcff3da6e80efabb162aba455d0b7 + CONTRIB_REPO_SHA: f8a4e171a9d8775753882d41f40a42f3108adaf8 jobs: build: From 5ae9e9848268fdaa764f1c70961c86c5c9eefa1a Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 16:25:30 -0600 Subject: [PATCH 17/28] Update SHA --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7e5c097eda3..e81b6319090 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: f8a4e171a9d8775753882d41f40a42f3108adaf8 + CONTRIB_REPO_SHA: c97e91fa97faf8c453162080895f8f1e2ff56f3f jobs: build: From 2a9b7b7a050b8d1449de8b6ca8d5160fdb484222 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 16:33:26 -0600 Subject: [PATCH 18/28] Update SHA --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e81b6319090..cb54b25b93b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: c97e91fa97faf8c453162080895f8f1e2ff56f3f + CONTRIB_REPO_SHA: 1b798428e9823853c921b41cd1000b17e3900430 jobs: build: From 3fa68d61a9fd8d5ca9b543faa92677f59146e1b9 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 17:57:42 -0600 Subject: [PATCH 19/28] More fixes --- docs/examples/datadog_exporter/client.py | 2 +- docs/examples/django/client.py | 2 +- .../benchmarks/trace/propagation/test_benchmark_b3_format.py | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/examples/datadog_exporter/client.py b/docs/examples/datadog_exporter/client.py index 6b4b5d00ec1..7c6196ad4ab 100644 --- a/docs/examples/datadog_exporter/client.py +++ b/docs/examples/datadog_exporter/client.py @@ -47,7 +47,7 @@ with tracer.start_as_current_span("client-server"): headers = {} - inject(dict.__setitem__, headers) + inject(headers) requested = get( "http://localhost:8082/server_request", params={"param": argv[1]}, diff --git a/docs/examples/django/client.py b/docs/examples/django/client.py index bc3606cbe76..3ae0cb6e1cf 100644 --- a/docs/examples/django/client.py +++ b/docs/examples/django/client.py @@ -36,7 +36,7 @@ with tracer.start_as_current_span("client-server"): headers = {} - inject(dict.__setitem__, headers) + inject(headers) requested = get( "http://localhost:8000", params={"param": argv[1]}, diff --git a/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py b/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py index ee870135875..3a7a251ad88 100644 --- a/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py +++ b/propagator/opentelemetry-propagator-b3/tests/performance/benchmarks/trace/propagation/test_benchmark_b3_format.py @@ -33,7 +33,6 @@ def test_inject_empty_context(benchmark): with tracer.start_as_current_span("Child Span"): benchmark( FORMAT.inject, - dict.__setitem__, { FORMAT.TRACE_ID_KEY: "bdb5b63237ed38aea578af665aa5aa60", FORMAT.SPAN_ID_KEY: "00000000000000000c32d953d73ad225", From 8a75bfa59a27a8703d920400ecbe7586eb8a7816 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 17:58:21 -0600 Subject: [PATCH 20/28] Fix SHA --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cb54b25b93b..2bf2e847e66 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: 1b798428e9823853c921b41cd1000b17e3900430 + CONTRIB_REPO_SHA: 3fa68d61a9fd8d5ca9b543faa92677f59146e1b9 jobs: build: From c81c7d17ff24e2d380532652df71ede3bbd53570 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 18:01:47 -0600 Subject: [PATCH 21/28] Update SHA --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2bf2e847e66..4fe5c784d7b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: 3fa68d61a9fd8d5ca9b543faa92677f59146e1b9 + CONTRIB_REPO_SHA: 24cad544b604b38252f18139cdbe4b1399e9c83a jobs: build: From 94d9c1eb77723123a779ddd18d2b12d4bec445fb Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 18:22:20 -0600 Subject: [PATCH 22/28] Fix SHA --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4fe5c784d7b..34d58b2cdb7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: 24cad544b604b38252f18139cdbe4b1399e9c83a + CONTRIB_REPO_SHA: 0d12fa39523212e268ef435825af2039a876fd75 jobs: build: From 7291825de49ca90e30b54e17eb0a6d8149b7edd4 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 19:47:05 -0600 Subject: [PATCH 23/28] Update opentelemetry-api/src/opentelemetry/propagate/__init__.py Co-authored-by: Leighton Chen --- opentelemetry-api/src/opentelemetry/propagate/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-api/src/opentelemetry/propagate/__init__.py b/opentelemetry-api/src/opentelemetry/propagate/__init__.py index b58bf567050..886f7ffe875 100644 --- a/opentelemetry-api/src/opentelemetry/propagate/__init__.py +++ b/opentelemetry-api/src/opentelemetry/propagate/__init__.py @@ -110,7 +110,7 @@ def inject( """Uses the configured propagator to inject a Context into the carrier. Args: - setter: A setter function that can set values + setter: A `Setter` object that can set values on the carrier. carrier: An object that contains a representation of HTTP headers. Should be paired with setter, which From 533a92665463ef253bf7ab3a07f60a5b187485c1 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 19:47:23 -0600 Subject: [PATCH 24/28] Update opentelemetry-api/src/opentelemetry/propagators/textmap.py Co-authored-by: Leighton Chen --- opentelemetry-api/src/opentelemetry/propagators/textmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-api/src/opentelemetry/propagators/textmap.py b/opentelemetry-api/src/opentelemetry/propagators/textmap.py index 39d1b122444..ec0a6287511 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/textmap.py +++ b/opentelemetry-api/src/opentelemetry/propagators/textmap.py @@ -168,7 +168,7 @@ def inject( carrier. Args: - setter: A setter function that can set values + setter: A `Setter` object that can set values on the carrier. carrier: An object that a place to define HTTP headers. Should be paired with setter, which should From 13f73ec01a921041401d0e98f5079fe77d4d02be Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Thu, 25 Mar 2021 19:47:32 -0600 Subject: [PATCH 25/28] Update opentelemetry-api/src/opentelemetry/propagators/textmap.py Co-authored-by: Leighton Chen --- opentelemetry-api/src/opentelemetry/propagators/textmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-api/src/opentelemetry/propagators/textmap.py b/opentelemetry-api/src/opentelemetry/propagators/textmap.py index ec0a6287511..0ce6f7ab421 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/textmap.py +++ b/opentelemetry-api/src/opentelemetry/propagators/textmap.py @@ -164,7 +164,7 @@ def inject( inject enables the propagation of values into HTTP clients or other objects which perform an HTTP request. Implementations - should use the setter method to set values on the + should use the `Setter` 's set method to set values on the carrier. Args: From 0244b2310ec6a8ea8ac825e147897d46a107a83b Mon Sep 17 00:00:00 2001 From: Alex Boten Date: Fri, 26 Mar 2021 08:20:29 -0700 Subject: [PATCH 26/28] addressing docs comments --- opentelemetry-api/src/opentelemetry/propagate/__init__.py | 6 +++--- opentelemetry-api/src/opentelemetry/propagators/textmap.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/propagate/__init__.py b/opentelemetry-api/src/opentelemetry/propagate/__init__.py index 886f7ffe875..091b5b8d44e 100644 --- a/opentelemetry-api/src/opentelemetry/propagate/__init__.py +++ b/opentelemetry-api/src/opentelemetry/propagate/__init__.py @@ -110,13 +110,13 @@ def inject( """Uses the configured propagator to inject a Context into the carrier. Args: - setter: A `Setter` object that can set values - on the carrier. carrier: An object that contains a representation of HTTP headers. Should be paired with setter, which should know how to set header values on the carrier. - context: an optional Context to use. Defaults to current + context: An optional Context to use. Defaults to current context if not set. + setter: An optional `Setter` object that can set values + on the carrier. """ get_global_textmap().inject(carrier, context=context, setter=setter) diff --git a/opentelemetry-api/src/opentelemetry/propagators/textmap.py b/opentelemetry-api/src/opentelemetry/propagators/textmap.py index 0ce6f7ab421..185701f4162 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/textmap.py +++ b/opentelemetry-api/src/opentelemetry/propagators/textmap.py @@ -168,13 +168,13 @@ def inject( carrier. Args: - setter: A `Setter` object that can set values - on the carrier. carrier: An object that a place to define HTTP headers. Should be paired with setter, which should know how to set header values on the carrier. context: an optional Context to use. Defaults to current context if not set. + setter: An optional `Setter` object that can set values + on the carrier. """ From f515e2db80a1d1cdbfb3f5e3d15a9c1468a3258e Mon Sep 17 00:00:00 2001 From: Alex Boten Date: Fri, 26 Mar 2021 08:22:50 -0700 Subject: [PATCH 27/28] adding docs --- opentelemetry-api/src/opentelemetry/propagators/textmap.py | 1 + 1 file changed, 1 insertion(+) diff --git a/opentelemetry-api/src/opentelemetry/propagators/textmap.py b/opentelemetry-api/src/opentelemetry/propagators/textmap.py index 185701f4162..df8e3db2d24 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/textmap.py +++ b/opentelemetry-api/src/opentelemetry/propagators/textmap.py @@ -109,6 +109,7 @@ def set( # type: ignore Args: carrier: dictionary in which header key: the key used to set the value + value: the value to set """ carrier[key] = value From 5be5eacdb3a1fbfc4beb4f8dbf4e40fe62d10633 Mon Sep 17 00:00:00 2001 From: Alex Boten Date: Fri, 26 Mar 2021 08:32:10 -0700 Subject: [PATCH 28/28] review feedback --- .../src/opentelemetry/propagators/textmap.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/propagators/textmap.py b/opentelemetry-api/src/opentelemetry/propagators/textmap.py index df8e3db2d24..45c2308f661 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/textmap.py +++ b/opentelemetry-api/src/opentelemetry/propagators/textmap.py @@ -73,12 +73,12 @@ def set(self, carrier: CarrierT, key: str, value: str) -> None: class DefaultGetter(Getter): def get( # type: ignore - self, carrier: typing.Dict[str, CarrierValT], key: str + self, carrier: typing.Mapping[str, CarrierValT], key: str ) -> typing.Optional[typing.List[str]]: """Getter implementation to retrieve a value from a dictionary. Args: - carrier: dictionary in which header + carrier: dictionary in which to get value key: the key used to get the value Returns: A list with a single string with the value if it exists, else None. @@ -102,12 +102,15 @@ def keys( # type: ignore class DefaultSetter(Setter): def set( # type: ignore - self, carrier: typing.Dict[str, CarrierValT], key: str, value: str + self, + carrier: typing.MutableMapping[str, CarrierValT], + key: str, + value: CarrierValT, ) -> None: """Setter implementation to set a value into a dictionary. Args: - carrier: dictionary in which header + carrier: dictionary in which to set value key: the key used to set the value value: the value to set """