ant_quic/logging/
filters.rs1use std::collections::HashMap;
5use tracing::Level;
6
7#[derive(Debug, Clone)]
9pub struct LogFilter {
10 component_levels: HashMap<String, Level>,
12 default_level: Level,
14 exclude_patterns: Vec<regex::Regex>,
16 include_patterns: Vec<regex::Regex>,
18}
19
20impl LogFilter {
21 pub fn new() -> Self {
23 Self {
24 component_levels: HashMap::new(),
25 default_level: Level::INFO,
26 exclude_patterns: Vec::new(),
27 include_patterns: Vec::new(),
28 }
29 }
30
31 pub fn with_default_level(mut self, level: Level) -> Self {
33 self.default_level = level;
34 self
35 }
36
37 pub fn with_module(mut self, module: &str, level: Level) -> Self {
39 self.component_levels.insert(module.to_string(), level);
40 self
41 }
42
43 pub fn exclude_pattern(mut self, pattern: &str) -> Result<Self, regex::Error> {
45 let regex = regex::Regex::new(pattern)?;
46 self.exclude_patterns.push(regex);
47 Ok(self)
48 }
49
50 pub fn include_pattern(mut self, pattern: &str) -> Result<Self, regex::Error> {
52 let regex = regex::Regex::new(pattern)?;
53 self.include_patterns.push(regex);
54 Ok(self)
55 }
56
57 pub fn should_log(&self, target: &str, level: Level, message: &str) -> bool {
59 for pattern in &self.include_patterns {
61 if pattern.is_match(message) || pattern.is_match(target) {
62 return true;
63 }
64 }
65
66 for pattern in &self.exclude_patterns {
68 if pattern.is_match(message) || pattern.is_match(target) {
69 return false;
70 }
71 }
72
73 let required_level = self.level_for(target).unwrap_or(self.default_level);
77 level <= required_level
78 }
79
80 pub fn level_for(&self, target: &str) -> Option<Level> {
82 if let Some(&level) = self.component_levels.get(target) {
84 return Some(level);
85 }
86
87 for (module, &level) in &self.component_levels {
89 if target.starts_with(module) {
90 return Some(level);
91 }
92 }
93
94 None
95 }
96}
97
98impl Default for LogFilter {
99 fn default() -> Self {
100 Self::new()
101 }
102}
103
104pub struct LogFilterBuilder {
106 filter: LogFilter,
107}
108
109impl Default for LogFilterBuilder {
110 fn default() -> Self {
111 Self::new()
112 }
113}
114
115impl LogFilterBuilder {
116 pub fn new() -> Self {
118 Self {
119 filter: LogFilter::new(),
120 }
121 }
122
123 pub fn default_level(mut self, level: Level) -> Self {
125 self.filter.default_level = level;
126 self
127 }
128
129 pub fn quic_defaults(mut self) -> Self {
131 self.filter
132 .component_levels
133 .insert("ant_quic::connection".to_string(), Level::DEBUG);
134 self.filter
135 .component_levels
136 .insert("ant_quic::endpoint".to_string(), Level::INFO);
137 self.filter
138 .component_levels
139 .insert("ant_quic::frame".to_string(), Level::TRACE);
140 self.filter
141 .component_levels
142 .insert("ant_quic::packet".to_string(), Level::TRACE);
143 self.filter
144 .component_levels
145 .insert("ant_quic::crypto".to_string(), Level::DEBUG);
146 self.filter
147 .component_levels
148 .insert("ant_quic::transport_params".to_string(), Level::DEBUG);
149 self
150 }
151
152 pub fn nat_traversal_debug(mut self) -> Self {
154 self.filter
155 .component_levels
156 .insert("ant_quic::nat_traversal".to_string(), Level::TRACE);
157 self.filter
158 .component_levels
159 .insert("ant_quic::candidate_discovery".to_string(), Level::DEBUG);
160 self.filter.component_levels.insert(
161 "ant_quic::connection::nat_traversal".to_string(),
162 Level::TRACE,
163 );
164 self
165 }
166
167 pub fn performance_analysis(mut self) -> Self {
169 self.filter
170 .component_levels
171 .insert("ant_quic::metrics".to_string(), Level::INFO);
172 self.filter
173 .component_levels
174 .insert("ant_quic::congestion".to_string(), Level::DEBUG);
175 self.filter
176 .component_levels
177 .insert("ant_quic::pacing".to_string(), Level::DEBUG);
178 self
179 }
180
181 pub fn production(mut self) -> Self {
183 self.filter.default_level = Level::WARN;
184 self.filter
185 .component_levels
186 .insert("ant_quic::connection::lifecycle".to_string(), Level::INFO);
187 self.filter
188 .component_levels
189 .insert("ant_quic::endpoint".to_string(), Level::INFO);
190 self.filter
191 .component_levels
192 .insert("ant_quic::metrics".to_string(), Level::INFO);
193 self
194 }
195
196 pub fn quiet(mut self) -> Self {
198 if let Ok(pattern) = regex::Regex::new(r"packet\.sent") {
200 self.filter.exclude_patterns.push(pattern);
201 }
202 if let Ok(pattern) = regex::Regex::new(r"packet\.received") {
203 self.filter.exclude_patterns.push(pattern);
204 }
205 if let Ok(pattern) = regex::Regex::new(r"frame\.sent") {
206 self.filter.exclude_patterns.push(pattern);
207 }
208 if let Ok(pattern) = regex::Regex::new(r"frame\.received") {
209 self.filter.exclude_patterns.push(pattern);
210 }
211 self
212 }
213
214 pub fn build(self) -> LogFilter {
216 self.filter
217 }
218}
219
220pub struct DynamicLogFilter {
222 inner: std::sync::RwLock<LogFilter>,
223}
224
225impl DynamicLogFilter {
226 pub fn new(filter: LogFilter) -> Self {
228 Self {
229 inner: std::sync::RwLock::new(filter),
230 }
231 }
232
233 pub fn update<F>(&self, updater: F) -> Result<(), Box<dyn std::error::Error>>
235 where
236 F: FnOnce(&mut LogFilter) -> Result<(), Box<dyn std::error::Error>>,
237 {
238 let mut filter = self.inner.write().unwrap();
239 updater(&mut filter)?;
240 Ok(())
241 }
242
243 pub fn should_log(&self, target: &str, level: Level, message: &str) -> bool {
245 self.inner
246 .read()
247 .unwrap()
248 .should_log(target, level, message)
249 }
250
251 pub fn level_for(&self, target: &str) -> Option<Level> {
253 self.inner.read().unwrap().level_for(target)
254 }
255}
256
257#[cfg(test)]
258mod tests {
259 use super::*;
260
261 #[test]
262 fn test_component_filtering() {
263 let filter = LogFilterBuilder::new()
264 .default_level(Level::WARN)
265 .quic_defaults()
266 .build();
267
268 assert!(filter.should_log("ant_quic::connection::mod", Level::DEBUG, "test"));
270 assert!(!filter.should_log("ant_quic::connection::mod", Level::TRACE, "test"));
271
272 assert!(filter.should_log("ant_quic::endpoint", Level::INFO, "test"));
274 assert!(!filter.should_log("ant_quic::endpoint", Level::DEBUG, "test"));
275
276 assert!(filter.should_log("other::module", Level::WARN, "test"));
278 assert!(!filter.should_log("other::module", Level::INFO, "test"));
279 }
280
281 #[test]
282 fn test_pattern_filtering() {
283 let filter = LogFilter::new()
284 .exclude_pattern(r"noisy")
285 .unwrap()
286 .include_pattern(r"important.*noisy")
287 .unwrap();
288
289 assert!(!filter.should_log("test", Level::INFO, "this is noisy"));
290 assert!(filter.should_log("test", Level::INFO, "this is important but noisy"));
291 assert!(filter.should_log("test", Level::INFO, "this is normal"));
292 }
293}