lmn_core/histogram/
status_code.rs1use std::collections::HashMap;
2
3pub struct StatusCodeHistogram {
7 counts: HashMap<u16, u64>,
8 error_count: u64,
9}
10
11impl StatusCodeHistogram {
12 pub fn new() -> Self {
14 Self {
15 counts: HashMap::new(),
16 error_count: 0,
17 }
18 }
19
20 pub fn record(&mut self, status_code: Option<u16>) {
24 match status_code {
25 Some(code) => *self.counts.entry(code).or_insert(0) += 1,
26 None => self.error_count += 1,
27 }
28 }
29
30 pub fn counts(&self) -> &HashMap<u16, u64> {
32 &self.counts
33 }
34
35 pub fn error_count(&self) -> u64 {
37 self.error_count
38 }
39
40 pub fn total(&self) -> u64 {
42 self.counts.values().sum::<u64>() + self.error_count
43 }
44}
45
46impl Default for StatusCodeHistogram {
47 fn default() -> Self {
48 Self::new()
49 }
50}
51
52#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn record_200_increments_count() {
60 let mut h = StatusCodeHistogram::new();
61 h.record(Some(200));
62 assert_eq!(h.counts()[&200], 1);
63 }
64
65 #[test]
66 fn record_none_increments_error_count() {
67 let mut h = StatusCodeHistogram::new();
68 h.record(None);
69 h.record(None);
70 assert_eq!(h.error_count(), 2);
71 }
72
73 #[test]
74 fn total_sums_all_codes_and_errors() {
75 let mut h = StatusCodeHistogram::new();
76 h.record(Some(200));
77 h.record(Some(200));
78 h.record(Some(404));
79 h.record(None);
80 assert_eq!(h.total(), 4);
81 }
82
83 #[test]
84 fn multiple_codes_tracked_independently() {
85 let mut h = StatusCodeHistogram::new();
86 h.record(Some(200));
87 h.record(Some(201));
88 h.record(Some(404));
89 h.record(Some(503));
90 assert_eq!(h.counts()[&200], 1);
91 assert_eq!(h.counts()[&201], 1);
92 assert_eq!(h.counts()[&404], 1);
93 assert_eq!(h.counts()[&503], 1);
94 }
95}