opentelemetry_resource_detectors/
k8s.rs

1use opentelemetry::KeyValue;
2use opentelemetry_sdk::resource::{Resource, ResourceDetector};
3use std::env;
4use std::fs::read_to_string;
5
6const K8S_NAMESPACE_PATH: &str = "/var/run/secrets/kubernetes.io/serviceaccount/namespace";
7
8/// Detect Kubernetes information.
9///
10/// This resource detector returns the following information:
11///
12/// - Pod name (`k8s.pod.name`)
13/// - Namespace (`k8s.namespace.name`).
14pub struct K8sResourceDetector;
15
16impl ResourceDetector for K8sResourceDetector {
17    fn detect(&self) -> Resource {
18        let pod_name = env::var("HOSTNAME").ok();
19
20        let namespace = read_to_string(K8S_NAMESPACE_PATH).ok();
21
22        Resource::builder_empty()
23            .with_attributes(
24                [
25                    pod_name.map(|name| {
26                        KeyValue::new(
27                            opentelemetry_semantic_conventions::attribute::K8S_POD_NAME,
28                            name,
29                        )
30                    }),
31                    namespace.map(|name| {
32                        KeyValue::new(
33                            opentelemetry_semantic_conventions::attribute::K8S_NAMESPACE_NAME,
34                            name,
35                        )
36                    }),
37                    env::var("NODE_NAME").ok().map(|name| {
38                        KeyValue::new(
39                            opentelemetry_semantic_conventions::attribute::K8S_NODE_NAME,
40                            name,
41                        )
42                    }),
43                ]
44                .into_iter()
45                .flatten(),
46            )
47            .build()
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54    use opentelemetry::{Key, Value};
55
56    #[test]
57    fn test_k8s_resource_detector_with_env_vars() {
58        temp_env::with_vars(
59            [
60                ("HOSTNAME", Some("test-pod")),
61                ("NODE_NAME", Some("test-node")),
62            ],
63            || {
64                let resource = K8sResourceDetector.detect();
65
66                assert_eq!(resource.len(), 2);
67
68                assert_eq!(
69                    resource.get(&Key::from_static_str(
70                        opentelemetry_semantic_conventions::attribute::K8S_POD_NAME
71                    )),
72                    Some(Value::from("test-pod"))
73                );
74
75                assert_eq!(
76                    resource.get(&Key::from_static_str(
77                        opentelemetry_semantic_conventions::attribute::K8S_NODE_NAME
78                    )),
79                    Some(Value::from("test-node"))
80                )
81            },
82        );
83    }
84
85    #[test]
86    fn test_k8s_resource_detector_with_missing_env_vars() {
87        // make sure no env var is accidentally set
88        temp_env::with_vars_unset(["HOSTNAME", "NODE_NAME"], || {
89            let resource = K8sResourceDetector.detect();
90
91            assert_eq!(resource.len(), 0);
92            assert!(resource
93                .get(&Key::from_static_str(
94                    opentelemetry_semantic_conventions::attribute::K8S_NODE_NAME
95                ))
96                .is_none())
97        });
98    }
99}