From edb4f896729758ceb4d3cae92b6db5976045de9f Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Mon, 30 Jun 2025 14:13:39 -0700 Subject: [PATCH 01/17] Update docker container ID test to use a UUID that's 64 hex-chars long, as this is what other tracers are testing --- test/test_platform_util.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_platform_util.cpp b/test/test_platform_util.cpp index e333e04e..4693de56 100644 --- a/test/test_platform_util.cpp +++ b/test/test_platform_util.cpp @@ -19,8 +19,8 @@ PLATFORM_UTIL_TEST("find docker container ID") { {__LINE__, "empty inputs", "", nullopt}, {__LINE__, "no docker container ID", "coucou", nullopt}, {__LINE__, "one line with docker container ID", - "0::/system.slice/docker-abcdef0123456789abcdef0123456789.scope", - "abcdef0123456789abcdef0123456789"}, + "0::/system.slice/docker-cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411.scope", + "cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411"}, {__LINE__, "multiline wihtout docker container ID", R"( 0::/ 10:memory:/user.slice/user-0.slice/session-14.scope @@ -41,7 +41,7 @@ PLATFORM_UTIL_TEST("find docker container ID") { 9:hugetlb:/ 8:cpuset:/ 7:pids:/user.slice/user-0.slice/session-14.scope -3:cpu:/system.slice/docker-abcdef0123456789abcdef0123456789.scope +3:cpu:/system.slice/docker-cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411.scope 6:freezer:/ 5:net_cls,net_prio:/ 4:perf_event:/ @@ -49,7 +49,7 @@ PLATFORM_UTIL_TEST("find docker container ID") { 2:devices:/user.slice/user-0.slice/session-14.scope 1:name=systemd:/user.slice/user-0.slice/session-14.scope )", - "abcdef0123456789abcdef0123456789"}, + "cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411"}, })); CAPTURE(test_case.name); From bb3d458af70b672064cfcb7135d8885451172e02 Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Mon, 30 Jun 2025 14:17:24 -0700 Subject: [PATCH 02/17] Rename container::find_docker_container_id to container::find_container_id and update its implementation so that it is regex-based and covers the same set of inputs as other tracers, like Java and .NET -- the implementation is borrowed from the Java tracer --- src/datadog/platform_util.cpp | 30 +++++++++++++---------- src/datadog/platform_util.h | 8 +++---- test/test_platform_util.cpp | 45 ++++++++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 18 deletions(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index 381a3aba..e9b62e1a 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include // clang-format off #if defined(__x86_64__) || defined(_M_X64) @@ -338,31 +340,33 @@ Optional get_cgroup_version() { return nullopt; } -Optional find_docker_container_id_from_cgroup() { +Optional find_container_id_from_cgroup() { auto cgroup_fd = std::ifstream("/proc/self/cgroup", std::ios::in); if (!cgroup_fd.is_open()) return nullopt; - return find_docker_container_id(cgroup_fd); + return find_container_id(cgroup_fd); } #endif } // namespace -Optional find_docker_container_id(std::istream& source) { - constexpr std::string_view docker_str = "docker-"; +Optional find_container_id(std::istream& source) { + static const std::string uuid_regex_str = "[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}|(?:[0-9a-f]{8}(?:-[0-9a-f]{4}){4}$)"; + static const std::string container_regex_str = "[0-9a-f]{64}"; + static const std::string task_regex_str = "[0-9a-f]{32}-\\d+"; + static const std::regex path_reg( + "(?:.+)?(" + uuid_regex_str + "|" + container_regex_str + "|" + task_regex_str + + ")(?:\\.scope)?$"); std::string line; while (std::getline(source, line)) { // Example: // `0::/system.slice/docker-abcdef0123456789abcdef0123456789.scope` - if (auto beg = line.find(docker_str); beg != std::string::npos) { - beg += docker_str.size(); - auto end = line.find(".scope", beg); - if (end == std::string::npos || end - beg <= 0) { - continue; - } + std::smatch match; + if (std::regex_match(line, match, path_reg)) { + assert(match.ready()); + assert(match.size() == 2); - auto container_id = line.substr(beg, end - beg); - return container_id; + return match.str(1); } } @@ -382,7 +386,7 @@ Optional get_id() { ContainerID id; switch (*maybe_cgroup) { case Cgroup::v1: { - if (auto maybe_id = find_docker_container_id_from_cgroup()) { + if (auto maybe_id = find_container_id_from_cgroup()) { id.value = *maybe_id; id.type = ContainerID::Type::container_id; break; diff --git a/src/datadog/platform_util.h b/src/datadog/platform_util.h index d7fd0c3b..a71d2df6 100644 --- a/src/datadog/platform_util.h +++ b/src/datadog/platform_util.h @@ -84,13 +84,13 @@ struct ContainerID final { std::string value; }; -/// Find the docker container ID from a given source. +/// Find the container ID from a given source. /// This function is exposed mainly for testing purposes. /// -/// @param source The input from which to read the Docker container ID. -/// @return An Optional containing the Docker container ID if found, otherwise +/// @param source The input from which to read the container ID. +/// @return An Optional containing the container ID if found, otherwise /// nothing. -Optional find_docker_container_id(std::istream& source); +Optional find_container_id(std::istream& source); /// Function to retrieve the container metadata. /// diff --git a/test/test_platform_util.cpp b/test/test_platform_util.cpp index 4693de56..30d95e53 100644 --- a/test/test_platform_util.cpp +++ b/test/test_platform_util.cpp @@ -56,7 +56,50 @@ PLATFORM_UTIL_TEST("find docker container ID") { std::istringstream is(test_case.input); - auto maybe_container_id = container::find_docker_container_id(is); + auto maybe_container_id = container::find_container_id(is); + if (test_case.expected_container_id.has_value()) { + REQUIRE(maybe_container_id.has_value()); + CHECK(*maybe_container_id == *test_case.expected_container_id); + } else { + CHECK(!maybe_container_id.has_value()); + } +} + +PLATFORM_UTIL_TEST("find Fargate 1.3 container ID") { + struct TestCase { + size_t line; + std::string_view name; + std::string input; + Optional expected_container_id; + }; + + auto test_case = GENERATE(values({ + {__LINE__, "empty inputs", "", nullopt}, + {__LINE__, "no Fargate 1.3 container ID", "coucou", nullopt}, + {__LINE__, "one line with Fargate 1.3 container ID", + "1:name=systemd:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da", + "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da"}, + {__LINE__, "multiline with Fargate 1.3 container ID", R"( +11:hugetlb:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +10:pids:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +9:cpuset:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +8:net_cls,net_prio:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +7:cpu,cpuacct:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +6:perf_event:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +5:freezer:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +4:devices:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +3:blkio:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +2:memory:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da +1:name=systemd:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da + )", + "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da"}, + })); + + CAPTURE(test_case.name); + + std::istringstream is(test_case.input); + + auto maybe_container_id = container::find_container_id(is); if (test_case.expected_container_id.has_value()) { REQUIRE(maybe_container_id.has_value()); CHECK(*maybe_container_id == *test_case.expected_container_id); From 2174c8089432e91db04232a10e8ccfb932ff2675 Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Mon, 30 Jun 2025 14:25:46 -0700 Subject: [PATCH 03/17] Add other cgroup file examples from the .NET Tracer --- test/test_platform_util.cpp | 99 ++++++++++++++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 7 deletions(-) diff --git a/test/test_platform_util.cpp b/test/test_platform_util.cpp index 30d95e53..caf2e03e 100644 --- a/test/test_platform_util.cpp +++ b/test/test_platform_util.cpp @@ -65,7 +65,7 @@ PLATFORM_UTIL_TEST("find docker container ID") { } } -PLATFORM_UTIL_TEST("find Fargate 1.3 container ID") { +PLATFORM_UTIL_TEST("find multiline container IDs") { struct TestCase { size_t line; std::string_view name; @@ -74,12 +74,50 @@ PLATFORM_UTIL_TEST("find Fargate 1.3 container ID") { }; auto test_case = GENERATE(values({ - {__LINE__, "empty inputs", "", nullopt}, - {__LINE__, "no Fargate 1.3 container ID", "coucou", nullopt}, - {__LINE__, "one line with Fargate 1.3 container ID", - "1:name=systemd:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da", - "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da"}, - {__LINE__, "multiline with Fargate 1.3 container ID", R"( + {__LINE__, "Docker", R"( +13:name=systemd:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +12:pids:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +11:hugetlb:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +10:net_prio:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +9:perf_event:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +8:net_cls:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +7:freezer:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +6:devices:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +5:memory:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +4:blkio:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +3:cpuacct:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +2:cpu:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 +1:cpuset:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860 + )", + "3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860"}, + {__LINE__, "Kubernetes", R"( +11:perf_event:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +10:pids:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +9:memory:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +8:cpu,cpuacct:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +7:blkio:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +6:cpuset:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +5:devices:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +4:freezer:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +3:net_cls,net_prio:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +2:hugetlb:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +1:name=systemd:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1 +1:name=systemd:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod2d3da189_6407_48e3_9ab6_78188d75e609.slice/docker-3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1.scope + )", + "3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1"}, + {__LINE__, "Ecs", R"( +9:perf_event:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +8:memory:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +7:hugetlb:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +6:freezer:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +5:devices:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +4:cpuset:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +3:cpuacct:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +2:cpu:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce +1:blkio:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce + )", + "38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce"}, + {__LINE__, "Fargate1Dot3", R"( 11:hugetlb:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da 10:pids:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da 9:cpuset:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da @@ -93,6 +131,53 @@ PLATFORM_UTIL_TEST("find Fargate 1.3 container ID") { 1:name=systemd:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da )", "432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da"}, + {__LINE__, "Fargate1Dot4", R"( +11:hugetlb:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890 +10:pids:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890 +9:cpuset:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890 +8:net_cls,net_prio:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890 +7:cpu,cpuacct:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890 +6:perf_event:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890 +5:freezer:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890 +4:devices:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890 +3:blkio:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890 +2:memory:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890 +1:name=systemd:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890 + )", + "34dc0b5e626f2c5c4c5170e34b10e765-1234567890"}, + {__LINE__, "EksNodegroup", R"( +11:blkio:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope +10:cpuset:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope +9:perf_event:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope +8:memory:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope +7:pids:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope +6:cpu,cpuacct:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope +5:net_cls,net_prio:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope +4:devices:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope +3:freezer:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope +2:hugetlb:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope +1:name=systemd:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope + )", + "26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4"}, + {__LINE__, "PcfContainer1", R"( +12:memory:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1 +11:rdma:/ +10:freezer:/garden/6f265890-5165-7fab-6b52-18d1 +9:hugetlb:/garden/6f265890-5165-7fab-6b52-18d1 +8:pids:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1 +7:perf_event:/garden/6f265890-5165-7fab-6b52-18d1 +6:cpu,cpuacct:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1 +5:net_cls,net_prio:/garden/6f265890-5165-7fab-6b52-18d1 +4:cpuset:/garden/6f265890-5165-7fab-6b52-18d1 +3:blkio:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1 +2:devices:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1 +1:name=systemd:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1 + )", + "6f265890-5165-7fab-6b52-18d1"}, + {__LINE__, "PcfContainer2", R"( +1:name=systemd:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1 + )", + "6f265890-5165-7fab-6b52-18d1"}, })); CAPTURE(test_case.name); From 136d4cc0a901ddfc5639db8a82d36875b1b057a9 Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Mon, 30 Jun 2025 16:40:25 -0700 Subject: [PATCH 04/17] Fix formatting --- src/datadog/platform_util.cpp | 12 +++++++----- test/test_platform_util.cpp | 4 +++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index e9b62e1a..00c50343 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -1,8 +1,8 @@ #include "platform_util.h" +#include #include #include -#include #include // clang-format off @@ -350,12 +350,14 @@ Optional find_container_id_from_cgroup() { } // namespace Optional find_container_id(std::istream& source) { - static const std::string uuid_regex_str = "[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}|(?:[0-9a-f]{8}(?:-[0-9a-f]{4}){4}$)"; + static const std::string uuid_regex_str = + "[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}" + "|(?:[0-9a-f]{8}(?:-[0-9a-f]{4}){4}$)"; static const std::string container_regex_str = "[0-9a-f]{64}"; static const std::string task_regex_str = "[0-9a-f]{32}-\\d+"; - static const std::regex path_reg( - "(?:.+)?(" + uuid_regex_str + "|" + container_regex_str + "|" + task_regex_str + - ")(?:\\.scope)?$"); + static const std::regex path_reg("(?:.+)?(" + uuid_regex_str + "|" + + container_regex_str + "|" + task_regex_str + + ")(?:\\.scope)?$"); std::string line; while (std::getline(source, line)) { diff --git a/test/test_platform_util.cpp b/test/test_platform_util.cpp index caf2e03e..6963c1e6 100644 --- a/test/test_platform_util.cpp +++ b/test/test_platform_util.cpp @@ -19,7 +19,9 @@ PLATFORM_UTIL_TEST("find docker container ID") { {__LINE__, "empty inputs", "", nullopt}, {__LINE__, "no docker container ID", "coucou", nullopt}, {__LINE__, "one line with docker container ID", - "0::/system.slice/docker-cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411.scope", + "0::/system.slice/" + "docker-" + "cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411.scope", "cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411"}, {__LINE__, "multiline wihtout docker container ID", R"( 0::/ From 43f214aa4d1199571364670eab64d98defed0233 Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Mon, 14 Jul 2025 12:58:54 -0700 Subject: [PATCH 05/17] Add temporary logging to stdout and stderr for the container-id parsing --- src/datadog/platform_util.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index 00c50343..d2e94cac 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include // clang-format off @@ -342,7 +343,10 @@ Optional get_cgroup_version() { Optional find_container_id_from_cgroup() { auto cgroup_fd = std::ifstream("/proc/self/cgroup", std::ios::in); - if (!cgroup_fd.is_open()) return nullopt; + if (!cgroup_fd.is_open()) { + std::cerr << "failed to open /proc/self/cgroup" << std::endl; + return nullopt; + } return find_container_id(cgroup_fd); } @@ -361,6 +365,7 @@ Optional find_container_id(std::istream& source) { std::string line; while (std::getline(source, line)) { + std::cout << "Reading line: " << line << std::endl; // Example: // `0::/system.slice/docker-abcdef0123456789abcdef0123456789.scope` std::smatch match; @@ -368,10 +373,12 @@ Optional find_container_id(std::istream& source) { assert(match.ready()); assert(match.size() == 2); + std::cout << "Found container ID: " << match.str(1) << std::endl; return match.str(1); } } + std::cout << "No container ID found" << std::endl; return nullopt; } From d6e929794c992f899a59a36313cb16f99f58dc3e Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Mon, 14 Jul 2025 13:43:01 -0700 Subject: [PATCH 06/17] This doesn't pass unit tests, but now I am writing some more helpful logs into our error logging so I can debug why this isn't working in system-tests --- src/datadog/datadog_agent.cpp | 2 +- src/datadog/platform_util.cpp | 29 +++++++++++++++++++---------- src/datadog/platform_util.h | 7 +++++-- test/test_platform_util.cpp | 5 +++-- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/datadog/datadog_agent.cpp b/src/datadog/datadog_agent.cpp index 6e788ae7..9201822c 100644 --- a/src/datadog/datadog_agent.cpp +++ b/src/datadog/datadog_agent.cpp @@ -171,7 +171,7 @@ DatadogAgent::DatadogAgent( // Origin Detection headers are not necessary when Unix Domain Socket (UDS) // is used to communicate with the Datadog Agent. if (!contains(config.url.scheme, "unix")) { - if (auto container_id = container::get_id()) { + if (auto container_id = container::get_id(logger_)) { if (container_id->type == container::ContainerID::Type::container_id) { headers_.emplace("Datadog-Container-ID", container_id->value); headers_.emplace("Datadog-Entity-Id", "ci-" + container_id->value); diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index d2e94cac..7061e57c 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include // clang-format off @@ -45,6 +46,8 @@ #endif // clang-format on +#include + namespace datadog { namespace tracing { namespace { @@ -341,19 +344,21 @@ Optional get_cgroup_version() { return nullopt; } -Optional find_container_id_from_cgroup() { +Optional find_container_id_from_cgroup( + const std::shared_ptr& logger) { auto cgroup_fd = std::ifstream("/proc/self/cgroup", std::ios::in); if (!cgroup_fd.is_open()) { - std::cerr << "failed to open /proc/self/cgroup" << std::endl; + logger->log_error("failed to open /proc/self/cgroup"); return nullopt; } - return find_container_id(cgroup_fd); + return find_container_id(cgroup_fd, logger); } #endif } // namespace -Optional find_container_id(std::istream& source) { +Optional find_container_id(std::istream& source, + const std::shared_ptr& logger) { static const std::string uuid_regex_str = "[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}" "|(?:[0-9a-f]{8}(?:-[0-9a-f]{4}){4}$)"; @@ -365,7 +370,7 @@ Optional find_container_id(std::istream& source) { std::string line; while (std::getline(source, line)) { - std::cout << "Reading line: " << line << std::endl; + logger->log_error("Reading line: " + line); // Example: // `0::/system.slice/docker-abcdef0123456789abcdef0123456789.scope` std::smatch match; @@ -373,29 +378,33 @@ Optional find_container_id(std::istream& source) { assert(match.ready()); assert(match.size() == 2); - std::cout << "Found container ID: " << match.str(1) << std::endl; + logger->log_error("Found container ID: " + match.str(1)); return match.str(1); } } - std::cout << "No container ID found" << std::endl; + logger->log_error("No container ID found"); return nullopt; } -Optional get_id() { +Optional get_id(const std::shared_ptr& logger) { #if defined(__linux__) || defined(__unix__) if (is_running_in_host_namespace()) { // Not in a container, no need to continue. + logger->log_error("Not in a container, no need to continue."); return nullopt; } auto maybe_cgroup = get_cgroup_version(); - if (!maybe_cgroup) return nullopt; + if (!maybe_cgroup) { + logger->log_error("Failed to get cgroup version."); + return nullopt; + } ContainerID id; switch (*maybe_cgroup) { case Cgroup::v1: { - if (auto maybe_id = find_container_id_from_cgroup()) { + if (auto maybe_id = find_container_id_from_cgroup(logger)) { id.value = *maybe_id; id.type = ContainerID::Type::container_id; break; diff --git a/src/datadog/platform_util.h b/src/datadog/platform_util.h index a71d2df6..0f4dca05 100644 --- a/src/datadog/platform_util.h +++ b/src/datadog/platform_util.h @@ -3,8 +3,10 @@ // This component provides platform-dependent miscellanea. #include +#include #include +#include #include namespace datadog { @@ -90,13 +92,14 @@ struct ContainerID final { /// @param source The input from which to read the container ID. /// @return An Optional containing the container ID if found, otherwise /// nothing. -Optional find_container_id(std::istream& source); +Optional find_container_id(std::istream& source, + const std::shared_ptr& logger); /// Function to retrieve the container metadata. /// /// @return A `ContainerID` object containing id of the container in /// which the current process is running. -Optional get_id(); +Optional get_id(const std::shared_ptr& logger); } // namespace container diff --git a/test/test_platform_util.cpp b/test/test_platform_util.cpp index 6963c1e6..e9a3213a 100644 --- a/test/test_platform_util.cpp +++ b/test/test_platform_util.cpp @@ -2,6 +2,7 @@ #include "platform_util.h" #include "test.h" +#include "null_logger.h" using namespace datadog::tracing; @@ -58,7 +59,7 @@ PLATFORM_UTIL_TEST("find docker container ID") { std::istringstream is(test_case.input); - auto maybe_container_id = container::find_container_id(is); + auto maybe_container_id = container::find_container_id(is, std::make_shared()); if (test_case.expected_container_id.has_value()) { REQUIRE(maybe_container_id.has_value()); CHECK(*maybe_container_id == *test_case.expected_container_id); @@ -186,7 +187,7 @@ PLATFORM_UTIL_TEST("find multiline container IDs") { std::istringstream is(test_case.input); - auto maybe_container_id = container::find_container_id(is); + auto maybe_container_id = container::find_container_id(is, std::make_shared()); if (test_case.expected_container_id.has_value()) { REQUIRE(maybe_container_id.has_value()); CHECK(*maybe_container_id == *test_case.expected_container_id); From 6251ac45adfbe6b7b7f43ca7746c62f6146eac4b Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Mon, 14 Jul 2025 15:34:58 -0700 Subject: [PATCH 07/17] Remove the host namespace check since it stops us from working on Docker Desktop. --- src/datadog/platform_util.cpp | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index 7061e57c..ef0ab82d 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -302,7 +302,7 @@ constexpr uint64_t CGROUP2_SUPER_MAGIC = 0x63677270; /// Magic number from linux/proc_ns.h: /// -constexpr ino_t HOST_CGROUP_NAMESPACE_INODE = 0xeffffffb; +// constexpr ino_t HOST_CGROUP_NAMESPACE_INODE = 0xeffffffb; /// Represents the cgroup version of the current process. enum class Cgroup : char { v1, v2 }; @@ -316,19 +316,6 @@ Optional get_inode(std::string_view path) { return buf.st_ino; } -// Host namespace inode number are hardcoded, which allows for dectection of -// whether the binary is running in host or not. However, it does not work when -// running in a Docker in Docker environment. -bool is_running_in_host_namespace() { - // linux procfs file that represents the cgroup namespace of the current - // process. - if (auto inode = get_inode("/proc/self/ns/cgroup")) { - return *inode == HOST_CGROUP_NAMESPACE_INODE; - } - - return false; -} - Optional get_cgroup_version() { struct statfs buf; @@ -389,11 +376,8 @@ Optional find_container_id(std::istream& source, Optional get_id(const std::shared_ptr& logger) { #if defined(__linux__) || defined(__unix__) - if (is_running_in_host_namespace()) { - // Not in a container, no need to continue. - logger->log_error("Not in a container, no need to continue."); - return nullopt; - } + // Comment out the host namespace check, following the algorithm from other tracers. + // This should allow us to detect containers running in Docker Desktop. auto maybe_cgroup = get_cgroup_version(); if (!maybe_cgroup) { From 7fb67c95d30be0898561180887fd424494368307 Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Mon, 14 Jul 2025 15:59:55 -0700 Subject: [PATCH 08/17] Also remove the eager cgroup lookup because that's stopping us from collecting the container-id on Docker Desktop --- src/datadog/platform_util.cpp | 52 ++++++++--------------------------- 1 file changed, 11 insertions(+), 41 deletions(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index ef0ab82d..3ab4a5d3 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -297,15 +297,15 @@ namespace { #if defined(__linux__) || defined(__unix__) /// Magic numbers from linux/magic.h: /// -constexpr uint64_t CGROUP_SUPER_MAGIC = 0x27e0eb; -constexpr uint64_t CGROUP2_SUPER_MAGIC = 0x63677270; +// constexpr uint64_t CGROUP_SUPER_MAGIC = 0x27e0eb; +// constexpr uint64_t CGROUP2_SUPER_MAGIC = 0x63677270; /// Magic number from linux/proc_ns.h: /// // constexpr ino_t HOST_CGROUP_NAMESPACE_INODE = 0xeffffffb; /// Represents the cgroup version of the current process. -enum class Cgroup : char { v1, v2 }; +// enum class Cgroup : char { v1, v2 }; Optional get_inode(std::string_view path) { struct stat buf; @@ -316,21 +316,6 @@ Optional get_inode(std::string_view path) { return buf.st_ino; } -Optional get_cgroup_version() { - struct statfs buf; - - if (statfs("/sys/fs/cgroup", &buf) != 0) { - return nullopt; - } - - if (buf.f_type == CGROUP_SUPER_MAGIC) - return Cgroup::v1; - else if (buf.f_type == CGROUP2_SUPER_MAGIC) - return Cgroup::v2; - - return nullopt; -} - Optional find_container_id_from_cgroup( const std::shared_ptr& logger) { auto cgroup_fd = std::ifstream("/proc/self/cgroup", std::ios::in); @@ -377,32 +362,17 @@ Optional find_container_id(std::istream& source, Optional get_id(const std::shared_ptr& logger) { #if defined(__linux__) || defined(__unix__) // Comment out the host namespace check, following the algorithm from other tracers. + // Also don't get the cgroup version upfront, following the algorithm from other tracers. // This should allow us to detect containers running in Docker Desktop. - auto maybe_cgroup = get_cgroup_version(); - if (!maybe_cgroup) { - logger->log_error("Failed to get cgroup version."); - return nullopt; - } - ContainerID id; - switch (*maybe_cgroup) { - case Cgroup::v1: { - if (auto maybe_id = find_container_id_from_cgroup(logger)) { - id.value = *maybe_id; - id.type = ContainerID::Type::container_id; - break; - } - } - // NOTE(@dmehala): failed to find the container ID, try getting the cgroup - // inode. - [[fallthrough]]; - case Cgroup::v2: { - if (auto maybe_inode = get_inode("/sys/fs/cgroup")) { - id.type = ContainerID::Type::cgroup_inode; - id.value = std::to_string(*maybe_inode); - } - }; break; + if (auto maybe_id = find_container_id_from_cgroup(logger)) { + id.value = *maybe_id; + id.type = ContainerID::Type::container_id; + } else if (auto maybe_inode = get_inode("/sys/fs/cgroup")) { + // NOTE(@dmehala): failed to find the container ID, try getting the cgroup inode. + id.type = ContainerID::Type::cgroup_inode; + id.value = std::to_string(*maybe_inode); } return id; From 70d6db4f5c851aeda972e408c825b804ead9f351 Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Mon, 14 Jul 2025 16:52:16 -0700 Subject: [PATCH 09/17] Refactor to better align with Java implementation --- src/datadog/platform_util.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index 3ab4a5d3..b78b4aa8 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -302,7 +302,7 @@ namespace { /// Magic number from linux/proc_ns.h: /// -// constexpr ino_t HOST_CGROUP_NAMESPACE_INODE = 0xeffffffb; +constexpr ino_t HOST_CGROUP_NAMESPACE_INODE = 0xeffffffb; /// Represents the cgroup version of the current process. // enum class Cgroup : char { v1, v2 }; @@ -316,6 +316,19 @@ Optional get_inode(std::string_view path) { return buf.st_ino; } +// Host namespace inode number are hardcoded, which allows for dectection of +// whether the binary is running in host or not. However, it does not work when +// running in a Docker in Docker environment. +bool is_running_in_host_namespace() { + // linux procfs file that represents the cgroup namespace of the current + // process. + if (auto inode = get_inode("/proc/self/ns/cgroup")) { + return *inode == HOST_CGROUP_NAMESPACE_INODE; + } + + return false; +} + Optional find_container_id_from_cgroup( const std::shared_ptr& logger) { auto cgroup_fd = std::ifstream("/proc/self/cgroup", std::ios::in); @@ -361,18 +374,18 @@ Optional find_container_id(std::istream& source, Optional get_id(const std::shared_ptr& logger) { #if defined(__linux__) || defined(__unix__) - // Comment out the host namespace check, following the algorithm from other tracers. - // Also don't get the cgroup version upfront, following the algorithm from other tracers. - // This should allow us to detect containers running in Docker Desktop. - + // Determine the container ID or inode ContainerID id; if (auto maybe_id = find_container_id_from_cgroup(logger)) { id.value = *maybe_id; id.type = ContainerID::Type::container_id; - } else if (auto maybe_inode = get_inode("/sys/fs/cgroup")) { + } else if (!is_running_in_host_namespace()) { // NOTE(@dmehala): failed to find the container ID, try getting the cgroup inode. - id.type = ContainerID::Type::cgroup_inode; - id.value = std::to_string(*maybe_inode); + auto maybe_inode = get_inode("/sys/fs/cgroup"); + if (maybe_inode) { + id.type = ContainerID::Type::cgroup_inode; + id.value = std::to_string(*maybe_inode); + } } return id; From f0abaadd01f42250723de772b61aec623badf8ab Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Mon, 14 Jul 2025 17:01:41 -0700 Subject: [PATCH 10/17] Remove all uses of logger now that we're done debugging system-tests issues. Also remove unused code. --- src/datadog/datadog_agent.cpp | 2 +- src/datadog/platform_util.cpp | 27 +++++---------------------- src/datadog/platform_util.h | 7 ++----- test/test_platform_util.cpp | 5 ++--- 4 files changed, 10 insertions(+), 31 deletions(-) diff --git a/src/datadog/datadog_agent.cpp b/src/datadog/datadog_agent.cpp index 9201822c..6e788ae7 100644 --- a/src/datadog/datadog_agent.cpp +++ b/src/datadog/datadog_agent.cpp @@ -171,7 +171,7 @@ DatadogAgent::DatadogAgent( // Origin Detection headers are not necessary when Unix Domain Socket (UDS) // is used to communicate with the Datadog Agent. if (!contains(config.url.scheme, "unix")) { - if (auto container_id = container::get_id(logger_)) { + if (auto container_id = container::get_id()) { if (container_id->type == container::ContainerID::Type::container_id) { headers_.emplace("Datadog-Container-ID", container_id->value); headers_.emplace("Datadog-Entity-Id", "ci-" + container_id->value); diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index b78b4aa8..223b4dba 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include // clang-format off @@ -46,8 +45,6 @@ #endif // clang-format on -#include - namespace datadog { namespace tracing { namespace { @@ -295,18 +292,10 @@ Expected InMemoryFile::make(StringView) { namespace container { namespace { #if defined(__linux__) || defined(__unix__) -/// Magic numbers from linux/magic.h: -/// -// constexpr uint64_t CGROUP_SUPER_MAGIC = 0x27e0eb; -// constexpr uint64_t CGROUP2_SUPER_MAGIC = 0x63677270; - /// Magic number from linux/proc_ns.h: /// constexpr ino_t HOST_CGROUP_NAMESPACE_INODE = 0xeffffffb; -/// Represents the cgroup version of the current process. -// enum class Cgroup : char { v1, v2 }; - Optional get_inode(std::string_view path) { struct stat buf; if (stat(path.data(), &buf) != 0) { @@ -329,21 +318,18 @@ bool is_running_in_host_namespace() { return false; } -Optional find_container_id_from_cgroup( - const std::shared_ptr& logger) { +Optional find_container_id_from_cgroup() { auto cgroup_fd = std::ifstream("/proc/self/cgroup", std::ios::in); if (!cgroup_fd.is_open()) { - logger->log_error("failed to open /proc/self/cgroup"); return nullopt; } - return find_container_id(cgroup_fd, logger); + return find_container_id(cgroup_fd); } #endif } // namespace -Optional find_container_id(std::istream& source, - const std::shared_ptr& logger) { +Optional find_container_id(std::istream& source) { static const std::string uuid_regex_str = "[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}" "|(?:[0-9a-f]{8}(?:-[0-9a-f]{4}){4}$)"; @@ -355,7 +341,6 @@ Optional find_container_id(std::istream& source, std::string line; while (std::getline(source, line)) { - logger->log_error("Reading line: " + line); // Example: // `0::/system.slice/docker-abcdef0123456789abcdef0123456789.scope` std::smatch match; @@ -363,20 +348,18 @@ Optional find_container_id(std::istream& source, assert(match.ready()); assert(match.size() == 2); - logger->log_error("Found container ID: " + match.str(1)); return match.str(1); } } - logger->log_error("No container ID found"); return nullopt; } -Optional get_id(const std::shared_ptr& logger) { +Optional get_id() { #if defined(__linux__) || defined(__unix__) // Determine the container ID or inode ContainerID id; - if (auto maybe_id = find_container_id_from_cgroup(logger)) { + if (auto maybe_id = find_container_id_from_cgroup()) { id.value = *maybe_id; id.type = ContainerID::Type::container_id; } else if (!is_running_in_host_namespace()) { diff --git a/src/datadog/platform_util.h b/src/datadog/platform_util.h index 0f4dca05..a71d2df6 100644 --- a/src/datadog/platform_util.h +++ b/src/datadog/platform_util.h @@ -3,10 +3,8 @@ // This component provides platform-dependent miscellanea. #include -#include #include -#include #include namespace datadog { @@ -92,14 +90,13 @@ struct ContainerID final { /// @param source The input from which to read the container ID. /// @return An Optional containing the container ID if found, otherwise /// nothing. -Optional find_container_id(std::istream& source, - const std::shared_ptr& logger); +Optional find_container_id(std::istream& source); /// Function to retrieve the container metadata. /// /// @return A `ContainerID` object containing id of the container in /// which the current process is running. -Optional get_id(const std::shared_ptr& logger); +Optional get_id(); } // namespace container diff --git a/test/test_platform_util.cpp b/test/test_platform_util.cpp index e9a3213a..6963c1e6 100644 --- a/test/test_platform_util.cpp +++ b/test/test_platform_util.cpp @@ -2,7 +2,6 @@ #include "platform_util.h" #include "test.h" -#include "null_logger.h" using namespace datadog::tracing; @@ -59,7 +58,7 @@ PLATFORM_UTIL_TEST("find docker container ID") { std::istringstream is(test_case.input); - auto maybe_container_id = container::find_container_id(is, std::make_shared()); + auto maybe_container_id = container::find_container_id(is); if (test_case.expected_container_id.has_value()) { REQUIRE(maybe_container_id.has_value()); CHECK(*maybe_container_id == *test_case.expected_container_id); @@ -187,7 +186,7 @@ PLATFORM_UTIL_TEST("find multiline container IDs") { std::istringstream is(test_case.input); - auto maybe_container_id = container::find_container_id(is, std::make_shared()); + auto maybe_container_id = container::find_container_id(is); if (test_case.expected_container_id.has_value()) { REQUIRE(maybe_container_id.has_value()); CHECK(*maybe_container_id == *test_case.expected_container_id); From 565c4e073e87014e135707a223408481d8f5148a Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Tue, 15 Jul 2025 11:30:46 -0700 Subject: [PATCH 11/17] Put back the get_cgroup_version and add temporary logging to confirm the f_type returned by the statfs call --- src/datadog/datadog_agent.cpp | 2 +- src/datadog/platform_util.cpp | 35 ++++++++++++++++++++++++++++++++++- src/datadog/platform_util.h | 4 +++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/datadog/datadog_agent.cpp b/src/datadog/datadog_agent.cpp index 6e788ae7..9201822c 100644 --- a/src/datadog/datadog_agent.cpp +++ b/src/datadog/datadog_agent.cpp @@ -171,7 +171,7 @@ DatadogAgent::DatadogAgent( // Origin Detection headers are not necessary when Unix Domain Socket (UDS) // is used to communicate with the Datadog Agent. if (!contains(config.url.scheme, "unix")) { - if (auto container_id = container::get_id()) { + if (auto container_id = container::get_id(logger_)) { if (container_id->type == container::ContainerID::Type::container_id) { headers_.emplace("Datadog-Container-ID", container_id->value); headers_.emplace("Datadog-Entity-Id", "ci-" + container_id->value); diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index 223b4dba..326a7714 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include // clang-format off @@ -45,6 +46,8 @@ #endif // clang-format on +#include + namespace datadog { namespace tracing { namespace { @@ -292,10 +295,18 @@ Expected InMemoryFile::make(StringView) { namespace container { namespace { #if defined(__linux__) || defined(__unix__) +/// Magic numbers from linux/magic.h: +/// +constexpr uint64_t CGROUP_SUPER_MAGIC = 0x27e0eb; +constexpr uint64_t CGROUP2_SUPER_MAGIC = 0x63677270; + /// Magic number from linux/proc_ns.h: /// constexpr ino_t HOST_CGROUP_NAMESPACE_INODE = 0xeffffffb; +/// Represents the cgroup version of the current process. +enum class Cgroup : char { v1, v2 }; + Optional get_inode(std::string_view path) { struct stat buf; if (stat(path.data(), &buf) != 0) { @@ -318,6 +329,25 @@ bool is_running_in_host_namespace() { return false; } +Optional get_cgroup_version(const std::shared_ptr& logger) { + struct statfs buf; + + if (statfs("/sys/fs/cgroup", &buf) != 0) { + logger->log_error("Failed to statfs /sys/fs/cgroup"); + return nullopt; + } + + logger->log_error([&](auto& stream) { + stream << "statfs /sys/fs/cgroup: f_type = " << buf.f_type; + }); + if (buf.f_type == CGROUP_SUPER_MAGIC) + return Cgroup::v1; + else if (buf.f_type == CGROUP2_SUPER_MAGIC) + return Cgroup::v2; + + return nullopt; +} + Optional find_container_id_from_cgroup() { auto cgroup_fd = std::ifstream("/proc/self/cgroup", std::ios::in); if (!cgroup_fd.is_open()) { @@ -355,8 +385,11 @@ Optional find_container_id(std::istream& source) { return nullopt; } -Optional get_id() { +Optional get_id(const std::shared_ptr& logger) { #if defined(__linux__) || defined(__unix__) + auto maybe_cgroup = get_cgroup_version(logger); + if (!maybe_cgroup) return nullopt; + // Determine the container ID or inode ContainerID id; if (auto maybe_id = find_container_id_from_cgroup()) { diff --git a/src/datadog/platform_util.h b/src/datadog/platform_util.h index a71d2df6..2b3c42cb 100644 --- a/src/datadog/platform_util.h +++ b/src/datadog/platform_util.h @@ -3,8 +3,10 @@ // This component provides platform-dependent miscellanea. #include +#include #include +#include #include namespace datadog { @@ -96,7 +98,7 @@ Optional find_container_id(std::istream& source); /// /// @return A `ContainerID` object containing id of the container in /// which the current process is running. -Optional get_id(); +Optional get_id(const std::shared_ptr& logger); } // namespace container From 587405f01679c9b2712ccedbee55f7071acb9ea0 Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Wed, 16 Jul 2025 08:27:48 -0700 Subject: [PATCH 12/17] Restore the cgroup logic, but also include TMPFS_MAGIC as a valid value for using our cgroup v1 lookup --- src/datadog/platform_util.cpp | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index 326a7714..e5f5971b 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -297,6 +297,7 @@ namespace { #if defined(__linux__) || defined(__unix__) /// Magic numbers from linux/magic.h: /// +constexpr uint64_t TMPFS_MAGIC = 0x01021994; constexpr uint64_t CGROUP_SUPER_MAGIC = 0x27e0eb; constexpr uint64_t CGROUP2_SUPER_MAGIC = 0x63677270; @@ -340,7 +341,7 @@ Optional get_cgroup_version(const std::shared_ptr& logg logger->log_error([&](auto& stream) { stream << "statfs /sys/fs/cgroup: f_type = " << buf.f_type; }); - if (buf.f_type == CGROUP_SUPER_MAGIC) + if (buf.f_type == CGROUP_SUPER_MAGIC || buf.f_type == TMPFS_MAGIC) return Cgroup::v1; else if (buf.f_type == CGROUP2_SUPER_MAGIC) return Cgroup::v2; @@ -392,16 +393,26 @@ Optional get_id(const std::shared_ptr& logger) { // Determine the container ID or inode ContainerID id; - if (auto maybe_id = find_container_id_from_cgroup()) { - id.value = *maybe_id; - id.type = ContainerID::Type::container_id; - } else if (!is_running_in_host_namespace()) { - // NOTE(@dmehala): failed to find the container ID, try getting the cgroup inode. - auto maybe_inode = get_inode("/sys/fs/cgroup"); - if (maybe_inode) { - id.type = ContainerID::Type::cgroup_inode; - id.value = std::to_string(*maybe_inode); + switch (*maybe_cgroup) { + case Cgroup::v1: { + if (auto maybe_id = find_container_id_from_cgroup()) { + id.value = *maybe_id; + id.type = ContainerID::Type::container_id; + break; + } } + // NOTE(@dmehala): failed to find the container ID, try getting the cgroup + // inode. + [[fallthrough]]; + case Cgroup::v2: { + if (!is_running_in_host_namespace()) { + auto maybe_inode = get_inode("/sys/fs/cgroup"); + if (maybe_inode) { + id.type = ContainerID::Type::cgroup_inode; + id.value = std::to_string(*maybe_inode); + } + } + }; break; } return id; From 08909b1efbecb290ed6166a01978a5d2799c44d5 Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Wed, 16 Jul 2025 10:25:03 -0700 Subject: [PATCH 13/17] Remove logging (again) and reduce the diff --- src/datadog/datadog_agent.cpp | 2 +- src/datadog/platform_util.cpp | 19 ++++--------------- src/datadog/platform_util.h | 4 +--- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/datadog/datadog_agent.cpp b/src/datadog/datadog_agent.cpp index 9201822c..6e788ae7 100644 --- a/src/datadog/datadog_agent.cpp +++ b/src/datadog/datadog_agent.cpp @@ -171,7 +171,7 @@ DatadogAgent::DatadogAgent( // Origin Detection headers are not necessary when Unix Domain Socket (UDS) // is used to communicate with the Datadog Agent. if (!contains(config.url.scheme, "unix")) { - if (auto container_id = container::get_id(logger_)) { + if (auto container_id = container::get_id()) { if (container_id->type == container::ContainerID::Type::container_id) { headers_.emplace("Datadog-Container-ID", container_id->value); headers_.emplace("Datadog-Entity-Id", "ci-" + container_id->value); diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index e5f5971b..23a9dc3f 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -3,8 +3,6 @@ #include #include #include -#include -#include #include // clang-format off @@ -46,8 +44,6 @@ #endif // clang-format on -#include - namespace datadog { namespace tracing { namespace { @@ -330,17 +326,13 @@ bool is_running_in_host_namespace() { return false; } -Optional get_cgroup_version(const std::shared_ptr& logger) { +Optional get_cgroup_version() { struct statfs buf; if (statfs("/sys/fs/cgroup", &buf) != 0) { - logger->log_error("Failed to statfs /sys/fs/cgroup"); return nullopt; } - logger->log_error([&](auto& stream) { - stream << "statfs /sys/fs/cgroup: f_type = " << buf.f_type; - }); if (buf.f_type == CGROUP_SUPER_MAGIC || buf.f_type == TMPFS_MAGIC) return Cgroup::v1; else if (buf.f_type == CGROUP2_SUPER_MAGIC) @@ -351,9 +343,7 @@ Optional get_cgroup_version(const std::shared_ptr& logg Optional find_container_id_from_cgroup() { auto cgroup_fd = std::ifstream("/proc/self/cgroup", std::ios::in); - if (!cgroup_fd.is_open()) { - return nullopt; - } + if (!cgroup_fd.is_open()) return nullopt; return find_container_id(cgroup_fd); } @@ -386,12 +376,11 @@ Optional find_container_id(std::istream& source) { return nullopt; } -Optional get_id(const std::shared_ptr& logger) { +Optional get_id() { #if defined(__linux__) || defined(__unix__) - auto maybe_cgroup = get_cgroup_version(logger); + auto maybe_cgroup = get_cgroup_version(); if (!maybe_cgroup) return nullopt; - // Determine the container ID or inode ContainerID id; switch (*maybe_cgroup) { case Cgroup::v1: { diff --git a/src/datadog/platform_util.h b/src/datadog/platform_util.h index 2b3c42cb..a71d2df6 100644 --- a/src/datadog/platform_util.h +++ b/src/datadog/platform_util.h @@ -3,10 +3,8 @@ // This component provides platform-dependent miscellanea. #include -#include #include -#include #include namespace datadog { @@ -98,7 +96,7 @@ Optional find_container_id(std::istream& source); /// /// @return A `ContainerID` object containing id of the container in /// which the current process is running. -Optional get_id(const std::shared_ptr& logger); +Optional get_id(); } // namespace container From 376793e51751608a1dbd7fda1e93266c0f260498 Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Wed, 16 Jul 2025 10:31:31 -0700 Subject: [PATCH 14/17] Restore the previous substring approach and execute this first before invoking regex matching --- src/datadog/platform_util.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index 23a9dc3f..e0b8a932 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -351,6 +351,7 @@ Optional find_container_id_from_cgroup() { } // namespace Optional find_container_id(std::istream& source) { + constexpr std::string_view docker_str = "docker-"; static const std::string uuid_regex_str = "[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}" "|(?:[0-9a-f]{8}(?:-[0-9a-f]{4}){4}$)"; @@ -361,6 +362,28 @@ Optional find_container_id(std::istream& source) { ")(?:\\.scope)?$"); std::string line; + + // First, iterate using the simple substring match. + while (std::getline(source, line)) { + // Example: + // `0::/system.slice/docker-abcdef0123456789abcdef0123456789.scope` + if (auto beg = line.find(docker_str); beg != std::string::npos) { + beg += docker_str.size(); + auto end = line.find(".scope", beg); + if (end == std::string::npos || end - beg <= 0) { + continue; + } + + auto container_id = line.substr(beg, end - beg); + return container_id; + } + } + + // Reset the stream to the beginning. + source.clear(); + source.seekg(0); + + // If no match is found, iterate using the regex match. while (std::getline(source, line)) { // Example: // `0::/system.slice/docker-abcdef0123456789abcdef0123456789.scope` From 039883aca953801c721b43292936c2a939ea280c Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Wed, 16 Jul 2025 14:36:15 -0700 Subject: [PATCH 15/17] Apply suggestions from code review Co-authored-by: Damien Mehala --- src/datadog/platform_util.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index e0b8a932..5a405e25 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -363,7 +363,7 @@ Optional find_container_id(std::istream& source) { std::string line; - // First, iterate using the simple substring match. + // Look for Docker container IDs in the basic format: `docker-.scope`. while (std::getline(source, line)) { // Example: // `0::/system.slice/docker-abcdef0123456789abcdef0123456789.scope` @@ -383,12 +383,13 @@ Optional find_container_id(std::istream& source) { source.clear(); source.seekg(0); - // If no match is found, iterate using the regex match. + // Perform a second pass using a regular expression for matching container IDs in a Fargate environment. + // This two-step approach is used because STL `regex` is relatively slow, so we avoid using it unless necessary. while (std::getline(source, line)) { // Example: // `0::/system.slice/docker-abcdef0123456789abcdef0123456789.scope` std::smatch match; - if (std::regex_match(line, match, path_reg)) { + if (std::regex_match(line, match, path_reg) && match.size() == 2) { assert(match.ready()); assert(match.size() == 2); From d8576b981b1929c95bf77dc75d83f96c298a901d Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Wed, 16 Jul 2025 15:24:55 -0700 Subject: [PATCH 16/17] Move the regex string literals closer to their usage --- src/datadog/platform_util.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index 5a405e25..ad58e855 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -351,19 +351,11 @@ Optional find_container_id_from_cgroup() { } // namespace Optional find_container_id(std::istream& source) { - constexpr std::string_view docker_str = "docker-"; - static const std::string uuid_regex_str = - "[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}" - "|(?:[0-9a-f]{8}(?:-[0-9a-f]{4}){4}$)"; - static const std::string container_regex_str = "[0-9a-f]{64}"; - static const std::string task_regex_str = "[0-9a-f]{32}-\\d+"; - static const std::regex path_reg("(?:.+)?(" + uuid_regex_str + "|" + - container_regex_str + "|" + task_regex_str + - ")(?:\\.scope)?$"); - std::string line; // Look for Docker container IDs in the basic format: `docker-.scope`. + constexpr std::string_view docker_str = "docker-"; + while (std::getline(source, line)) { // Example: // `0::/system.slice/docker-abcdef0123456789abcdef0123456789.scope` @@ -385,6 +377,15 @@ Optional find_container_id(std::istream& source) { // Perform a second pass using a regular expression for matching container IDs in a Fargate environment. // This two-step approach is used because STL `regex` is relatively slow, so we avoid using it unless necessary. + static const std::string uuid_regex_str = + "[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}" + "|(?:[0-9a-f]{8}(?:-[0-9a-f]{4}){4}$)"; + static const std::string container_regex_str = "[0-9a-f]{64}"; + static const std::string task_regex_str = "[0-9a-f]{32}-\\d+"; + static const std::regex path_reg("(?:.+)?(" + uuid_regex_str + "|" + + container_regex_str + "|" + task_regex_str + + ")(?:\\.scope)?$"); + while (std::getline(source, line)) { // Example: // `0::/system.slice/docker-abcdef0123456789abcdef0123456789.scope` From 9d1946b3a2fa18c28caf42fd3542e7f0e3a7d572 Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Wed, 16 Jul 2025 15:26:48 -0700 Subject: [PATCH 17/17] Fix formatting --- src/datadog/platform_util.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/datadog/platform_util.cpp b/src/datadog/platform_util.cpp index ad58e855..854c1178 100644 --- a/src/datadog/platform_util.cpp +++ b/src/datadog/platform_util.cpp @@ -375,8 +375,9 @@ Optional find_container_id(std::istream& source) { source.clear(); source.seekg(0); - // Perform a second pass using a regular expression for matching container IDs in a Fargate environment. - // This two-step approach is used because STL `regex` is relatively slow, so we avoid using it unless necessary. + // Perform a second pass using a regular expression for matching container IDs + // in a Fargate environment. This two-step approach is used because STL + // `regex` is relatively slow, so we avoid using it unless necessary. static const std::string uuid_regex_str = "[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}" "|(?:[0-9a-f]{8}(?:-[0-9a-f]{4}){4}$)";