123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- #[cfg(feature = "chrono")]
- use chrono::Local;
- #[cfg(feature = "colored")]
- use colored::*;
- use log::{Level, LevelFilter, Log, Metadata, Record, SetLoggerError};
- use std::collections::HashMap;
- pub struct SimpleLogger {
-
- default_level: LevelFilter,
-
-
-
-
-
- module_levels: Vec<(String, LevelFilter)>,
- }
- impl SimpleLogger {
-
-
-
-
-
-
-
-
-
-
-
-
-
- #[must_use = "You must call init() to begin logging"]
- pub fn new() -> SimpleLogger {
- SimpleLogger {
- default_level: LevelFilter::Off,
- module_levels: Vec::new(),
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #[must_use = "You must call init() to begin logging"]
- #[deprecated(
- since = "1.12.0",
- note = "Use [`env`](#method.env) instead. This predates use of the builder pattern in this library."
- )]
- pub fn from_env() -> SimpleLogger {
- SimpleLogger::new().with_level(log::LevelFilter::Error).env()
- }
-
-
-
-
-
-
- #[must_use = "You must call init() to begin logging"]
- pub fn env(mut self) -> SimpleLogger {
- let level = match std::env::var("RUST_LOG") {
- Ok(x) => match x.to_lowercase().as_str() {
- "trace" => self.default_level = log::LevelFilter::Trace,
- "debug" => self.default_level = log::LevelFilter::Debug,
- "info" => self.default_level = log::LevelFilter::Info,
- "warn" => self.default_level = log::LevelFilter::Warn,
- "error" => self.default_level = log::LevelFilter::Error,
- _ => (),
- },
- _ => (),
- };
- self
- }
-
-
-
-
-
- #[must_use = "You must call init() to begin logging"]
- pub fn with_level(mut self, level: LevelFilter) -> SimpleLogger {
- self.default_level = level;
- self
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #[must_use = "You must call init() to begin logging"]
- pub fn with_module_level(mut self, target: &str, level: LevelFilter) -> SimpleLogger {
- self.module_levels.push((target.to_string(), level));
-
- #[cfg(test)]
- self.module_levels
- .sort_by_key(|(name, _level)| name.len().wrapping_neg());
- self
- }
-
- #[must_use = "You must call init() to begin logging"]
- #[deprecated(
- since = "1.11.0",
- note = "This is a leftover from before there was the builder pattern. Use [`with_module_level`](#method.with_module_level) instead."
- )]
- pub fn with_target_levels(
- mut self,
- target_levels: HashMap<String, LevelFilter>,
- ) -> SimpleLogger {
- self.module_levels = target_levels.into_iter().collect();
-
- #[cfg(test)]
- self.module_levels
- .sort_by_key(|(name, _level)| name.len().wrapping_neg());
- self
- }
-
-
- pub fn init(mut self) -> Result<(), SetLoggerError> {
- #[cfg(all(windows, feature = "colored"))]
- set_up_color_terminal();
-
- self.module_levels
- .sort_by_key(|(name, _level)| name.len().wrapping_neg());
- let max_level = self
- .module_levels
- .iter()
- .map(|(_name, level)| level)
- .copied()
- .max();
- let max_level = max_level
- .map(|lvl| lvl.max(self.default_level))
- .unwrap_or(self.default_level);
- log::set_max_level(max_level);
- log::set_boxed_logger(Box::new(self))?;
- Ok(())
- }
- }
- impl Default for SimpleLogger {
-
- fn default() -> Self {
- SimpleLogger::new()
- }
- }
- impl Log for SimpleLogger {
- fn enabled(&self, metadata: &Metadata) -> bool {
- &metadata.level().to_level_filter()
- <= self
- .module_levels
- .iter()
-
- .find(|(name, _level)| metadata.target().starts_with(name))
- .map(|(_name, level)| level)
- .unwrap_or(&self.default_level)
- }
- fn log(&self, record: &Record) {
- if self.enabled(record.metadata()) {
- let level_string = {
- #[cfg(feature = "colored")]
- {
- match record.level() {
- Level::Error => record.level().to_string().red(),
- Level::Warn => record.level().to_string().yellow(),
- Level::Info => record.level().to_string().cyan(),
- Level::Debug => record.level().to_string().purple(),
- Level::Trace => record.level().to_string().normal(),
- }
- }
- #[cfg(not(feature = "colored"))]
- {
- record.level().to_string()
- }
- };
- let target = if !record.target().is_empty() {
- record.target()
- } else {
- record.module_path().unwrap_or_default()
- };
- #[cfg(feature = "chrono")]
- {
- println!(
- "{} {:<5} [{}] {}",
- Local::now().format("%Y-%m-%d %H:%M:%S,%3f"),
- level_string,
- target,
- record.args()
- );
- }
- #[cfg(not(feature = "chrono"))]
- {
- println!("{:<5} [{}] {}", level_string, target, record.args());
- }
- }
- }
- fn flush(&self) {}
- }
- #[cfg(windows)]
- fn set_up_color_terminal() {
- use atty::Stream;
- if atty::is(Stream::Stdout) {
- unsafe {
- use winapi::um::consoleapi::*;
- use winapi::um::handleapi::*;
- use winapi::um::processenv::*;
- use winapi::um::winbase::*;
- use winapi::um::wincon::*;
- let stdout = GetStdHandle(STD_OUTPUT_HANDLE);
- if stdout == INVALID_HANDLE_VALUE {
- return;
- }
- let mut mode: winapi::shared::minwindef::DWORD = 0;
- if GetConsoleMode(stdout, &mut mode) == 0 {
- return;
- }
- SetConsoleMode(stdout, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
- }
- }
- }
- pub fn init_with_level(level: Level) -> Result<(), SetLoggerError> {
- SimpleLogger::new()
- .with_level(level.to_level_filter())
- .init()
- }
- pub fn init() -> Result<(), SetLoggerError> {
- SimpleLogger::new().init()
- }
- pub fn init_by_env() {
- SimpleLogger::from_env().init().unwrap()
- }
- #[cfg(test)]
- mod test {
- use super::*;
- #[test]
- fn test_module_levels_allowlist() {
- let logger = SimpleLogger::new()
- .with_level(LevelFilter::Off)
- .with_module_level("my_crate", LevelFilter::Info);
- assert!(logger.enabled(&create_log("my_crate", Level::Info)));
- assert!(logger.enabled(&create_log("my_crate::module", Level::Info)));
- assert!(!logger.enabled(&create_log("my_crate::module", Level::Debug)));
- assert!(!logger.enabled(&create_log("not_my_crate", Level::Debug)));
- assert!(!logger.enabled(&create_log("not_my_crate::module", Level::Error)));
- }
- #[test]
- fn test_module_levels_denylist() {
- let logger = SimpleLogger::new()
- .with_level(LevelFilter::Debug)
- .with_module_level("my_crate", LevelFilter::Trace)
- .with_module_level("chatty_dependency", LevelFilter::Info);
- assert!(logger.enabled(&create_log("my_crate", Level::Info)));
- assert!(logger.enabled(&create_log("my_crate", Level::Trace)));
- assert!(logger.enabled(&create_log("my_crate::module", Level::Info)));
- assert!(logger.enabled(&create_log("my_crate::module", Level::Trace)));
- assert!(logger.enabled(&create_log("not_my_crate", Level::Debug)));
- assert!(!logger.enabled(&create_log("not_my_crate::module", Level::Trace)));
- assert!(logger.enabled(&create_log("chatty_dependency", Level::Info)));
- assert!(!logger.enabled(&create_log("chatty_dependency", Level::Debug)));
- assert!(!logger.enabled(&create_log("chatty_dependency::module", Level::Debug)));
- assert!(logger.enabled(&create_log("chatty_dependency::module", Level::Warn)));
- }
- fn create_log(name: &str, level: Level) -> Metadata {
- let mut builder = Metadata::builder();
- builder.level(level);
- builder.target(name);
- builder.build()
- }
- }
|