nonblock_logger/
filter.rs1use crate::Error;
2use log::{Level, LevelFilter, Metadata, Record};
3use std::cmp::{max, Ordering};
4
5pub trait Filter: Send + Sync + 'static {
6 fn boxed(self) -> Result<Box<dyn Filter>, Error>;
7 fn log(&self, record: &Record) -> bool;
8 fn enabled(&self, metadata: &Metadata) -> bool;
9 fn maxlevel(&self) -> LevelFilter;
10}
11
12impl Filter for BaseFilter {
13 fn boxed(self) -> Result<Box<dyn Filter>, Error> {
14 Ok(Box::new(self.built()?) as _)
15 }
16
17 fn log(&self, record: &Record) -> bool {
18 self.check(record.target(), record.level())
19 }
20
21 fn enabled(&self, metadata: &Metadata) -> bool {
22 self.check(metadata.target(), metadata.level())
23 }
24
25 fn maxlevel(&self) -> LevelFilter {
26 self.max_level
27 }
28}
29
30impl BaseFilter {
31 fn built(mut self) -> Result<Self, Error> {
32 self.filters.sort_by(|a, b| a.0.cmp(&b.0));
34 self.max_level = self.max_level_get();
37 let filters_length = self.filters.len();
38
39 let starts_with = self.starts_with;
40 self.filters
41 .dedup_by(|a, b| if starts_with { b.0.starts_with(&a.0) } else { b.0 == a.0 });
42
43 if filters_length > self.filters.len() {
46 Err("dedup token effect")?;
47 }
48
49 Ok(self)
50 }
51
52 fn check(&self, target: &str, level: Level) -> bool {
53 if let Some(idx) = self
54 .filters
55 .binary_search_by(|(t, _level)| {
56 if self.starts_with && target.starts_with(t) {
57 Ordering::Equal
58 } else {
59 t.as_str().cmp(target)
60 }
61 })
62 .ok()
63 {
64 unsafe { self.filters.get_unchecked(idx).1 >= level }
65 } else {
66 self.notfound
67 }
68 }
69}
70
71#[derive(Debug, Clone)]
72pub struct BaseFilter {
73 filters: Vec<(String, LevelFilter)>,
74 max_level: LevelFilter,
75 starts_with: bool,
76 notfound: bool,
77}
78
79impl Default for BaseFilter {
80 fn default() -> Self {
81 Self::new()
82 }
83}
84
85impl BaseFilter {
86 pub fn new() -> Self {
87 Self {
88 filters: vec![],
89 max_level: LevelFilter::Trace,
90 starts_with: false,
91 notfound: true,
92 }
93 }
94
95 pub fn notfound(mut self, pass: bool) -> Self {
96 self.notfound = pass;
97 self
98 }
99
100 pub fn starts_with(mut self, yes: bool) -> Self {
101 self.starts_with = yes;
102 self
103 }
104
105 pub fn chain_iter<I>(mut self, filters: I) -> Self
106 where
107 I: IntoIterator<Item = (String, LevelFilter)>,
108 {
109 filters.into_iter().for_each(|tl| self.filters.push(tl));
110 self
111 }
112
113 pub fn chain<S: Into<String>>(mut self, target: S, level: LevelFilter) -> Self {
114 self.filters.push((target.into(), level));
115 self
116 }
117
118 pub fn max_level(mut self, max_level: LevelFilter) -> Self {
119 self.max_level = max_level;
120 self
121 }
122
123 pub fn max_level_get(&self) -> LevelFilter {
125 let has = self.max_level;
126 if let Some(compute) = self.filters.iter().max_by(|a, b| a.1.cmp(&b.1)) {
127 if self.notfound {
128 return max(compute.1, has);
129 } else {
130 return compute.1;
131 }
132 }
133 has
134 }
135
136 pub fn starts_with_get(&self) -> bool {
137 self.starts_with
138 }
139}