Skip to content

Commit

Permalink
Remove setters and getters
Browse files Browse the repository at this point in the history
Fixes #1644
  • Loading branch information
ocelotl committed Mar 17, 2021
1 parent 9418013 commit 8c59877
Show file tree
Hide file tree
Showing 24 changed files with 606 additions and 859 deletions.
1 change: 0 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",),
]
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/auto-instrumentation/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/auto-instrumentation/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]},
Expand Down
3 changes: 1 addition & 2 deletions docs/examples/auto-instrumentation/server_instrumented.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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),
):
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/datadog_exporter/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]},
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/django/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]},
Expand Down
92 changes: 38 additions & 54 deletions opentelemetry-api/src/opentelemetry/baggage/propagation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,29 @@
# 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 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,
TextMapPropagatorT,
)


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: TextMapPropagatorT, context: Optional[Context] = None,
) -> Context:
"""Extract Baggage from the carrier.
Expand All @@ -44,67 +44,51 @@ def extract(
if context is None:
context = get_current()

header = _extract_first_element(
getter.get(carrier, self._BAGGAGE_HEADER_NAME)
)
value = carrier.get(self._baggage_header_name)

if value is None:
header = None
else:
header = next(iter(value), None)

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: TextMapPropagatorT, context: Optional[Context] = None,
) -> None:
"""Injects Baggage into the carrier.
See
`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}
56 changes: 21 additions & 35 deletions opentelemetry-api/src/opentelemetry/propagate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand All @@ -68,23 +57,25 @@ 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 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,
TextMapPropagatorT,
)

logger = getLogger(__name__)
_logger = getLogger(__name__)


def extract(
getter: textmap.Getter[textmap.TextMapPropagatorT],
carrier: textmap.TextMapPropagatorT,
context: typing.Optional[Context] = None,
carrier: TextMapPropagatorT, context: Optional[Context] = None,
) -> Context:
"""Uses the configured propagator to extract a Context from the carrier.
Expand All @@ -99,26 +90,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: TextMapPropagatorT, 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:
Expand All @@ -138,16 +124,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
49 changes: 23 additions & 26 deletions opentelemetry-api/src/opentelemetry/propagators/composite.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,63 +11,60 @@
# 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 Optional, Sequence, Set

from opentelemetry.context.context import Context
from opentelemetry.propagators import textmap
from opentelemetry.propagators.textmap import (
TextMapPropagator,
TextMapPropagatorT,
)

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.
Args:
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: TextMapPropagatorT, 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: TextMapPropagatorT, 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
Expand Down
Loading

0 comments on commit 8c59877

Please sign in to comment.