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}