Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#pragma once

#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(const std::string &line);

} // namespace resource
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
3 changes: 2 additions & 1 deletion sdk/src/resource/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0

add_library(opentelemetry_resources resource.cc resource_detector.cc)
add_library(opentelemetry_resources resource.cc resource_detector.cc
container.cc container_detector.cc)

set_target_properties(opentelemetry_resources PROPERTIES EXPORT_NAME resources)
set_target_version(opentelemetry_resources)
Expand Down
47 changes: 47 additions & 0 deletions sdk/src/resource/container.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#include "opentelemetry/sdk/resource/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 ExtractContainerIDFromLine(const std::string &line)
{
static const std::regex container_id_regex(R"(^.*/(?:.*[-:])?([0-9a-f]+)(?:\.|\s*$))");
std::smatch match;

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

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

#include "opentelemetry/nostd/variant.h"
#include "opentelemetry/sdk/resource/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>

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace resource
{

/**
* This is the file path from where we can get container.id
*/
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] = container_id;
return ResourceDetector::Create(attributes);
}

} // namespace resource
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
10 changes: 7 additions & 3 deletions sdk/src/resource/resource.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <utility>

#include "opentelemetry/nostd/variant.h"
#include "opentelemetry/sdk/resource/container_resource_detector.h"
#include "opentelemetry/sdk/resource/resource.h"
#include "opentelemetry/sdk/resource/resource_detector.h"
#include "opentelemetry/sdk/version/version.h"
Expand Down Expand Up @@ -40,9 +41,12 @@ Resource Resource::Merge(const Resource &other) const noexcept

Resource Resource::Create(const ResourceAttributes &attributes, const std::string &schema_url)
{
static auto otel_resource = OTELResourceDetector().Detect();
auto resource =
Resource::GetDefault().Merge(otel_resource).Merge(Resource{attributes, schema_url});
static auto otel_resource = OTELResourceDetector().Detect();
static auto container_resource = ContainerResourceDetector().Detect();
auto resource = Resource::GetDefault()
.Merge(otel_resource)
.Merge(container_resource)
.Merge(Resource{attributes, schema_url});

if (resource.attributes_.find(semconv::service::kServiceName) == resource.attributes_.end())
{
Expand Down
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";
const char *KOtelResourceAttributes = "OTEL_RESOURCE_ATTRIBUTES";
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
52 changes: 52 additions & 0 deletions sdk/test/resource/resource_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +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/variant.h"
#include "opentelemetry/sdk/common/attribute_utils.h"
#include "opentelemetry/sdk/resource/container_resource_detector.h"
#include "opentelemetry/sdk/resource/resource.h"
#include "opentelemetry/sdk/resource/resource_detector.h"
#include "opentelemetry/sdk/version/version.h"
Expand Down Expand Up @@ -292,3 +295,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
}
Loading