opentelemetry_spanprocessor_any/sdk/resource/
env.rs1use crate::sdk::{resource::ResourceDetector, Resource};
6use crate::{Key, KeyValue};
7use std::env;
8use std::time::Duration;
9
10const OTEL_RESOURCE_ATTRIBUTES: &str = "OTEL_RESOURCE_ATTRIBUTES";
11const OTEL_SERVICE_NAME: &str = "OTEL_SERVICE_NAME";
12
13#[derive(Debug)]
20pub struct EnvResourceDetector {
21 _private: (),
22}
23
24impl ResourceDetector for EnvResourceDetector {
25 fn detect(&self, _timeout: Duration) -> Resource {
26 match env::var(OTEL_RESOURCE_ATTRIBUTES) {
27 Ok(s) if !s.is_empty() => construct_otel_resources(s),
28 Ok(_) | Err(_) => Resource::new(vec![]), }
30 }
31}
32
33impl EnvResourceDetector {
34 pub fn new() -> Self {
36 EnvResourceDetector { _private: () }
37 }
38}
39
40impl Default for EnvResourceDetector {
41 fn default() -> Self {
42 EnvResourceDetector::new()
43 }
44}
45
46fn construct_otel_resources(s: String) -> Resource {
49 Resource::new(s.split_terminator(',').filter_map(|entry| {
50 let mut parts = entry.splitn(2, '=');
51 let key = parts.next()?.trim();
52 let value = parts.next()?.trim();
53 if value.find('=').is_some() {
54 return None;
55 }
56
57 Some(KeyValue::new(key.to_owned(), value.to_owned()))
58 }))
59}
60
61#[derive(Debug)]
76pub struct SdkProvidedResourceDetector;
77
78impl ResourceDetector for SdkProvidedResourceDetector {
79 fn detect(&self, _timeout: Duration) -> Resource {
80 Resource::new(vec![KeyValue::new(
81 "service.name",
82 env::var(OTEL_SERVICE_NAME)
83 .ok()
84 .filter(|s| !s.is_empty())
85 .unwrap_or_else(|| {
86 EnvResourceDetector::new()
87 .detect(Duration::from_secs(0))
88 .get(Key::new("service.name"))
89 .map(|v| v.to_string())
90 .filter(|s| !s.is_empty())
91 .unwrap_or_else(|| "unknown_service".to_string())
92 }),
93 )])
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use crate::sdk::resource::env::{
100 SdkProvidedResourceDetector, OTEL_RESOURCE_ATTRIBUTES, OTEL_SERVICE_NAME,
101 };
102 use crate::sdk::resource::{EnvResourceDetector, Resource, ResourceDetector};
103 use crate::{Key, KeyValue, Value};
104 use std::time::Duration;
105 use std::{env, time};
106
107 #[test]
108 fn test_read_from_env() {
109 env::set_var(OTEL_RESOURCE_ATTRIBUTES, "key=value, k = v , a= x, a=z");
110 env::set_var("irrelevant".to_uppercase(), "20200810");
111
112 let detector = EnvResourceDetector::new();
113 let resource = detector.detect(time::Duration::from_secs(5));
114 assert_eq!(
115 resource,
116 Resource::new(vec![
117 KeyValue::new("key", "value"),
118 KeyValue::new("k", "v"),
119 KeyValue::new("a", "x"),
120 KeyValue::new("a", "z"),
121 ])
122 );
123
124 env::set_var(OTEL_RESOURCE_ATTRIBUTES, "");
126
127 let detector = EnvResourceDetector::new();
128 let resource = detector.detect(time::Duration::from_secs(5));
129 assert!(resource.is_empty());
130 }
131
132 #[test]
133 fn test_sdk_provided_resource_detector() {
134 const SERVICE_NAME: &str = "service.name";
135 let no_env = SdkProvidedResourceDetector.detect(Duration::from_secs(1));
136 assert_eq!(
137 no_env.get(Key::from_static_str(SERVICE_NAME)),
138 Some(Value::from("unknown_service")),
139 );
140
141 env::set_var(OTEL_SERVICE_NAME, "test service");
142 let with_service = SdkProvidedResourceDetector.detect(Duration::from_secs(1));
143 assert_eq!(
144 with_service.get(Key::from_static_str(SERVICE_NAME)),
145 Some(Value::from("test service")),
146 );
147 env::set_var(OTEL_SERVICE_NAME, ""); env::set_var(OTEL_RESOURCE_ATTRIBUTES, "service.name=test service1");
151 let with_service = SdkProvidedResourceDetector.detect(Duration::from_secs(1));
152 assert_eq!(
153 with_service.get(Key::from_static_str(SERVICE_NAME)),
154 Some(Value::from("test service1"))
155 );
156
157 env::set_var(OTEL_SERVICE_NAME, "test service");
159 let with_service = SdkProvidedResourceDetector.detect(Duration::from_secs(1));
160 assert_eq!(
161 with_service.get(Key::from_static_str(SERVICE_NAME)),
162 Some(Value::from("test service"))
163 );
164 env::set_var(OTEL_RESOURCE_ATTRIBUTES, "");
165 env::set_var(OTEL_SERVICE_NAME, ""); }
167}