1const WARN: [char; 4] = ['w', 'a', 'r', 'n'];
18
19pub trait Transform {
20 fn transform_error(&self, msg: String) -> String;
22 fn transform_warning(&self, msg: String) -> String;
24}
25struct Logger<T>(T);
26impl<T: Transform + Send + Sync> log::Log for Logger<T> {
27 fn enabled(&self, m: &log::Metadata) -> bool {
28 m.level() <= log::Level::Info
29 }
30
31 fn log(&self, record: &log::Record) {
32 match record.level() {
33 log::Level::Error => {
34 let mut log = record.args().to_string();
35 if contains_warn(&log) {
36 log = self.0.transform_error(log);
37 }
38
39 eprintln!("{}", log);
40 },
41 log::Level::Warn => {
42 let mut log = record.args().to_string();
43 if !contains_warn(&log) {
44 log = self.0.transform_warning(log);
45 }
46
47 eprintln!("{}", log);
48 }
49 log::Level::Info => println!("{}", record.args()),
50 _ => {}
51 }
52
53 }
54
55 fn flush(&self) {}
56}
57pub fn contains_warn(s: &str) -> bool {
59 let mut warn_ptr = 0;
60 for ch in s.chars() {
61 if ch.eq_ignore_ascii_case(&WARN[warn_ptr]) {
62 if warn_ptr == 3 {
63 return true
64 }
65 warn_ptr += 1;
66 } else {
67 warn_ptr = 0;
68 }
69 }
70 false
71}
72
73pub struct DefaultTransform;
74impl Transform for DefaultTransform {
75 fn transform_error(&self, msg: String) -> String {
76 let mut transformed = base64::encode(&msg);
77
78 if !contains_warn(&transformed) {
79 "base64-encoded log: ".to_string() + &transformed
80 } else {
81 transformed = base64::encode(transformed);
82 if !contains_warn(&transformed) {
83 "base64-encoded-twice log: ".to_string() + &transformed
84 } else {
85 "The following error log has to be logged as Warning: \n".to_string() + &msg
87 }
88 }
89 }
90
91 fn transform_warning(&self, msg: String) -> String {
92 "warning: ".to_string() + &msg
93 }
94}
95
96pub fn init() {
97 init_transform(DefaultTransform);
98}
99
100pub fn init_transform<T: Transform + 'static + Send + Sync>(transform: T) {
101 log::set_logger(Box::leak(Box::new(Logger(transform))))
102 .expect("Failed to initialize logger");
103 log::set_max_level(log::LevelFilter::Info);
104}
105
106
107#[cfg(test)]
108mod tests {
109 use crate::contains_warn;
110
111 #[test]
112 fn test_no_warn() {
113 assert!(!contains_warn("abcdefg"));
114 }
115 #[test]
116 fn has_warn() {
117 assert!(contains_warn("awarng"));
118 }
119 #[test]
120 fn differnt_case_warn() {
121 assert!(contains_warn("awARng"));
122 }
123 #[test]
124 fn suffix_warn() {
125 assert!(contains_warn("awARn"));
126 }
127 #[test]
128 fn split_warn() {
129 assert!(!contains_warn("wa#rn"));
130 }
131}
132