Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
edb4f89
Update docker container ID test to use a UUID that's 64 hex-chars lon…
zacharycmontoya Jun 30, 2025
bb3d458
Rename container::find_docker_container_id to container::find_contain…
zacharycmontoya Jun 30, 2025
2174c80
Add other cgroup file examples from the .NET Tracer
zacharycmontoya Jun 30, 2025
136d4cc
Fix formatting
zacharycmontoya Jun 30, 2025
43f214a
Add temporary logging to stdout and stderr for the container-id parsing
zacharycmontoya Jul 14, 2025
d6e9297
This doesn't pass unit tests, but now I am writing some more helpful …
zacharycmontoya Jul 14, 2025
6251ac4
Remove the host namespace check since it stops us from working on Doc…
zacharycmontoya Jul 14, 2025
7fb67c9
Also remove the eager cgroup lookup because that's stopping us from c…
zacharycmontoya Jul 14, 2025
70d6db4
Refactor to better align with Java implementation
zacharycmontoya Jul 14, 2025
f0abaad
Remove all uses of logger now that we're done debugging system-tests …
zacharycmontoya Jul 15, 2025
565c4e0
Put back the get_cgroup_version and add temporary logging to confirm …
zacharycmontoya Jul 15, 2025
587405f
Restore the cgroup logic, but also include TMPFS_MAGIC as a valid val…
zacharycmontoya Jul 16, 2025
08909b1
Remove logging (again) and reduce the diff
zacharycmontoya Jul 16, 2025
376793e
Restore the previous substring approach and execute this first before…
zacharycmontoya Jul 16, 2025
039883a
Apply suggestions from code review
zacharycmontoya Jul 16, 2025
d8576b9
Move the regex string literals closer to their usage
zacharycmontoya Jul 16, 2025
9d1946b
Fix formatting
zacharycmontoya Jul 16, 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
90 changes: 31 additions & 59 deletions src/datadog/platform_util.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#include "platform_util.h"

#include <cassert>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <regex>

// clang-format off
#if defined(__x86_64__) || defined(_M_X64)
Expand Down Expand Up @@ -289,18 +292,10 @@ Expected<InMemoryFile> InMemoryFile::make(StringView) {
namespace container {
namespace {
#if defined(__linux__) || defined(__unix__)
/// Magic numbers from linux/magic.h:
/// <https://github.com/torvalds/linux/blob/ca91b9500108d4cf083a635c2e11c884d5dd20ea/include/uapi/linux/magic.h#L71>
constexpr uint64_t CGROUP_SUPER_MAGIC = 0x27e0eb;
constexpr uint64_t CGROUP2_SUPER_MAGIC = 0x63677270;

/// Magic number from linux/proc_ns.h:
/// <https://github.com/torvalds/linux/blob/5859a2b1991101d6b978f3feb5325dad39421f29/include/linux/proc_ns.h#L41-L49>
constexpr ino_t HOST_CGROUP_NAMESPACE_INODE = 0xeffffffb;

/// Represents the cgroup version of the current process.
enum class Cgroup : char { v1, v2 };

Optional<ino_t> get_inode(std::string_view path) {
struct stat buf;
if (stat(path.data(), &buf) != 0) {
Expand All @@ -323,46 +318,37 @@ bool is_running_in_host_namespace() {
return false;
}

Optional<Cgroup> get_cgroup_version() {
struct statfs buf;

if (statfs("/sys/fs/cgroup", &buf) != 0) {
Optional<std::string> find_container_id_from_cgroup() {
auto cgroup_fd = std::ifstream("/proc/self/cgroup", std::ios::in);
if (!cgroup_fd.is_open()) {
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<std::string> find_docker_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<std::string> find_docker_container_id(std::istream& source) {
constexpr std::string_view docker_str = "docker-";
Optional<std::string> 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)?$");
Comment thread
zacharycmontoya marked this conversation as resolved.
Outdated

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)) {
Comment thread
zacharycmontoya marked this conversation as resolved.
Outdated
assert(match.ready());
assert(match.size() == 2);

auto container_id = line.substr(beg, end - beg);
return container_id;
return match.str(1);
}
}

Expand All @@ -371,32 +357,18 @@ Optional<std::string> find_docker_container_id(std::istream& source) {

Optional<ContainerID> get_id() {
#if defined(__linux__) || defined(__unix__)
if (is_running_in_host_namespace()) {
// Not in a container, no need to continue.
return nullopt;
}

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: {
if (auto maybe_id = find_docker_container_id_from_cgroup()) {
id.value = *maybe_id;
id.type = ContainerID::Type::container_id;
break;
}
if (auto maybe_id = find_container_id_from_cgroup()) {
Copy link
Copy Markdown
Contributor Author

@zacharycmontoya zacharycmontoya Jul 15, 2025

Choose a reason for hiding this comment

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

At this moment, this changes the behavior to align more closely with the .NET and Java libraries:

  • Get the container-id first by reading (and parsing if available) the file /proc/self/cgroup
  • If getting the container-id fails, then try to get the inode, but if we are in the host cgroup namespace then do not do this. This host cgroup namespace check was implemented before, but this PR moves the logic to only run the check when invoking the inode fallback

Additional changes I plan to make:

  • This still doesn't incorporate the fast-path logic to avoid the regex usage, so I still plan to include that.

This has been tested with system-tests by running the cpp_nginx library locally against this system-tests PR (system-tests#4925). To get an nginx-datadog build, I had the CI run on the zach.montoya/test-dd-trace-cpp-container-id branch of Datadog/nginx-datadog, with the latest commit here.

Copy link
Copy Markdown
Contributor

@dmehala dmehala Jul 15, 2025

Choose a reason for hiding this comment

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

In the current code, we clearly follow two paths: one for cgroup v1 and one for cgroup v2. Most importantly, since we know for sure we can’t get the container ID for cgroup v2, there’s no need to try in that case.

I spent a good amount of time reading the RFC, and I believe this version matches it better. I suggest we keep it this way.

EDIT: Given that the container ID is not found, it should report the inode. My understanding is using the inode alone be should sufficient for host-level tag correlation. Have we had a chance to investigate why this approach might not be working as expected?

Copy link
Copy Markdown
Contributor Author

@zacharycmontoya zacharycmontoya Jul 15, 2025

Choose a reason for hiding this comment

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

The issue I had (maybe this is simply a Docker in Docker scenario) is that the original get_cgroup_version() implementation failed when running system-tests locally, even though getting the container ID via /proc/self/cgroup would end up succeeding. For this reason, I removed that logic entirely.

I can take a closer look at /sys/fs/cgroup to understand why the existing cgroup v1/v2 lookup failed, but to emphasize, I made the changes to both move the host namespace and remove the cgroup lookup because they were failing in the system-tests cpp_nginx weblog container, and revising the logic to align more closely with .NET and Java (while also passing the system-tests) yielded this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I spent a good amount of time reading the RFC, and I believe this version matches it better. I suggest we keep it this way.

Just to make sure I'm understanding you correctly on this, is the newly proposed code your preference? Or is your preference the previous code where we clearly separated the logical paths based on cgroup v1 / v2? The "this" and "current" words in your comment were slightly ambiguous to me when reading

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Following up on this, I ran the nginx:1.25.4 container (the one where the cpp_nginx weblog is deployed) and there's no statfs command available. When making the call from the stdlib, does statfs have to be available for that call to succeed? Because it was the statfs("/sys/fs/cgroup", &buf) that was failing before

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

So actually, I was able to run this, which I think functions the same as statfs():

# stat -f /sys/fs/cgroup
  File: "/sys/fs/cgroup"
    ID: 40b90acb90ae1b43 Namelen: 255     Type: tmpfs
Block size: 4096       Fundamental block size: 4096
Blocks: Total: 2020153    Free: 2020153    Available: 2020153
Inodes: Total: 2020153    Free: 2020137

However, the type is tmpfs, which is not CGROUP_SUPER_MAGIC 0x27e0eb or CGROUP2_SUPER_MAGIC 0x63677270.

I've also confirmed that the statfs("/sys/fs/cgroup", &buf) call returns TMPFS_MAGIC 0x01021994. So this means in the Docker in Docker scenario where we can find a container-ID, we get the f_type of tmpfs. Shall we restore the previous Cgroup logic but consider tmpfs as Cgroup::v1?

Copy link
Copy Markdown
Contributor

@dmehala dmehala Jul 16, 2025

Choose a reason for hiding this comment

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

is the newly proposed code your preference? Or is your preference the previous code where we clearly separated the logical paths based on cgroup v1 / v2? The "this" and "current" words in your comment were slightly ambiguous to me when reading

My bad. I'd rather keep the previous code.

I've also confirmed that the statfs("/sys/fs/cgroup", &buf) call returns TMPFS_MAGIC 0x01021994

cgroup v1 controller are usually mounter under tmpfs source. We should restore the previous cgroup logic and consider bothCGROUP_SUPER_MAGIC, TMPFS_MAGIC.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Understood, will follow up with the requested changes 👍🏼

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok I added the following:

  • Restore the original cgroup control flow with tmpfs in 587405f
  • Change the container-id lookup to do the substring logic first then + regex as fallback in 376793e

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);
}
// 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;
}

return id;
Expand Down
8 changes: 4 additions & 4 deletions src/datadog/platform_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string> find_docker_container_id(std::istream& source);
Optional<std::string> find_container_id(std::istream& source);

/// Function to retrieve the container metadata.
///
Expand Down
140 changes: 135 additions & 5 deletions test/test_platform_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ 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
Expand All @@ -41,22 +43,150 @@ 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:/
3:cpu,cpuacct:/user.slice/user-0.slice/session-14.scope
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);

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 multiline container IDs") {
struct TestCase {
size_t line;
std::string_view name;
std::string input;
Optional<std::string> expected_container_id;
};

auto test_case = GENERATE(values<TestCase>({
{__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
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"},
{__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);

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);
Expand Down