#![doc = include_str!("README.md")] #![forbid(unsafe_code)] use std::{ffi::OsStr, io::Write}; /// Default initialization /// /// Sets the main crate log level to `info`, everything else to `warn` by default. /// Allows overriding from `{main}_LOG` and `RUST_LOG`. /// /// Invoke as: /// ``` /// femtofemme::init(env!("CARGO_CRATE_NAME")); /// ``` pub fn init(main: &str) { init_custom( &[ format!("{}_LOG", main).as_str(), format!("{}_LOG", main.to_uppercase().replace('-', "_")).as_str(), "RUST_LOG", ], &format!("warn,{}=info", main.to_lowercase()), ); } /// Custom initialization /// /// Read the filter from the first set environment variable, or fall back to a default. pub fn init_custom(env: &[impl AsRef], default_filter: &str) { env_logger::Builder::new() .format(|buf, record| { let mut levelcolor = buf.style(); levelcolor.set_color(match record.level() { log::Level::Error => env_logger::fmt::Color::Red, log::Level::Warn => env_logger::fmt::Color::Yellow, log::Level::Info => env_logger::fmt::Color::Green, log::Level::Debug => env_logger::fmt::Color::Blue, log::Level::Trace => env_logger::fmt::Color::Magenta, }); writeln!( buf, "{} {} {}", chrono::offset::Local::now().format("%Y-%m-%d %H:%M:%S"), levelcolor.value(record.target()), record.args(), )?; #[cfg(feature = "kv")] { struct Visitor<'a> { buf: &'a mut env_logger::fmt::Formatter, } impl<'kvs, 'a> log::kv::Visitor<'kvs> for Visitor<'a> { fn visit_pair( &mut self, key: log::kv::Key<'kvs>, val: log::kv::Value<'kvs>, ) -> Result<(), log::kv::Error> { let mut bold = self.buf.style(); bold.set_bold(true); writeln!( self.buf, " {} {}", bold.value(key), format!("{:#?}", val).replace('\n', "\n ") )?; Ok(()) } } let mut visitor = Visitor { buf }; record.key_values().visit(&mut visitor).unwrap(); } Ok(()) }) .parse_filters( env.iter() .find_map(|e| std::env::var(e).ok()) .as_deref() .unwrap_or(default_filter), ) .init(); }