filter_logger/
lib.rs

1extern crate chrono;
2#[macro_use] extern crate log;
3
4use std::boxed::Box;
5
6#[derive(Clone)]
7pub struct FilterLogger {
8    level: log::Level,
9    mod_filter: Vec<String>,
10    body_filter: Vec<String>,
11    format: String,
12}
13
14impl FilterLogger
15{
16    pub fn init(level: log::Level,
17                mod_filter: Vec<String>,
18                body_filter: Vec<String>,) -> Self {
19        let logger = FilterLogger {
20            level,
21            mod_filter,
22            body_filter,
23            format: "%Y-%m-%d %H:%M:%S%z".into(),
24        };
25
26        let _ = log::set_boxed_logger(Box::new(logger.clone()));
27        log::set_max_level(level.to_level_filter());
28
29        logger
30    }
31
32    pub fn with_format(level: log::Level,
33                       mod_filter: Vec<String>,
34                       body_filter: Vec<String>,
35                       format: String) -> Self {
36        let logger = FilterLogger {
37            level,
38            mod_filter,
39            body_filter,
40            format,
41        };
42
43        let _ = log::set_boxed_logger(Box::new(logger.clone()));
44        log::set_max_level(level.to_level_filter());
45
46        logger
47    }
48}
49
50impl log::Log for FilterLogger {
51    fn enabled(&self, metadata: &log::Metadata) -> bool {
52        metadata.level() <= self.level
53    }
54
55    fn log(&self, record: &log::Record) {
56        let now = chrono::Utc::now();
57        let skip = record.module_path()
58            .map(|m| {
59                self.mod_filter.iter()
60                    .filter(|f| m.contains(*f))
61                    .next()
62                    .is_some()
63            })
64            .unwrap_or(false);
65        let msg_str = format!("{}", record.args());
66        let body_skip =
67            self.body_filter.iter()
68                .filter(|f| msg_str.contains(*f))
69                .next()
70                .is_some();
71        if !skip && !body_skip {
72            println!("{time} {level} [{module}] {body}",
73                     time = now.format(self.format.as_ref()),
74                     level = record.level(),
75                     module = record.module_path().unwrap_or("default"),
76                     body = msg_str);
77        }
78    }
79
80    fn flush(&self) {
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    mod test1 {
89        pub fn log_it() {
90            debug!("test debug");
91            info!("test info");
92            trace!("test trace");
93            error!("test error");
94        }
95    }
96
97    mod test2 {
98        pub fn log_it() {
99            debug!("test debug");
100            info!("test info");
101            trace!("test trace");
102            error!("test error");
103        }
104    }
105
106    #[test]
107    fn test_log() {
108        FilterLogger::init(log::Level::Trace, vec![], vec![]);
109        println!("test_log = 8 Goods Expected (INFO, ERROR, DEBUG, TRACE)");
110        test1::log_it();
111        test2::log_it();
112    }
113
114    #[test]
115    fn test_level() {
116        FilterLogger::init(log::Level::Info, vec![], vec![]);
117        println!("test_level = 4 Goods Expected (INFO and ERROR)");
118        test1::log_it();
119        test2::log_it();
120    }
121
122    #[test]
123    fn test_filter() {
124        FilterLogger::init(log::Level::Info, vec!["test2".to_string()], vec!["test error".to_string()]);
125        println!("test_filter = 1 Good Expected (INFO, module='test1')");
126        test1::log_it();
127        test2::log_it();
128    }
129}