webserver_colin_ugo/utils/
stats.rs1use std::collections::HashMap;
2use std::sync::{Arc, Mutex};
3use serde::Serialize;
4
5#[derive(Debug, Clone, Serialize)]
7pub struct ServerStats {
8 pub total_requests: u64,
10 pub error_counts: HashMap<String, u64>,
12}
13
14impl Default for ServerStats {
15 fn default() -> Self {
16 Self {
17 total_requests: 0,
18 error_counts: HashMap::new(),
19 }
20 }
21}
22
23pub struct StatsManager {
25 stats: Arc<Mutex<ServerStats>>,
26}
27
28impl StatsManager {
29 pub fn new() -> Self {
31 Self {
32 stats: Arc::new(Mutex::new(ServerStats::default())),
33 }
34 }
35
36 pub fn get_stats(&self) -> ServerStats {
38 self.stats.lock().unwrap().clone()
39 }
40
41 pub fn increment_request_count(&self) {
43 let mut stats = self.stats.lock().unwrap();
44 stats.total_requests += 1;
45 }
46
47 pub fn increment_error_count(&self, status_code: &str) {
53 if !status_code.starts_with("4") && !status_code.starts_with("5") {
54 return;
55 }
56
57 let mut stats = self.stats.lock().unwrap();
58 let counter = stats.error_counts.entry(status_code.to_string()).or_insert(0);
59 *counter += 1;
60 }
61
62 pub fn to_json(&self) -> Result<String, serde_json::Error> {
64 let stats = self.get_stats();
65 serde_json::to_string_pretty(&stats)
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn test_stats_manager() {
75 let stats_manager = StatsManager::new();
76
77 stats_manager.increment_request_count();
79 stats_manager.increment_request_count();
80 let stats = stats_manager.get_stats();
81 assert_eq!(stats.total_requests, 2);
82
83 stats_manager.increment_error_count("404 Not Found");
85 stats_manager.increment_error_count("404 Not Found");
86 stats_manager.increment_error_count("500 Internal Server Error");
87
88 let stats = stats_manager.get_stats();
89 assert_eq!(*stats.error_counts.get("404 Not Found").unwrap(), 2);
90 assert_eq!(*stats.error_counts.get("500 Internal Server Error").unwrap(), 1);
91 }
92
93 #[test]
94 fn test_error_counts_only_for_errors() {
95 let stats_manager = StatsManager::new();
96
97 stats_manager.increment_error_count("200 OK");
98
99 let stats = stats_manager.get_stats();
100 assert!(stats.error_counts.get("200 OK").is_none());
101 }
102
103 #[test]
104 fn test_to_json() {
105 let stats_manager = StatsManager::new();
106 stats_manager.increment_request_count();
107 stats_manager.increment_error_count("404 Not Found");
108
109 let json = stats_manager.to_json().unwrap();
110 assert!(json.contains("total_requests"));
111 assert!(json.contains("error_counts"));
112 assert!(json.contains("404 Not Found"));
113 }
114}