libdd_trace_utils/
config_utils.rs1use crate::trace_utils;
5use std::env;
6use tracing::{debug, error};
7
8pub const PROD_INTAKE_SUBDOMAIN: &str = "trace.agent";
9
10const TRACE_INTAKE_ROUTE: &str = "/api/v0.2/traces";
11const TRACE_STATS_INTAKE_ROUTE: &str = "/api/v0.2/stats";
12
13pub fn read_cloud_env() -> Option<(String, trace_utils::EnvironmentType)> {
14 let mut detected: Vec<(String, trace_utils::EnvironmentType)> = Vec::new();
15
16 if env::var("AWS_LAMBDA_INITIALIZATION_TYPE").is_ok() {
17 match env::var("AWS_LAMBDA_FUNCTION_NAME") {
18 Ok(name) => detected.push((name, trace_utils::EnvironmentType::LambdaFunction)),
19 Err(_) => {
20 error!("AWS Lambda environment detected but AWS_LAMBDA_FUNCTION_NAME is not set");
21 }
22 }
23 }
24
25 if env::var("FUNCTIONS_EXTENSION_VERSION").is_ok()
26 && env::var("FUNCTIONS_WORKER_RUNTIME").is_ok()
27 {
28 match env::var("WEBSITE_SITE_NAME") {
29 Ok(name) => detected.push((name, trace_utils::EnvironmentType::AzureFunction)),
30 Err(_) => {
31 error!("Azure Functions environment detected but WEBSITE_SITE_NAME is not set");
32 }
33 }
34 }
35
36 if let (Ok(name), Ok(_)) = (env::var("K_SERVICE"), env::var("FUNCTION_TARGET")) {
37 detected.push((name, trace_utils::EnvironmentType::CloudFunction));
39 } else if let (Ok(name), Ok(_)) = (env::var("FUNCTION_NAME"), env::var("GCP_PROJECT")) {
40 detected.push((name, trace_utils::EnvironmentType::CloudFunction));
42 }
43
44 if let Ok(name) = env::var("ASCSVCRT_SPRING__APPLICATION__NAME") {
45 detected.push((name, trace_utils::EnvironmentType::AzureSpringApp));
47 }
48
49 match detected.len() {
50 0 => {
51 error!("No cloud environment detected");
52 None
53 }
54 1 => {
55 let (ref name, ref env_type) = detected[0];
56 debug!("Cloud environment detected: {env_type:?} ({name})");
57 detected.into_iter().next()
58 }
59 _ => {
60 let env_names: Vec<String> = detected
61 .iter()
62 .map(|(name, env_type)| format!("{env_type:?}({name})"))
63 .collect();
64 error!(
65 "Multiple cloud environments detected: {}",
66 env_names.join(", ")
67 );
68 None
69 }
70 }
71}
72
73pub fn trace_intake_url(site: &str) -> String {
74 construct_trace_intake_url(site, TRACE_INTAKE_ROUTE)
75}
76
77pub fn trace_intake_url_prefixed(endpoint_prefix: &str) -> String {
78 format!("{endpoint_prefix}{TRACE_INTAKE_ROUTE}")
79}
80
81pub fn trace_stats_url(site: &str) -> String {
82 construct_trace_intake_url(site, TRACE_STATS_INTAKE_ROUTE)
83}
84
85pub fn trace_stats_url_prefixed(endpoint_prefix: &str) -> String {
86 format!("{endpoint_prefix}{TRACE_STATS_INTAKE_ROUTE}")
87}
88
89fn construct_trace_intake_url(prefix: &str, route: &str) -> String {
90 format!("https://{PROD_INTAKE_SUBDOMAIN}.{prefix}{route}")
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use std::sync::Mutex;
97
98 static ENV_TEST_LOCK: Mutex<()> = Mutex::new(());
100
101 fn clear_all_env_vars() {
102 unsafe {
103 env::remove_var("AWS_LAMBDA_INITIALIZATION_TYPE");
104 env::remove_var("AWS_LAMBDA_FUNCTION_NAME");
105 env::remove_var("FUNCTIONS_EXTENSION_VERSION");
106 env::remove_var("FUNCTIONS_WORKER_RUNTIME");
107 env::remove_var("WEBSITE_SITE_NAME");
108 env::remove_var("FUNCTION_NAME");
109 env::remove_var("GCP_PROJECT");
110 env::remove_var("K_SERVICE");
111 env::remove_var("FUNCTION_TARGET");
112 env::remove_var("ASCSVCRT_SPRING__APPLICATION__NAME");
113 }
114 }
115
116 #[test]
117 fn test_aws_lambda_detected() {
118 let _lock = ENV_TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
119 clear_all_env_vars();
120 unsafe {
121 env::set_var("AWS_LAMBDA_INITIALIZATION_TYPE", "on-demand");
122 env::set_var("AWS_LAMBDA_FUNCTION_NAME", "my-function");
123 }
124 let result = read_cloud_env();
125 assert_eq!(
126 result,
127 Some((
128 "my-function".to_string(),
129 trace_utils::EnvironmentType::LambdaFunction
130 ))
131 );
132 }
133
134 #[test]
135 fn test_aws_lambda_missing_function_name() {
136 let _lock = ENV_TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
137 clear_all_env_vars();
138 unsafe { env::set_var("AWS_LAMBDA_INITIALIZATION_TYPE", "on-demand") };
139 let result = read_cloud_env();
140 assert_eq!(result, None);
141 }
142
143 #[test]
144 fn test_aws_lambda_not_detected_without_init_type() {
145 let _lock = ENV_TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
146 clear_all_env_vars();
147 unsafe { env::set_var("AWS_LAMBDA_FUNCTION_NAME", "my-function") };
148 let result = read_cloud_env();
149 assert_eq!(result, None);
150 }
151
152 #[test]
153 fn test_azure_function_detected() {
154 let _lock = ENV_TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
155 clear_all_env_vars();
156 unsafe {
157 env::set_var("FUNCTIONS_EXTENSION_VERSION", "~4");
158 env::set_var("FUNCTIONS_WORKER_RUNTIME", "java");
159 env::set_var("WEBSITE_SITE_NAME", "my-azure-app");
160 }
161 let result = read_cloud_env();
162 assert_eq!(
163 result,
164 Some((
165 "my-azure-app".to_string(),
166 trace_utils::EnvironmentType::AzureFunction
167 ))
168 );
169 }
170
171 #[test]
172 fn test_azure_function_missing_site_name() {
173 let _lock = ENV_TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
174 clear_all_env_vars();
175 unsafe {
176 env::set_var("FUNCTIONS_EXTENSION_VERSION", "~4");
177 env::set_var("FUNCTIONS_WORKER_RUNTIME", "java");
178 }
179 let result = read_cloud_env();
180 assert_eq!(result, None);
181 }
182
183 #[test]
184 fn test_azure_function_not_detected_with_only_one_var() {
185 let _lock = ENV_TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
186 clear_all_env_vars();
187 unsafe { env::set_var("FUNCTIONS_EXTENSION_VERSION", "~4") };
188 let result = read_cloud_env();
189 assert_eq!(result, None);
190 }
191
192 #[test]
193 fn test_gcp_1st_gen_detected() {
194 let _lock = ENV_TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
195 clear_all_env_vars();
196 unsafe {
197 env::set_var("FUNCTION_NAME", "my-gcp-function");
198 env::set_var("GCP_PROJECT", "my-project");
199 }
200 let result = read_cloud_env();
201 assert_eq!(
202 result,
203 Some((
204 "my-gcp-function".to_string(),
205 trace_utils::EnvironmentType::CloudFunction
206 ))
207 );
208 }
209
210 #[test]
211 fn test_gcp_1st_gen_not_detected_without_gcp_project() {
212 let _lock = ENV_TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
213 clear_all_env_vars();
214 unsafe { env::set_var("FUNCTION_NAME", "my-gcp-function") };
215 let result = read_cloud_env();
216 assert_eq!(result, None);
217 }
218
219 #[test]
220 fn test_gcp_2nd_gen_detected() {
221 let _lock = ENV_TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
222 clear_all_env_vars();
223 unsafe {
224 env::set_var("K_SERVICE", "my-cloud-run-fn");
225 env::set_var("FUNCTION_TARGET", "myHandler");
226 }
227 let result = read_cloud_env();
228 assert_eq!(
229 result,
230 Some((
231 "my-cloud-run-fn".to_string(),
232 trace_utils::EnvironmentType::CloudFunction
233 ))
234 );
235 }
236
237 #[test]
238 fn test_gcp_2nd_gen_not_detected_without_function_target() {
239 let _lock = ENV_TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
240 clear_all_env_vars();
241 unsafe { env::set_var("K_SERVICE", "my-cloud-run-fn") };
242 let result = read_cloud_env();
243 assert_eq!(result, None);
244 }
245
246 #[test]
247 fn test_azure_spring_app_detected() {
248 let _lock = ENV_TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
249 clear_all_env_vars();
250 unsafe { env::set_var("ASCSVCRT_SPRING__APPLICATION__NAME", "my-spring-app") };
251 let result = read_cloud_env();
252 assert_eq!(
253 result,
254 Some((
255 "my-spring-app".to_string(),
256 trace_utils::EnvironmentType::AzureSpringApp
257 ))
258 );
259 }
260
261 #[test]
262 fn test_no_environment_detected() {
263 let _lock = ENV_TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
264 clear_all_env_vars();
265 let result = read_cloud_env();
266 assert_eq!(result, None);
267 }
268
269 #[test]
270 fn test_multiple_environments_returns_none() {
271 let _lock = ENV_TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
272 clear_all_env_vars();
273 unsafe {
274 env::set_var("AWS_LAMBDA_INITIALIZATION_TYPE", "on-demand");
275 env::set_var("AWS_LAMBDA_FUNCTION_NAME", "my-lambda");
276 env::set_var("FUNCTIONS_EXTENSION_VERSION", "~4");
277 env::set_var("FUNCTIONS_WORKER_RUNTIME", "java");
278 env::set_var("WEBSITE_SITE_NAME", "my-azure-app");
279 }
280 let result = read_cloud_env();
281 assert_eq!(result, None);
282 }
283}