From 5945e967e9796f4762dce752351db5b807e80f5b Mon Sep 17 00:00:00 2001 From: Shashank RM Date: Tue, 18 Aug 2026 21:24:05 +0530 Subject: [PATCH 01/11] [RESOURCE DETECTOR] Add service detector utilities for #4414 --- resource_detectors/BUILD | 15 +++ resource_detectors/CMakeLists.txt | 16 +++ .../detail/process_detector_utils.h | 12 +++ .../detail/service_detector_utils.h | 34 ++++++ .../src/process_detector_utils.cc | 44 ++++++++ .../src/service_detector_utils.cc | 102 ++++++++++++++++++ resource_detectors/test/BUILD | 12 +++ resource_detectors/test/CMakeLists.txt | 14 +++ .../test/process_detector_test.cc | 9 ++ .../test/service_detector_utils_test.cc | 69 ++++++++++++ 10 files changed, 327 insertions(+) create mode 100644 resource_detectors/include/opentelemetry/resource_detectors/detail/service_detector_utils.h create mode 100644 resource_detectors/src/service_detector_utils.cc create mode 100644 resource_detectors/test/service_detector_utils_test.cc diff --git a/resource_detectors/BUILD b/resource_detectors/BUILD index 83af6d4a7a..68a25de9e1 100644 --- a/resource_detectors/BUILD +++ b/resource_detectors/BUILD @@ -95,6 +95,21 @@ cc_library( ], ) +cc_library( + name = "service_resource_detector_utils", + srcs = ["src/service_detector_utils.cc"], + copts = ["-fexceptions"], + deps = [ + ":process_resource_detector", + "//api", + "//resource_detectors:headers", + "//sdk:headers", + "//sdk/src/common:env_variables", + "//sdk/src/common:random", + "//sdk/src/resource", + ], +) + # Convenience target linking all resource detectors. cc_library( name = "resource_detectors", diff --git a/resource_detectors/CMakeLists.txt b/resource_detectors/CMakeLists.txt index 8ec9d7ece1..1f87a3046a 100644 --- a/resource_detectors/CMakeLists.txt +++ b/resource_detectors/CMakeLists.txt @@ -136,6 +136,22 @@ target_link_libraries( PRIVATE opentelemetry_process_resource_detector opentelemetry_configuration_core) +# +# opentelemetry_service_resource_detector_utils +# + +add_library(opentelemetry_service_resource_detector_utils + src/service_detector_utils.cc) + +target_link_libraries( + opentelemetry_service_resource_detector_utils + PUBLIC opentelemetry_resources + PRIVATE opentelemetry_process_resource_detector) +target_include_directories( + opentelemetry_service_resource_detector_utils + PUBLIC "$" + "$") + # # opentelemetry_resource_detectors (interface to all detectors) # diff --git a/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h b/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h index 4cd6a12382..82086b4ae8 100644 --- a/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h +++ b/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h @@ -32,6 +32,18 @@ std::string FormFilePath(const int32_t &pid, const char *process_type); */ std::string GetExecutablePath(const int32_t &pid); +/** + * Retrieves the executable file name for a given PID. + * Platform-specific behavior: + * - Windows: Basename of the path from GetExecutablePath(). + * - Linux: Basename of the path from /proc//exe. + * - macOS: Uses _NSGetExecutablePath() for the current process only; returns + * an empty string for other PIDs. + * + * @param pid Process ID. + */ +std::string GetExecutableName(const int32_t &pid); + /** * Extracts the command-line arguments and the command. * Platform-specific behavior: diff --git a/resource_detectors/include/opentelemetry/resource_detectors/detail/service_detector_utils.h b/resource_detectors/include/opentelemetry/resource_detectors/detail/service_detector_utils.h new file mode 100644 index 0000000000..1abf8622b4 --- /dev/null +++ b/resource_detectors/include/opentelemetry/resource_detectors/detail/service_detector_utils.h @@ -0,0 +1,34 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace resource_detector +{ +namespace detail +{ + +/** + * Resolves the logical service name for the service resource detector. + * Platform-specific behavior: + * - Reads OTEL_SERVICE_NAME when set. + * - Otherwise falls back to unknown_service: when the + * executable name is available for the current process. + * - Otherwise returns unknown_service. + */ +std::string GetServiceName(); + +/** + * Returns a stable service.instance.id for the current process. + * A new RFC 4122 UUID version 4 value is generated when the process ID changes. + */ +std::string GenerateServiceInstanceId() noexcept; + +} // namespace detail +} // namespace resource_detector +OPENTELEMETRY_END_NAMESPACE diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index 9da40a52a8..c250008403 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -7,6 +7,10 @@ #include #include +#if defined(__APPLE__) +# include +#endif + #ifdef _MSC_VER // clang-format off # include @@ -31,6 +35,25 @@ namespace detail constexpr const char *kExecutableName = "exe"; constexpr const char *kCmdlineName = "cmdline"; +namespace +{ +std::string Basename(const std::string &path) +{ + if (path.empty()) + { + return std::string(); + } + + const size_t pos = path.find_last_of("/\\"); + if (pos == std::string::npos) + { + return path; + } + + return path.substr(pos + 1); +} +} // namespace + std::string GetExecutablePath(const int32_t &pid) { #ifdef _MSC_VER @@ -71,6 +94,27 @@ std::string GetExecutablePath(const int32_t &pid) #endif } +std::string GetExecutableName(const int32_t &pid) +{ +#if defined(__APPLE__) + if (pid != static_cast(getpid())) + { + return std::string(); + } + + char path[4096]; + uint32_t size = sizeof(path); + if (_NSGetExecutablePath(path, &size) != 0) + { + return std::string(); + } + + return Basename(path); +#else + return Basename(GetExecutablePath(pid)); +#endif +} + std::vector ExtractCommandWithArgs(const std::string &command_line_path) { std::vector commands; diff --git a/resource_detectors/src/service_detector_utils.cc b/resource_detectors/src/service_detector_utils.cc new file mode 100644 index 0000000000..17ab60c96a --- /dev/null +++ b/resource_detectors/src/service_detector_utils.cc @@ -0,0 +1,102 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/resource_detectors/detail/service_detector_utils.h" + +#include +#include +#include + +#ifdef _MSC_VER +# include +# define getpid _getpid +#else +# include +#endif + +#include "opentelemetry/nostd/span.h" +#include "opentelemetry/resource_detectors/detail/process_detector_utils.h" +#include "opentelemetry/sdk/common/env_variables.h" +#include "opentelemetry/version.h" +#include "src/common/random.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace resource_detector +{ +namespace detail +{ + +namespace +{ +constexpr const char *kOtelServiceName = "OTEL_SERVICE_NAME"; +constexpr const char *kUnknownService = "unknown_service"; +constexpr const char *kUnknownServicePrefix = "unknown_service:"; +constexpr const char kUuidHexDigits[] = "0123456789abcdef"; + +std::string FormatUuidV4(const uint8_t bytes[16]) noexcept +{ + std::string uuid; + uuid.reserve(36); + for (size_t i = 0; i < 16; ++i) + { + if (i == 4 || i == 6 || i == 8 || i == 10) + { + uuid.push_back('-'); + } + uuid.push_back(kUuidHexDigits[bytes[i] >> 4]); + uuid.push_back(kUuidHexDigits[bytes[i] & 0x0F]); + } + return uuid; +} + +std::string GenerateUuidV4() noexcept +{ + uint8_t bytes[16]; + opentelemetry::sdk::common::Random::GenerateRandomBuffer( + opentelemetry::nostd::span(bytes)); + bytes[6] = static_cast((bytes[6] & 0x0F) | 0x40); + bytes[8] = static_cast((bytes[8] & 0x3F) | 0x80); + return FormatUuidV4(bytes); +} + +} // namespace + +std::string GetServiceName() +{ + std::string service_name; + if (opentelemetry::sdk::common::GetStringEnvironmentVariable(kOtelServiceName, service_name) && + !service_name.empty()) + { + return service_name; + } + + const std::string executable_name = GetExecutableName(static_cast(getpid())); + if (!executable_name.empty()) + { + std::string fallback_service_name(kUnknownServicePrefix); + fallback_service_name.append(executable_name); + return fallback_service_name; + } + + return std::string{kUnknownService}; +} + +std::string GenerateServiceInstanceId() noexcept +{ + static std::mutex mutex; + static int32_t cached_pid = -1; + static std::string cached_id; + + const int32_t pid = static_cast(getpid()); + const std::lock_guard lock(mutex); + if (cached_pid != pid || cached_id.empty()) + { + cached_pid = pid; + cached_id = GenerateUuidV4(); + } + return cached_id; +} + +} // namespace detail +} // namespace resource_detector +OPENTELEMETRY_END_NAMESPACE diff --git a/resource_detectors/test/BUILD b/resource_detectors/test/BUILD index 9438ec1a4d..110b0d86e1 100644 --- a/resource_detectors/test/BUILD +++ b/resource_detectors/test/BUILD @@ -82,3 +82,15 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "service_resource_detector_utils_test", + srcs = ["service_detector_utils_test.cc"], + tags = ["test"], + deps = [ + "//resource_detectors:process_resource_detector", + "//resource_detectors:service_resource_detector_utils", + "//sdk/src/resource", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/resource_detectors/test/CMakeLists.txt b/resource_detectors/test/CMakeLists.txt index c53738426b..fb3f8c815c 100644 --- a/resource_detectors/test/CMakeLists.txt +++ b/resource_detectors/test/CMakeLists.txt @@ -85,3 +85,17 @@ gtest_add_tests( TARGET process_resource_detector_builder_test TEST_PREFIX resource_detector. TEST_LIST process_resource_detector_builder_test) + +# +# service_resource_detector_utils tests +# + +add_executable(service_resource_detector_utils_test service_detector_utils_test.cc) +target_link_libraries( + service_resource_detector_utils_test + PRIVATE opentelemetry_service_resource_detector_utils + opentelemetry_process_resource_detector GTest::gtest_main) +gtest_add_tests( + TARGET service_resource_detector_utils_test + TEST_PREFIX resource_detector. + TEST_LIST service_resource_detector_utils_test) diff --git a/resource_detectors/test/process_detector_test.cc b/resource_detectors/test/process_detector_test.cc index 4782c18d22..3db2302ba0 100644 --- a/resource_detectors/test/process_detector_test.cc +++ b/resource_detectors/test/process_detector_test.cc @@ -112,6 +112,15 @@ TEST(ProcessDetectorUtilsTest, GetExecutablePathTest) EXPECT_EQ(path, expected_path); } +TEST(ProcessDetectorUtilsTest, GetExecutableNameTest) +{ + int32_t pid = getpid(); + std::string executable_name = opentelemetry::resource_detector::detail::GetExecutableName(pid); + EXPECT_FALSE(executable_name.empty()); + EXPECT_EQ(executable_name.find('/'), std::string::npos); + EXPECT_EQ(executable_name.find('\\'), std::string::npos); +} + TEST(ProcessDetectorUtilsTest, CommandTest) { int32_t pid = getpid(); diff --git a/resource_detectors/test/service_detector_utils_test.cc b/resource_detectors/test/service_detector_utils_test.cc new file mode 100644 index 0000000000..9e53245b10 --- /dev/null +++ b/resource_detectors/test/service_detector_utils_test.cc @@ -0,0 +1,69 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include +#include + +#ifdef _MSC_VER +# include "opentelemetry/sdk/common/env_variables.h" +using opentelemetry::sdk::common::setenv; +using opentelemetry::sdk::common::unsetenv; +#else +# include +#endif + +#include "opentelemetry/resource_detectors/detail/service_detector_utils.h" + +namespace detail = opentelemetry::resource_detector::detail; + +namespace +{ +constexpr const char *kOtelServiceName = "OTEL_SERVICE_NAME"; + +bool IsUuidV4(const std::string &value) +{ + static const std::regex kUuidV4Pattern( + "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"); + return std::regex_match(value, kUuidV4Pattern); +} +} // namespace + +TEST(ServiceDetectorUtilsTest, GetServiceNameFromEnvironment) +{ + setenv(kOtelServiceName, "stage1-test-service", 1); + + EXPECT_EQ(detail::GetServiceName(), std::string{"stage1-test-service"}); + + unsetenv(kOtelServiceName); +} + +TEST(ServiceDetectorUtilsTest, GetServiceNameFallbackUsesUnknownServicePrefix) +{ + unsetenv(kOtelServiceName); + + const std::string service_name = detail::GetServiceName(); + if (service_name.rfind("unknown_service:", 0) == 0) + { + EXPECT_GT(service_name.size(), std::string{"unknown_service:"}.size()); + } + else + { + EXPECT_EQ(service_name, std::string{"unknown_service"}); + } +} + +TEST(ServiceDetectorUtilsTest, GenerateServiceInstanceIdIsUuidV4) +{ + const std::string instance_id = detail::GenerateServiceInstanceId(); + EXPECT_FALSE(instance_id.empty()); + EXPECT_TRUE(IsUuidV4(instance_id)); +} + +TEST(ServiceDetectorUtilsTest, GenerateServiceInstanceIdIsStableWithinProcess) +{ + const std::string first_id = detail::GenerateServiceInstanceId(); + const std::string second_id = detail::GenerateServiceInstanceId(); + EXPECT_EQ(first_id, second_id); +} From 7c2f2388e48a29cda103934815c24de4a8e3c837 Mon Sep 17 00:00:00 2001 From: Shashank RM Date: Tue, 18 Aug 2026 22:00:33 +0530 Subject: [PATCH 02/11] [RESOURCE DETECTOR] Add the service resource detector (#4414) --- resource_detectors/BUILD | 13 ++++ resource_detectors/CMakeLists.txt | 17 +++++ .../resource_detectors/service_detector.h | 33 +++++++++ resource_detectors/src/service_detector.cc | 27 +++++++ resource_detectors/test/BUILD | 11 +++ resource_detectors/test/CMakeLists.txt | 13 ++++ .../test/service_detector_test.cc | 74 +++++++++++++++++++ 7 files changed, 188 insertions(+) create mode 100644 resource_detectors/include/opentelemetry/resource_detectors/service_detector.h create mode 100644 resource_detectors/src/service_detector.cc create mode 100644 resource_detectors/test/service_detector_test.cc diff --git a/resource_detectors/BUILD b/resource_detectors/BUILD index 68a25de9e1..2936523dd6 100644 --- a/resource_detectors/BUILD +++ b/resource_detectors/BUILD @@ -110,6 +110,19 @@ cc_library( ], ) +cc_library( + name = "service_resource_detector", + srcs = ["src/service_detector.cc"], + copts = ["-fexceptions"], + deps = [ + ":service_resource_detector_utils", + "//api", + "//resource_detectors:headers", + "//sdk:headers", + "//sdk/src/resource", + ], +) + # Convenience target linking all resource detectors. cc_library( name = "resource_detectors", diff --git a/resource_detectors/CMakeLists.txt b/resource_detectors/CMakeLists.txt index 1f87a3046a..6509aa418c 100644 --- a/resource_detectors/CMakeLists.txt +++ b/resource_detectors/CMakeLists.txt @@ -152,6 +152,23 @@ target_include_directories( PUBLIC "$" "$") +# +# opentelemetry_service_resource_detector +# + +add_library(opentelemetry_service_resource_detector src/service_detector.cc) + +set_target_properties(opentelemetry_service_resource_detector + PROPERTIES EXPORT_NAME service_resource_detector) +set_target_version(opentelemetry_service_resource_detector) + +target_link_libraries(opentelemetry_service_resource_detector + PUBLIC opentelemetry_service_resource_detector_utils) +target_include_directories( + opentelemetry_service_resource_detector + PUBLIC "$" + "$") + # # opentelemetry_resource_detectors (interface to all detectors) # diff --git a/resource_detectors/include/opentelemetry/resource_detectors/service_detector.h b/resource_detectors/include/opentelemetry/resource_detectors/service_detector.h new file mode 100644 index 0000000000..8d321235d9 --- /dev/null +++ b/resource_detectors/include/opentelemetry/resource_detectors/service_detector.h @@ -0,0 +1,33 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/sdk/resource/resource_detector.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace resource_detector +{ + +/** + * ServiceResourceDetector to detect resource attributes describing the service + * the process belongs to. It sets service.name and service.instance.id following + * the OpenTelemetry semantic conventions. + * + * Platform specific behavior and limitations: + * - service.name is read from the OTEL_SERVICE_NAME environment variable when set. + * - When OTEL_SERVICE_NAME is not set, service.name falls back to + * unknown_service: or unknown_service when the + * executable name is unavailable. + * - service.instance.id is a stable RFC 4122 UUID version 4 value for the + * current process. + */ +class ServiceResourceDetector : public opentelemetry::sdk::resource::ResourceDetector +{ +public: + opentelemetry::sdk::resource::Resource Detect() noexcept override; +}; + +} // namespace resource_detector +OPENTELEMETRY_END_NAMESPACE diff --git a/resource_detectors/src/service_detector.cc b/resource_detectors/src/service_detector.cc new file mode 100644 index 0000000000..ea1da10596 --- /dev/null +++ b/resource_detectors/src/service_detector.cc @@ -0,0 +1,27 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/resource_detectors/service_detector.h" +#include "opentelemetry/resource_detectors/detail/service_detector_utils.h" +#include "opentelemetry/sdk/resource/resource.h" +#include "opentelemetry/sdk/resource/resource_detector.h" +#include "opentelemetry/semconv/schema_url.h" +#include "opentelemetry/semconv/service_attributes.h" +#include "opentelemetry/version.h" + +#include + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace resource_detector +{ + +opentelemetry::sdk::resource::Resource ServiceResourceDetector::Detect() noexcept +{ + opentelemetry::sdk::resource::ResourceAttributes attributes; + attributes[semconv::service::kServiceName] = detail::GetServiceName(); + attributes[semconv::service::kServiceInstanceId] = detail::GenerateServiceInstanceId(); + return ResourceDetector::Create(attributes, semconv::kSchemaUrl); +} + +} // namespace resource_detector +OPENTELEMETRY_END_NAMESPACE diff --git a/resource_detectors/test/BUILD b/resource_detectors/test/BUILD index 110b0d86e1..16c6645193 100644 --- a/resource_detectors/test/BUILD +++ b/resource_detectors/test/BUILD @@ -94,3 +94,14 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "service_resource_detector_test", + srcs = ["service_detector_test.cc"], + tags = ["test"], + deps = [ + "//resource_detectors:service_resource_detector", + "//sdk/src/resource", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/resource_detectors/test/CMakeLists.txt b/resource_detectors/test/CMakeLists.txt index fb3f8c815c..a85f3306c0 100644 --- a/resource_detectors/test/CMakeLists.txt +++ b/resource_detectors/test/CMakeLists.txt @@ -99,3 +99,16 @@ gtest_add_tests( TARGET service_resource_detector_utils_test TEST_PREFIX resource_detector. TEST_LIST service_resource_detector_utils_test) + +# +# service_resource_detector tests +# + +add_executable(service_resource_detector_test service_detector_test.cc) +target_link_libraries( + service_resource_detector_test PRIVATE opentelemetry_service_resource_detector + GTest::gtest_main) +gtest_add_tests( + TARGET service_resource_detector_test + TEST_PREFIX resource_detector. + TEST_LIST service_resource_detector_test) diff --git a/resource_detectors/test/service_detector_test.cc b/resource_detectors/test/service_detector_test.cc new file mode 100644 index 0000000000..f9120170f4 --- /dev/null +++ b/resource_detectors/test/service_detector_test.cc @@ -0,0 +1,74 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +#ifdef _MSC_VER +# include "opentelemetry/sdk/common/env_variables.h" +using opentelemetry::sdk::common::setenv; +using opentelemetry::sdk::common::unsetenv; +#else +# include +#endif + +#include "opentelemetry/nostd/variant.h" +#include "opentelemetry/resource_detectors/detail/service_detector_utils.h" +#include "opentelemetry/resource_detectors/service_detector.h" +#include "opentelemetry/semconv/schema_url.h" +#include "opentelemetry/semconv/service_attributes.h" + +namespace semconv = opentelemetry::semconv; + +namespace +{ +constexpr const char *kOtelServiceName = "OTEL_SERVICE_NAME"; +} // namespace + +TEST(ServiceDetectorTest, DetectSetsServiceAttributes) +{ + opentelemetry::resource_detector::ServiceResourceDetector detector; + auto resource = detector.Detect(); + const auto &attrs = resource.GetAttributes(); + + auto name_it = attrs.find(semconv::service::kServiceName); + ASSERT_NE(name_it, attrs.end()); + EXPECT_FALSE(opentelemetry::nostd::get(name_it->second).empty()); + + auto instance_id_it = attrs.find(semconv::service::kServiceInstanceId); + ASSERT_NE(instance_id_it, attrs.end()); + EXPECT_EQ(opentelemetry::nostd::get(instance_id_it->second), + opentelemetry::resource_detector::detail::GenerateServiceInstanceId()); + + EXPECT_EQ(resource.GetSchemaURL(), std::string{semconv::kSchemaUrl}); +} + +TEST(ServiceDetectorTest, DetectUsesServiceNameFromEnvironment) +{ + setenv(kOtelServiceName, "stage2-detector-service", 1); + + opentelemetry::resource_detector::ServiceResourceDetector detector; + auto resource = detector.Detect(); + const auto &attrs = resource.GetAttributes(); + + auto name_it = attrs.find(semconv::service::kServiceName); + ASSERT_NE(name_it, attrs.end()); + EXPECT_EQ(opentelemetry::nostd::get(name_it->second), + std::string{"stage2-detector-service"}); + + unsetenv(kOtelServiceName); +} + +TEST(ServiceDetectorTest, DetectUsesServiceNameFallbackWhenEnvUnset) +{ + unsetenv(kOtelServiceName); + + opentelemetry::resource_detector::ServiceResourceDetector detector; + auto resource = detector.Detect(); + const auto &attrs = resource.GetAttributes(); + + auto name_it = attrs.find(semconv::service::kServiceName); + ASSERT_NE(name_it, attrs.end()); + EXPECT_EQ(opentelemetry::nostd::get(name_it->second), + opentelemetry::resource_detector::detail::GetServiceName()); +} From 94ccd061045636ad7eeab75bceba530625d69ae3 Mon Sep 17 00:00:00 2001 From: Shashank RM Date: Wed, 19 Aug 2026 06:47:49 +0530 Subject: [PATCH 03/11] [RESOURCE DETECTOR] Add service detector builder (#4414) --- resource_detectors/BUILD | 11 +++++ resource_detectors/CMakeLists.txt | 34 ++++++++++++++- .../service_detector_builder.h | 37 +++++++++++++++++ .../src/service_detector_builder.cc | 32 +++++++++++++++ resource_detectors/test/BUILD | 12 ++++++ resource_detectors/test/CMakeLists.txt | 14 +++++++ .../test/service_detector_builder_test.cc | 41 +++++++++++++++++++ 7 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 resource_detectors/include/opentelemetry/resource_detectors/service_detector_builder.h create mode 100644 resource_detectors/src/service_detector_builder.cc create mode 100644 resource_detectors/test/service_detector_builder_test.cc diff --git a/resource_detectors/BUILD b/resource_detectors/BUILD index 2936523dd6..e0a715f55b 100644 --- a/resource_detectors/BUILD +++ b/resource_detectors/BUILD @@ -123,6 +123,15 @@ cc_library( ], ) +cc_library( + name = "service_resource_detector_builder", + srcs = ["src/service_detector_builder.cc"], + deps = [ + ":service_resource_detector", + "//sdk/src/configuration:configuration_core", + ], +) + # Convenience target linking all resource detectors. cc_library( name = "resource_detectors", @@ -131,6 +140,7 @@ cc_library( ":env_entity_resource_detector", ":host_resource_detector", ":process_resource_detector", + ":service_resource_detector", ], ) @@ -141,5 +151,6 @@ cc_library( ":container_resource_detector_builder", ":host_resource_detector_builder", ":process_resource_detector_builder", + ":service_resource_detector_builder", ], ) diff --git a/resource_detectors/CMakeLists.txt b/resource_detectors/CMakeLists.txt index 6509aa418c..02c0d88c28 100644 --- a/resource_detectors/CMakeLists.txt +++ b/resource_detectors/CMakeLists.txt @@ -143,6 +143,10 @@ target_link_libraries( add_library(opentelemetry_service_resource_detector_utils src/service_detector_utils.cc) +set_target_properties(opentelemetry_service_resource_detector_utils + PROPERTIES EXPORT_NAME service_resource_detector_utils) +set_target_version(opentelemetry_service_resource_detector_utils) + target_link_libraries( opentelemetry_service_resource_detector_utils PUBLIC opentelemetry_resources @@ -169,6 +173,27 @@ target_include_directories( PUBLIC "$" "$") +# +# opentelemetry_service_resource_detector_builder +# + +add_library(opentelemetry_service_resource_detector_builder + src/service_detector_builder.cc) + +set_target_properties(opentelemetry_service_resource_detector_builder + PROPERTIES EXPORT_NAME service_resource_detector_builder) +set_target_version(opentelemetry_service_resource_detector_builder) + +target_include_directories( + opentelemetry_service_resource_detector_builder + PUBLIC "$" + "$") + +target_link_libraries( + opentelemetry_service_resource_detector_builder + PRIVATE opentelemetry_service_resource_detector + opentelemetry_configuration_core) + # # opentelemetry_resource_detectors (interface to all detectors) # @@ -183,7 +208,8 @@ target_link_libraries( INTERFACE opentelemetry_container_resource_detector opentelemetry_env_entity_resource_detector opentelemetry_host_resource_detector - opentelemetry_process_resource_detector) + opentelemetry_process_resource_detector + opentelemetry_service_resource_detector) # # opentelemetry_resource_detectors_builders (interface to all builders) @@ -198,7 +224,8 @@ target_link_libraries( opentelemetry_resource_detectors_builders INTERFACE opentelemetry_container_resource_detector_builder opentelemetry_host_resource_detector_builder - opentelemetry_process_resource_detector_builder) + opentelemetry_process_resource_detector_builder + opentelemetry_service_resource_detector_builder) otel_add_component( COMPONENT @@ -213,6 +240,9 @@ otel_add_component( opentelemetry_host_resource_detector_builder opentelemetry_process_resource_detector opentelemetry_process_resource_detector_builder + opentelemetry_service_resource_detector + opentelemetry_service_resource_detector_builder + opentelemetry_service_resource_detector_utils FILES_DIRECTORY "include/opentelemetry/" FILES_DESTINATION diff --git a/resource_detectors/include/opentelemetry/resource_detectors/service_detector_builder.h b/resource_detectors/include/opentelemetry/resource_detectors/service_detector_builder.h new file mode 100644 index 0000000000..f57d0ae42b --- /dev/null +++ b/resource_detectors/include/opentelemetry/resource_detectors/service_detector_builder.h @@ -0,0 +1,37 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +#include "opentelemetry/sdk/configuration/service_resource_detector_builder.h" +#include "opentelemetry/sdk/configuration/service_resource_detector_configuration.h" +#include "opentelemetry/sdk/resource/resource_detector.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace configuration +{ +class Registry; +} // namespace configuration +} // namespace sdk + +namespace resource_detector +{ + +class ServiceDetectorBuilder + : public opentelemetry::sdk::configuration::ServiceResourceDetectorBuilder +{ +public: + static void Register(opentelemetry::sdk::configuration::Registry *registry); + + std::unique_ptr Build( + const opentelemetry::sdk::configuration::ServiceResourceDetectorConfiguration *model) + const override; +}; + +} // namespace resource_detector +OPENTELEMETRY_END_NAMESPACE diff --git a/resource_detectors/src/service_detector_builder.cc b/resource_detectors/src/service_detector_builder.cc new file mode 100644 index 0000000000..11c093c485 --- /dev/null +++ b/resource_detectors/src/service_detector_builder.cc @@ -0,0 +1,32 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +#include "opentelemetry/resource_detectors/service_detector.h" +#include "opentelemetry/resource_detectors/service_detector_builder.h" +#include "opentelemetry/sdk/configuration/registry.h" +#include "opentelemetry/sdk/configuration/service_resource_detector_builder.h" +#include "opentelemetry/sdk/resource/resource_detector.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace resource_detector +{ + +void ServiceDetectorBuilder::Register(opentelemetry::sdk::configuration::Registry *registry) +{ + auto builder = std::make_unique(); + registry->SetServiceResourceDetectorBuilder(std::move(builder)); +} + +std::unique_ptr ServiceDetectorBuilder::Build( + const opentelemetry::sdk::configuration::ServiceResourceDetectorConfiguration * /* model */) + const +{ + return std::make_unique(); +} + +} // namespace resource_detector +OPENTELEMETRY_END_NAMESPACE diff --git a/resource_detectors/test/BUILD b/resource_detectors/test/BUILD index 16c6645193..8c8fcd10ff 100644 --- a/resource_detectors/test/BUILD +++ b/resource_detectors/test/BUILD @@ -105,3 +105,15 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "service_resource_detector_builder_test", + srcs = ["service_detector_builder_test.cc"], + tags = ["test"], + deps = [ + "//resource_detectors:service_resource_detector_builder", + "//sdk/src/configuration:configuration_core", + "//sdk/src/resource", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/resource_detectors/test/CMakeLists.txt b/resource_detectors/test/CMakeLists.txt index a85f3306c0..04965c4fd1 100644 --- a/resource_detectors/test/CMakeLists.txt +++ b/resource_detectors/test/CMakeLists.txt @@ -112,3 +112,17 @@ gtest_add_tests( TARGET service_resource_detector_test TEST_PREFIX resource_detector. TEST_LIST service_resource_detector_test) + +# +# service_resource_detector_builder tests +# + +add_executable(service_resource_detector_builder_test service_detector_builder_test.cc) +target_link_libraries( + service_resource_detector_builder_test + PRIVATE opentelemetry_service_resource_detector_builder + opentelemetry_configuration_core GTest::gtest_main) +gtest_add_tests( + TARGET service_resource_detector_builder_test + TEST_PREFIX resource_detector. + TEST_LIST service_resource_detector_builder_test) diff --git a/resource_detectors/test/service_detector_builder_test.cc b/resource_detectors/test/service_detector_builder_test.cc new file mode 100644 index 0000000000..eeeda16fa9 --- /dev/null +++ b/resource_detectors/test/service_detector_builder_test.cc @@ -0,0 +1,41 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +#include "opentelemetry/resource_detectors/service_detector.h" +#include "opentelemetry/resource_detectors/service_detector_builder.h" +#include "opentelemetry/sdk/configuration/registry.h" +#include "opentelemetry/sdk/configuration/service_resource_detector_configuration.h" +#include "opentelemetry/sdk/resource/resource_detector.h" + +TEST(ServiceDetectorBuilderTest, Register) +{ + opentelemetry::sdk::configuration::Registry registry; + ASSERT_EQ(registry.GetServiceResourceDetectorBuilder(), nullptr); + + opentelemetry::resource_detector::ServiceDetectorBuilder::Register(®istry); + ASSERT_NE(registry.GetServiceResourceDetectorBuilder(), nullptr); +} + +TEST(ServiceDetectorBuilderTest, Build) +{ + opentelemetry::resource_detector::ServiceDetectorBuilder builder; + opentelemetry::sdk::configuration::ServiceResourceDetectorConfiguration model; + + auto detector = builder.Build(&model); + ASSERT_NE(detector, nullptr); +} + +TEST(ServiceDetectorBuilderTest, BuildCreatesServiceResourceDetector) +{ + opentelemetry::resource_detector::ServiceDetectorBuilder builder; + opentelemetry::sdk::configuration::ServiceResourceDetectorConfiguration model; + + auto detector = builder.Build(&model); + ASSERT_NE(detector, nullptr); + ASSERT_NE( + dynamic_cast(detector.get()), + nullptr); +} From be25fcd1e2c0b59255d4173149b30e3c8e279f9b Mon Sep 17 00:00:00 2001 From: Shashank RM Date: Wed, 19 Aug 2026 07:39:52 +0530 Subject: [PATCH 04/11] [RESOURCE DETECTOR] Complete service detector integration (#4414) --- CHANGELOG.md | 2 ++ examples/configuration/kitchen-sink.yaml | 4 +-- examples/configuration/main.cc | 2 ++ .../resource_detectors/CMakeLists.txt | 2 ++ .../cmake/fetch_content_test/CMakeLists.txt | 2 ++ install/test/src/test_resource_detectors.cc | 36 +++++++++++++++++++ resource_detectors/README.md | 29 +++++++++++++-- 7 files changed, 72 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4206a30157..805c832e50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ Increment the: * [RESOURCE DETECTOR] Add the host resource detector [#4413](https://github.com/open-telemetry/opentelemetry-cpp/issues/4413) +* [RESOURCE DETECTOR] Add the service resource detector and builder + [#4414](https://github.com/open-telemetry/opentelemetry-cpp/issues/4414) * [CONFIGURATION] deprecate config builder cmake components [#4428](https://github.com/open-telemetry/opentelemetry-cpp/pull/4428) diff --git a/examples/configuration/kitchen-sink.yaml b/examples/configuration/kitchen-sink.yaml index cab02d8f5e..0e377c5be9 100644 --- a/examples/configuration/kitchen-sink.yaml +++ b/examples/configuration/kitchen-sink.yaml @@ -1067,8 +1067,8 @@ resource: host: - # Enable the process resource detector, which populates process.* attributes. process: - # - # Enable the service detector, which populates service.name based on the OTEL_SERVICE_NAME environment variable and service.instance.id. - # service: + - # Enable the service resource detector, which populates service.name based on the OTEL_SERVICE_NAME environment variable and service.instance.id. + service: # - # Enable an extension resource detector registered by name. # my_custom_detector: # Configure resource schema URL. diff --git a/examples/configuration/main.cc b/examples/configuration/main.cc index 053304823b..ecd173efdc 100644 --- a/examples/configuration/main.cc +++ b/examples/configuration/main.cc @@ -60,6 +60,7 @@ # include "opentelemetry/resource_detectors/container_detector_builder.h" # include "opentelemetry/resource_detectors/host_detector_builder.h" # include "opentelemetry/resource_detectors/process_detector_builder.h" +# include "opentelemetry/resource_detectors/service_detector_builder.h" #endif static bool opt_help = false; @@ -226,6 +227,7 @@ void InitOtel(const std::string &config_file) opentelemetry::resource_detector::ContainerDetectorBuilder::Register(registry.get()); opentelemetry::resource_detector::HostDetectorBuilder::Register(registry.get()); opentelemetry::resource_detector::ProcessDetectorBuilder::Register(registry.get()); + opentelemetry::resource_detector::ServiceDetectorBuilder::Register(registry.get()); #endif } diff --git a/install/test/cmake/component_tests/resource_detectors/CMakeLists.txt b/install/test/cmake/component_tests/resource_detectors/CMakeLists.txt index 2e03eee785..1b9970485b 100644 --- a/install/test/cmake/component_tests/resource_detectors/CMakeLists.txt +++ b/install/test/cmake/component_tests/resource_detectors/CMakeLists.txt @@ -22,6 +22,8 @@ target_link_libraries( opentelemetry-cpp::host_resource_detector_builder opentelemetry-cpp::process_resource_detector opentelemetry-cpp::process_resource_detector_builder + opentelemetry-cpp::service_resource_detector + opentelemetry-cpp::service_resource_detector_builder GTest::gtest GTest::gtest_main) diff --git a/install/test/cmake/fetch_content_test/CMakeLists.txt b/install/test/cmake/fetch_content_test/CMakeLists.txt index bcebfa9bf5..432523d966 100644 --- a/install/test/cmake/fetch_content_test/CMakeLists.txt +++ b/install/test/cmake/fetch_content_test/CMakeLists.txt @@ -112,6 +112,8 @@ target_link_libraries( opentelemetry-cpp::host_resource_detector_builder opentelemetry-cpp::process_resource_detector opentelemetry-cpp::process_resource_detector_builder + opentelemetry-cpp::service_resource_detector + opentelemetry-cpp::service_resource_detector_builder opentelemetry-cpp::http_client opentelemetry-cpp::http_client_curl opentelemetry-cpp::in_memory_span_exporter diff --git a/install/test/src/test_resource_detectors.cc b/install/test/src/test_resource_detectors.cc index bd5b7f06d1..e0b8b2cc89 100644 --- a/install/test/src/test_resource_detectors.cc +++ b/install/test/src/test_resource_detectors.cc @@ -3,6 +3,7 @@ #include +#include #include #include #include @@ -10,7 +11,13 @@ #include #include #include +#include +#include +#include #include +#include + +namespace semconv = opentelemetry::semconv; TEST(ResourceDetectorsInstall, ContainerResourceDetector) { @@ -44,6 +51,24 @@ TEST(ResourceDetectorsInstall, ProcessResourceDetector) ASSERT_NO_THROW(auto resource = detector->Detect()); } +TEST(ResourceDetectorsInstall, ServiceResourceDetector) +{ + std::unique_ptr detector = + std::make_unique(); + ASSERT_TRUE(detector != nullptr); + + auto resource = detector->Detect(); + const auto &attrs = resource.GetAttributes(); + + auto name_it = attrs.find(semconv::service::kServiceName); + ASSERT_NE(name_it, attrs.end()); + EXPECT_FALSE(opentelemetry::nostd::get(name_it->second).empty()); + + auto instance_id_it = attrs.find(semconv::service::kServiceInstanceId); + ASSERT_NE(instance_id_it, attrs.end()); + EXPECT_FALSE(opentelemetry::nostd::get(instance_id_it->second).empty()); +} + TEST(ResourceDetectorsInstall, ContainerDetectorBuilder) { auto builder = std::make_unique(); @@ -73,3 +98,14 @@ TEST(ResourceDetectorsInstall, ProcessDetectorBuilder) auto detector = builder->Build(&model); ASSERT_TRUE(detector != nullptr); } + +TEST(ResourceDetectorsInstall, ServiceDetectorBuilder) +{ + auto builder = std::make_unique(); + ASSERT_TRUE(builder != nullptr); + + opentelemetry::sdk::configuration::ServiceResourceDetectorConfiguration model; + auto detector = builder->Build(&model); + ASSERT_TRUE(detector != nullptr); + ASSERT_NO_THROW(auto resource = detector->Detect()); +} diff --git a/resource_detectors/README.md b/resource_detectors/README.md index 62aa9d12a1..8d6fb4f266 100644 --- a/resource_detectors/README.md +++ b/resource_detectors/README.md @@ -29,7 +29,25 @@ Contributions to detect more attributes for each Entity are welcome. [Entity: Service](https://opentelemetry.io/docs/specs/semconv/registry/entities/service/) -Not implemented. +| Attribute | Description | Linux | macOS | Windows | +| --- | --- | --- | --- | --- | +| `service.name` | From `OTEL_SERVICE_NAME` when set | Yes | Yes | Yes | +| `service.name` | Fallback `unknown_service:` or `unknown_service` | Yes | Yes | Yes | +| `service.instance.id` | Stable RFC 4122 UUID version 4 for the current process | Yes | Yes | Yes | + +`service.name` is read only from the `OTEL_SERVICE_NAME` environment variable. When +that variable is unset, the detector falls back to +`unknown_service:` when the executable name is +available for the current process, otherwise `unknown_service`. + +`service.instance.id` is generated once per process and remains stable until the +process ID changes (for example after `fork()`). + +Limitations: + +- The detector does not read `OTEL_RESOURCE_ATTRIBUTES`. +- Executable-name fallback reuses process detector utilities; on macOS the + executable name is available for the current process only. ### Container Resource Detector @@ -102,8 +120,7 @@ resource: - container: - host: - process: - # NOTE: service detector cannot be configured currently - - service: # not implemented (github.com/open-telemetry/opentelemetry-cpp/issues/4414) + - service: ``` Call `Register` for each builder before creating the SDK: @@ -112,10 +129,12 @@ Call `Register` for each builder before creating the SDK: #include "opentelemetry/resource_detectors/container_detector_builder.h" #include "opentelemetry/resource_detectors/host_detector_builder.h" #include "opentelemetry/resource_detectors/process_detector_builder.h" +#include "opentelemetry/resource_detectors/service_detector_builder.h" opentelemetry::resource_detector::ContainerDetectorBuilder::Register(registry.get()); opentelemetry::resource_detector::HostDetectorBuilder::Register(registry.get()); opentelemetry::resource_detector::ProcessDetectorBuilder::Register(registry.get()); +opentelemetry::resource_detector::ServiceDetectorBuilder::Register(registry.get()); ``` ## Linking with CMake @@ -172,6 +191,8 @@ All targets are part of the `resource_detectors` component. | `opentelemetry-cpp::host_resource_detector_builder` | Host detector builder for declaritive configuration | | `opentelemetry-cpp::process_resource_detector` | Process detector | | `opentelemetry-cpp::process_resource_detector_builder` | Process detector builder for declaritive configuration | +| `opentelemetry-cpp::service_resource_detector` | Service detector | +| `opentelemetry-cpp::service_resource_detector_builder` | Service detector builder for declaritive configuration | ## Linking with Bazel @@ -219,3 +240,5 @@ deps = ["//resource_detectors:process_resource_detector_builder"] | `//resource_detectors:host_resource_detector_builder` | Host detector builder | | `//resource_detectors:process_resource_detector` | Process detector | | `//resource_detectors:process_resource_detector_builder` | Process detector builder | +| `//resource_detectors:service_resource_detector` | Service detector | +| `//resource_detectors:service_resource_detector_builder` | Service detector builder | From 27496ec01a0130fbf7b93ba85cc0b10e288f0e29 Mon Sep 17 00:00:00 2001 From: Shashank RM Date: Wed, 19 Aug 2026 19:28:51 +0530 Subject: [PATCH 05/11] [RESOURCE DETECTOR] Fix service detector CI issues (#4414) --- resource_detectors/README.md | 12 ++++++------ resource_detectors/src/service_detector.cc | 1 + resource_detectors/src/service_detector_utils.cc | 2 ++ resource_detectors/test/CMakeLists.txt | 8 +++++--- .../test/service_detector_builder_test.cc | 14 +------------- resource_detectors/test/service_detector_test.cc | 2 ++ .../test/service_detector_utils_test.cc | 1 - 7 files changed, 17 insertions(+), 23 deletions(-) diff --git a/resource_detectors/README.md b/resource_detectors/README.md index 8d6fb4f266..cb05f6715f 100644 --- a/resource_detectors/README.md +++ b/resource_detectors/README.md @@ -139,7 +139,7 @@ opentelemetry::resource_detector::ServiceDetectorBuilder::Register(registry.get( ## Linking with CMake -### Linking to detectors directly (not required for declaritive config) +### Linking to detectors directly (not required for declarative config) Link to all available detectors: @@ -155,9 +155,9 @@ find_package(opentelemetry-cpp CONFIG REQUIRED COMPONENTS resource_detectors) target_link_libraries(my_target PRIVATE opentelemetry-cpp::host_resource_detector) ``` -### Linking to builders for declaritive configuration +### Linking to builders for declarative configuration -Builder targets make detectors available for declaritive configuration and hide +Builder targets make detectors available for declarative configuration and hide the concrete detector implementations. Link all builders: @@ -185,14 +185,14 @@ All targets are part of the `resource_detectors` component. | `opentelemetry-cpp::resource_detectors` | Interface: links all detectors | | `opentelemetry-cpp::resource_detectors_builders` | Interface: links all builders | | `opentelemetry-cpp::container_resource_detector` | Container detector | -| `opentelemetry-cpp::container_resource_detector_builder` | Container detector builder for declaritive configuration | +| `opentelemetry-cpp::container_resource_detector_builder` | Container detector builder for declarative configuration | | `opentelemetry-cpp::env_entity_resource_detector` | Env entity detector | | `opentelemetry-cpp::host_resource_detector` | Host detector | | `opentelemetry-cpp::host_resource_detector_builder` | Host detector builder for declaritive configuration | | `opentelemetry-cpp::process_resource_detector` | Process detector | -| `opentelemetry-cpp::process_resource_detector_builder` | Process detector builder for declaritive configuration | +| `opentelemetry-cpp::process_resource_detector_builder` | Process detector builder for declarative configuration | | `opentelemetry-cpp::service_resource_detector` | Service detector | -| `opentelemetry-cpp::service_resource_detector_builder` | Service detector builder for declaritive configuration | +| `opentelemetry-cpp::service_resource_detector_builder` | Service detector builder for declarative configuration | ## Linking with Bazel diff --git a/resource_detectors/src/service_detector.cc b/resource_detectors/src/service_detector.cc index ea1da10596..c86b840e5d 100644 --- a/resource_detectors/src/service_detector.cc +++ b/resource_detectors/src/service_detector.cc @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "opentelemetry/resource_detectors/service_detector.h" +#include "opentelemetry/nostd/variant.h" #include "opentelemetry/resource_detectors/detail/service_detector_utils.h" #include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/sdk/resource/resource_detector.h" diff --git a/resource_detectors/src/service_detector_utils.cc b/resource_detectors/src/service_detector_utils.cc index 17ab60c96a..a6fd47fcd0 100644 --- a/resource_detectors/src/service_detector_utils.cc +++ b/resource_detectors/src/service_detector_utils.cc @@ -3,6 +3,8 @@ #include "opentelemetry/resource_detectors/detail/service_detector_utils.h" +#include + #include #include #include diff --git a/resource_detectors/test/CMakeLists.txt b/resource_detectors/test/CMakeLists.txt index 04965c4fd1..5e6212f0c8 100644 --- a/resource_detectors/test/CMakeLists.txt +++ b/resource_detectors/test/CMakeLists.txt @@ -90,7 +90,8 @@ gtest_add_tests( # service_resource_detector_utils tests # -add_executable(service_resource_detector_utils_test service_detector_utils_test.cc) +add_executable(service_resource_detector_utils_test + service_detector_utils_test.cc) target_link_libraries( service_resource_detector_utils_test PRIVATE opentelemetry_service_resource_detector_utils @@ -107,7 +108,7 @@ gtest_add_tests( add_executable(service_resource_detector_test service_detector_test.cc) target_link_libraries( service_resource_detector_test PRIVATE opentelemetry_service_resource_detector - GTest::gtest_main) + GTest::gtest_main) gtest_add_tests( TARGET service_resource_detector_test TEST_PREFIX resource_detector. @@ -117,7 +118,8 @@ gtest_add_tests( # service_resource_detector_builder tests # -add_executable(service_resource_detector_builder_test service_detector_builder_test.cc) +add_executable(service_resource_detector_builder_test + service_detector_builder_test.cc) target_link_libraries( service_resource_detector_builder_test PRIVATE opentelemetry_service_resource_detector_builder diff --git a/resource_detectors/test/service_detector_builder_test.cc b/resource_detectors/test/service_detector_builder_test.cc index eeeda16fa9..9358dcc6c3 100644 --- a/resource_detectors/test/service_detector_builder_test.cc +++ b/resource_detectors/test/service_detector_builder_test.cc @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include #include -#include "opentelemetry/resource_detectors/service_detector.h" #include "opentelemetry/resource_detectors/service_detector_builder.h" #include "opentelemetry/sdk/configuration/registry.h" #include "opentelemetry/sdk/configuration/service_resource_detector_configuration.h" @@ -27,15 +27,3 @@ TEST(ServiceDetectorBuilderTest, Build) auto detector = builder.Build(&model); ASSERT_NE(detector, nullptr); } - -TEST(ServiceDetectorBuilderTest, BuildCreatesServiceResourceDetector) -{ - opentelemetry::resource_detector::ServiceDetectorBuilder builder; - opentelemetry::sdk::configuration::ServiceResourceDetectorConfiguration model; - - auto detector = builder.Build(&model); - ASSERT_NE(detector, nullptr); - ASSERT_NE( - dynamic_cast(detector.get()), - nullptr); -} diff --git a/resource_detectors/test/service_detector_test.cc b/resource_detectors/test/service_detector_test.cc index f9120170f4..cb1afbde20 100644 --- a/resource_detectors/test/service_detector_test.cc +++ b/resource_detectors/test/service_detector_test.cc @@ -3,6 +3,7 @@ #include #include +#include #ifdef _MSC_VER # include "opentelemetry/sdk/common/env_variables.h" @@ -15,6 +16,7 @@ using opentelemetry::sdk::common::unsetenv; #include "opentelemetry/nostd/variant.h" #include "opentelemetry/resource_detectors/detail/service_detector_utils.h" #include "opentelemetry/resource_detectors/service_detector.h" +#include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/semconv/schema_url.h" #include "opentelemetry/semconv/service_attributes.h" diff --git a/resource_detectors/test/service_detector_utils_test.cc b/resource_detectors/test/service_detector_utils_test.cc index 9e53245b10..8229f4410b 100644 --- a/resource_detectors/test/service_detector_utils_test.cc +++ b/resource_detectors/test/service_detector_utils_test.cc @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 #include -#include #include #include From 182d124130c34720559141ccb2c84e49e95889d2 Mon Sep 17 00:00:00 2001 From: Shashank RM Date: Thu, 20 Aug 2026 08:23:23 +0530 Subject: [PATCH 06/11] [RESOURCE DETECTOR] Fix remaining CI issue IWYU (#4414) --- resource_detectors/src/service_detector_utils.cc | 4 +--- resource_detectors/test/service_detector_builder_test.cc | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/resource_detectors/src/service_detector_utils.cc b/resource_detectors/src/service_detector_utils.cc index a6fd47fcd0..3208383004 100644 --- a/resource_detectors/src/service_detector_utils.cc +++ b/resource_detectors/src/service_detector_utils.cc @@ -16,7 +16,6 @@ # include #endif -#include "opentelemetry/nostd/span.h" #include "opentelemetry/resource_detectors/detail/process_detector_utils.h" #include "opentelemetry/sdk/common/env_variables.h" #include "opentelemetry/version.h" @@ -54,8 +53,7 @@ std::string FormatUuidV4(const uint8_t bytes[16]) noexcept std::string GenerateUuidV4() noexcept { uint8_t bytes[16]; - opentelemetry::sdk::common::Random::GenerateRandomBuffer( - opentelemetry::nostd::span(bytes)); + opentelemetry::sdk::common::Random::GenerateRandomBuffer(bytes); bytes[6] = static_cast((bytes[6] & 0x0F) | 0x40); bytes[8] = static_cast((bytes[8] & 0x3F) | 0x80); return FormatUuidV4(bytes); diff --git a/resource_detectors/test/service_detector_builder_test.cc b/resource_detectors/test/service_detector_builder_test.cc index 9358dcc6c3..4b1b5618da 100644 --- a/resource_detectors/test/service_detector_builder_test.cc +++ b/resource_detectors/test/service_detector_builder_test.cc @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 #include -#include #include #include "opentelemetry/resource_detectors/service_detector_builder.h" From b0bbfc34ef10de705f3a2f6da7668d49ab4dae53 Mon Sep 17 00:00:00 2001 From: Shashank RM Date: Thu, 20 Aug 2026 12:13:12 +0530 Subject: [PATCH 07/11] Add include for nostd/span in service_detector_utils | CI issue IWYU (#44114) --- resource_detectors/src/service_detector_utils.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/resource_detectors/src/service_detector_utils.cc b/resource_detectors/src/service_detector_utils.cc index 3208383004..ce231e532f 100644 --- a/resource_detectors/src/service_detector_utils.cc +++ b/resource_detectors/src/service_detector_utils.cc @@ -1,6 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +#include "opentelemetry/nostd/span.h" #include "opentelemetry/resource_detectors/detail/service_detector_utils.h" #include From 0e2cdd4c21ad7e07ed6892a4069cd5159e7de35a Mon Sep 17 00:00:00 2001 From: Shashank RM Date: Thu, 20 Aug 2026 16:18:49 +0530 Subject: [PATCH 08/11] Reorder include statements in service_detector_utils.cc for CI format checks --- resource_detectors/src/service_detector_utils.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resource_detectors/src/service_detector_utils.cc b/resource_detectors/src/service_detector_utils.cc index ce231e532f..e3a1f6918e 100644 --- a/resource_detectors/src/service_detector_utils.cc +++ b/resource_detectors/src/service_detector_utils.cc @@ -1,8 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -#include "opentelemetry/nostd/span.h" #include "opentelemetry/resource_detectors/detail/service_detector_utils.h" +#include "opentelemetry/nostd/span.h" #include From f70095867a3d8ecadf8848429a629a395f9fc3c6 Mon Sep 17 00:00:00 2001 From: Shashank RM Date: Thu, 20 Aug 2026 22:08:10 +0530 Subject: [PATCH 09/11] [RESOURCE DETECTOR] Fix cppcheck issue by not using span.h (#4414) --- resource_detectors/src/service_detector_utils.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/resource_detectors/src/service_detector_utils.cc b/resource_detectors/src/service_detector_utils.cc index e3a1f6918e..eac161922e 100644 --- a/resource_detectors/src/service_detector_utils.cc +++ b/resource_detectors/src/service_detector_utils.cc @@ -2,11 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 #include "opentelemetry/resource_detectors/detail/service_detector_utils.h" -#include "opentelemetry/nostd/span.h" #include #include +#include #include #include @@ -54,7 +54,11 @@ std::string FormatUuidV4(const uint8_t bytes[16]) noexcept std::string GenerateUuidV4() noexcept { uint8_t bytes[16]; - opentelemetry::sdk::common::Random::GenerateRandomBuffer(bytes); + for (size_t i = 0; i < sizeof(bytes); i += sizeof(uint64_t)) + { + uint64_t value = opentelemetry::sdk::common::Random::GenerateRandom64(); + std::memcpy(&bytes[i], &value, sizeof(uint64_t)); + } bytes[6] = static_cast((bytes[6] & 0x0F) | 0x40); bytes[8] = static_cast((bytes[8] & 0x3F) | 0x80); return FormatUuidV4(bytes); From 3de450294306342cc2d4fa7e76cc734154ccd731 Mon Sep 17 00:00:00 2001 From: Shashank RM Date: Fri, 21 Aug 2026 08:03:17 +0530 Subject: [PATCH 10/11] Remove unused header stddef.h from service_detector_utils.cc Removed unnecessary inclusion of stddef.h. --- resource_detectors/src/service_detector_utils.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/resource_detectors/src/service_detector_utils.cc b/resource_detectors/src/service_detector_utils.cc index eac161922e..b8a1ed7a4b 100644 --- a/resource_detectors/src/service_detector_utils.cc +++ b/resource_detectors/src/service_detector_utils.cc @@ -3,8 +3,6 @@ #include "opentelemetry/resource_detectors/detail/service_detector_utils.h" -#include - #include #include #include From 83b9868daeb2988c3c7be4e9c4a6b3243f8bf56a Mon Sep 17 00:00:00 2001 From: Shashank RM Date: Fri, 21 Aug 2026 19:40:33 +0530 Subject: [PATCH 11/11] Address review feedback for executable path --- resource_detectors/README.md | 5 +- .../detail/process_detector_utils.h | 13 +---- .../src/process_detector_utils.cc | 52 +++++-------------- .../src/service_detector_utils.cc | 15 +++++- .../test/process_detector_test.cc | 23 ++++---- 5 files changed, 43 insertions(+), 65 deletions(-) diff --git a/resource_detectors/README.md b/resource_detectors/README.md index cb05f6715f..c9ac85ac55 100644 --- a/resource_detectors/README.md +++ b/resource_detectors/README.md @@ -80,10 +80,7 @@ or inaccessible. | Attribute | Description | Linux | macOS | Windows | | --- | --- | --- | --- | --- | | `process.pid` | Process ID | Yes | Yes | Yes | -| `process.executable.path` | Path via `/proc` (Linux) or Win32 APIs | Yes | No | Yes | - -Limitation: current macOS implementation does not populate -`process.executable.path`. +| `process.executable.path` | Path via `/proc` (Linux) or Win32 APIs | Yes | Yes | Yes | ### Env Entity Resource Detector (Experimental) diff --git a/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h b/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h index 82086b4ae8..95a8648671 100644 --- a/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h +++ b/resource_detectors/include/opentelemetry/resource_detectors/detail/process_detector_utils.h @@ -26,23 +26,12 @@ std::string FormFilePath(const int32_t &pid, const char *process_type); * Platform-specific behavior: * - Windows: Uses OpenProcess() + GetProcessImageFileNameW(). * - Linux/Unix: Reads the /proc//exe symbolic link. - * - TODO: Need to implement for Darwin - * - * @param pid Process ID. - */ -std::string GetExecutablePath(const int32_t &pid); - -/** - * Retrieves the executable file name for a given PID. - * Platform-specific behavior: - * - Windows: Basename of the path from GetExecutablePath(). - * - Linux: Basename of the path from /proc//exe. * - macOS: Uses _NSGetExecutablePath() for the current process only; returns * an empty string for other PIDs. * * @param pid Process ID. */ -std::string GetExecutableName(const int32_t &pid); +std::string GetExecutablePath(const int32_t &pid); /** * Extracts the command-line arguments and the command. diff --git a/resource_detectors/src/process_detector_utils.cc b/resource_detectors/src/process_detector_utils.cc index c250008403..fe4823bf95 100644 --- a/resource_detectors/src/process_detector_utils.cc +++ b/resource_detectors/src/process_detector_utils.cc @@ -35,25 +35,6 @@ namespace detail constexpr const char *kExecutableName = "exe"; constexpr const char *kCmdlineName = "cmdline"; -namespace -{ -std::string Basename(const std::string &path) -{ - if (path.empty()) - { - return std::string(); - } - - const size_t pos = path.find_last_of("/\\"); - if (pos == std::string::npos) - { - return path; - } - - return path.substr(pos + 1); -} -} // namespace - std::string GetExecutablePath(const int32_t &pid) { #ifdef _MSC_VER @@ -79,24 +60,7 @@ std::string GetExecutablePath(const int32_t &pid) WideCharToMultiByte(CP_UTF8, 0, wbuffer, len, &utf8_path[0], size_needed, NULL, NULL); return utf8_path; -#else - std::string path = FormFilePath(pid, kExecutableName); - char buffer[4096]; - - ssize_t len = readlink(path.c_str(), buffer, sizeof(buffer) - 1); - if (len != -1) - { - buffer[len] = '\0'; - return std::string(buffer); - } - - return std::string(); -#endif -} - -std::string GetExecutableName(const int32_t &pid) -{ -#if defined(__APPLE__) +#elif defined(__APPLE__) if (pid != static_cast(getpid())) { return std::string(); @@ -109,9 +73,19 @@ std::string GetExecutableName(const int32_t &pid) return std::string(); } - return Basename(path); + return std::string(path); #else - return Basename(GetExecutablePath(pid)); + std::string path = FormFilePath(pid, kExecutableName); + char buffer[4096]; + + ssize_t len = readlink(path.c_str(), buffer, sizeof(buffer) - 1); + if (len != -1) + { + buffer[len] = '\0'; + return std::string(buffer); + } + + return std::string(); #endif } diff --git a/resource_detectors/src/service_detector_utils.cc b/resource_detectors/src/service_detector_utils.cc index b8a1ed7a4b..3a45bb72c6 100644 --- a/resource_detectors/src/service_detector_utils.cc +++ b/resource_detectors/src/service_detector_utils.cc @@ -73,7 +73,20 @@ std::string GetServiceName() return service_name; } - const std::string executable_name = GetExecutableName(static_cast(getpid())); + const std::string executable_path = GetExecutablePath(static_cast(getpid())); + std::string executable_name; + if (!executable_path.empty()) + { + const size_t pos = executable_path.find_last_of("/\\"); + if (pos == std::string::npos) + { + executable_name = executable_path; + } + else + { + executable_name = executable_path.substr(pos + 1); + } + } if (!executable_name.empty()) { std::string fallback_service_name(kUnknownServicePrefix); diff --git a/resource_detectors/test/process_detector_test.cc b/resource_detectors/test/process_detector_test.cc index 3db2302ba0..f331d22d53 100644 --- a/resource_detectors/test/process_detector_test.cc +++ b/resource_detectors/test/process_detector_test.cc @@ -18,6 +18,9 @@ # include # include # include +# if defined(__APPLE__) +# include +# endif #endif #include "opentelemetry/resource_detectors/detail/process_detector_utils.h" @@ -93,6 +96,17 @@ TEST(ProcessDetectorUtilsTest, GetExecutablePathTest) path = utf8_path; } } +#elif defined(__APPLE__) + char buffer[4096]; + uint32_t size = sizeof(buffer); + if (_NSGetExecutablePath(buffer, &size) != 0) + { + path = std::string(); + } + else + { + path = std::string(buffer); + } #else std::string exe_path = opentelemetry::resource_detector::detail::FormFilePath(pid, "exe"); char buffer[4096]; @@ -112,15 +126,6 @@ TEST(ProcessDetectorUtilsTest, GetExecutablePathTest) EXPECT_EQ(path, expected_path); } -TEST(ProcessDetectorUtilsTest, GetExecutableNameTest) -{ - int32_t pid = getpid(); - std::string executable_name = opentelemetry::resource_detector::detail::GetExecutableName(pid); - EXPECT_FALSE(executable_name.empty()); - EXPECT_EQ(executable_name.find('/'), std::string::npos); - EXPECT_EQ(executable_name.find('\\'), std::string::npos); -} - TEST(ProcessDetectorUtilsTest, CommandTest) { int32_t pid = getpid();