Skip to main content

provide_telemetry/config/
mod.rs

1// SPDX-FileCopyrightText: Copyright (C) 2026 provide.io llc
2// SPDX-License-Identifier: Apache-2.0
3// SPDX-Comment: Part of provide-telemetry.
4//
5
6use std::collections::HashMap;
7
8use serde::{Deserialize, Serialize};
9
10mod from_env;
11mod parse;
12mod redact;
13
14pub use redact::redact_config;
15
16#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Default)]
17#[serde(default)]
18pub struct RuntimeOverrides {
19    pub sampling: Option<SamplingConfig>,
20    pub backpressure: Option<BackpressureConfig>,
21    pub exporter: Option<ExporterPolicyConfig>,
22    pub security: Option<SecurityConfig>,
23    pub slo: Option<SLOConfig>,
24    pub pii_max_depth: Option<usize>,
25    pub strict_schema: Option<bool>,
26    pub event_schema: Option<EventSchemaConfig>,
27    /// Hot-reloadable logging overrides. When `Some(cfg)`, the logger is
28    /// reconfigured so subsequent log events honor the new level, format,
29    /// and module-level thresholds. Matches Python's reference behavior.
30    pub logging: Option<LoggingConfig>,
31}
32
33#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
34#[serde(default)]
35pub struct LoggingConfig {
36    pub level: String,
37    pub fmt: String,
38    /// Whether to include an ISO 8601 timestamp in JSON log output.
39    /// Controlled by `PROVIDE_LOG_INCLUDE_TIMESTAMP` (default: true).
40    pub include_timestamp: bool,
41    pub otlp_headers: HashMap<String, String>,
42    /// OTLP endpoint URL for logs export. Falls back to the shared
43    /// `OTEL_EXPORTER_OTLP_ENDPOINT` when `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`
44    /// is unset. `None` means no endpoint configured.
45    pub otlp_endpoint: Option<String>,
46    /// OTLP transport protocol for logs. Empty string means default
47    /// (resolved at exporter-build time to `http/protobuf`). Values:
48    /// `http/protobuf`, `http/json`, `grpc` (the latter requires the
49    /// `otel-grpc` cargo feature).
50    pub otlp_protocol: String,
51    /// Per-module log level overrides. Keys are module-name prefixes
52    /// (longest-prefix wins); values are level strings (TRACE/DEBUG/
53    /// INFO/WARN/ERROR). Controlled by `PROVIDE_LOG_MODULE_LEVELS`.
54    pub module_levels: HashMap<String, String>,
55}
56
57impl Default for LoggingConfig {
58    fn default() -> Self {
59        Self {
60            level: "INFO".to_string(),
61            fmt: "console".to_string(),
62            include_timestamp: true,
63            otlp_headers: HashMap::new(),
64            otlp_endpoint: None,
65            otlp_protocol: String::new(),
66            module_levels: HashMap::new(),
67        }
68    }
69}
70
71#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
72#[serde(default)]
73pub struct TracingConfig {
74    pub enabled: bool,
75    /// Per-signal sample rate for traces (PROVIDE_TRACE_SAMPLE_RATE).
76    /// Combined with sampling.traces_rate via min() in apply_policies.
77    pub sample_rate: f64,
78    pub otlp_headers: HashMap<String, String>,
79    /// OTLP endpoint URL for traces export. Falls back to the shared
80    /// `OTEL_EXPORTER_OTLP_ENDPOINT` when `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`
81    /// is unset.
82    pub otlp_endpoint: Option<String>,
83    /// OTLP transport protocol for traces. See `LoggingConfig::otlp_protocol`.
84    pub otlp_protocol: String,
85}
86
87impl Default for TracingConfig {
88    fn default() -> Self {
89        Self {
90            enabled: true,
91            sample_rate: 1.0,
92            otlp_headers: HashMap::new(),
93            otlp_endpoint: None,
94            otlp_protocol: String::new(),
95        }
96    }
97}
98
99#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
100#[serde(default)]
101pub struct MetricsConfig {
102    pub enabled: bool,
103    pub otlp_headers: HashMap<String, String>,
104    /// OTLP endpoint URL for metrics export. Falls back to the shared
105    /// `OTEL_EXPORTER_OTLP_ENDPOINT` when `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`
106    /// is unset.
107    pub otlp_endpoint: Option<String>,
108    /// OTLP transport protocol for metrics. See `LoggingConfig::otlp_protocol`.
109    pub otlp_protocol: String,
110    /// How often (in milliseconds) the `PeriodicReader` pushes metrics to the
111    /// OTLP endpoint. Parsed from `OTEL_METRIC_EXPORT_INTERVAL` (OTel spec).
112    /// Default: 60 000 ms (60 seconds).
113    pub metric_export_interval_ms: u64,
114}
115
116fn default_metric_export_interval_ms() -> u64 {
117    60_000
118}
119
120impl Default for MetricsConfig {
121    fn default() -> Self {
122        Self {
123            enabled: true,
124            otlp_headers: HashMap::new(),
125            otlp_endpoint: None,
126            otlp_protocol: String::new(),
127            metric_export_interval_ms: default_metric_export_interval_ms(),
128        }
129    }
130}
131
132#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
133#[serde(default)]
134pub struct EventSchemaConfig {
135    pub strict_event_name: bool,
136    pub required_keys: Vec<String>,
137}
138
139#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
140#[serde(default)]
141pub struct SamplingConfig {
142    pub logs_rate: f64,
143    pub traces_rate: f64,
144    pub metrics_rate: f64,
145}
146
147impl Default for SamplingConfig {
148    fn default() -> Self {
149        Self {
150            logs_rate: 1.0,
151            traces_rate: 1.0,
152            metrics_rate: 1.0,
153        }
154    }
155}
156
157#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
158#[serde(default)]
159pub struct BackpressureConfig {
160    pub logs_maxsize: usize,
161    pub traces_maxsize: usize,
162    pub metrics_maxsize: usize,
163}
164
165#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
166#[serde(default)]
167pub struct ExporterPolicyConfig {
168    pub logs_retries: usize,
169    pub traces_retries: usize,
170    pub metrics_retries: usize,
171    pub logs_backoff_seconds: f64,
172    pub traces_backoff_seconds: f64,
173    pub metrics_backoff_seconds: f64,
174    pub logs_timeout_seconds: f64,
175    pub traces_timeout_seconds: f64,
176    pub metrics_timeout_seconds: f64,
177    pub logs_fail_open: bool,
178    pub traces_fail_open: bool,
179    pub metrics_fail_open: bool,
180}
181
182impl Default for ExporterPolicyConfig {
183    fn default() -> Self {
184        Self {
185            logs_retries: 0,
186            traces_retries: 0,
187            metrics_retries: 0,
188            logs_backoff_seconds: 0.0,
189            traces_backoff_seconds: 0.0,
190            metrics_backoff_seconds: 0.0,
191            logs_timeout_seconds: 10.0,
192            traces_timeout_seconds: 10.0,
193            metrics_timeout_seconds: 10.0,
194            logs_fail_open: true,
195            traces_fail_open: true,
196            metrics_fail_open: true,
197        }
198    }
199}
200
201#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
202#[serde(default)]
203pub struct SLOConfig {
204    pub enable_red_metrics: bool,
205    pub enable_use_metrics: bool,
206}
207
208#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
209#[serde(default)]
210pub struct SecurityConfig {
211    pub max_attr_value_length: usize,
212    pub max_attr_count: usize,
213    pub max_nesting_depth: usize,
214}
215
216impl Default for SecurityConfig {
217    fn default() -> Self {
218        Self {
219            max_attr_value_length: 1024,
220            max_attr_count: 64,
221            max_nesting_depth: 8,
222        }
223    }
224}
225
226#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
227#[serde(default)]
228pub struct TelemetryConfig {
229    pub service_name: String,
230    pub environment: String,
231    pub version: String,
232    pub strict_schema: bool,
233    pub pii_max_depth: usize,
234    pub logging: LoggingConfig,
235    pub tracing: TracingConfig,
236    pub metrics: MetricsConfig,
237    pub event_schema: EventSchemaConfig,
238    pub sampling: SamplingConfig,
239    pub backpressure: BackpressureConfig,
240    pub exporter: ExporterPolicyConfig,
241    pub slo: SLOConfig,
242    pub security: SecurityConfig,
243}
244
245impl Default for TelemetryConfig {
246    fn default() -> Self {
247        Self {
248            service_name: "provide-service".to_string(),
249            environment: "dev".to_string(),
250            version: "0.0.0".to_string(),
251            strict_schema: false,
252            pii_max_depth: 8,
253            logging: LoggingConfig::default(),
254            tracing: TracingConfig::default(),
255            metrics: MetricsConfig::default(),
256            event_schema: EventSchemaConfig::default(),
257            sampling: SamplingConfig::default(),
258            backpressure: BackpressureConfig::default(),
259            exporter: ExporterPolicyConfig::default(),
260            slo: SLOConfig::default(),
261            security: SecurityConfig::default(),
262        }
263    }
264}