opentelemetry_sdk/resource/
env.rs
1use crate::resource::{Resource, ResourceDetector};
6use opentelemetry::{Key, KeyValue, Value};
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)]
18pub struct EnvResourceDetector {
19 _private: (),
20}
21
22impl ResourceDetector for EnvResourceDetector {
23 fn detect(&self, _timeout: Duration) -> Resource {
24 match env::var(OTEL_RESOURCE_ATTRIBUTES) {
25 Ok(s) if !s.is_empty() => construct_otel_resources(s),
26 Ok(_) | Err(_) => Resource::new(vec![]), }
28 }
29}
30
31impl EnvResourceDetector {
32 pub fn new() -> Self {
34 EnvResourceDetector { _private: () }
35 }
36}
37
38impl Default for EnvResourceDetector {
39 fn default() -> Self {
40 EnvResourceDetector::new()
41 }
42}
43
44fn construct_otel_resources(s: String) -> Resource {
47 Resource::new(s.split_terminator(',').filter_map(|entry| {
48 let mut parts = entry.splitn(2, '=');
49 let key = parts.next()?.trim();
50 let value = parts.next()?.trim();
51 if value.find('=').is_some() {
52 return None;
53 }
54
55 Some(KeyValue::new(key.to_owned(), value.to_owned()))
56 }))
57}
58
59#[derive(Debug)]
72pub struct SdkProvidedResourceDetector;
73
74impl ResourceDetector for SdkProvidedResourceDetector {
75 fn detect(&self, _timeout: Duration) -> Resource {
76 Resource::new(vec![KeyValue::new(
77 super::SERVICE_NAME,
78 env::var(OTEL_SERVICE_NAME)
79 .ok()
80 .filter(|s| !s.is_empty())
81 .map(Value::from)
82 .or_else(|| {
83 EnvResourceDetector::new()
84 .detect(Duration::from_secs(0))
85 .get(Key::new(super::SERVICE_NAME))
86 })
87 .unwrap_or_else(|| "unknown_service".into()),
88 )])
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use crate::resource::env::{
95 SdkProvidedResourceDetector, OTEL_RESOURCE_ATTRIBUTES, OTEL_SERVICE_NAME,
96 };
97 use crate::resource::{EnvResourceDetector, Resource, ResourceDetector};
98 use opentelemetry::{Key, KeyValue, Value};
99 use std::time::Duration;
100
101 #[test]
102 fn test_read_from_env() {
103 temp_env::with_vars(
104 [
105 (
106 "OTEL_RESOURCE_ATTRIBUTES",
107 Some("key=value, k = v , a= x, a=z"),
108 ),
109 ("IRRELEVANT", Some("20200810")),
110 ],
111 || {
112 let detector = EnvResourceDetector::new();
113 let resource = detector.detect(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 );
125
126 let detector = EnvResourceDetector::new();
127 let resource = detector.detect(Duration::from_secs(5));
128 assert!(resource.is_empty());
129 }
130
131 #[test]
132 fn test_sdk_provided_resource_detector() {
133 let no_env = SdkProvidedResourceDetector.detect(Duration::from_secs(1));
135 assert_eq!(
136 no_env.get(Key::from_static_str(crate::resource::SERVICE_NAME)),
137 Some(Value::from("unknown_service")),
138 );
139
140 temp_env::with_var(OTEL_SERVICE_NAME, Some("test service"), || {
141 let with_service = SdkProvidedResourceDetector.detect(Duration::from_secs(1));
142 assert_eq!(
143 with_service.get(Key::from_static_str(crate::resource::SERVICE_NAME)),
144 Some(Value::from("test service")),
145 )
146 });
147
148 temp_env::with_var(
149 OTEL_RESOURCE_ATTRIBUTES,
150 Some("service.name=test service1"),
151 || {
152 let with_service = SdkProvidedResourceDetector.detect(Duration::from_secs(1));
153 assert_eq!(
154 with_service.get(Key::from_static_str(crate::resource::SERVICE_NAME)),
155 Some(Value::from("test service1")),
156 )
157 },
158 );
159
160 temp_env::with_vars(
162 [
163 (OTEL_SERVICE_NAME, Some("test service")),
164 (OTEL_RESOURCE_ATTRIBUTES, Some("service.name=test service3")),
165 ],
166 || {
167 let with_service = SdkProvidedResourceDetector.detect(Duration::from_secs(1));
168 assert_eq!(
169 with_service.get(Key::from_static_str(crate::resource::SERVICE_NAME)),
170 Some(Value::from("test service"))
171 );
172 },
173 );
174 }
175}