synwire_core/observability/
tracing_config.rs1use serde::{Deserialize, Serialize};
6use std::time::Duration;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct BatchConfig {
13 pub max_batch_size: usize,
15 #[serde(with = "duration_secs")]
17 pub max_wait: Duration,
18 pub max_concurrent_exports: usize,
20}
21
22impl Default for BatchConfig {
23 fn default() -> Self {
24 Self {
25 max_batch_size: 512,
26 max_wait: Duration::from_secs(5),
27 max_concurrent_exports: 4,
28 }
29 }
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct TracingConfig {
59 pub enabled: bool,
61 pub service_name: String,
63 pub content_filter: super::TraceContentFilter,
65 pub batch: BatchConfig,
67}
68
69impl Default for TracingConfig {
70 fn default() -> Self {
71 Self {
72 enabled: false,
73 service_name: "synwire".to_owned(),
74 content_filter: super::TraceContentFilter::default(),
75 batch: BatchConfig::default(),
76 }
77 }
78}
79
80impl TracingConfig {
81 pub fn builder() -> TracingConfigBuilder {
83 TracingConfigBuilder::default()
84 }
85}
86
87#[derive(Debug, Default)]
89pub struct TracingConfigBuilder {
90 config: TracingConfig,
91}
92
93impl TracingConfigBuilder {
94 pub const fn enabled(mut self, value: bool) -> Self {
96 self.config.enabled = value;
97 self
98 }
99
100 pub fn service_name(mut self, name: String) -> Self {
102 self.config.service_name = name;
103 self
104 }
105
106 pub const fn content_filter(mut self, filter: super::TraceContentFilter) -> Self {
108 self.config.content_filter = filter;
109 self
110 }
111
112 pub const fn batch(mut self, batch: BatchConfig) -> Self {
114 self.config.batch = batch;
115 self
116 }
117
118 pub fn build(self) -> TracingConfig {
120 self.config
121 }
122}
123
124mod duration_secs {
126 use serde::{Deserialize, Deserializer, Serialize, Serializer};
127 use std::time::Duration;
128
129 pub fn serialize<S: Serializer>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error> {
131 duration.as_secs_f64().serialize(serializer)
132 }
133
134 pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Duration, D::Error> {
136 let secs = f64::deserialize(deserializer)?;
137 Ok(Duration::from_secs_f64(secs))
138 }
139}
140
141#[cfg(test)]
142#[allow(clippy::unwrap_used)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn default_config_is_disabled() {
148 let config = TracingConfig::default();
149 assert!(!config.enabled);
150 assert_eq!(config.service_name, "synwire");
151 }
152
153 #[test]
154 fn builder_overrides() {
155 let config = TracingConfig::builder()
156 .enabled(true)
157 .service_name("test-agent".to_owned())
158 .build();
159 assert!(config.enabled);
160 assert_eq!(config.service_name, "test-agent");
161 }
162
163 #[test]
164 fn batch_config_defaults() {
165 let batch = BatchConfig::default();
166 assert_eq!(batch.max_batch_size, 512);
167 assert_eq!(batch.max_wait, Duration::from_secs(5));
168 assert_eq!(batch.max_concurrent_exports, 4);
169 }
170
171 #[test]
172 fn tracing_config_serialization_roundtrip() {
173 let config = TracingConfig::builder()
174 .enabled(true)
175 .service_name("roundtrip".to_owned())
176 .build();
177 let json = serde_json::to_string(&config).unwrap();
178 let deserialized: TracingConfig = serde_json::from_str(&json).unwrap();
179 assert_eq!(deserialized.enabled, config.enabled);
180 assert_eq!(deserialized.service_name, config.service_name);
181 }
182}