1use serde::{Deserialize, Serialize};
6use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
7use std::sync::Arc;
8use std::time::Instant;
9
10#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
12pub struct ServerStats {
13 pub active_connections: usize,
15 pub total_requests: u64,
17 pub cache_hit_rate: f64,
19 pub uptime_secs: u64,
21 pub bytes_sent: u64,
23 pub bytes_received: u64,
25}
26
27#[derive(Debug)]
29pub struct StatsCollector {
30 start_time: Instant,
32 active_connections: Arc<AtomicUsize>,
34 total_requests: Arc<AtomicU64>,
36 cache_hits: Arc<AtomicU64>,
38 cache_misses: Arc<AtomicU64>,
40 bytes_sent: Arc<AtomicU64>,
42 bytes_received: Arc<AtomicU64>,
44 ready: Arc<AtomicBool>,
46}
47
48impl Default for StatsCollector {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54impl StatsCollector {
55 pub fn new() -> Self {
57 Self {
58 start_time: Instant::now(),
59 active_connections: Arc::new(AtomicUsize::new(0)),
60 total_requests: Arc::new(AtomicU64::new(0)),
61 cache_hits: Arc::new(AtomicU64::new(0)),
62 cache_misses: Arc::new(AtomicU64::new(0)),
63 bytes_sent: Arc::new(AtomicU64::new(0)),
64 bytes_received: Arc::new(AtomicU64::new(0)),
65 ready: Arc::new(AtomicBool::new(true)),
66 }
67 }
68
69 pub fn get_stats(&self) -> ServerStats {
71 let cache_hits = self.cache_hits.load(Ordering::Relaxed);
72 let cache_misses = self.cache_misses.load(Ordering::Relaxed);
73 let total_cache_requests = cache_hits + cache_misses;
74
75 let cache_hit_rate = if total_cache_requests > 0 {
76 cache_hits as f64 / total_cache_requests as f64
77 } else {
78 0.0
79 };
80
81 ServerStats {
82 active_connections: self.active_connections.load(Ordering::Relaxed),
83 total_requests: self.total_requests.load(Ordering::Relaxed),
84 cache_hit_rate,
85 uptime_secs: self.start_time.elapsed().as_secs(),
86 bytes_sent: self.bytes_sent.load(Ordering::Relaxed),
87 bytes_received: self.bytes_received.load(Ordering::Relaxed),
88 }
89 }
90
91 pub fn increment_connections(&self) {
93 self.active_connections.fetch_add(1, Ordering::Relaxed);
94 }
95
96 pub fn decrement_connections(&self) {
98 self.active_connections.fetch_sub(1, Ordering::Relaxed);
99 }
100
101 pub fn increment_requests(&self) {
103 self.total_requests.fetch_add(1, Ordering::Relaxed);
104 }
105
106 pub fn record_cache_hit(&self) {
108 self.cache_hits.fetch_add(1, Ordering::Relaxed);
109 }
110
111 pub fn record_cache_miss(&self) {
113 self.cache_misses.fetch_add(1, Ordering::Relaxed);
114 }
115
116 pub fn add_bytes_sent(&self, bytes: u64) {
118 self.bytes_sent.fetch_add(bytes, Ordering::Relaxed);
119 }
120
121 pub fn add_bytes_received(&self, bytes: u64) {
123 self.bytes_received.fetch_add(bytes, Ordering::Relaxed);
124 }
125
126 pub fn is_ready(&self) -> bool {
128 self.ready.load(Ordering::Relaxed)
129 }
130
131 pub fn set_ready(&self, ready: bool) {
133 self.ready.store(ready, Ordering::Relaxed);
134 }
135
136 pub fn active_connections_counter(&self) -> Arc<AtomicUsize> {
138 Arc::clone(&self.active_connections)
139 }
140
141 pub fn total_requests_counter(&self) -> Arc<AtomicU64> {
143 Arc::clone(&self.total_requests)
144 }
145
146 pub fn cache_hits_counter(&self) -> Arc<AtomicU64> {
148 Arc::clone(&self.cache_hits)
149 }
150
151 pub fn cache_misses_counter(&self) -> Arc<AtomicU64> {
153 Arc::clone(&self.cache_misses)
154 }
155
156 pub fn bytes_sent_counter(&self) -> Arc<AtomicU64> {
158 Arc::clone(&self.bytes_sent)
159 }
160
161 pub fn bytes_received_counter(&self) -> Arc<AtomicU64> {
163 Arc::clone(&self.bytes_received)
164 }
165}
166
167impl Clone for StatsCollector {
168 fn clone(&self) -> Self {
169 Self {
170 start_time: self.start_time,
171 active_connections: Arc::clone(&self.active_connections),
172 total_requests: Arc::clone(&self.total_requests),
173 cache_hits: Arc::clone(&self.cache_hits),
174 cache_misses: Arc::clone(&self.cache_misses),
175 bytes_sent: Arc::clone(&self.bytes_sent),
176 bytes_received: Arc::clone(&self.bytes_received),
177 ready: Arc::clone(&self.ready),
178 }
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185 use std::thread;
186 use std::time::Duration;
187
188 #[test]
189 fn test_stats_collector_creation() {
190 let collector = StatsCollector::new();
191 let stats = collector.get_stats();
192
193 assert_eq!(stats.active_connections, 0);
194 assert_eq!(stats.total_requests, 0);
195 assert_eq!(stats.cache_hit_rate, 0.0);
196 assert_eq!(stats.bytes_sent, 0);
197 assert_eq!(stats.bytes_received, 0);
198 }
199
200 #[test]
201 fn test_increment_connections() {
202 let collector = StatsCollector::new();
203 collector.increment_connections();
204 collector.increment_connections();
205
206 let stats = collector.get_stats();
207 assert_eq!(stats.active_connections, 2);
208 }
209
210 #[test]
211 fn test_decrement_connections() {
212 let collector = StatsCollector::new();
213 collector.increment_connections();
214 collector.increment_connections();
215 collector.decrement_connections();
216
217 let stats = collector.get_stats();
218 assert_eq!(stats.active_connections, 1);
219 }
220
221 #[test]
222 fn test_increment_requests() {
223 let collector = StatsCollector::new();
224 collector.increment_requests();
225 collector.increment_requests();
226 collector.increment_requests();
227
228 let stats = collector.get_stats();
229 assert_eq!(stats.total_requests, 3);
230 }
231
232 #[test]
233 fn test_cache_hit_rate_no_requests() {
234 let collector = StatsCollector::new();
235 let stats = collector.get_stats();
236 assert_eq!(stats.cache_hit_rate, 0.0);
237 }
238
239 #[test]
240 fn test_cache_hit_rate_all_hits() {
241 let collector = StatsCollector::new();
242 collector.record_cache_hit();
243 collector.record_cache_hit();
244 collector.record_cache_hit();
245
246 let stats = collector.get_stats();
247 assert!((stats.cache_hit_rate - 1.0).abs() < f64::EPSILON);
248 }
249
250 #[test]
251 fn test_cache_hit_rate_all_misses() {
252 let collector = StatsCollector::new();
253 collector.record_cache_miss();
254 collector.record_cache_miss();
255
256 let stats = collector.get_stats();
257 assert!((stats.cache_hit_rate - 0.0).abs() < f64::EPSILON);
258 }
259
260 #[test]
261 fn test_cache_hit_rate_mixed() {
262 let collector = StatsCollector::new();
263 collector.record_cache_hit();
264 collector.record_cache_hit();
265 collector.record_cache_miss();
266
267 let stats = collector.get_stats();
268 assert!((stats.cache_hit_rate - 0.6666666666666666).abs() < 0.0001);
269 }
270
271 #[test]
272 fn test_bytes_sent() {
273 let collector = StatsCollector::new();
274 collector.add_bytes_sent(100);
275 collector.add_bytes_sent(200);
276
277 let stats = collector.get_stats();
278 assert_eq!(stats.bytes_sent, 300);
279 }
280
281 #[test]
282 fn test_bytes_received() {
283 let collector = StatsCollector::new();
284 collector.add_bytes_received(50);
285 collector.add_bytes_received(150);
286
287 let stats = collector.get_stats();
288 assert_eq!(stats.bytes_received, 200);
289 }
290
291 #[test]
292 fn test_uptime() {
293 let collector = StatsCollector::new();
294 thread::sleep(Duration::from_millis(100));
295 let stats = collector.get_stats();
296 assert!(stats.uptime_secs < 2);
298 }
299
300 #[test]
301 fn test_ready_state() {
302 let collector = StatsCollector::new();
303 assert!(collector.is_ready());
304
305 collector.set_ready(false);
306 assert!(!collector.is_ready());
307
308 collector.set_ready(true);
309 assert!(collector.is_ready());
310 }
311
312 #[test]
313 fn test_stats_collector_clone() {
314 let collector = StatsCollector::new();
315 collector.increment_requests();
316
317 let cloned = collector.clone();
318 cloned.increment_requests();
319
320 let stats = collector.get_stats();
321 assert_eq!(stats.total_requests, 2); }
323
324 #[test]
325 fn test_server_stats_serialization() {
326 let stats = ServerStats {
327 active_connections: 5,
328 total_requests: 100,
329 cache_hit_rate: 0.85,
330 uptime_secs: 3600,
331 bytes_sent: 1024000,
332 bytes_received: 512000,
333 };
334
335 let json = serde_json::to_string(&stats).unwrap();
336 assert!(json.contains("\"active_connections\":5"));
337 assert!(json.contains("\"total_requests\":100"));
338 assert!(json.contains("\"cache_hit_rate\":0.85"));
339 }
340
341 #[test]
342 fn test_server_stats_deserialization() {
343 let json = r#"{
344 "active_connections": 10,
345 "total_requests": 500,
346 "cache_hit_rate": 0.75,
347 "uptime_secs": 7200,
348 "bytes_sent": 2048000,
349 "bytes_received": 1024000
350 }"#;
351
352 let stats: ServerStats = serde_json::from_str(json).unwrap();
353 assert_eq!(stats.active_connections, 10);
354 assert_eq!(stats.total_requests, 500);
355 assert!((stats.cache_hit_rate - 0.75).abs() < f64::EPSILON);
356 assert_eq!(stats.uptime_secs, 7200);
357 assert_eq!(stats.bytes_sent, 2048000);
358 assert_eq!(stats.bytes_received, 1024000);
359 }
360
361 #[test]
362 fn test_server_stats_equality() {
363 let stats1 = ServerStats {
364 active_connections: 5,
365 total_requests: 100,
366 cache_hit_rate: 0.85,
367 uptime_secs: 3600,
368 bytes_sent: 1024000,
369 bytes_received: 512000,
370 };
371 let stats2 = ServerStats {
372 active_connections: 5,
373 total_requests: 100,
374 cache_hit_rate: 0.85,
375 uptime_secs: 3600,
376 bytes_sent: 1024000,
377 bytes_received: 512000,
378 };
379 assert_eq!(stats1, stats2);
380 }
381
382 #[test]
383 fn test_server_stats_clone() {
384 let stats = ServerStats {
385 active_connections: 5,
386 total_requests: 100,
387 cache_hit_rate: 0.85,
388 uptime_secs: 3600,
389 bytes_sent: 1024000,
390 bytes_received: 512000,
391 };
392 let cloned = stats.clone();
393 assert_eq!(stats, cloned);
394 }
395
396 #[test]
397 fn test_server_stats_debug() {
398 let stats = ServerStats {
399 active_connections: 5,
400 total_requests: 100,
401 cache_hit_rate: 0.85,
402 uptime_secs: 3600,
403 bytes_sent: 1024000,
404 bytes_received: 512000,
405 };
406 let debug_str = format!("{:?}", stats);
407 assert!(debug_str.contains("ServerStats"));
408 assert!(debug_str.contains("active_connections"));
409 }
410
411 #[test]
412 fn test_stats_collector_default() {
413 let collector = StatsCollector::default();
414 let stats = collector.get_stats();
415 assert_eq!(stats.active_connections, 0);
416 assert_eq!(stats.total_requests, 0);
417 }
418
419 #[test]
420 fn test_concurrent_increment_requests() {
421 let collector = Arc::new(StatsCollector::new());
422 let mut handles = vec![];
423
424 for _ in 0..10 {
425 let collector_clone = Arc::clone(&collector);
426 handles.push(thread::spawn(move || {
427 for _ in 0..100 {
428 collector_clone.increment_requests();
429 }
430 }));
431 }
432
433 for handle in handles {
434 handle.join().unwrap();
435 }
436
437 let stats = collector.get_stats();
438 assert_eq!(stats.total_requests, 1000);
439 }
440
441 #[test]
442 fn test_concurrent_connections() {
443 let collector = Arc::new(StatsCollector::new());
444 let mut handles = vec![];
445
446 for _ in 0..5 {
447 let collector_clone = Arc::clone(&collector);
448 handles.push(thread::spawn(move || {
449 collector_clone.increment_connections();
450 thread::sleep(Duration::from_millis(10));
451 collector_clone.decrement_connections();
452 }));
453 }
454
455 for handle in handles {
456 handle.join().unwrap();
457 }
458
459 let stats = collector.get_stats();
460 assert_eq!(stats.active_connections, 0);
461 }
462
463 #[test]
464 fn test_get_counter_clones() {
465 let collector = StatsCollector::new();
466
467 let active_conn = collector.active_connections_counter();
468 active_conn.fetch_add(5, Ordering::Relaxed);
469
470 let stats = collector.get_stats();
471 assert_eq!(stats.active_connections, 5);
472 }
473
474 #[test]
475 fn test_cache_counters_clone() {
476 let collector = StatsCollector::new();
477
478 let hits = collector.cache_hits_counter();
479 let misses = collector.cache_misses_counter();
480
481 hits.fetch_add(10, Ordering::Relaxed);
482 misses.fetch_add(5, Ordering::Relaxed);
483
484 let stats = collector.get_stats();
485 assert!((stats.cache_hit_rate - 0.6666666666666666).abs() < 0.0001);
486 }
487
488 #[test]
489 fn test_bytes_counters_clone() {
490 let collector = StatsCollector::new();
491
492 let sent = collector.bytes_sent_counter();
493 let received = collector.bytes_received_counter();
494
495 sent.fetch_add(1000, Ordering::Relaxed);
496 received.fetch_add(500, Ordering::Relaxed);
497
498 let stats = collector.get_stats();
499 assert_eq!(stats.bytes_sent, 1000);
500 assert_eq!(stats.bytes_received, 500);
501 }
502
503 #[test]
504 fn test_large_numbers() {
505 let collector = StatsCollector::new();
506
507 collector.add_bytes_sent(u64::MAX / 2);
508 collector.add_bytes_sent(u64::MAX / 2 + 1);
509
510 let stats = collector.get_stats();
511 assert_eq!(stats.bytes_sent, u64::MAX);
512 }
513
514 #[test]
515 fn test_cache_hit_rate_precision() {
516 let collector = StatsCollector::new();
517
518 for _ in 0..7 {
520 collector.record_cache_hit();
521 }
522 for _ in 0..3 {
523 collector.record_cache_miss();
524 }
525
526 let stats = collector.get_stats();
527 assert!((stats.cache_hit_rate - 0.7).abs() < 0.0001);
528 }
529}