1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
use slog::{o, Drain, FilterLevel, FnValue, Fuse, Logger};
use slog_async::{Async, OverflowStrategy};
use slog_envlogger::LogBuilder;
use slog_scope::set_global_logger;
use slog_term::{Decorator, FullFormat, PlainDecorator, TermDecorator};
use std::env;
use std::fs::OpenOptions;

const DEFAULT_CHAIN_SIZE: usize = 256;
const RUST_LOG: &str = "RUST_LOG";

pub fn init_logger(file_path: Option<String>) -> Logger {
    let logger = setup_logger(file_path);
    let global_logger = set_global_logger(logger.clone());
    slog_stdlog::init().expect("failed to init logger");
    global_logger.cancel_reset();
    logger
}

fn setup_logger(file_path: Option<String>) -> Logger {
    let drain = match file_path {
        Some(file_path) => {
            let outfile = OpenOptions::new().create(true).append(true).open(file_path).unwrap();

            let file_decorator = PlainDecorator::new(outfile);
            create_drain(file_decorator)
        }
        None => {
            let decorator = TermDecorator::new().build();
            create_drain(decorator)
        }
    };

    Logger::root(
        drain,
        o!("module" => FnValue(move |info| {
            format!("[{}]", info.module())
        })),
    )
}

fn create_drain<T: Decorator + Send + 'static>(decorator: T) -> Fuse<Async> {
    let drain_decorator = FullFormat::new(decorator).build().fuse();
    let env_drain = LogBuilder::new(drain_decorator)
        .filter(None, FilterLevel::Info)
        .parse(env::var(RUST_LOG).unwrap_or_default().as_str())
        .build();

    Async::new(env_drain.fuse())
        .chan_size(DEFAULT_CHAIN_SIZE)
        .overflow_strategy(OverflowStrategy::DropAndReport)
        .build()
        .fuse()
}