Skip to content

Commit e6f82a7

Browse files
committed
wire host resource detector in declarative config
Makes _HostResourceDetector public as HostResourceDetector and wires it to detection_development.detectors[].host in _run_detectors(). Assisted-by: Claude Sonnet 4.6
1 parent 8fde77a commit e6f82a7

3 files changed

Lines changed: 81 additions & 4 deletions

File tree

opentelemetry-sdk/src/opentelemetry/sdk/_configuration/_resource.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from opentelemetry.sdk.resources import (
3030
_DEFAULT_RESOURCE,
3131
SERVICE_NAME,
32+
HostResourceDetector,
3233
Resource,
3334
)
3435

@@ -152,6 +153,8 @@ def _run_detectors(
152153
is updated in-place; later detectors overwrite earlier ones for the
153154
same key.
154155
"""
156+
if detector_config.host is not None:
157+
detected_attrs.update(HostResourceDetector().detect().attributes)
155158

156159

157160
def _filter_attributes(

opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -490,10 +490,8 @@ def detect(self) -> "Resource":
490490
)
491491

492492

493-
class _HostResourceDetector(ResourceDetector): # type: ignore[reportUnusedClass]
494-
"""
495-
The HostResourceDetector detects the hostname and architecture attributes.
496-
"""
493+
class HostResourceDetector(ResourceDetector):
494+
"""Detects host.name (hostname) and host.arch (CPU architecture)."""
497495

498496
def detect(self) -> "Resource":
499497
return Resource(

opentelemetry-sdk/tests/_configuration/test_resource.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,22 @@
1313
# limitations under the License.
1414

1515
import os
16+
import socket
1617
import unittest
1718
from unittest.mock import patch
1819

1920
from opentelemetry.sdk._configuration._resource import create_resource
2021
from opentelemetry.sdk._configuration.models import (
2122
AttributeNameValue,
2223
AttributeType,
24+
ExperimentalResourceDetection,
25+
ExperimentalResourceDetector,
26+
IncludeExclude,
2327
)
2428
from opentelemetry.sdk._configuration.models import Resource as ResourceConfig
2529
from opentelemetry.sdk.resources import (
30+
HOST_ARCH,
31+
HOST_NAME,
2632
SERVICE_NAME,
2733
TELEMETRY_SDK_LANGUAGE,
2834
TELEMETRY_SDK_NAME,
@@ -295,3 +301,73 @@ def test_attributes_list_invalid_pair_skipped(self):
295301
self.assertEqual(resource.attributes["foo"], "bar")
296302
self.assertNotIn("no-equals", resource.attributes)
297303
self.assertTrue(any("no-equals" in msg for msg in cm.output))
304+
305+
306+
class TestHostResourceDetector(unittest.TestCase):
307+
def _config_with_host(self) -> ResourceConfig:
308+
return ResourceConfig(
309+
detection_development=ExperimentalResourceDetection(
310+
detectors=[ExperimentalResourceDetector(host={})]
311+
)
312+
)
313+
314+
def test_host_detector_adds_host_attributes(self):
315+
resource = create_resource(self._config_with_host())
316+
self.assertIn(HOST_NAME, resource.attributes)
317+
self.assertEqual(resource.attributes[HOST_NAME], socket.gethostname())
318+
self.assertIn(HOST_ARCH, resource.attributes)
319+
320+
def test_host_detector_also_includes_sdk_defaults(self):
321+
resource = create_resource(self._config_with_host())
322+
self.assertEqual(resource.attributes[TELEMETRY_SDK_LANGUAGE], "python")
323+
self.assertIn(TELEMETRY_SDK_VERSION, resource.attributes)
324+
325+
def test_host_detector_not_run_when_absent(self):
326+
resource = create_resource(ResourceConfig())
327+
self.assertNotIn(HOST_NAME, resource.attributes)
328+
self.assertNotIn(HOST_ARCH, resource.attributes)
329+
330+
def test_host_detector_not_run_when_detection_development_is_none(self):
331+
resource = create_resource(ResourceConfig(detection_development=None))
332+
self.assertNotIn(HOST_NAME, resource.attributes)
333+
334+
def test_host_detector_not_run_when_detectors_list_empty(self):
335+
config = ResourceConfig(
336+
detection_development=ExperimentalResourceDetection(detectors=[])
337+
)
338+
resource = create_resource(config)
339+
self.assertNotIn(HOST_NAME, resource.attributes)
340+
341+
def test_explicit_attributes_override_host_detector(self):
342+
config = ResourceConfig(
343+
attributes=[
344+
AttributeNameValue(name="host.name", value="custom-host")
345+
],
346+
detection_development=ExperimentalResourceDetection(
347+
detectors=[ExperimentalResourceDetector(host={})]
348+
),
349+
)
350+
resource = create_resource(config)
351+
self.assertEqual(resource.attributes[HOST_NAME], "custom-host")
352+
353+
def test_included_filter_limits_host_attributes(self):
354+
config = ResourceConfig(
355+
detection_development=ExperimentalResourceDetection(
356+
detectors=[ExperimentalResourceDetector(host={})],
357+
attributes=IncludeExclude(included=["host.name"]),
358+
)
359+
)
360+
resource = create_resource(config)
361+
self.assertIn(HOST_NAME, resource.attributes)
362+
self.assertNotIn(HOST_ARCH, resource.attributes)
363+
364+
def test_excluded_filter_removes_host_attributes(self):
365+
config = ResourceConfig(
366+
detection_development=ExperimentalResourceDetection(
367+
detectors=[ExperimentalResourceDetector(host={})],
368+
attributes=IncludeExclude(excluded=["host.name"]),
369+
)
370+
)
371+
resource = create_resource(config)
372+
self.assertNotIn(HOST_NAME, resource.attributes)
373+
self.assertIn(HOST_ARCH, resource.attributes)

0 commit comments

Comments
 (0)