Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

- `opentelemetry-sdk`: add propagator plugin loading to declarative file configuration via the `opentelemetry_propagator` entry point group, matching the spec's PluginComponentProvider mechanism
([#5098](https://github.com/open-telemetry/opentelemetry-python/pull/5098))
- `opentelemetry-sdk`: add `additional_properties` support to generated config models via custom `datamodel-codegen` template, enabling plugin/custom component names to flow through typed dataclasses
([#5131](https://github.com/open-telemetry/opentelemetry-python/pull/5131))
- Fix incorrect code example in `create_tracer()` docstring
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,37 @@
TraceContextTextMapPropagator,
)


def _load_entry_point_propagator(name: str) -> TextMapPropagator:
"""Load and instantiate a propagator by name."""
return load_entry_point("opentelemetry_propagator", name)()
# Propagators bundled with the SDK — no entry point lookup needed.
_PROPAGATOR_REGISTRY: dict = {
"tracecontext": lambda _: TraceContextTextMapPropagator(),
"baggage": lambda _: W3CBaggagePropagator(),
}


def _propagators_from_textmap_config(
config: TextMapPropagatorConfig,
) -> list[TextMapPropagator]:
"""Resolve a single TextMapPropagator config entry to a list of propagators."""
"""Resolve a TextMapPropagator config to a list of propagators.

Known names (tracecontext, baggage) are bootstrapped directly via
_PROPAGATOR_REGISTRY. Known schema fields not in the registry (b3, b3multi)
and unknown plugin names from additional_properties are loaded via the
``opentelemetry_propagator`` entry point group.
"""
result: list[TextMapPropagator] = []
if config.tracecontext is not None:
result.append(TraceContextTextMapPropagator())
if config.baggage is not None:
result.append(W3CBaggagePropagator())
if config.b3 is not None:
result.append(_load_entry_point_propagator("b3"))
if config.b3multi is not None:
result.append(_load_entry_point_propagator("b3multi"))
for name in _PROPAGATOR_REGISTRY:
if getattr(config, name, None) is not None:
result.append(_PROPAGATOR_REGISTRY[name](getattr(config, name)))

# Known schema fields not in registry (b3, b3multi) — loaded via entry point
for name in ("b3", "b3multi"):
if getattr(config, name, None) is not None:
result.append(load_entry_point("opentelemetry_propagator", name)())

# Plugin propagators from additional_properties
for name in config.additional_properties:
result.append(load_entry_point("opentelemetry_propagator", name)())

return result


Expand Down Expand Up @@ -85,7 +97,7 @@ def create_propagator(
name = name.strip()
if not name or name.lower() == "none":
continue
propagator = _load_entry_point_propagator(name)
propagator = load_entry_point("opentelemetry_propagator", name)()
propagators.setdefault(type(propagator), propagator)

return CompositePropagator(list(propagators.values()))
Expand Down
34 changes: 34 additions & 0 deletions opentelemetry-sdk/tests/_configuration/test_propagator.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,40 @@ def test_unknown_composite_list_propagator_raises(self):
with self.assertRaises(ConfigurationError):
create_propagator(config)

def test_plugin_propagator_via_entry_point(self):
mock_propagator = MagicMock()
mock_ep = MagicMock()
mock_ep.load.return_value = lambda: mock_propagator

with patch(
"opentelemetry.sdk._configuration._common.entry_points",
return_value=[mock_ep],
):
config = PropagatorConfig(
composite=[
# pylint: disable=unexpected-keyword-arg
TextMapPropagatorConfig(my_custom_propagator={})
]
)
result = create_propagator(config)

self.assertEqual(len(result._propagators), 1) # type: ignore[attr-defined]
self.assertIs(result._propagators[0], mock_propagator) # type: ignore[attr-defined]

def test_unknown_composite_propagator_raises(self):
with patch(
"opentelemetry.sdk._configuration._common.entry_points",
return_value=[],
):
config = PropagatorConfig(
composite=[
# pylint: disable=unexpected-keyword-arg
TextMapPropagatorConfig(nonexistent={})
]
)
with self.assertRaises(ConfigurationError):
create_propagator(config)


class TestConfigurePropagator(unittest.TestCase):
def test_configure_propagator_calls_set_global_textmap(self):
Expand Down
Loading