init_tracing_opentelemetry/
resource.rs

1use opentelemetry::KeyValue;
2// use opentelemetry_resource_detectors::OsResourceDetector;
3use opentelemetry_sdk::{resource::ResourceDetector, Resource};
4use opentelemetry_semantic_conventions::resource;
5
6/// To log detected value set environement variable `RUST_LOG="...,otel::setup::resource=debug"`
7/// ```rust
8/// use init_tracing_opentelemetry::resource::DetectResource;
9/// # fn main() {
10/// let otel_rsrc = DetectResource::default()
11///     .with_fallback_service_name(env!("CARGO_PKG_NAME"))
12///     .with_fallback_service_version(env!("CARGO_PKG_VERSION"))
13///     .build();
14/// # }
15///
16/// ```
17#[derive(Debug, Default)]
18pub struct DetectResource {
19    fallback_service_name: Option<&'static str>,
20    fallback_service_version: Option<&'static str>,
21}
22
23impl DetectResource {
24    /// `service.name` is first extracted from environment variables
25    /// (in this order) `OTEL_SERVICE_NAME`, `SERVICE_NAME`, `APP_NAME`.
26    /// But a default value can be provided with this method.
27    #[must_use]
28    pub fn with_fallback_service_name(mut self, fallback_service_name: &'static str) -> Self {
29        self.fallback_service_name = Some(fallback_service_name);
30        self
31    }
32
33    /// `service.name` is first extracted from environment variables
34    /// (in this order) `SERVICE_VERSION`, `APP_VERSION`.
35    /// But a default value can be provided with this method.
36    #[must_use]
37    pub fn with_fallback_service_version(mut self, fallback_service_version: &'static str) -> Self {
38        self.fallback_service_version = Some(fallback_service_version);
39        self
40    }
41
42    #[must_use]
43    pub fn build(mut self) -> Resource {
44        //Box::new(OsResourceDetector), //FIXME enable when available for opentelemetry >= 0.25
45        //Box::new(ProcessResourceDetector),
46        let rsrc = Resource::builder()
47            .with_detector(Box::new(ServiceInfoDetector {
48                fallback_service_name: self.fallback_service_name.take(),
49                fallback_service_version: self.fallback_service_version.take(),
50            }))
51            .build();
52        debug_resource(&rsrc);
53        rsrc
54    }
55}
56
57pub fn debug_resource(rsrc: &Resource) {
58    rsrc.iter().for_each(
59        |kv| tracing::debug!(target: "otel::setup::resource", key = %kv.0, value = %kv.1),
60    );
61}
62
63#[derive(Debug)]
64pub struct ServiceInfoDetector {
65    fallback_service_name: Option<&'static str>,
66    fallback_service_version: Option<&'static str>,
67}
68
69impl ResourceDetector for ServiceInfoDetector {
70    fn detect(&self) -> Resource {
71        let service_name = std::env::var("OTEL_SERVICE_NAME")
72            .or_else(|_| std::env::var("SERVICE_NAME"))
73            .or_else(|_| std::env::var("APP_NAME"))
74            .ok()
75            .or_else(|| {
76                self.fallback_service_name
77                    .map(std::string::ToString::to_string)
78            })
79            .map(|v| KeyValue::new(resource::SERVICE_NAME, v));
80        let service_version = std::env::var("SERVICE_VERSION")
81            .or_else(|_| std::env::var("APP_VERSION"))
82            .ok()
83            .or_else(|| {
84                self.fallback_service_version
85                    .map(std::string::ToString::to_string)
86            })
87            .map(|v| KeyValue::new(resource::SERVICE_VERSION, v));
88        let mut resource = Resource::builder_empty();
89        if let Some(service_name) = service_name {
90            resource = resource.with_attribute(service_name);
91        }
92        if let Some(service_version) = service_version {
93            resource = resource.with_attribute(service_version);
94        }
95        resource.build()
96    }
97}