From d283edbdd3db121429093818e9e4899d265c5196 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Tue, 11 Aug 2026 12:22:31 +0200 Subject: [PATCH 1/3] opentelemetry.configuration: fix default service name When the service name is unknown and the process executable name is available we should join them. --- .../opentelemetry/configuration/_resource.py | 5 +++- .../tests/test_resource.py | 23 ++++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/opentelemetry-configuration/src/opentelemetry/configuration/_resource.py b/opentelemetry-configuration/src/opentelemetry/configuration/_resource.py index 7d4a7a90f4..a150a2619f 100644 --- a/opentelemetry-configuration/src/opentelemetry/configuration/_resource.py +++ b/opentelemetry-configuration/src/opentelemetry/configuration/_resource.py @@ -7,6 +7,7 @@ import fnmatch import logging import os +import sys from collections.abc import Callable from typing import Any from urllib import parse @@ -101,7 +102,9 @@ def create_resource(config: ResourceConfig | None) -> Resource: """ # Spec requires service.name to always be present; detectors and explicit # config attributes can override this default. - base = _DEFAULT_RESOURCE.merge(Resource({SERVICE_NAME: "unknown_service"})) + executable_name = os.path.basename(sys.executable) if sys.executable else None + default_service_name = f"unknown_service:{executable_name}" if executable_name else "unknown_service" + base = _DEFAULT_RESOURCE.merge(Resource({SERVICE_NAME: default_service_name})) if config is None: return base diff --git a/opentelemetry-configuration/tests/test_resource.py b/opentelemetry-configuration/tests/test_resource.py index b550fadc0e..fec43d29cd 100644 --- a/opentelemetry-configuration/tests/test_resource.py +++ b/opentelemetry-configuration/tests/test_resource.py @@ -34,14 +34,16 @@ class TestCreateResourceDefaults(unittest.TestCase): + @patch("sys.executable", "/usr/bin/python3") def test_none_config_returns_sdk_defaults(self): resource = create_resource(None) self.assertIsInstance(resource, Resource) self.assertEqual(resource.attributes[TELEMETRY_SDK_LANGUAGE], "python") self.assertEqual(resource.attributes[TELEMETRY_SDK_NAME], "opentelemetry") self.assertIn(TELEMETRY_SDK_VERSION, resource.attributes) - self.assertEqual(resource.attributes[SERVICE_NAME], "unknown_service") + self.assertEqual(resource.attributes[SERVICE_NAME], "unknown_service:python3") + @patch("sys.executable", "/usr/bin/python3") def test_none_config_does_not_read_env_vars(self): with patch.dict( os.environ, @@ -52,23 +54,30 @@ def test_none_config_does_not_read_env_vars(self): ): resource = create_resource(None) self.assertNotIn("foo", resource.attributes) - self.assertEqual(resource.attributes[SERVICE_NAME], "unknown_service") + self.assertEqual(resource.attributes[SERVICE_NAME], "unknown_service:python3") + @patch("sys.executable", "/usr/bin/python3") def test_empty_resource_config(self): resource = create_resource(ResourceConfig()) self.assertEqual(resource.attributes[TELEMETRY_SDK_LANGUAGE], "python") - self.assertEqual(resource.attributes[SERVICE_NAME], "unknown_service") + self.assertEqual(resource.attributes[SERVICE_NAME], "unknown_service:python3") + @patch("sys.executable", "/usr/bin/python3") def test_service_name_default_added_when_missing(self): config = ResourceConfig(attributes=[AttributeNameValue(name="env", value="staging")]) resource = create_resource(config) - self.assertEqual(resource.attributes[SERVICE_NAME], "unknown_service") + self.assertEqual(resource.attributes[SERVICE_NAME], "unknown_service:python3") def test_service_name_not_overridden_when_set(self): config = ResourceConfig(attributes=[AttributeNameValue(name="service.name", value="my-app")]) resource = create_resource(config) self.assertEqual(resource.attributes[SERVICE_NAME], "my-app") + @patch("sys.executable", None) + def test_default_service_name_without_sys_executable_returns_plain_unkwnon_service(self): + resource = create_resource(None) + self.assertEqual(resource.attributes[SERVICE_NAME], "unknown_service") + def test_env_vars_not_read(self): """OTEL_RESOURCE_ATTRIBUTES must not affect declarative config resource.""" with patch.dict( @@ -294,10 +303,11 @@ def test_service_detector_reads_otel_service_name_env_var(self): resource = create_resource(self._config_with_service()) self.assertEqual(resource.attributes[SERVICE_NAME], "my-service") + @patch("sys.executable", "/usr/bin/python3") def test_service_detector_no_env_var_leaves_default_service_name(self): with patch.dict(os.environ, {}, clear=True): resource = create_resource(self._config_with_service()) - self.assertEqual(resource.attributes[SERVICE_NAME], "unknown_service") + self.assertEqual(resource.attributes[SERVICE_NAME], "unknown_service:python3") def test_explicit_service_name_overrides_env_var(self): """Config attributes win over the service detector's env-var value.""" @@ -333,6 +343,7 @@ def test_service_detector_also_includes_sdk_defaults(self): self.assertEqual(resource.attributes[TELEMETRY_SDK_LANGUAGE], "python") self.assertIn(TELEMETRY_SDK_VERSION, resource.attributes) + @patch("sys.executable", "/usr/bin/python3") def test_included_filter_limits_service_attributes(self): config = ResourceConfig( detection_development=ExperimentalResourceDetection( @@ -345,7 +356,7 @@ def test_included_filter_limits_service_attributes(self): self.assertIn(SERVICE_INSTANCE_ID, resource.attributes) # service.name comes from the filter-excluded detector output, but the # default "unknown_service" is still added by create_resource directly - self.assertEqual(resource.attributes[SERVICE_NAME], "unknown_service") + self.assertEqual(resource.attributes[SERVICE_NAME], "unknown_service:python3") class TestHostResourceDetector(unittest.TestCase): From f635a27d3d8b168f72f10f683f4c626235d1eff3 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Tue, 11 Aug 2026 12:39:28 +0200 Subject: [PATCH 2/3] Add changelog --- .changelog/5534.fixed | 1 + 1 file changed, 1 insertion(+) create mode 100644 .changelog/5534.fixed diff --git a/.changelog/5534.fixed b/.changelog/5534.fixed new file mode 100644 index 0000000000..795d2370f0 --- /dev/null +++ b/.changelog/5534.fixed @@ -0,0 +1 @@ +`opentelemetry-configuration`: add missing process executable name to default service name when available From 53efc3a72336bb16c3568bf456270db4bf51c630 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Tue, 11 Aug 2026 14:32:54 +0200 Subject: [PATCH 3/3] Improve changelog --- .changelog/5534.fixed | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/5534.fixed b/.changelog/5534.fixed index 795d2370f0..f56a5b9500 100644 --- a/.changelog/5534.fixed +++ b/.changelog/5534.fixed @@ -1 +1 @@ -`opentelemetry-configuration`: add missing process executable name to default service name when available +`opentelemetry-configuration`: add missing process executable name to default service name when available in resource attributes