Jelajahi Sumber

Merge pull request #20 from creekorful/builder-pattern

Implement builder pattern
Sam Clements 4 tahun lalu
induk
melakukan
e2c6040f9b

+ 1 - 1
Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "simple_logger"
-version = "1.7.0"
+version = "1.8.0"
 license = "MIT"
 authors = ["Sam Clements <sam@borntyping.co.uk>"]
 description = "A logger that prints all messages with a readable output format"

+ 1 - 1
README.md

@@ -13,7 +13,7 @@ Usage
 
 ```rust
 fn main() {
-    simple_logger::init().unwrap();
+    SimpleLogger::new().init().unwrap();
 
     log::warn!("This is an example message.");
 }

+ 3 - 1
examples/init.rs

@@ -1,5 +1,7 @@
+use simple_logger::SimpleLogger;
+
 fn main() {
-    simple_logger::init().unwrap();
+    SimpleLogger::new().init().unwrap();
 
     log::warn!("This is an example message.");
 }

+ 6 - 2
examples/init_with_level.rs

@@ -1,7 +1,11 @@
-use log::Level;
+use log::LevelFilter;
+use simple_logger::SimpleLogger;
 
 fn main() {
-    simple_logger::init_with_level(Level::Warn).unwrap();
+    SimpleLogger::new()
+        .with_level(LevelFilter::Warn)
+        .init()
+        .unwrap();
 
     log::warn!("This will be logged.");
     log::info!("This will NOT be logged.");

+ 0 - 7
examples/init_with_level_and_targets.rs

@@ -1,7 +0,0 @@
-use log::Level;
-
-fn main() {
-    simple_logger::init_with_level_and_targets(Level::Info, &["wrong_target"]).unwrap();
-
-    log::info!("This will NOT be logged. (Wrong target)");
-}

+ 12 - 0
examples/init_with_target_level.rs

@@ -0,0 +1,12 @@
+use log::LevelFilter;
+use simple_logger::SimpleLogger;
+
+fn main() {
+    SimpleLogger::new()
+        .with_level(LevelFilter::Info)
+        .with_module_level("init_with_target_level", LevelFilter::Off)
+        .init()
+        .unwrap();
+
+    log::info!("This will NOT be logged. (Target disabled)");
+}

+ 128 - 77
src/lib.rs

@@ -4,23 +4,128 @@
 use chrono::Local;
 #[cfg(feature = "colored")]
 use colored::*;
-use log::{Level, Log, Metadata, Record, SetLoggerError};
+use log::{Level, LevelFilter, Log, Metadata, Record, SetLoggerError};
+use std::collections::HashMap;
+
+pub struct SimpleLogger {
+    /// The default logging level
+    default_level: LevelFilter,
+    /// The specific logging level for each modules
+    module_levels: HashMap<String, LevelFilter>,
+}
+
+impl SimpleLogger {
+    /// Initializes the global logger with a SimpleLogger instance with
+    /// default log level set to `Level::Trace`.
+    ///
+    /// ```no_run
+    /// use simple_logger::SimpleLogger;
+    /// SimpleLogger::new();
+    /// log::warn!("This is an example message.");
+    /// ```
+    pub fn new() -> SimpleLogger {
+        SimpleLogger {
+            default_level: LevelFilter::Trace,
+            module_levels: HashMap::new(),
+        }
+    }
+
+    /// A macro for simulating env_logger behavior, which enables the user to choose log level by
+    /// setting a `RUST_LOG` environment variable. The `RUST_LOG` is not set or its value is not
+    /// recognized as one of the log levels, this function with use the `Error` level by default.
+    ///
+    /// ```no_run
+    /// use simple_logger::SimpleLogger;
+    /// SimpleLogger::from_env();
+    /// log::warn!("This is an example message.");
+    /// ```
+    pub fn from_env() -> SimpleLogger {
+        let level = match std::env::var("RUST_LOG") {
+            Ok(x) => match x.to_lowercase().as_str() {
+                "trace" => log::LevelFilter::Trace,
+                "debug" => log::LevelFilter::Debug,
+                "info" => log::LevelFilter::Info,
+                "warn" => log::LevelFilter::Warn,
+                _ => log::LevelFilter::Error,
+            },
+            _ => log::LevelFilter::Error,
+        };
+
+        SimpleLogger::new().with_level(level)
+    }
+
+    /// Set the 'default' log level.
+    pub fn with_level(mut self, level: LevelFilter) -> SimpleLogger {
+        self.default_level = level;
+        self
+    }
+
+    /// Override the log level for specific module.
+    ///
+    /// # Examples
+    ///
+    /// Change log level for specific crate:
+    ///
+    /// ```no_run
+    /// use simple_logger::SimpleLogger;
+    /// use log::LevelFilter;
+    ///
+    /// SimpleLogger::new().with_module_level("something", LevelFilter::Warn).init();
+    /// ```
+    ///
+    /// Disable logging for specific crate:
+    ///
+    /// ```no_run
+    /// use simple_logger::SimpleLogger;
+    /// use log::LevelFilter;
+    ///
+    /// SimpleLogger::new().with_module_level("something", LevelFilter::Off).init();
+    /// ```
+    pub fn with_module_level(mut self, target: &str, level: LevelFilter) -> SimpleLogger {
+        self.module_levels.insert(target.to_string(), level);
+        self
+    }
 
-struct SimpleLogger {
-    level: Level,
-    /// List of whitelisted log targets
-    /// if empty everything will be logged
-    whitelisted_targets: Vec<String>,
+    /// Override the log level for specific targets.
+    pub fn with_target_levels(
+        mut self,
+        target_levels: HashMap<String, LevelFilter>,
+    ) -> SimpleLogger {
+        self.module_levels = target_levels;
+        self
+    }
+
+    /// 'Init' the actual logger, instantiate it and configure it,
+    /// this method MUST be called in order for the logger to be effective.
+    pub fn init(self) -> Result<(), SetLoggerError> {
+        #[cfg(all(windows, feature = "colored"))]
+        set_up_color_terminal();
+
+        let max_level = self.module_levels.values().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 {
+    /// See [this](struct.SimpleLogger.html#method.new)
+    fn default() -> Self {
+        SimpleLogger::new()
+    }
 }
 
 impl Log for SimpleLogger {
     fn enabled(&self, metadata: &Metadata) -> bool {
-        metadata.level() <= self.level
-            && (self.whitelisted_targets.is_empty()
-                || self
-                    .whitelisted_targets
-                    .iter()
-                    .any(|t| t == metadata.target()))
+        metadata.level().to_level_filter()
+            <= self
+                .module_levels
+                .get(metadata.target())
+                .copied()
+                .unwrap_or_else(|| self.default_level)
     }
 
     fn log(&self, record: &Record) {
@@ -95,76 +200,22 @@ fn set_up_color_terminal() {
     }
 }
 
-/// Initializes the global logger with a SimpleLogger instance with
-/// `max_log_level` set to a specific log level.
-///
-/// ```
-/// simple_logger::init_with_level(log::Level::Warn).unwrap();
-///
-/// log::warn!("This is an example message.");
-/// log::info!("This message will not be logged.");
-/// ```
+/// See [this](struct.SimpleLogger.html#method.with_level)
+#[deprecated(since = "1.8.0", note = "Please use the Builder pattern instead.")]
 pub fn init_with_level(level: Level) -> Result<(), SetLoggerError> {
-    #[cfg(all(windows, feature = "colored"))]
-    set_up_color_terminal();
-
-    let logger = SimpleLogger {
-        level,
-        whitelisted_targets: vec![],
-    };
-    log::set_boxed_logger(Box::new(logger))?;
-    log::set_max_level(level.to_level_filter());
-    Ok(())
-}
-
-/// Initializes the global logger with a SimpleLogger instance with
-/// `max_log_level` set to a specific log level as well as specific log targets.
-///
-/// ```
-/// simple_logger::init_with_level_and_targets(log::Level::Info, &["wrong_target"]).unwrap();
-///
-/// log::info!("This will NOT be logged. (Wrong target)");
-/// ```
-pub fn init_with_level_and_targets(level: Level, targets: &[&str]) -> Result<(), SetLoggerError> {
-    #[cfg(all(windows, feature = "colored"))]
-    set_up_color_terminal();
-
-    let logger = SimpleLogger {
-        level,
-        whitelisted_targets: targets.iter().map(|s| s.to_string()).collect(),
-    };
-    log::set_boxed_logger(Box::new(logger))?;
-    log::set_max_level(level.to_level_filter());
-    Ok(())
+    SimpleLogger::new()
+        .with_level(level.to_level_filter())
+        .init()
 }
 
-/// Initializes the global logger with a SimpleLogger instance with
-/// `max_log_level` set to `LogLevel::Trace`.
-///
-/// ```
-/// simple_logger::init().unwrap();
-/// log::warn!("This is an example message.");
-/// ```
+/// See [this](struct.SimpleLogger.html#method.new)
+#[deprecated(since = "1.8.0", note = "Please use the Builder pattern instead.")]
 pub fn init() -> Result<(), SetLoggerError> {
-    init_with_level(Level::Trace)
+    SimpleLogger::new().init()
 }
 
-/// A macro for simulating env_logger behavior, which enables the user to choose log level by
-/// setting a `RUST_LOG` environment variable. The `RUST_LOG` is not set or its value is not
-/// recognized as one of the log levels, this function with use the `Error` level by default.
-/// ```
-/// simple_logger::init_by_env();
-/// log::warn!("This is an example message.");
-/// ```
+/// See [this](struct.SimpleLogger.html#method.from_env)
+#[deprecated(since = "1.8.0", note = "Please use the Builder pattern instead.")]
 pub fn init_by_env() {
-    match std::env::var("RUST_LOG") {
-        Ok(x) => match x.to_lowercase().as_str() {
-            "trace" => init_with_level(log::Level::Trace).unwrap(),
-            "debug" => init_with_level(log::Level::Debug).unwrap(),
-            "info" => init_with_level(log::Level::Info).unwrap(),
-            "warn" => init_with_level(log::Level::Warn).unwrap(),
-            _ => init_with_level(log::Level::Error).unwrap(),
-        },
-        _ => init_with_level(log::Level::Error).unwrap(),
-    }
+    SimpleLogger::from_env().init().unwrap()
 }