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(|| "unknown_service".into()),
90 )])
91 .build()
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use crate::resource::env::{
98 SdkProvidedResourceDetector, OTEL_RESOURCE_ATTRIBUTES, OTEL_SERVICE_NAME,
99 };
100 use crate::resource::{EnvResourceDetector, Resource, ResourceDetector};
101 use opentelemetry::{Key, KeyValue, Value};
102
103 #[test]
104 fn test_read_from_env() {
105 temp_env::with_vars(
106 [
107 (
108 "OTEL_RESOURCE_ATTRIBUTES",
109 Some("key=value, k = v , a= x, a=z,base64=SGVsbG8sIFdvcmxkIQ=="),
110 ),
111 ("IRRELEVANT", Some("20200810")),
112 ],
113 || {
114 let detector = EnvResourceDetector::new();
115 let resource = detector.detect();
116 assert_eq!(
117 resource,
118 Resource::builder_empty()
119 .with_attributes([
120 KeyValue::new("key", "value"),
121 KeyValue::new("k", "v"),
122 KeyValue::new("a", "x"),
123 KeyValue::new("a", "z"),
124 KeyValue::new("base64", "SGVsbG8sIFdvcmxkIQ=="), ])
126 .build()
127 );
128 },
129 );
130
131 let detector = EnvResourceDetector::new();
132 let resource = detector.detect();
133 assert!(resource.is_empty());
134 }
135
136 #[test]
137 fn test_sdk_provided_resource_detector() {
138 let no_env = SdkProvidedResourceDetector.detect();
140 assert_eq!(
141 no_env.get(&Key::from_static_str(crate::resource::SERVICE_NAME)),
142 Some(Value::from("unknown_service")),
143 );
144
145 temp_env::with_var(OTEL_SERVICE_NAME, Some("test service"), || {
146 let with_service = SdkProvidedResourceDetector.detect();
147 assert_eq!(
148 with_service.get(&Key::from_static_str(crate::resource::SERVICE_NAME)),
149 Some(Value::from("test service")),
150 )
151 });
152
153 temp_env::with_var(
154 OTEL_RESOURCE_ATTRIBUTES,
155 Some("service.name=test service1"),
156 || {
157 let with_service = SdkProvidedResourceDetector.detect();
158 assert_eq!(
159 with_service.get(&Key::from_static_str(crate::resource::SERVICE_NAME)),
160 Some(Value::from("test service1")),
161 )
162 },
163 );
164
165 temp_env::with_vars(
167 [
168 (OTEL_SERVICE_NAME, Some("test service")),
169 (OTEL_RESOURCE_ATTRIBUTES, Some("service.name=test service3")),
170 ],
171 || {
172 let with_service = SdkProvidedResourceDetector.detect();
173 assert_eq!(
174 with_service.get(&Key::from_static_str(crate::resource::SERVICE_NAME)),
175 Some(Value::from("test service"))
176 );
177 },
178 );
179 }
180}