oxihuman_core/
log_aggregator.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
9pub enum AggLogLevel {
10 Trace = 0,
11 Debug = 1,
12 Info = 2,
13 Warn = 3,
14 Error = 4,
15 Fatal = 5,
16}
17
18#[derive(Debug, Clone)]
20pub struct AggLogEntry {
21 pub level: AggLogLevel,
22 pub message: String,
23 pub source: String,
24}
25
26#[derive(Debug)]
28pub struct LogAggregator {
29 min_level: AggLogLevel,
30 entries: Vec<AggLogEntry>,
31}
32
33impl LogAggregator {
34 pub fn new(min_level: AggLogLevel) -> Self {
35 Self {
36 min_level,
37 entries: Vec::new(),
38 }
39 }
40
41 pub fn push(&mut self, level: AggLogLevel, source: &str, message: &str) {
42 if level >= self.min_level {
43 self.entries.push(AggLogEntry {
44 level,
45 message: message.to_string(),
46 source: source.to_string(),
47 });
48 }
49 }
50
51 pub fn entries(&self) -> &[AggLogEntry] {
52 &self.entries
53 }
54
55 pub fn count(&self) -> usize {
56 self.entries.len()
57 }
58
59 pub fn count_at_level(&self, level: AggLogLevel) -> usize {
60 self.entries.iter().filter(|e| e.level == level).count()
61 }
62
63 pub fn set_min_level(&mut self, level: AggLogLevel) {
64 self.min_level = level;
65 }
66
67 pub fn clear(&mut self) {
68 self.entries.clear();
69 }
70
71 pub fn filter_source<'a>(&'a self, source: &str) -> Vec<&'a AggLogEntry> {
72 self.entries.iter().filter(|e| e.source == source).collect()
73 }
74}
75
76pub fn new_log_aggregator(min_level: AggLogLevel) -> LogAggregator {
77 LogAggregator::new(min_level)
78}
79
80pub fn agg_push(agg: &mut LogAggregator, level: AggLogLevel, source: &str, msg: &str) {
81 agg.push(level, source, msg);
82}
83
84pub fn agg_count(agg: &LogAggregator) -> usize {
85 agg.count()
86}
87
88pub fn agg_count_level(agg: &LogAggregator, level: AggLogLevel) -> usize {
89 agg.count_at_level(level)
90}
91
92pub fn agg_set_min(agg: &mut LogAggregator, level: AggLogLevel) {
93 agg.set_min_level(level);
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn test_push_above_min() {
102 let mut agg = new_log_aggregator(AggLogLevel::Info);
103 agg_push(&mut agg, AggLogLevel::Info, "srv", "started");
104 assert_eq!(agg_count(&agg), 1);
105 }
106
107 #[test]
108 fn test_filter_below_min() {
109 let mut agg = new_log_aggregator(AggLogLevel::Warn);
110 agg_push(&mut agg, AggLogLevel::Debug, "srv", "verbose");
111 assert_eq!(agg_count(&agg), 0);
112 }
113
114 #[test]
115 fn test_count_at_level() {
116 let mut agg = new_log_aggregator(AggLogLevel::Debug);
117 agg_push(&mut agg, AggLogLevel::Error, "src", "boom");
118 agg_push(&mut agg, AggLogLevel::Info, "src", "ok");
119 assert_eq!(agg_count_level(&agg, AggLogLevel::Error), 1);
120 }
121
122 #[test]
123 fn test_clear() {
124 let mut agg = new_log_aggregator(AggLogLevel::Info);
125 agg_push(&mut agg, AggLogLevel::Info, "s", "msg");
126 agg.clear();
127 assert_eq!(agg_count(&agg), 0);
128 }
129
130 #[test]
131 fn test_set_min_level_changes_filtering() {
132 let mut agg = new_log_aggregator(AggLogLevel::Error);
133 agg_set_min(&mut agg, AggLogLevel::Debug);
134 agg_push(&mut agg, AggLogLevel::Debug, "s", "now visible");
135 assert_eq!(agg_count(&agg), 1);
136 }
137
138 #[test]
139 fn test_filter_source() {
140 let mut agg = new_log_aggregator(AggLogLevel::Info);
141 agg_push(&mut agg, AggLogLevel::Info, "auth", "login");
142 agg_push(&mut agg, AggLogLevel::Info, "api", "req");
143 let auth_entries = agg.filter_source("auth");
144 assert_eq!(auth_entries.len(), 1);
145 }
146
147 #[test]
148 fn test_level_ordering() {
149 assert!(AggLogLevel::Error > AggLogLevel::Info);
150 }
151
152 #[test]
153 fn test_fatal_always_captured() {
154 let mut agg = new_log_aggregator(AggLogLevel::Error);
155 agg_push(&mut agg, AggLogLevel::Fatal, "sys", "crashed");
156 assert_eq!(agg_count(&agg), 1);
157 }
158
159 #[test]
160 fn test_multiple_sources() {
161 let mut agg = new_log_aggregator(AggLogLevel::Info);
162 agg_push(&mut agg, AggLogLevel::Info, "a", "msg1");
163 agg_push(&mut agg, AggLogLevel::Info, "b", "msg2");
164 agg_push(&mut agg, AggLogLevel::Info, "a", "msg3");
165 assert_eq!(agg.filter_source("a").len(), 2);
166 assert_eq!(agg.filter_source("b").len(), 1);
167 }
168}