Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c740ddb
[SDK] Implementation of container resource as per semconv
nikhilbhatia08 Jul 29, 2025
4bf2bfb
[sdk] minor changes in format, linking and var naming
nikhilbhatia08 Jul 30, 2025
f075c93
changes for ci
nikhilbhatia08 Jul 31, 2025
86cebd6
Merge branch 'main' into implement_resource_detectors
lalitb Aug 2, 2025
00decf9
ci and requested changes
nikhilbhatia08 Aug 2, 2025
b84840f
Merge branch 'implement_resource_detectors' of https://github.com/nik…
nikhilbhatia08 Aug 2, 2025
edef26e
iwyu-fix
nikhilbhatia08 Aug 2, 2025
3742932
newline-fix
nikhilbhatia08 Aug 2, 2025
a495294
newline-fix
nikhilbhatia08 Aug 2, 2025
72565ec
Merge branch 'implement_resource_detectors' of https://github.com/nik…
nikhilbhatia08 Aug 7, 2025
f7b5e94
[EXPORTER] Fixes tsan warnings (#3531)
owent Jul 29, 2025
a836349
[DOC] Document minimum required versions (#3562)
markus456 Jul 29, 2025
5ec872c
Bump github/codeql-action from 3.29.4 to 3.29.5 (#3574)
dependabot[bot] Jul 30, 2025
81624a3
Add subscript to issue templates (#3576)
opentelemetrybot Aug 1, 2025
4cebe35
iwyu-fix
nikhilbhatia08 Aug 2, 2025
a1778b9
newline-fix
nikhilbhatia08 Aug 2, 2025
926517f
Restore ci.yml to match main
nikhilbhatia08 Aug 2, 2025
bd7a71c
Merge branch 'implement_resource_detectors' of https://github.com/nik…
nikhilbhatia08 Aug 7, 2025
2546661
new folder for resource detectors
nikhilbhatia08 Aug 7, 2025
75c495c
BUILD file for resource_detectors
nikhilbhatia08 Aug 7, 2025
220a5ad
BUILD file(resource_detectors) minor changes
nikhilbhatia08 Aug 7, 2025
439e92c
added comments and changes as required
nikhilbhatia08 Aug 7, 2025
9e5bc55
changed to nostd::string_view
nikhilbhatia08 Aug 7, 2025
9bc07e1
regex fix based on nostd::string_view
nikhilbhatia08 Aug 8, 2025
047e35c
Merge branch 'main' into implement_resource_detectors
lalitb Aug 8, 2025
a404c80
constants naming fix
nikhilbhatia08 Aug 8, 2025
7cbcc59
namespace change and tests
nikhilbhatia08 Aug 9, 2025
0e7d011
iwyu and BUILD fix
nikhilbhatia08 Aug 9, 2025
fd93b32
namespace change
nikhilbhatia08 Aug 9, 2025
b030cc9
cmakelists flags addition and fix
nikhilbhatia08 Aug 10, 2025
018a1f8
resource detectors preview-options
nikhilbhatia08 Aug 10, 2025
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
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,7 @@ if(DEFINED OPENTELEMETRY_BUILD_DLL)
endif()

add_subdirectory(api)
add_subdirectory(resource_detectors)

if(WITH_OPENTRACING)
add_subdirectory(opentracing-shim)
Expand Down
24 changes: 24 additions & 0 deletions resource_detectors/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0

package(default_visibility = ["//visibility:public"])

cc_library(
name = "headers",
hdrs = glob(["include/**/*.h"]),
strip_include_prefix = "include",
)

cc_library(
name = "resource_detectors",
srcs = [
"container.cc",
"container_detector.cc",
],
deps = [
"//api",
"//resource_detectors:headers",
"//sdk:headers",
"//sdk/src/resource",
],
)
23 changes: 23 additions & 0 deletions resource_detectors/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0

add_library(opentelemetry_resource_detectors container.cc container_detector.cc)

set_target_properties(opentelemetry_resource_detectors
PROPERTIES EXPORT_NAME resource_detectors)
set_target_version(opentelemetry_resource_detectors)

target_link_libraries(opentelemetry_resource_detectors
PUBLIC opentelemetry_common)

target_include_directories(
opentelemetry_resource_detectors
PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/resource_detectors/include>"
PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/sdk/include>")

if(OPENTELEMETRY_INSTALL)
opentelemetry_add_pkgconfig(
resource_detectors "OpenTelemetry - Resource detectors"
"Components for resource detection in the OpenTelemetry resource detectors."
)
endif()
58 changes: 58 additions & 0 deletions resource_detectors/container.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#include "opentelemetry/nostd/string_view.h"
#include "opentelemetry/resource_detectors/container_resource_detector.h"

#include <fstream>
#include <regex>
#include <string>

#include "opentelemetry/version.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace resource
{
std::string GetContainerIDFromCgroup(const char *file_path)
{
std::ifstream cgroup_file(file_path);
std::string line;

while (std::getline(cgroup_file, line))
{
std::string container_id = ExtractContainerIDFromLine(line);
if (!container_id.empty())
{
return container_id;
}
}
return std::string();
}

std::string ExtractContainerIDFromLine(nostd::string_view line)
{
/**
* This regex is designed to extract container IDs from cgroup file lines.
* It matches hexadecimal container IDs used by container runtimes like Docker, containerd, and
* cri-o.
* Examples of matching lines:
* - 0::/docker/3fae9b2c6d7e8f90123456789abcdef0123456789abcdef0123456789abcdef0
* - "13:name=systemd:/podruntime/docker/kubepods/ac679f8a8319c8cf7d38e1adf263bc08d23.aaaa"
* - "e857a4bf05a69080a759574949d7a0e69572e27647800fa7faff6a05a8332aa1"
* Please see the test cases in resource_test.cc for more examples.
*/
static const std::regex container_id_regex(R"(^.*/(?:.*[-:])?([0-9a-f]+)(?:\.|\s*$))");
std::match_results<const char *> match;

if (std::regex_search(line.data(), line.data() + line.size(), match, container_id_regex))
{
return match.str(1);
}

return std::string();
}
} // namespace resource
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
42 changes: 42 additions & 0 deletions resource_detectors/container_detector.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#include "opentelemetry/nostd/variant.h"
#include "opentelemetry/resource_detectors/container_resource_detector.h"
#include "opentelemetry/sdk/resource/resource.h"
#include "opentelemetry/sdk/resource/resource_detector.h"
#include "opentelemetry/semconv/incubating/container_attributes.h"
#include "opentelemetry/version.h"

#include <string>
#include <unordered_map>
#include <utility>

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace resource
{

/**
* This is the file path from where we can get container.id
*/
constexpr const char *KCGroupPath = "/proc/self/cgroup";

Resource ContainerResourceDetector::Detect() noexcept
{
std::string container_id = opentelemetry::sdk::resource::GetContainerIDFromCgroup(KCGroupPath);
if (container_id.empty())
{
return ResourceDetector::Create({});
}

ResourceAttributes attributes;

attributes[semconv::container::kContainerId] = std::move(container_id);
return ResourceDetector::Create(attributes);
}

} // namespace resource
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "opentelemetry/nostd/string_view.h"
#include "opentelemetry/sdk/resource/resource.h"
#include "opentelemetry/sdk/resource/resource_detector.h"
#include "opentelemetry/version.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace resource
{

/**
* ContainerResourceDetector to detect resource attributes when running inside a containerized
* environment. This detector extracts metadata such as container ID from cgroup information and
* sets attributes like container.id following the OpenTelemetry semantic conventions.
*/
class ContainerResourceDetector : public ResourceDetector
{
public:
Resource Detect() noexcept override;
};

/**
* Reads the container.id from /proc/self/cgroup file.
* @param file_path file path of cgroup
* @return container.id as string or empty string
*/
std::string GetContainerIDFromCgroup(const char *file_path);

/**
* Matches the line with the regex to find container.id
* @param line a single line of text, typically from the /proc/self/cgroup file
* @return matched id or empty string
*/
std::string ExtractContainerIDFromLine(nostd::string_view line);

} // namespace resource
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
8 changes: 4 additions & 4 deletions sdk/src/resource/resource_detector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ namespace sdk
namespace resource
{

const char *OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES";
const char *OTEL_SERVICE_NAME = "OTEL_SERVICE_NAME";
constexpr const char *KOtelResourceAttributes = "OTEL_RESOURCE_ATTRIBUTES";
constexpr const char *KOtelServiceName = "OTEL_SERVICE_NAME";

Resource ResourceDetector::Create(const ResourceAttributes &attributes,
const std::string &schema_url)
Expand All @@ -33,9 +33,9 @@ Resource OTELResourceDetector::Detect() noexcept
std::string attributes_str, service_name;

bool attributes_exists = opentelemetry::sdk::common::GetStringEnvironmentVariable(
OTEL_RESOURCE_ATTRIBUTES, attributes_str);
KOtelResourceAttributes, attributes_str);
bool service_name_exists =
opentelemetry::sdk::common::GetStringEnvironmentVariable(OTEL_SERVICE_NAME, service_name);
opentelemetry::sdk::common::GetStringEnvironmentVariable(KOtelServiceName, service_name);

if (!attributes_exists && !service_name_exists)
{
Expand Down
1 change: 1 addition & 0 deletions sdk/test/resource/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ cc_test(
tags = ["test"],
deps = [
"//api",
"//resource_detectors",
"//sdk/src/resource",
"@com_google_googletest//:gtest_main",
],
Expand Down
5 changes: 3 additions & 2 deletions sdk/test/resource/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

foreach(testname resource_test)
add_executable(${testname} "${testname}.cc")
target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT} opentelemetry_resources)
target_link_libraries(
${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}
opentelemetry_resources opentelemetry_resource_detectors)
gtest_add_tests(
TARGET ${testname}
TEST_PREFIX resources.
Expand Down
53 changes: 53 additions & 0 deletions sdk/test/resource/resource_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@

#include <gtest/gtest.h>
#include <stdint.h>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <map>
#include <string>
#include <unordered_map>
#include <utility>

#include "opentelemetry/nostd/string_view.h"
#include "opentelemetry/nostd/variant.h"
#include "opentelemetry/resource_detectors/container_resource_detector.h"
#include "opentelemetry/sdk/common/attribute_utils.h"
#include "opentelemetry/sdk/resource/resource.h"
#include "opentelemetry/sdk/resource/resource_detector.h"
Expand Down Expand Up @@ -292,3 +296,52 @@ TEST(ResourceTest, DerivedResourceDetector)
EXPECT_EQ(resource.GetSchemaURL(), detector.schema_url);
EXPECT_TRUE(received_attributes.find("key") != received_attributes.end());
}

TEST(ResourceTest, ExtractValidContainerId)
{
std::string line =
"13:name=systemd:/podruntime/docker/kubepods/ac679f8a8319c8cf7d38e1adf263bc08d23.aaaa";
std::string extracted_id = opentelemetry::sdk::resource::ExtractContainerIDFromLine(line);
EXPECT_EQ(std::string{"ac679f8a8319c8cf7d38e1adf263bc08d23"}, extracted_id);
}

TEST(ResourceTest, ExtractIdFromMockUpCGroupFile)
{
const char *filename = "test_cgroup.txt";

{
std::ofstream outfile(filename);
outfile << "13:name=systemd:/kuberuntime/containerd"
"/kubepods-pod872d2066_00ef_48ea_a7d8_51b18b72d739:cri-containerd:"
"e857a4bf05a69080a759574949d7a0e69572e27647800fa7faff6a05a8332aa1\n";
outfile << "9:cpu:/not-a-container\n";
}

std::string container_id = opentelemetry::sdk::resource::GetContainerIDFromCgroup(filename);
EXPECT_EQ(container_id,
std::string{"e857a4bf05a69080a759574949d7a0e69572e27647800fa7faff6a05a8332aa1"});

std::remove(filename);
Copy link

Copilot AI Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test file cleanup should be in a finally block or use RAII to ensure cleanup occurs even if the test fails. Consider using a test fixture with proper cleanup or a temporary file wrapper.

Suggested change
std::remove(filename);

Copilot uses AI. Check for mistakes.

}

TEST(ResourceTest, DoesNotExtractInvalidLine)
{
std::string line = "this line does not contain a container id";
std::string id = opentelemetry::sdk::resource::ExtractContainerIDFromLine(line);
EXPECT_EQ(id, std::string{""});
}

TEST(ContainerIdDetectorTest, ReturnsEmptyOnNoMatch)
{
const char *filename = "test_empty_cgroup.txt";

{
std::ofstream outfile(filename);
outfile << "no container id here\n";
}

std::string id = opentelemetry::sdk::resource::GetContainerIDFromCgroup(filename);
EXPECT_EQ(id, std::string{""});

std::remove(filename); // cleanup
}