litellm_rs/config/models/
monitoring.rs1use super::*;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8pub struct MonitoringConfig {
9 #[serde(default)]
11 pub metrics: MetricsConfig,
12 #[serde(default)]
14 pub tracing: TracingConfig,
15 #[serde(default)]
17 pub health: HealthConfig,
18}
19
20impl MonitoringConfig {
21 pub fn merge(mut self, other: Self) -> Self {
23 self.metrics = self.metrics.merge(other.metrics);
24 self.tracing = self.tracing.merge(other.tracing);
25 self.health = self.health.merge(other.health);
26 self
27 }
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct MetricsConfig {
33 #[serde(default = "default_true")]
35 pub enabled: bool,
36 #[serde(default = "default_metrics_port")]
38 pub port: u16,
39 #[serde(default = "default_metrics_path")]
41 pub path: String,
42}
43
44impl Default for MetricsConfig {
45 fn default() -> Self {
46 Self {
47 enabled: true,
48 port: default_metrics_port(),
49 path: default_metrics_path(),
50 }
51 }
52}
53
54impl MetricsConfig {
55 pub fn merge(mut self, other: Self) -> Self {
57 if !other.enabled {
58 self.enabled = other.enabled;
59 }
60 if other.port != default_metrics_port() {
61 self.port = other.port;
62 }
63 if other.path != default_metrics_path() {
64 self.path = other.path;
65 }
66 self
67 }
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct TracingConfig {
73 #[serde(default)]
75 pub enabled: bool,
76 pub endpoint: Option<String>,
78 #[serde(default = "default_service_name")]
80 pub service_name: String,
81}
82
83impl Default for TracingConfig {
84 fn default() -> Self {
85 Self {
86 enabled: false,
87 endpoint: None,
88 service_name: default_service_name(),
89 }
90 }
91}
92
93impl TracingConfig {
94 pub fn merge(mut self, other: Self) -> Self {
96 if other.enabled {
97 self.enabled = other.enabled;
98 }
99 if other.endpoint.is_some() {
100 self.endpoint = other.endpoint;
101 }
102 if other.service_name != default_service_name() {
103 self.service_name = other.service_name;
104 }
105 self
106 }
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
111pub struct HealthConfig {
112 #[serde(default = "default_health_path")]
114 pub path: String,
115 #[serde(default = "default_true")]
117 pub detailed: bool,
118}
119
120impl Default for HealthConfig {
121 fn default() -> Self {
122 Self {
123 path: default_health_path(),
124 detailed: true,
125 }
126 }
127}
128
129impl HealthConfig {
130 pub fn merge(mut self, other: Self) -> Self {
132 if other.path != default_health_path() {
133 self.path = other.path;
134 }
135 if !other.detailed {
136 self.detailed = other.detailed;
137 }
138 self
139 }
140}
141
142fn default_true() -> bool {
143 true
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149
150 #[test]
153 fn test_metrics_config_default() {
154 let config = MetricsConfig::default();
155 assert!(config.enabled);
156 assert_eq!(config.port, 9090);
157 assert_eq!(config.path, "/metrics");
158 }
159
160 #[test]
161 fn test_metrics_config_structure() {
162 let config = MetricsConfig {
163 enabled: false,
164 port: 8080,
165 path: "/prometheus".to_string(),
166 };
167 assert!(!config.enabled);
168 assert_eq!(config.port, 8080);
169 assert_eq!(config.path, "/prometheus");
170 }
171
172 #[test]
173 fn test_metrics_config_serialization() {
174 let config = MetricsConfig {
175 enabled: true,
176 port: 9100,
177 path: "/stats".to_string(),
178 };
179 let json = serde_json::to_value(&config).unwrap();
180 assert_eq!(json["enabled"], true);
181 assert_eq!(json["port"], 9100);
182 assert_eq!(json["path"], "/stats");
183 }
184
185 #[test]
186 fn test_metrics_config_deserialization() {
187 let json = r#"{"enabled": false, "port": 3000, "path": "/api/metrics"}"#;
188 let config: MetricsConfig = serde_json::from_str(json).unwrap();
189 assert!(!config.enabled);
190 assert_eq!(config.port, 3000);
191 }
192
193 #[test]
194 fn test_metrics_config_merge_disabled() {
195 let base = MetricsConfig::default();
196 let other = MetricsConfig {
197 enabled: false,
198 port: 9090,
199 path: "/metrics".to_string(),
200 };
201 let merged = base.merge(other);
202 assert!(!merged.enabled);
203 }
204
205 #[test]
206 fn test_metrics_config_merge_port() {
207 let base = MetricsConfig::default();
208 let other = MetricsConfig {
209 enabled: true,
210 port: 8888,
211 path: "/metrics".to_string(),
212 };
213 let merged = base.merge(other);
214 assert_eq!(merged.port, 8888);
215 }
216
217 #[test]
218 fn test_metrics_config_clone() {
219 let config = MetricsConfig::default();
220 let cloned = config.clone();
221 assert_eq!(config.enabled, cloned.enabled);
222 assert_eq!(config.port, cloned.port);
223 }
224
225 #[test]
228 fn test_tracing_config_default() {
229 let config = TracingConfig::default();
230 assert!(!config.enabled);
231 assert!(config.endpoint.is_none());
232 assert_eq!(config.service_name, "litellm-rs");
233 }
234
235 #[test]
236 fn test_tracing_config_structure() {
237 let config = TracingConfig {
238 enabled: true,
239 endpoint: Some("http://jaeger:14268".to_string()),
240 service_name: "my-gateway".to_string(),
241 };
242 assert!(config.enabled);
243 assert_eq!(config.endpoint, Some("http://jaeger:14268".to_string()));
244 }
245
246 #[test]
247 fn test_tracing_config_serialization() {
248 let config = TracingConfig {
249 enabled: true,
250 endpoint: Some("http://otel:4317".to_string()),
251 service_name: "api-gateway".to_string(),
252 };
253 let json = serde_json::to_value(&config).unwrap();
254 assert_eq!(json["enabled"], true);
255 assert_eq!(json["endpoint"], "http://otel:4317");
256 }
257
258 #[test]
259 fn test_tracing_config_deserialization() {
260 let json =
261 r#"{"enabled": true, "endpoint": "http://zipkin:9411", "service_name": "tracer"}"#;
262 let config: TracingConfig = serde_json::from_str(json).unwrap();
263 assert!(config.enabled);
264 assert_eq!(config.service_name, "tracer");
265 }
266
267 #[test]
268 fn test_tracing_config_merge_enabled() {
269 let base = TracingConfig::default();
270 let other = TracingConfig {
271 enabled: true,
272 endpoint: None,
273 service_name: "litellm-gateway".to_string(),
274 };
275 let merged = base.merge(other);
276 assert!(merged.enabled);
277 }
278
279 #[test]
280 fn test_tracing_config_merge_endpoint() {
281 let base = TracingConfig::default();
282 let other = TracingConfig {
283 enabled: false,
284 endpoint: Some("http://collector:4317".to_string()),
285 service_name: "litellm-gateway".to_string(),
286 };
287 let merged = base.merge(other);
288 assert_eq!(merged.endpoint, Some("http://collector:4317".to_string()));
289 }
290
291 #[test]
292 fn test_tracing_config_clone() {
293 let config = TracingConfig::default();
294 let cloned = config.clone();
295 assert_eq!(config.enabled, cloned.enabled);
296 assert_eq!(config.service_name, cloned.service_name);
297 }
298
299 #[test]
302 fn test_health_config_default() {
303 let config = HealthConfig::default();
304 assert_eq!(config.path, "/health");
305 assert!(config.detailed);
306 }
307
308 #[test]
309 fn test_health_config_structure() {
310 let config = HealthConfig {
311 path: "/api/health".to_string(),
312 detailed: false,
313 };
314 assert_eq!(config.path, "/api/health");
315 assert!(!config.detailed);
316 }
317
318 #[test]
319 fn test_health_config_serialization() {
320 let config = HealthConfig {
321 path: "/status".to_string(),
322 detailed: true,
323 };
324 let json = serde_json::to_value(&config).unwrap();
325 assert_eq!(json["path"], "/status");
326 assert_eq!(json["detailed"], true);
327 }
328
329 #[test]
330 fn test_health_config_deserialization() {
331 let json = r#"{"path": "/ready", "detailed": false}"#;
332 let config: HealthConfig = serde_json::from_str(json).unwrap();
333 assert_eq!(config.path, "/ready");
334 assert!(!config.detailed);
335 }
336
337 #[test]
338 fn test_health_config_merge_path() {
339 let base = HealthConfig::default();
340 let other = HealthConfig {
341 path: "/healthz".to_string(),
342 detailed: true,
343 };
344 let merged = base.merge(other);
345 assert_eq!(merged.path, "/healthz");
346 }
347
348 #[test]
349 fn test_health_config_merge_detailed() {
350 let base = HealthConfig::default();
351 let other = HealthConfig {
352 path: "/health".to_string(),
353 detailed: false,
354 };
355 let merged = base.merge(other);
356 assert!(!merged.detailed);
357 }
358
359 #[test]
360 fn test_health_config_clone() {
361 let config = HealthConfig::default();
362 let cloned = config.clone();
363 assert_eq!(config.path, cloned.path);
364 assert_eq!(config.detailed, cloned.detailed);
365 }
366
367 #[test]
370 fn test_monitoring_config_default() {
371 let config = MonitoringConfig::default();
372 assert!(config.metrics.enabled);
373 assert!(!config.tracing.enabled);
374 assert!(config.health.detailed);
375 }
376
377 #[test]
378 fn test_monitoring_config_structure() {
379 let config = MonitoringConfig {
380 metrics: MetricsConfig::default(),
381 tracing: TracingConfig::default(),
382 health: HealthConfig::default(),
383 };
384 assert_eq!(config.metrics.port, 9090);
385 }
386
387 #[test]
388 fn test_monitoring_config_serialization() {
389 let config = MonitoringConfig::default();
390 let json = serde_json::to_value(&config).unwrap();
391 assert!(json["metrics"].is_object());
392 assert!(json["tracing"].is_object());
393 assert!(json["health"].is_object());
394 }
395
396 #[test]
397 fn test_monitoring_config_merge() {
398 let base = MonitoringConfig::default();
399 let other = MonitoringConfig {
400 metrics: MetricsConfig {
401 enabled: false,
402 port: 9090,
403 path: "/metrics".to_string(),
404 },
405 tracing: TracingConfig::default(),
406 health: HealthConfig::default(),
407 };
408 let merged = base.merge(other);
409 assert!(!merged.metrics.enabled);
410 }
411
412 #[test]
413 fn test_monitoring_config_clone() {
414 let config = MonitoringConfig::default();
415 let cloned = config.clone();
416 assert_eq!(config.metrics.enabled, cloned.metrics.enabled);
417 }
418}