opentelemetry_resource_detectors/
host.rs1use opentelemetry::KeyValue;
5use opentelemetry_sdk::resource::ResourceDetector;
6use opentelemetry_sdk::Resource;
7use std::env::consts::ARCH;
8#[cfg(target_os = "linux")]
9use std::fs::read_to_string;
10#[cfg(target_os = "linux")]
11use std::path::Path;
12#[cfg(target_os = "macos")]
13use std::process::Command;
14
15pub struct HostResourceDetector {
22 host_id_detect: fn() -> Option<String>,
23}
24
25impl ResourceDetector for HostResourceDetector {
26 fn detect(&self) -> Resource {
27 Resource::builder_empty()
28 .with_attributes(
29 [
30 (self.host_id_detect)().map(|host_id| {
32 KeyValue::new(
33 opentelemetry_semantic_conventions::attribute::HOST_ID,
34 host_id,
35 )
36 }),
37 Some(KeyValue::new(
39 opentelemetry_semantic_conventions::attribute::HOST_ARCH,
40 ARCH,
41 )),
42 ]
43 .into_iter()
44 .flatten(),
45 )
46 .build()
47 }
48}
49
50#[cfg(target_os = "linux")]
51fn host_id_detect() -> Option<String> {
52 let machine_id_path = Path::new("/etc/machine-id");
53 let dbus_machine_id_path = Path::new("/var/lib/dbus/machine-id");
54 read_to_string(machine_id_path)
55 .or_else(|_| read_to_string(dbus_machine_id_path))
56 .map(|id| id.trim().to_string())
57 .ok()
58}
59
60#[cfg(target_os = "macos")]
61fn host_id_detect() -> Option<String> {
62 let output = Command::new("ioreg")
63 .arg("-rd1")
64 .arg("-c")
65 .arg("IOPlatformExpertDevice")
66 .output()
67 .ok()?
68 .stdout;
69
70 let output = String::from_utf8(output).ok()?;
71 let line = output
72 .lines()
73 .find(|line| line.contains("IOPlatformUUID"))?;
74
75 Some(line.split_once('=')?.1.trim().trim_matches('"').to_owned())
76}
77
78#[cfg(not(any(target_os = "linux", target_os = "macos")))]
80fn host_id_detect() -> Option<String> {
81 None
82}
83
84impl Default for HostResourceDetector {
85 fn default() -> Self {
86 Self { host_id_detect }
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::HostResourceDetector;
93 use opentelemetry::{Key, Value};
94 use opentelemetry_sdk::resource::ResourceDetector;
95
96 #[cfg(target_os = "linux")]
97 #[test]
98 fn test_host_resource_detector_linux() {
99 let resource = HostResourceDetector::default().detect();
100 assert_eq!(resource.len(), 2);
101 assert!(resource
102 .get(&Key::from_static_str(
103 opentelemetry_semantic_conventions::attribute::HOST_ID
104 ))
105 .is_some());
106 assert!(resource
107 .get(&Key::from_static_str(
108 opentelemetry_semantic_conventions::attribute::HOST_ARCH
109 ))
110 .is_some())
111 }
112
113 #[cfg(target_os = "macos")]
114 #[test]
115 fn test_host_resource_detector_macos() {
116 let resource = HostResourceDetector::default().detect(Duration::from_secs(0));
117 dbg!(&resource);
118 assert_eq!(resource.len(), 2);
119 assert!(resource
120 .get(Key::from_static_str(
121 opentelemetry_semantic_conventions::attribute::HOST_ID
122 ))
123 .is_some());
124 assert!(resource
125 .get(Key::from_static_str(
126 opentelemetry_semantic_conventions::attribute::HOST_ARCH
127 ))
128 .is_some())
129 }
130
131 #[test]
132 fn test_resource_host_arch_value() {
133 let resource = HostResourceDetector::default().detect();
134
135 assert!(resource
136 .get(&Key::from_static_str(
137 opentelemetry_semantic_conventions::attribute::HOST_ARCH
138 ))
139 .is_some());
140
141 #[cfg(target_arch = "x86_64")]
142 assert_eq!(
143 resource.get(&Key::from_static_str(
144 opentelemetry_semantic_conventions::attribute::HOST_ARCH
145 )),
146 Some(Value::from("x86_64"))
147 );
148
149 #[cfg(target_arch = "aarch64")]
150 assert_eq!(
151 resource.get(&Key::from_static_str(
152 opentelemetry_semantic_conventions::attribute::HOST_ARCH
153 )),
154 Some(Value::from("aarch64"))
155 )
156 }
157}