Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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 `host` resource detector support to declarative file configuration via `detection_development.detectors[].host`
([#5002](https://github.com/open-telemetry/opentelemetry-python/pull/5002))
- `opentelemetry-sdk`: Add `create_resource` and `create_propagator`/`configure_propagator` to declarative file configuration, enabling Resource and propagator instantiation from config files without reading env vars
([#4979](https://github.com/open-telemetry/opentelemetry-python/pull/4979))
- `opentelemetry-sdk`: Map Python `CRITICAL` log level to OTel `FATAL` severity text per the specification
Expand Down
2 changes: 1 addition & 1 deletion opentelemetry-sdk/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ console = "opentelemetry.sdk.trace.export:ConsoleSpanExporter"
otel = "opentelemetry.sdk.resources:OTELResourceDetector"
process = "opentelemetry.sdk.resources:ProcessResourceDetector"
os = "opentelemetry.sdk.resources:OsResourceDetector"
host = "opentelemetry.sdk.resources:_HostResourceDetector"
host = "opentelemetry.sdk.resources:HostResourceDetector"

[project.urls]
Homepage = "https://github.com/open-telemetry/opentelemetry-python/tree/main/opentelemetry-sdk"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from opentelemetry.sdk.resources import (
_DEFAULT_RESOURCE,
SERVICE_NAME,
HostResourceDetector,
Resource,
)

Expand Down Expand Up @@ -149,6 +150,8 @@ def _run_detectors(
is updated in-place; later detectors overwrite earlier ones for the
same key.
"""
if detector_config.host is not None:
detected_attrs.update(HostResourceDetector().detect().attributes)


def _filter_attributes(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -490,10 +490,8 @@ def detect(self) -> "Resource":
)


class _HostResourceDetector(ResourceDetector): # type: ignore[reportUnusedClass]
"""
The HostResourceDetector detects the hostname and architecture attributes.
"""
class HostResourceDetector(ResourceDetector):
"""Detects host.name (hostname) and host.arch (CPU architecture)."""

def detect(self) -> "Resource":
return Resource(
Expand Down
77 changes: 77 additions & 0 deletions opentelemetry-sdk/tests/_configuration/test_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,22 @@
# limitations under the License.

import os
import socket
import unittest
from unittest.mock import patch

from opentelemetry.sdk._configuration._resource import create_resource
from opentelemetry.sdk._configuration.models import (
AttributeNameValue,
AttributeType,
ExperimentalResourceDetection,
ExperimentalResourceDetector,
IncludeExclude,
)
from opentelemetry.sdk._configuration.models import Resource as ResourceConfig
from opentelemetry.sdk.resources import (
HOST_ARCH,
HOST_NAME,
SERVICE_NAME,
TELEMETRY_SDK_LANGUAGE,
TELEMETRY_SDK_NAME,
Expand Down Expand Up @@ -295,3 +301,74 @@ def test_attributes_list_invalid_pair_skipped(self):
self.assertEqual(resource.attributes["foo"], "bar")
self.assertNotIn("no-equals", resource.attributes)
self.assertTrue(any("no-equals" in msg for msg in cm.output))


class TestHostResourceDetector(unittest.TestCase):
@staticmethod
def _config_with_host() -> ResourceConfig:
return ResourceConfig(
detection_development=ExperimentalResourceDetection(
detectors=[ExperimentalResourceDetector(host={})]
)
)

def test_host_detector_adds_host_attributes(self):
resource = create_resource(self._config_with_host())
self.assertIn(HOST_NAME, resource.attributes)
self.assertEqual(resource.attributes[HOST_NAME], socket.gethostname())
self.assertIn(HOST_ARCH, resource.attributes)

def test_host_detector_also_includes_sdk_defaults(self):
resource = create_resource(self._config_with_host())
self.assertEqual(resource.attributes[TELEMETRY_SDK_LANGUAGE], "python")
self.assertIn(TELEMETRY_SDK_VERSION, resource.attributes)

def test_host_detector_not_run_when_absent(self):
resource = create_resource(ResourceConfig())
self.assertNotIn(HOST_NAME, resource.attributes)
self.assertNotIn(HOST_ARCH, resource.attributes)

def test_host_detector_not_run_when_detection_development_is_none(self):
resource = create_resource(ResourceConfig(detection_development=None))
self.assertNotIn(HOST_NAME, resource.attributes)

def test_host_detector_not_run_when_detectors_list_empty(self):
config = ResourceConfig(
detection_development=ExperimentalResourceDetection(detectors=[])
)
resource = create_resource(config)
self.assertNotIn(HOST_NAME, resource.attributes)

def test_explicit_attributes_override_host_detector(self):
config = ResourceConfig(
attributes=[
AttributeNameValue(name="host.name", value="custom-host")
],
detection_development=ExperimentalResourceDetection(
detectors=[ExperimentalResourceDetector(host={})]
),
)
resource = create_resource(config)
self.assertEqual(resource.attributes[HOST_NAME], "custom-host")

def test_included_filter_limits_host_attributes(self):
config = ResourceConfig(
detection_development=ExperimentalResourceDetection(
detectors=[ExperimentalResourceDetector(host={})],
attributes=IncludeExclude(included=["host.name"]),
)
)
resource = create_resource(config)
self.assertIn(HOST_NAME, resource.attributes)
self.assertNotIn(HOST_ARCH, resource.attributes)

def test_excluded_filter_removes_host_attributes(self):
config = ResourceConfig(
detection_development=ExperimentalResourceDetection(
detectors=[ExperimentalResourceDetector(host={})],
attributes=IncludeExclude(excluded=["host.name"]),
)
)
resource = create_resource(config)
self.assertNotIn(HOST_NAME, resource.attributes)
self.assertIn(HOST_ARCH, resource.attributes)
4 changes: 2 additions & 2 deletions opentelemetry-sdk/tests/resources/test_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@
TELEMETRY_SDK_LANGUAGE,
TELEMETRY_SDK_NAME,
TELEMETRY_SDK_VERSION,
HostResourceDetector,
OsResourceDetector,
OTELResourceDetector,
ProcessResourceDetector,
Resource,
ResourceDetector,
_HostResourceDetector,
get_aggregated_resources,
)

Expand Down Expand Up @@ -813,7 +813,7 @@ class TestHostResourceDetector(unittest.TestCase):
@patch("platform.machine", lambda: "AMD64")
def test_host_resource_detector(self):
resource = get_aggregated_resources(
[_HostResourceDetector()],
[HostResourceDetector()],
Resource({}),
)
self.assertEqual(resource.attributes[HOST_NAME], "foo")
Expand Down
Loading