opentelemetry_sdk/resource/
env.rs1use crate::resource::{Resource, ResourceDetector};
6use opentelemetry::{Key, KeyValue, Value};
7use std::env;
8
9const OTEL_RESOURCE_ATTRIBUTES: &str = "OTEL_RESOURCE_ATTRIBUTES";
10const OTEL_SERVICE_NAME: &str = "OTEL_SERVICE_NAME";
11
12#[derive(Debug)]
17pub struct EnvResourceDetector {
18 _private: (),
19}
20
21impl ResourceDetector for EnvResourceDetector {
22 fn detect(&self) -> Resource {
23 match env::var(OTEL_RESOURCE_ATTRIBUTES) {
24 Ok(s) if !s.is_empty() => construct_otel_resources(s),
25 Ok(_) | Err(_) => Resource::empty(), }
27 }
28}
29
30impl EnvResourceDetector {
31 pub fn new() -> Self {
33 EnvResourceDetector { _private: () }
34 }
35}
36
37impl Default for EnvResourceDetector {
38 fn default() -> Self {
39 EnvResourceDetector::new()
40 }
41}
42
43fn construct_otel_resources(s: String) -> Resource {
46 Resource::builder_empty()
47 .with_attributes(s.split_terminator(',').filter_map(|entry| {
48 let parts = match entry.split_once('=') {
49 Some(p) => p,
50 None => return None,
51 };
52 let key = parts.0.trim();
53 let value = parts.1.trim();
54
55 Some(KeyValue::new(key.to_owned(), value.to_owned()))
56 }))
57 .build()
58}
59
60#[derive(Debug)]
73pub struct SdkProvidedResourceDetector;
74
75impl ResourceDetector for SdkProvidedResourceDetector {
76 fn detect(&self) -> Resource {
77 Resource::builder_empty()
78 .with_attributes([KeyValue::new(
79 super::SERVICE_NAME,
80 env::var(OTEL_SERVICE_NAME)
81 .ok()
82 .filter(|s| !s.is_empty())
83 .map(Value::from)
84 .or_else(|| {
85 EnvResourceDetector::new()
86 .detect()
87 .get(&Key::new(super::SERVICE_NAME))
88 })
89 .unwrap_or_else(|| {
90 env::current_exe()
93 .ok()
94 .and_then(|path| {
95 path.file_name()
96 .and_then(|name| name.to_str())
97 .map(|name| format!("unknown_service:{}", name))
98 })
99 .unwrap_or_else(|| "unknown_service".to_string())
100 .into()
101 }),
102 )])
103 .build()
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use crate::resource::env::{
110 SdkProvidedResourceDetector, OTEL_RESOURCE_ATTRIBUTES, OTEL_SERVICE_NAME,
111 };
112 use crate::resource::{EnvResourceDetector, Resource, ResourceDetector};
113 use opentelemetry::{Key, KeyValue, Value};
114
115 #[test]
116 fn test_read_from_env() {
117 temp_env::with_vars(
118 [
119 (
120 "OTEL_RESOURCE_ATTRIBUTES",
121 Some("key=value, k = v , a= x, a=z,base64=SGVsbG8sIFdvcmxkIQ=="),
122 ),
123 ("IRRELEVANT", Some("20200810")),
124 ],
125 || {
126 let detector = EnvResourceDetector::new();
127 let resource = detector.detect();
128 assert_eq!(
129 resource,
130 Resource::builder_empty()
131 .with_attributes([
132 KeyValue::new("key", "value"),
133 KeyValue::new("k", "v"),
134 KeyValue::new("a", "x"),
135 KeyValue::new("a", "z"),
136 KeyValue::new("base64", "SGVsbG8sIFdvcmxkIQ=="), ])
138 .build()
139 );
140 },
141 );
142
143 let detector = EnvResourceDetector::new();
144 let resource = detector.detect();
145 assert!(resource.is_empty());
146 }
147
148 #[test]
149 fn test_sdk_provided_resource_detector() {
150 let no_env = SdkProvidedResourceDetector.detect();
153 let service_name = no_env
154 .get(&Key::from_static_str(crate::resource::SERVICE_NAME))
155 .map(|v| v.to_string())
156 .unwrap();
157
158 assert!(
159 service_name.starts_with("unknown_service:opentelemetry_sdk-"),
160 "Expected service name to start with 'unknown_service:opentelemetry_sdk-', got: {}",
161 service_name
162 );
163
164 temp_env::with_var(OTEL_SERVICE_NAME, Some("test service"), || {
165 let with_service = SdkProvidedResourceDetector.detect();
166 assert_eq!(
167 with_service.get(&Key::from_static_str(crate::resource::SERVICE_NAME)),
168 Some(Value::from("test service")),
169 )
170 });
171
172 temp_env::with_var(
173 OTEL_RESOURCE_ATTRIBUTES,
174 Some("service.name=test service1"),
175 || {
176 let with_service = SdkProvidedResourceDetector.detect();
177 assert_eq!(
178 with_service.get(&Key::from_static_str(crate::resource::SERVICE_NAME)),
179 Some(Value::from("test service1")),
180 )
181 },
182 );
183
184 temp_env::with_vars(
186 [
187 (OTEL_SERVICE_NAME, Some("test service")),
188 (OTEL_RESOURCE_ATTRIBUTES, Some("service.name=test service3")),
189 ],
190 || {
191 let with_service = SdkProvidedResourceDetector.detect();
192 assert_eq!(
193 with_service.get(&Key::from_static_str(crate::resource::SERVICE_NAME)),
194 Some(Value::from("test service"))
195 );
196 },
197 );
198 }
199}