__init__.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. # Copyright The OpenTelemetry Authors
  2. # SPDX-License-Identifier: Apache-2.0
  3. """
  4. API for propagation of context.
  5. The propagators for the
  6. ``opentelemetry.propagators.composite.CompositePropagator`` can be defined
  7. via configuration in the ``OTEL_PROPAGATORS`` environment variable. This
  8. variable should be set to a comma-separated string of names of values for the
  9. ``opentelemetry_propagator`` entry point. For example, setting
  10. ``OTEL_PROPAGATORS`` to ``tracecontext,baggage`` (which is the default value)
  11. would instantiate
  12. ``opentelemetry.propagators.composite.CompositePropagator`` with 2
  13. propagators, one of type
  14. ``opentelemetry.trace.propagation.tracecontext.TraceContextTextMapPropagator``
  15. and other of type ``opentelemetry.baggage.propagation.W3CBaggagePropagator``.
  16. Notice that these propagator classes are defined as
  17. ``opentelemetry_propagator`` entry points in the ``pyproject.toml`` file of
  18. ``opentelemetry``.
  19. Example::
  20. import flask
  21. import requests
  22. from opentelemetry import propagate
  23. PROPAGATOR = propagate.get_global_textmap()
  24. def get_header_from_flask_request(request, key):
  25. return request.headers.get_all(key)
  26. def set_header_into_requests_request(request: requests.Request,
  27. key: str, value: str):
  28. request.headers[key] = value
  29. def example_route():
  30. context = PROPAGATOR.extract(
  31. get_header_from_flask_request,
  32. flask.request
  33. )
  34. request_to_downstream = requests.Request(
  35. "GET", "http://httpbin.org/get"
  36. )
  37. PROPAGATOR.inject(
  38. set_header_into_requests_request,
  39. request_to_downstream,
  40. context=context
  41. )
  42. session = requests.Session()
  43. session.send(request_to_downstream.prepare())
  44. .. _Propagation API Specification:
  45. https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/api-propagators.md
  46. """
  47. from logging import getLogger
  48. from os import environ
  49. from opentelemetry.context.context import Context
  50. from opentelemetry.environment_variables import OTEL_PROPAGATORS
  51. from opentelemetry.propagators import composite, textmap
  52. logger = getLogger(__name__)
  53. def extract(
  54. carrier: textmap.CarrierT,
  55. context: Context | None = None,
  56. getter: textmap.Getter[textmap.CarrierT] = textmap.default_getter,
  57. ) -> Context:
  58. """Uses the configured propagator to extract a Context from the carrier.
  59. Args:
  60. getter: an object which contains a get function that can retrieve zero
  61. or more values from the carrier and a keys function that can get all the keys
  62. from carrier.
  63. carrier: and object which contains values that are
  64. used to construct a Context. This object
  65. must be paired with an appropriate getter
  66. which understands how to extract a value from it.
  67. context: an optional Context to use. Defaults to root
  68. context if not set.
  69. """
  70. return get_global_textmap().extract(carrier, context, getter=getter)
  71. def inject(
  72. carrier: textmap.CarrierT,
  73. context: Context | None = None,
  74. setter: textmap.Setter[textmap.CarrierT] = textmap.default_setter,
  75. ) -> None:
  76. """Uses the configured propagator to inject a Context into the carrier.
  77. Args:
  78. carrier: the medium used by Propagators to read
  79. values from and write values to.
  80. Should be paired with setter, which
  81. should know how to set header values on the carrier.
  82. context: An optional Context to use. Defaults to current
  83. context if not set.
  84. setter: An optional `Setter` object that can set values
  85. on the carrier.
  86. """
  87. get_global_textmap().inject(carrier, context=context, setter=setter)
  88. def _load_propagators() -> textmap.TextMapPropagator:
  89. configured = environ.get(OTEL_PROPAGATORS)
  90. if not configured:
  91. # pylint: disable=import-outside-toplevel,no-name-in-module
  92. from opentelemetry.baggage.propagation import ( # noqa: PLC0415
  93. W3CBaggagePropagator,
  94. )
  95. # pylint: disable=import-outside-toplevel,no-name-in-module
  96. from opentelemetry.trace.propagation.tracecontext import ( # noqa: PLC0415
  97. TraceContextTextMapPropagator,
  98. )
  99. return composite.CompositePropagator(
  100. [TraceContextTextMapPropagator(), W3CBaggagePropagator()]
  101. )
  102. # pylint: disable=import-outside-toplevel,no-name-in-module
  103. from opentelemetry.util._importlib_metadata import ( # noqa: PLC0415
  104. entry_points,
  105. )
  106. _propagators: list[textmap.TextMapPropagator] = []
  107. for _propagator in configured.split(","):
  108. _propagator = _propagator.strip()
  109. if _propagator.lower() == "none":
  110. logger.debug(
  111. "OTEL_PROPAGATORS environment variable contains none, removing all propagators"
  112. )
  113. return composite.CompositePropagator([])
  114. try:
  115. _propagators.append(
  116. next( # type: ignore
  117. iter( # type: ignore
  118. entry_points( # type: ignore[misc]
  119. group="opentelemetry_propagator",
  120. name=_propagator,
  121. )
  122. )
  123. ).load()()
  124. )
  125. except StopIteration:
  126. raise ValueError(
  127. f"Propagator {_propagator} not found. It is either misspelled or not installed."
  128. )
  129. except Exception: # pylint: disable=broad-exception-caught
  130. logger.exception("Failed to load propagator: %s", _propagator)
  131. raise
  132. return composite.CompositePropagator(_propagators)
  133. _HTTP_TEXT_FORMAT: textmap.TextMapPropagator = _load_propagators()
  134. # Deprecated: propagators, environ_propagators and propagator names were never intendended to be part of the public API.
  135. propagators: list[textmap.TextMapPropagator] = []
  136. environ_propagators = environ.get(OTEL_PROPAGATORS, "tracecontext,baggage")
  137. for propagator in environ_propagators.split(","): # type: ignore[assignment]
  138. propagator = propagator.strip()
  139. def get_global_textmap() -> textmap.TextMapPropagator:
  140. return _HTTP_TEXT_FORMAT
  141. def set_global_textmap(
  142. http_text_format: textmap.TextMapPropagator,
  143. ) -> None:
  144. global _HTTP_TEXT_FORMAT # pylint:disable=global-statement
  145. _HTTP_TEXT_FORMAT = http_text_format