|
| 1 | +mod storage; |
| 2 | + |
| 3 | +use crate::prelude::*; |
| 4 | +use log::{Log, Metadata, Record}; |
| 5 | +use std::cell::RefCell; |
| 6 | +use std::thread::LocalKey; |
| 7 | + |
| 8 | +pub(crate) use self::storage::LogStorage; |
| 9 | + |
| 10 | +thread_local! { |
| 11 | + static SCOPED: RefCell<Vec<Box<Log>>> = RefCell::new(Vec::new()); |
| 12 | +} |
| 13 | + |
| 14 | +struct MultiLogger { |
| 15 | + global: Vec<Box<Log>>, |
| 16 | + scoped: &'static LocalKey<RefCell<Vec<Box<Log>>>>, |
| 17 | +} |
| 18 | + |
| 19 | +impl MultiLogger { |
| 20 | + fn new(global: Vec<Box<Log>>, scoped: &'static LocalKey<RefCell<Vec<Box<Log>>>>) -> Self { |
| 21 | + MultiLogger { global, scoped } |
| 22 | + } |
| 23 | + |
| 24 | + fn each<F: FnMut(&Log)>(&self, mut f: F) { |
| 25 | + for logger in &self.global { |
| 26 | + f(logger.as_ref()); |
| 27 | + } |
| 28 | + self.scoped.with(|scoped| { |
| 29 | + for logger in &*scoped.borrow() { |
| 30 | + f(logger.as_ref()); |
| 31 | + } |
| 32 | + }); |
| 33 | + } |
| 34 | +} |
| 35 | + |
| 36 | +impl Log for MultiLogger { |
| 37 | + fn enabled(&self, metadata: &Metadata) -> bool { |
| 38 | + let mut result = false; |
| 39 | + self.each(|logger| { |
| 40 | + if logger.enabled(metadata) { |
| 41 | + result = true; |
| 42 | + } |
| 43 | + }); |
| 44 | + result |
| 45 | + } |
| 46 | + |
| 47 | + fn log(&self, record: &Record) { |
| 48 | + self.each(|logger| { |
| 49 | + logger.log(record); |
| 50 | + }); |
| 51 | + } |
| 52 | + |
| 53 | + fn flush(&self) { |
| 54 | + self.each(|logger| { |
| 55 | + logger.flush(); |
| 56 | + }); |
| 57 | + } |
| 58 | +} |
| 59 | + |
| 60 | +pub fn capture<F, R, L>(storage: &L, f: F) -> Fallible<R> |
| 61 | +where |
| 62 | + F: FnOnce() -> Fallible<R>, |
| 63 | + L: Log + Clone + 'static, |
| 64 | +{ |
| 65 | + let storage = Box::new(storage.clone()); |
| 66 | + SCOPED.with(|scoped| scoped.borrow_mut().push(storage)); |
| 67 | + let result = f(); |
| 68 | + SCOPED.with(|scoped| { |
| 69 | + let _ = scoped.borrow_mut().pop(); |
| 70 | + }); |
| 71 | + result |
| 72 | +} |
| 73 | + |
| 74 | +pub fn init() -> Fallible<()> { |
| 75 | + // Initialize env_logger |
| 76 | + // This doesn't use from_default_env() because it doesn't allow to override filter_module() |
| 77 | + // with the RUST_LOG environment variable |
| 78 | + let mut env = env_logger::Builder::new(); |
| 79 | + env.filter_module("crater", log::LevelFilter::Info); |
| 80 | + if let Ok(content) = std::env::var("RUST_LOG") { |
| 81 | + env.parse(&content); |
| 82 | + } |
| 83 | + |
| 84 | + let multi = MultiLogger::new(vec![Box::new(env.build())], &SCOPED); |
| 85 | + log::set_boxed_logger(Box::new(multi))?; |
| 86 | + log::set_max_level(log::LevelFilter::Trace); |
| 87 | + |
| 88 | + Ok(()) |
| 89 | +} |
0 commit comments