datasynth_server/observability/
metrics.rs1use std::sync::atomic::{AtomicU64, Ordering};
8use std::sync::Arc;
9use std::time::Instant;
10
11#[derive(Clone)]
17pub struct ServerMetrics {
18 pub entries_total: Arc<AtomicU64>,
20 pub errors_total: Arc<AtomicU64>,
22 pub active_sessions: Arc<AtomicU64>,
24}
25
26impl Default for ServerMetrics {
27 fn default() -> Self {
28 Self::new()
29 }
30}
31
32impl ServerMetrics {
33 pub fn new() -> Self {
34 Self {
35 entries_total: Arc::new(AtomicU64::new(0)),
36 errors_total: Arc::new(AtomicU64::new(0)),
37 active_sessions: Arc::new(AtomicU64::new(0)),
38 }
39 }
40
41 pub fn record_entries(&self, count: u64) {
43 self.entries_total.fetch_add(count, Ordering::Relaxed);
44 }
45
46 pub fn record_error(&self) {
48 self.errors_total.fetch_add(1, Ordering::Relaxed);
49 }
50
51 pub fn session_started(&self) {
53 self.active_sessions.fetch_add(1, Ordering::Relaxed);
54 }
55
56 pub fn session_ended(&self) {
58 self.active_sessions.fetch_sub(1, Ordering::Relaxed);
59 }
60}
61
62pub struct DurationTimer {
64 start: Instant,
65 label: String,
66}
67
68impl DurationTimer {
69 pub fn new(label: impl Into<String>) -> Self {
70 Self {
71 start: Instant::now(),
72 label: label.into(),
73 }
74 }
75
76 pub fn finish(self) -> u64 {
78 let duration_ms = self.start.elapsed().as_millis() as u64;
79 tracing::debug!(
80 label = %self.label,
81 duration_ms = duration_ms,
82 "Operation completed"
83 );
84 duration_ms
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn test_server_metrics_default() {
94 let metrics = ServerMetrics::new();
95 assert_eq!(metrics.entries_total.load(Ordering::Relaxed), 0);
96 assert_eq!(metrics.errors_total.load(Ordering::Relaxed), 0);
97 assert_eq!(metrics.active_sessions.load(Ordering::Relaxed), 0);
98 }
99
100 #[test]
101 fn test_record_entries() {
102 let metrics = ServerMetrics::new();
103 metrics.record_entries(100);
104 metrics.record_entries(50);
105 assert_eq!(metrics.entries_total.load(Ordering::Relaxed), 150);
106 }
107
108 #[test]
109 fn test_record_errors() {
110 let metrics = ServerMetrics::new();
111 metrics.record_error();
112 metrics.record_error();
113 assert_eq!(metrics.errors_total.load(Ordering::Relaxed), 2);
114 }
115
116 #[test]
117 fn test_session_tracking() {
118 let metrics = ServerMetrics::new();
119 metrics.session_started();
120 metrics.session_started();
121 assert_eq!(metrics.active_sessions.load(Ordering::Relaxed), 2);
122 metrics.session_ended();
123 assert_eq!(metrics.active_sessions.load(Ordering::Relaxed), 1);
124 }
125
126 #[test]
127 fn test_duration_timer() {
128 let timer = DurationTimer::new("test_op");
129 std::thread::sleep(std::time::Duration::from_millis(10));
130 let duration = timer.finish();
131 assert!(duration >= 10);
132 }
133}