libdd_common/entity_id/mod.rs
1// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/
2// SPDX-License-Identifier: Apache-2.0
3
4//! Extract the entity id, container id and external env
5//!
6//! The container id can be extracted from `/proc/self/group`
7//!
8//! The entity id is one of:
9//! - `cid:<container id>` if available
10//! - `in:<cgroup node inode>` if container id is not available (e.g. when using cgroupV2)
11//!
12//! The external env is an environment variable provided by the admission controller.
13//!
14//! # References
15//! - [DataDog/dd-trace-go](https://github.com/DataDog/dd-trace-go/blob/v1/internal/container.go)
16//! - [Qard/container-info](https://github.com/Qard/container-info/blob/master/index.js)
17//! # Supported environments
18//! ## Docker
19//! /proc/self/cgroup should contain lines like:
20//! ```text
21//! 13:name=systemd:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860
22//! ```
23//! ## Kubernetes
24//! /proc/self/cgroup should contain lines like:
25//! ```text
26//! 11:perf_event:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1
27//! ```
28//!
29//! Possibly with extra characters before id:
30//! ```text
31//! 1:name=systemd:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod2d3da189_6407_48e3_9ab6_78188d75e609.slice/docker-7b8952daecf4c0e44bbcefe1b5c5ebc7b4839d4eefeccefe694709d3809b6199.scope
32//! ```
33//!
34//! Or a UUID:
35//! ```text
36//! 1:name=systemd:/kubepods/besteffort/pode9b90526-f47d-11e8-b2a5-080027b9f4fb/15aa6e53-b09a-40c7-8558-c6c31e36c88a
37//! ```
38//! ## ECS
39//! /proc/self/cgroup should contain lines like:
40//! ```text
41//! 9:perf_event:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce
42//! ```
43//! ## Fargate 1.3-:
44//! /proc/self/cgroup should contain lines like:
45//! ```test
46//! 11:hugetlb:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da
47//! ```
48//! ## Fargate 1.4+:
49//! Here we match a task id with a suffix
50//! ```test
51//! 1:name=systemd:/ecs/8cd79a803caf4d2aa945152e934a5c00/8cd79a803caf4d2aa945152e934a5c00-1053176469
52//! ```
53
54use crate::config::parse_env;
55use std::sync::LazyLock;
56
57const EXTERNAL_ENV_ENVIRONMENT_VARIABLE: &str = "DD_EXTERNAL_ENV";
58
59/// Unix specific module allowing the use of unix specific functions
60#[cfg(unix)]
61mod unix;
62
63/// Set the path to cgroup file to mock it during tests
64#[cfg(feature = "cgroup_testing")]
65pub fn set_cgroup_file(_file: String) {
66 #[cfg(unix)]
67 {
68 unix::set_cgroup_file(_file)
69 }
70}
71
72/// Returns the `container_id` if available in the cgroup file, otherwise returns `None`
73pub fn get_container_id() -> Option<&'static str> {
74 #[cfg(unix)]
75 {
76 *unix::CONTAINER_ID
77 }
78 #[cfg(not(unix))]
79 {
80 None
81 }
82}
83
84/// Returns the `entity_id` if available, either `cid-<container_id>` or `in-<cgroup_inode>`
85pub fn get_entity_id() -> Option<&'static str> {
86 #[cfg(unix)]
87 {
88 *unix::ENTITY_ID
89 }
90 #[cfg(not(unix))]
91 {
92 None
93 }
94}
95
96pub static DD_EXTERNAL_ENV: LazyLock<Option<&'static str>> = LazyLock::new(|| {
97 let leaked: Option<&'static str> = parse_env::str_not_empty(EXTERNAL_ENV_ENVIRONMENT_VARIABLE)
98 .map(|s| &*Box::leak(s.into_boxed_str()));
99
100 leaked
101});
102
103/// Returns an iterator of entity-related headers (container-id, entity-id, external-env)
104/// as (header_name, header_value) string tuples for any that are available.
105pub fn get_entity_headers() -> impl Iterator<Item = (&'static str, &'static str)> {
106 [
107 get_container_id().map(|v| ("datadog-container-id", v)),
108 get_entity_id().map(|v| ("datadog-entity-id", v)),
109 (*DD_EXTERNAL_ENV).map(|v| ("datadog-external-env", v)),
110 ]
111 .into_iter()
112 .flatten()
113}