-
Notifications
You must be signed in to change notification settings - Fork 867
feat(config): generic resource detector plugin loading for declarative config #5129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5c5e868
7e6739d
808a956
70204ee
a156db5
fb81ae3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,13 +14,15 @@ | |
|
|
||
| from __future__ import annotations | ||
|
|
||
| import dataclasses | ||
| import fnmatch | ||
| import logging | ||
| import os | ||
| import uuid | ||
| from typing import Callable, Optional | ||
| from urllib import parse | ||
|
|
||
| from opentelemetry.sdk._configuration._common import load_entry_point | ||
| from opentelemetry.sdk._configuration.models import ( | ||
| AttributeNameValue, | ||
| AttributeType, | ||
|
|
@@ -37,7 +39,6 @@ | |
| Resource, | ||
| _HostResourceDetector, | ||
| ) | ||
| from opentelemetry.util._importlib_metadata import entry_points | ||
|
|
||
| _logger = logging.getLogger(__name__) | ||
|
|
||
|
|
@@ -146,55 +147,56 @@ def create_resource(config: Optional[ResourceConfig]) -> Resource: | |
| return result.merge(config_resource) | ||
|
|
||
|
|
||
| def _detect_service(_config) -> dict[str, object]: | ||
| """Service detector: generates instance ID and reads OTEL_SERVICE_NAME.""" | ||
| attrs: dict[str, object] = { | ||
| SERVICE_INSTANCE_ID: str(uuid.uuid4()), | ||
| } | ||
| service_name = os.environ.get(OTEL_SERVICE_NAME) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: use the walrus operator to save a line ?
|
||
| if service_name: | ||
| attrs[SERVICE_NAME] = service_name | ||
| return attrs | ||
|
|
||
|
|
||
| _RESOURCE_DETECTOR_REGISTRY: dict = { | ||
| "service": _detect_service, | ||
| "host": lambda _: dict(_HostResourceDetector().detect().attributes), | ||
| "process": lambda _: dict(ProcessResourceDetector().detect().attributes), | ||
| } | ||
|
|
||
|
|
||
| def _run_detectors( | ||
| detector_config: ExperimentalResourceDetector, | ||
| detected_attrs: dict[str, object], | ||
| ) -> None: | ||
| """Run any detectors present in a single detector config entry. | ||
| """Run detectors present in a single detector config entry. | ||
|
|
||
| Each detector PR adds its own branch here. The detected_attrs dict | ||
| is updated in-place; later detectors overwrite earlier ones for the | ||
| same key. | ||
| Known detectors (service, host, process) are handled directly via | ||
| _RESOURCE_DETECTOR_REGISTRY. All other detectors — including known | ||
| schema fields like container that require contrib packages, and | ||
| unknown plugin detectors captured in additional_properties — are | ||
| loaded via the ``opentelemetry_resource_detector`` entry point group. | ||
|
|
||
| The detected_attrs dict is updated in-place; later detectors overwrite | ||
| earlier ones for the same key. | ||
| """ | ||
| if detector_config.service is not None: | ||
| attrs: dict[str, object] = { | ||
| SERVICE_INSTANCE_ID: str(uuid.uuid4()), | ||
| } | ||
| service_name = os.environ.get(OTEL_SERVICE_NAME) | ||
| if service_name: | ||
| attrs[SERVICE_NAME] = service_name | ||
| detected_attrs.update(attrs) | ||
|
|
||
| if detector_config.host is not None: | ||
| detected_attrs.update(_HostResourceDetector().detect().attributes) | ||
|
|
||
| if detector_config.container is not None: | ||
| # The container detector is not part of the core SDK. It is provided | ||
| # by the opentelemetry-resource-detector-containerid contrib package, | ||
| # which registers itself under the opentelemetry_resource_detector | ||
| # entry point group as "container". Loading via entry point matches | ||
| # the env-var config counterpart (OTEL_EXPERIMENTAL_RESOURCE_DETECTORS) | ||
| # and avoids a hard import dependency on contrib. See also: | ||
| # https://github.com/open-telemetry/opentelemetry-configuration/issues/570 | ||
| ep = next( | ||
| iter( | ||
| entry_points( | ||
| group="opentelemetry_resource_detector", name="container" | ||
| ) | ||
| ), | ||
| None, | ||
| ) | ||
| if ep is None: | ||
| _logger.warning( | ||
| "container resource detector requested but " | ||
| "'opentelemetry-resource-detector-containerid' is not " | ||
| "installed; install it to enable container detection" | ||
| for name in dataclasses.fields(detector_config): | ||
| value = getattr(detector_config, name.name, None) | ||
| if value is None: | ||
| continue | ||
| if name.name in _RESOURCE_DETECTOR_REGISTRY: | ||
| detected_attrs.update( | ||
| _RESOURCE_DETECTOR_REGISTRY[name.name](value) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we just discard |
||
| ) | ||
| else: | ||
| detected_attrs.update(ep.load()().detect().attributes) | ||
| cls = load_entry_point( | ||
| "opentelemetry_resource_detector", name.name | ||
| ) | ||
| detected_attrs.update(cls().detect().attributes) | ||
|
|
||
| if detector_config.process is not None: | ||
| detected_attrs.update(ProcessResourceDetector().detect().attributes) | ||
| for name in detector_config.additional_properties: | ||
| cls = load_entry_point("opentelemetry_resource_detector", name) | ||
| detected_attrs.update(cls().detect().attributes) | ||
|
|
||
|
|
||
| def _filter_attributes( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the argument to this function is not used ?