1use std::sync::atomic::{AtomicU64, Ordering};
4use std::sync::Arc;
5use std::time::{Duration, Instant};
6
7pub struct Metrics {
9 packets_sent: Arc<AtomicU64>,
11 packets_received: Arc<AtomicU64>,
13 bytes_sent: Arc<AtomicU64>,
15 bytes_received: Arc<AtomicU64>,
17 errors: Arc<AtomicU64>,
19 start_time: Instant,
21}
22
23impl Metrics {
24 pub fn new() -> Self {
26 Self {
27 packets_sent: Arc::new(AtomicU64::new(0)),
28 packets_received: Arc::new(AtomicU64::new(0)),
29 bytes_sent: Arc::new(AtomicU64::new(0)),
30 bytes_received: Arc::new(AtomicU64::new(0)),
31 errors: Arc::new(AtomicU64::new(0)),
32 start_time: Instant::now(),
33 }
34 }
35
36 pub fn record_packet_sent(&self, size: usize) {
38 self.packets_sent.fetch_add(1, Ordering::Relaxed);
39 self.bytes_sent.fetch_add(size as u64, Ordering::Relaxed);
40 }
41
42 pub fn record_packet_received(&self, size: usize) {
44 self.packets_received.fetch_add(1, Ordering::Relaxed);
45 self.bytes_received.fetch_add(size as u64, Ordering::Relaxed);
46 }
47
48 pub fn record_error(&self) {
50 self.errors.fetch_add(1, Ordering::Relaxed);
51 }
52
53 pub fn snapshot(&self) -> MetricsSnapshot {
55 MetricsSnapshot {
56 packets_sent: self.packets_sent.load(Ordering::Relaxed),
57 packets_received: self.packets_received.load(Ordering::Relaxed),
58 bytes_sent: self.bytes_sent.load(Ordering::Relaxed),
59 bytes_received: self.bytes_received.load(Ordering::Relaxed),
60 errors: self.errors.load(Ordering::Relaxed),
61 uptime: self.start_time.elapsed(),
62 }
63 }
64
65 pub fn reset(&self) {
67 self.packets_sent.store(0, Ordering::Relaxed);
68 self.packets_received.store(0, Ordering::Relaxed);
69 self.bytes_sent.store(0, Ordering::Relaxed);
70 self.bytes_received.store(0, Ordering::Relaxed);
71 self.errors.store(0, Ordering::Relaxed);
72 }
73}
74
75impl Default for Metrics {
76 fn default() -> Self {
77 Self::new()
78 }
79}
80
81impl Clone for Metrics {
82 fn clone(&self) -> Self {
83 Self {
84 packets_sent: self.packets_sent.clone(),
85 packets_received: self.packets_received.clone(),
86 bytes_sent: self.bytes_sent.clone(),
87 bytes_received: self.bytes_received.clone(),
88 errors: self.errors.clone(),
89 start_time: self.start_time,
90 }
91 }
92}
93
94#[derive(Debug, Clone)]
96pub struct MetricsSnapshot {
97 pub packets_sent: u64,
98 pub packets_received: u64,
99 pub bytes_sent: u64,
100 pub bytes_received: u64,
101 pub errors: u64,
102 pub uptime: Duration,
103}
104
105impl MetricsSnapshot {
106 pub fn packets_per_second(&self) -> f64 {
108 let total_packets = self.packets_sent + self.packets_received;
109 total_packets as f64 / self.uptime.as_secs_f64()
110 }
111
112 pub fn bytes_per_second(&self) -> f64 {
114 let total_bytes = self.bytes_sent + self.bytes_received;
115 total_bytes as f64 / self.uptime.as_secs_f64()
116 }
117
118 pub fn error_rate(&self) -> f64 {
120 let total_ops = self.packets_sent + self.packets_received;
121 if total_ops == 0 {
122 0.0
123 } else {
124 self.errors as f64 / total_ops as f64
125 }
126 }
127
128 pub fn format(&self) -> String {
130 format!(
131 "Packets: {} sent, {} received | Bytes: {} sent, {} received | Errors: {} | Uptime: {:?}",
132 self.packets_sent,
133 self.packets_received,
134 self.bytes_sent,
135 self.bytes_received,
136 self.errors,
137 self.uptime
138 )
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn test_metrics_tracking() {
148 let metrics = Metrics::new();
149
150 metrics.record_packet_sent(100);
151 metrics.record_packet_received(200);
152
153 let snapshot = metrics.snapshot();
154
155 assert_eq!(snapshot.packets_sent, 1);
156 assert_eq!(snapshot.packets_received, 1);
157 assert_eq!(snapshot.bytes_sent, 100);
158 assert_eq!(snapshot.bytes_received, 200);
159 }
160
161 #[test]
162 fn test_metrics_reset() {
163 let metrics = Metrics::new();
164
165 metrics.record_packet_sent(100);
166 metrics.reset();
167
168 let snapshot = metrics.snapshot();
169 assert_eq!(snapshot.packets_sent, 0);
170 }
171
172 #[test]
173 fn test_snapshot_calculations() {
174 let snapshot = MetricsSnapshot {
175 packets_sent: 100,
176 packets_received: 100,
177 bytes_sent: 10000,
178 bytes_received: 10000,
179 errors: 5,
180 uptime: Duration::from_secs(10),
181 };
182
183 assert_eq!(snapshot.packets_per_second(), 20.0);
184 assert_eq!(snapshot.bytes_per_second(), 2000.0);
185 assert!((snapshot.error_rate() - 0.025).abs() < 0.001);
186 }
187}