Skip to main content

tracing_kickstart/
conf.rs

1use opentelemetry::{Key, Value};
2use secrecy::SecretString;
3use serde::{Deserialize, Serialize};
4use std::time::Duration;
5
6// !- Builder
7
8pub struct TracingConfigBuilder {
9    inner: TracingConfig,
10    runtime: TracingConfigOverride,
11}
12impl TracingConfigBuilder {
13    pub fn new(runtime_config: &TracingConfigOverride) -> Self {
14        Self {
15            inner: TracingConfig {
16                filter: None,
17                filter_append: runtime_config.filter_append.clone(),
18                log_file_path: None,
19                ansi_output: true,
20                ansi_sanitization: true,
21                deployment_env: runtime_config.deployment_env.clone(),
22                custom_resource_attrs: None,
23                metrics_interval: None,
24                otel_config: runtime_config.otel_config.clone(),
25            },
26            runtime: runtime_config.clone(),
27        }
28    }
29
30    pub fn build(self) -> TracingConfig {
31        // ensure overrides are set - can skip override-only as they are immutable
32        let (mut config, runtime) = (self.inner, self.runtime);
33        config.filter = runtime.filter.or(config.filter);
34        config.log_file_path = runtime.log_file_path.or(config.log_file_path);
35        config.ansi_output = runtime.ansi_output.unwrap_or(config.ansi_output);
36        config.ansi_sanitization = runtime.ansi_sanitization.unwrap_or(config.ansi_sanitization);
37        config.metrics_interval = runtime.metrics_interval.or(config.metrics_interval);
38
39        config
40    }
41
42    /// Enables file logging at given path, if provided
43    pub fn log_file_path(mut self, path: Option<String>) -> Self {
44        self.inner.log_file_path = path;
45        self
46    }
47    /// enables ANSI (color) output in tracing-subscriber
48    ///
49    /// Default value: `true`
50    pub fn ansi_output(mut self, val: bool) -> Self {
51        self.inner.ansi_output = val;
52        self
53    }
54    /// enables ANSI sanitization in tracing-subscriber
55    ///
56    /// Default value: `true`
57    pub fn ansi_sanitization(mut self, val: bool) -> Self {
58        self.inner.ansi_sanitization = val;
59        self
60    }
61    /// Custom env filter which takes priority over RUST_LOG, if provided
62    ///
63    /// This is useful for providing a sane default for logging
64    ///
65    /// It's recommended to use [`TracingOverrideConfig::filter_append`] to make adjustments at runtime.
66    pub fn filter(mut self, filter: Option<String>) -> Self {
67        self.inner.filter = filter;
68        self
69    }
70
71    /// If provided, will configure the metrics export period (duration in seconds)
72    pub fn metrics_interval(mut self, interval: Option<u64>) -> Self {
73        self.inner.metrics_interval = interval;
74        self
75    }
76
77    /// Custom OTEL resource attributes
78    ///
79    /// Can only be set using the [`TracingConfigBuilder`]
80    pub fn custom_resource_attrs(mut self, attrs: Option<Vec<(Key, Value)>>) -> Self {
81        self.inner.custom_resource_attrs = attrs;
82        self
83    }
84}
85
86// !- Tracing config
87
88#[derive(Debug, Clone, Serialize)]
89pub struct TracingConfig {
90    /// Custom env filter which takes priority over RUST_LOG
91    ///
92    /// This is beneficial when loading app conf from env,
93    /// as it allows overriding the env filter without setting a global RUST_LOG
94    pub(crate) filter: Option<String>,
95
96    /// Appends the resolved logging filter with the provided text
97    pub(crate) filter_append: Option<String>,
98
99    /// Enables file logging at the provided path
100    pub(crate) log_file_path: Option<String>,
101
102    /// tracing-subscriber ANDI output
103    pub(crate) ansi_output: bool,
104
105    /// tracing-subscriber ANSI sanitization
106    pub(crate) ansi_sanitization: bool,
107
108    /// If set, will be user as the value for the `deployment.environment.name` attribute
109    pub(crate) deployment_env: Option<String>,
110
111    /// Custom OTEL resource attributes
112    ///
113    /// Can only be set using the [`TracingConfigBuildsr`]
114    #[serde(skip_serializing)]
115    pub(crate) custom_resource_attrs: Option<Vec<(Key, Value)>>,
116
117    /// If set, will configure the metrics export period (duration in seconds)
118    pub(crate) metrics_interval: Option<u64>,
119
120    pub(crate) otel_config: Option<TracingOtelConfig>,
121}
122impl TracingConfig {
123    pub fn builder(runtime_config: &TracingConfigOverride) -> TracingConfigBuilder {
124        TracingConfigBuilder::new(runtime_config)
125    }
126    pub fn metrics_interval_duration(&self) -> Option<Duration> {
127        self.metrics_interval.map(Duration::from_secs)
128    }
129    pub fn log_file_path(&self) -> Option<&str> {
130        self.log_file_path.as_deref()
131    }
132    pub fn otel_config(&self) -> &Option<TracingOtelConfig> {
133        &self.otel_config
134    }
135}
136
137// !- Override config
138
139/// Runtime overrides for config
140///
141/// This is the struct you should use for deserializing env var & .env/config file
142#[derive(Debug, Clone, Default, Serialize, Deserialize)]
143pub struct TracingConfigOverride {
144    // ! Override-only (set at runtime)
145
146    #[serde(flatten)]
147    pub(crate) otel_config: Option<TracingOtelConfig>,
148
149    /// Appends input to tracing filter, preserving the base filter.
150    ///
151    /// Thls allows for updating the filter at runtime without needing to copy over all the base filters
152    ///
153    /// A leading comma is **not** required
154    pub(crate) filter_append: Option<String>,
155
156    /// If set, will be user as the value for the `deployment.environment.name` attribute
157    ///
158    /// e.g. prod, staging
159    pub(crate) deployment_env: Option<String>,
160
161    // ! Base config overrides
162
163    pub(crate) filter: Option<String>,
164
165    pub(crate) log_file_path: Option<String>,
166
167    pub(crate) ansi_output: Option<bool>,
168
169    pub(crate) ansi_sanitization: Option<bool>,
170
171    pub(crate) metrics_interval: Option<u64>,
172}
173
174// !- OTEL config
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
177pub struct TracingOtelConfig {
178    pub collector_url: String,
179
180    #[serde(default, skip_serializing)]
181    pub collector_auth_header: Option<SecretString>,
182}