opentelemetry_aws/detector/
lambda.rs1use opentelemetry::{Array, KeyValue, StringValue, Value};
2use opentelemetry_sdk::resource::ResourceDetector;
3use opentelemetry_sdk::Resource;
4use opentelemetry_semantic_conventions as semconv;
5use std::env;
6
7const AWS_LAMBDA_FUNCTION_NAME_ENV_VAR: &str = "AWS_LAMBDA_FUNCTION_NAME";
10const AWS_REGION_ENV_VAR: &str = "AWS_REGION";
11const AWS_LAMBDA_FUNCTION_VERSION_ENV_VAR: &str = "AWS_LAMBDA_FUNCTION_VERSION";
12const AWS_LAMBDA_LOG_STREAM_NAME_ENV_VAR: &str = "AWS_LAMBDA_LOG_STREAM_NAME";
13const AWS_LAMBDA_MEMORY_LIMIT_ENV_VAR: &str = "AWS_LAMBDA_FUNCTION_MEMORY_SIZE";
14const AWS_LAMBDA_LOG_GROUP_NAME_ENV_VAR: &str = "AWS_LAMBDA_LOG_GROUP_NAME";
15
16pub struct LambdaResourceDetector;
18
19impl ResourceDetector for LambdaResourceDetector {
20 fn detect(&self) -> Resource {
21 let lambda_name = env::var(AWS_LAMBDA_FUNCTION_NAME_ENV_VAR).unwrap_or_default();
22 if lambda_name.is_empty() {
25 return Resource::builder_empty().build();
26 }
27
28 let aws_region = env::var(AWS_REGION_ENV_VAR).unwrap_or_default();
29 let function_version = env::var(AWS_LAMBDA_FUNCTION_VERSION_ENV_VAR).unwrap_or_default();
30 let function_memory_limit = env::var(AWS_LAMBDA_MEMORY_LIMIT_ENV_VAR)
32 .map(|s| s.parse::<i64>().unwrap_or_default() * 1024 * 1024)
33 .unwrap_or_default();
34 let instance = env::var(AWS_LAMBDA_LOG_STREAM_NAME_ENV_VAR).unwrap_or_default();
37 let log_group_name = env::var(AWS_LAMBDA_LOG_GROUP_NAME_ENV_VAR).unwrap_or_default();
38
39 let attributes = [
40 KeyValue::new(semconv::resource::CLOUD_PROVIDER, "aws"),
41 KeyValue::new(semconv::resource::CLOUD_REGION, aws_region),
42 KeyValue::new(semconv::resource::FAAS_INSTANCE, instance),
43 KeyValue::new(semconv::resource::FAAS_NAME, lambda_name),
44 KeyValue::new(semconv::resource::FAAS_VERSION, function_version),
45 KeyValue::new(semconv::resource::FAAS_MAX_MEMORY, function_memory_limit),
46 KeyValue::new(
47 semconv::resource::AWS_LOG_GROUP_NAMES,
48 Value::Array(Array::from(vec![StringValue::from(log_group_name)])),
49 ),
50 ];
51
52 Resource::builder_empty()
53 .with_attributes(attributes)
54 .build()
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use sealed_test::prelude::*;
62
63 #[sealed_test]
64 fn test_aws_lambda_detector() {
65 temp_env::with_vars(
66 [
67 (AWS_LAMBDA_FUNCTION_NAME_ENV_VAR, Some("my-lambda-function")),
68 (AWS_REGION_ENV_VAR, Some("eu-west-3")),
69 (AWS_LAMBDA_FUNCTION_VERSION_ENV_VAR, Some("$LATEST")),
70 (
71 AWS_LAMBDA_LOG_STREAM_NAME_ENV_VAR,
72 Some("2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc"),
73 ),
74 (AWS_LAMBDA_MEMORY_LIMIT_ENV_VAR, Some("128")),
75 (
76 AWS_LAMBDA_LOG_GROUP_NAME_ENV_VAR,
77 Some("/aws/lambda/my-lambda-function"),
78 ),
79 ],
80 || {
81 let expected = Resource::builder_empty()
82 .with_attributes([
83 KeyValue::new(semconv::resource::CLOUD_PROVIDER, "aws"),
84 KeyValue::new(semconv::resource::CLOUD_REGION, "eu-west-3"),
85 KeyValue::new(
86 semconv::resource::FAAS_INSTANCE,
87 "2023/01/01/[$LATEST]5d1edb9e525d486696cf01a3503487bc",
88 ),
89 KeyValue::new(semconv::resource::FAAS_NAME, "my-lambda-function"),
90 KeyValue::new(semconv::resource::FAAS_VERSION, "$LATEST"),
91 KeyValue::new(semconv::resource::FAAS_MAX_MEMORY, 128 * 1024 * 1024),
92 KeyValue::new(
93 semconv::resource::AWS_LOG_GROUP_NAMES,
94 Value::Array(Array::from(vec![StringValue::from(
95 "/aws/lambda/my-lambda-function".to_string(),
96 )])),
97 ),
98 ])
99 .build();
100
101 let detector = LambdaResourceDetector {};
102 let got = detector.detect();
103
104 assert_eq!(expected, got);
105 },
106 );
107 }
108
109 #[sealed_test]
110 fn test_aws_lambda_detector_returns_empty_if_no_lambda_environment() {
111 let detector = LambdaResourceDetector {};
112 let got = detector.detect();
113 assert_eq!(Resource::builder_empty().build(), got);
114 }
115}