logging_toolkit/
lib.rs

1#[macro_use]
2extern crate slog;
3#[macro_use]
4extern crate lazy_static;
5
6use slog::Drain;
7use slog::FnValue;
8use slog::Level;
9use slog::LevelFilter;
10use slog::Logger;
11use std::env;
12use std::fs::OpenOptions;
13
14lazy_static! {
15    static ref ROOT_LOGGER: Logger = make_root_logger(
16        "FIL_PROOFS_LOG_JSON",
17        "FIL_PROOFS_MIN_LOG_LEVEL",
18        "FIL_PROOFS_LOG_FILE"
19    );
20}
21
22pub fn make_root_logger(
23    use_json_env_name: &str,
24    min_log_level_env_name: &str,
25    log_file_env_name: &str,
26) -> Logger {
27    let log_file_name = env::var(log_file_env_name).unwrap_or_else(|_| "/dev/stdout".to_string());
28    let log_file: Box<dyn std::io::Write + Send> = match log_file_name.as_ref() {
29        "/dev/stdout" => Box::new(std::io::stdout()),
30        "/dev/stderr" => Box::new(std::io::stderr()),
31        filename => {
32            let tryfile = OpenOptions::new().create(true).append(true).open(filename);
33            match tryfile {
34                Ok(file) => Box::new(file),
35                // Fallback to stdout if file cannot be opened
36                Err(_) => Box::new(std::io::stdout()),
37            }
38        }
39    };
40
41    let drain = match env::var(use_json_env_name).as_ref().map(String::as_str) {
42        Ok("true") => {
43            let json_drain = slog_json::Json::new(log_file)
44                .add_default_keys()
45                .build()
46                .fuse();
47
48            slog_async::Async::new(json_drain).build().fuse()
49        }
50        _ => {
51            match log_file_name.as_ref() {
52                // Colored output for stdout/stderr
53                "/dev/stdout" | "/dev/stderr" => {
54                    let term_decorator = slog_term::TermDecorator::new().build();
55                    let term_drain = slog_term::FullFormat::new(term_decorator).build().fuse();
56
57                    slog_async::Async::new(term_drain).build().fuse()
58                }
59                // Use plain output if it is written into a file
60                _ => {
61                    let plain_decorator = slog_term::PlainDecorator::new(log_file);
62                    let plain_drain = slog_term::FullFormat::new(plain_decorator).build().fuse();
63
64                    slog_async::Async::new(plain_drain).build().fuse()
65                }
66            }
67        }
68    };
69
70    let min_log_level = match env::var(min_log_level_env_name) {
71        Ok(val) => match val.parse::<u64>() {
72            Ok(parsed) => match Level::from_usize(parsed as usize) {
73                Some(level) => level,
74                None => Level::Info,
75            },
76            _ => Level::Info,
77        },
78        _ => Level::Info,
79    };
80
81    let with_filter = LevelFilter::new(drain, min_log_level).map(slog::Fuse);
82
83    Logger::root(
84        with_filter,
85        o!("place" => FnValue(move |info| {
86            format!("{}:{} {}",
87                    info.file(),
88                    info.line(),
89                    info.module(),
90                    )
91        })),
92    )
93}
94
95pub fn make_logger(root_name: &'static str) -> Logger {
96    ROOT_LOGGER.new(o!("root" => root_name))
97}