use failure::{bail, Fallible}; pub const LOG_LEVELS: [&str; 5] = ["error", "warn", "info", "debug", "trace"]; /// 3rd-party libraries that produce log spam - we set these to a fixed higher level /// to allow using e.g. TRACE without drowing our custom messages pub const SPAMMY_LIBS: [&str; 5] = ["tokio_reactor", "hyper", "reqwest", "mio", "want"]; pub fn add_clap_args<'b, 'a: 'b>(clap : clap::App<'a, 'b>) -> clap::App<'a, 'b> { clap .arg(clap::Arg::with_name("verbose") .short("v").multiple(true) .help("Increase logging verbosity (repeat to increase)")) .arg(clap::Arg::with_name("log-level") .short("l").long("log") .takes_value(true).value_name("LEVEL") .validator(|s| { if LOG_LEVELS.contains(&s.as_str()) { return Ok(()); } Err(format!("Bad log level: {}", s)) }) .help("Set logging verbosity (error,warning,info,debug,trace)")) } /// Initialize logging, using `level` as the base if not changed via command-line /// arguments pub fn init<'a, 'b>(mut level: &'a str, argv: &'a clap::ArgMatches, suppress: Option<&'b [&str]>) -> Fallible<&'a str> { if !LOG_LEVELS.contains(&level) { bail!("Invalid default log level: {}", level); } /* env RUST_LOG overrides default if set, but can be changed by CLI args */ let env_level = option_env!("RUST_LOG").unwrap_or(""); //env_logger::DEFAULT_FILTER_ENV if !env_level.is_empty() { level = env_level; if !LOG_LEVELS.contains(&level) { bail!("Invalid env log level: {}", level); } } /* Explicitly requested level */ if let Some(l) = argv.value_of("log-level") { level = l; // validated by clap } /* Verbosity increased */ if argv.is_present("verbose") { // bump verbosity if -v's are present let pos = LOG_LEVELS .iter() .position(|x| x == &level) .unwrap(); level = match LOG_LEVELS .iter() .nth(pos + argv.occurrences_of("verbose") as usize) { Some(new_level) => new_level, None => "trace", }; } let env = env_logger::Env::default().default_filter_or(level); let mut builder = env_logger::Builder::from_env(env); builder.format_timestamp_millis(); // set logging level for spammy libs. Ensure the configured log level is not exceeded let mut lib_level = log::LevelFilter::Info; if level == "warn" { lib_level = log::LevelFilter::Warn; } else if level == "error" { lib_level = log::LevelFilter::Error; } for lib in suppress.unwrap_or(&SPAMMY_LIBS) { builder.filter_module(lib, lib_level); } builder.init(); Ok(level) }