From 8a2e66f3a73b7e231cb8b59f5a39c41fe6f00e42 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Thu, 8 Oct 2015 08:53:50 -0700 Subject: [PATCH 1/2] Replace cfg(log_level) with Cargo features --- Cargo.toml | 15 +++++++++++++ src/lib.rs | 34 ++++++++++++++++++++++++++++ src/macros.rs | 62 +++++++++++++++++++++++++++++---------------------- 3 files changed, 84 insertions(+), 27 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3826840d4..25ab4ec50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,3 +18,18 @@ harness = false [dependencies] libc = "0.1" + +[features] +max_level_off = [] +max_level_error = [] +max_level_warn = [] +max_level_info = [] +max_level_debug = [] +max_level_trace = [] + +release_max_level_off = [] +release_max_level_error = [] +release_max_level_warn = [] +release_max_level_info = [] +release_max_level_debug = [] +release_max_level_trace = [] diff --git a/src/lib.rs b/src/lib.rs index f6059ab3c..01a4dc9f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -563,6 +563,40 @@ pub fn max_log_level() -> LogLevelFilter { unsafe { mem::transmute(MAX_LOG_LEVEL_FILTER.load(Ordering::Relaxed)) } } +#[inline(always)] +#[doc(hidden)] +pub fn __static_max_level() -> LogLevelFilter { + if !cfg!(debug_assertions) { + // This is a release build. Check `release_max_level_*` first. + if cfg!(feature = "release_max_level_off") { + return LogLevelFilter::Off + } else if cfg!(feature = "release_max_level_error") { + return LogLevelFilter::Error + } else if cfg!(feature = "release_max_level_warn") { + return LogLevelFilter::Warn + } else if cfg!(feature = "release_max_level_info") { + return LogLevelFilter::Info + } else if cfg!(feature = "release_max_level_debug") { + return LogLevelFilter::Debug + } else if cfg!(feature = "release_max_level_trace") { + return LogLevelFilter::Trace + } + } + if cfg!(feature = "max_level_off") { + LogLevelFilter::Off + } else if cfg!(feature = "max_level_error") { + LogLevelFilter::Error + } else if cfg!(feature = "max_level_warn") { + LogLevelFilter::Warn + } else if cfg!(feature = "max_level_info") { + LogLevelFilter::Info + } else if cfg!(feature = "max_level_debug") { + LogLevelFilter::Debug + } else { + LogLevelFilter::Trace + } +} + /// Sets the global logger. /// /// The `make_logger` closure is passed a `MaxLogLevel` object, which the diff --git a/src/macros.rs b/src/macros.rs index 3a1a487f0..7037f9ac0 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -12,8 +12,8 @@ /// This macro will generically log with the specified `LogLevel` and `format!` /// based argument list. /// -/// The `log_level` cfg can be used to statically disable logging at various -/// levels. +/// The `max_level_*` features can be used to statically disable logging at +/// various levels. #[macro_export] macro_rules! log { (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({ @@ -23,12 +23,7 @@ macro_rules! log { __module_path: module_path!(), }; let lvl = $lvl; - if !cfg!(log_level = "off") && - (lvl <= $crate::LogLevel::Error || !cfg!(log_level = "error")) && - (lvl <= $crate::LogLevel::Warn || !cfg!(log_level = "warn")) && - (lvl <= $crate::LogLevel::Debug || !cfg!(log_level = "debug")) && - (lvl <= $crate::LogLevel::Info || !cfg!(log_level = "info")) && - lvl <= $crate::max_log_level() { + if lvl <= $crate::__static_max_level() && lvl <= $crate::max_log_level() { $crate::__log(lvl, $target, &_LOC, format_args!($($arg)+)) } }); @@ -37,8 +32,7 @@ macro_rules! log { /// Logs a message at the error level. /// -/// Logging at this level is disabled if the `log_level = "off"` cfg is -/// present. +/// Logging at this level is disabled if the `max_level_off` feature is present. #[macro_export] macro_rules! error { (target: $target:expr, $($arg:tt)*) => ( @@ -51,8 +45,12 @@ macro_rules! error { /// Logs a message at the warn level. /// -/// Logging at this level is disabled if any of the following cfgs are present: -/// `log_level = "off"` or `log_level = "error"`. +/// Logging at this level is disabled if any of the following features are +/// present: `max_level_off` or `max_level_error`. +/// +/// When building in release mode (i.e., without the `debug_assertions` option), +/// logging at this level is also disabled if any of the following features are +/// present: `release_max_level_off` or `max_level_error`. #[macro_export] macro_rules! warn { (target: $target:expr, $($arg:tt)*) => ( @@ -65,9 +63,13 @@ macro_rules! warn { /// Logs a message at the info level. /// -/// Logging at this level is disabled if any of the following cfgs are present: -/// `log_level = "off"`, `log_level = "error"`, or -/// `log_level = "warn"`. +/// Logging at this level is disabled if any of the following features are +/// present: `max_level_off`, `max_level_error`, or `max_level_warn`. +/// +/// When building in release mode (i.e., without the `debug_assertions` option), +/// logging at this level is also disabled if any of the following features are +/// present: `release_max_level_off`, `release_max_level_error`, or +/// `release_max_level_warn`. #[macro_export] macro_rules! info { (target: $target:expr, $($arg:tt)*) => ( @@ -80,9 +82,14 @@ macro_rules! info { /// Logs a message at the debug level. /// -/// Logging at this level is disabled if any of the following cfgs are present: -/// `log_level = "off"`, `log_level = "error"`, `log_level = "warn"`, -/// or `log_level = "info"`. +/// Logging at this level is disabled if any of the following features are +/// present: `max_level_off`, `max_level_error`, `max_level_warn`, or +/// `max_level_info`. +/// +/// When building in release mode (i.e., without the `debug_assertions` option), +/// logging at this level is also disabled if any of the following features are +/// present: `release_max_level_off`, `release_max_level_error`, +/// `release_max_level_warn`, or `release_max_level_info`. #[macro_export] macro_rules! debug { (target: $target:expr, $($arg:tt)*) => ( @@ -95,9 +102,15 @@ macro_rules! debug { /// Logs a message at the trace level. /// -/// Logging at this level is disabled if any of the following cfgs are present: -/// `log_level = "off"`, `log_level = "error"`, `log_level = "warn"`, -/// `log_level = "info"`, or `log_level = "debug"`. +/// Logging at this level is disabled if any of the following features are +/// present: `max_level_off`, `max_level_error`, `max_level_warn`, +/// `max_level_info`, or `max_level_debug`. +/// +/// When building in release mode (i.e., without the `debug_assertions` option), +/// logging at this level is also disabled if any of the following features are +/// present: `release_max_level_off`, `release_max_level_error`, +/// `release_max_level_warn`, `release_max_level_info`, or +/// `release_max_level_debug`. #[macro_export] macro_rules! trace { (target: $target:expr, $($arg:tt)*) => ( @@ -135,12 +148,7 @@ macro_rules! trace { macro_rules! log_enabled { (target: $target:expr, $lvl:expr) => ({ let lvl = $lvl; - !cfg!(log_level = "off") && - (lvl <= $crate::LogLevel::Error || !cfg!(log_level = "error")) && - (lvl <= $crate::LogLevel::Warn || !cfg!(log_level = "warn")) && - (lvl <= $crate::LogLevel::Debug || !cfg!(log_level = "debug")) && - (lvl <= $crate::LogLevel::Info || !cfg!(log_level = "info")) && - lvl <= $crate::max_log_level() && + lvl <= $crate::__static_max_level() && lvl <= $crate::max_log_level() && $crate::__enabled(lvl, $target) }); ($lvl:expr) => (log_enabled!(target: module_path!(), $lvl)) From 737f8ecbfab64171d5ebd7f65d1309f29df4d7b5 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 2 Oct 2015 12:11:46 -0700 Subject: [PATCH 2/2] Test the max_level features --- .travis.yml | 3 ++ tests/max_level_features/Cargo.toml | 11 +++++ tests/max_level_features/main.rs | 72 +++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 tests/max_level_features/Cargo.toml create mode 100644 tests/max_level_features/main.rs diff --git a/.travis.yml b/.travis.yml index a9ea05ef2..700e23b74 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,12 +2,15 @@ language: rust sudo: false rust: - 1.0.0 + - stable - beta - nightly script: - cargo build --verbose - cargo test --verbose - cargo test --verbose --manifest-path env/Cargo.toml + - cargo run --verbose --manifest-path tests/max_level_features/Cargo.toml + - cargo run --verbose --manifest-path tests/max_level_features/Cargo.toml --release - cargo doc --manifest-path env/Cargo.toml after_success: | [ $TRAVIS_BRANCH = master ] && diff --git a/tests/max_level_features/Cargo.toml b/tests/max_level_features/Cargo.toml new file mode 100644 index 000000000..819d2d5d6 --- /dev/null +++ b/tests/max_level_features/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "optimized" +version = "0.1.0" + +[[bin]] +name = "max_level_features" +path = "main.rs" + +[dependencies.log] +path = "../.." +features = ["max_level_debug", "release_max_level_info"] diff --git a/tests/max_level_features/main.rs b/tests/max_level_features/main.rs new file mode 100644 index 000000000..707bff6ae --- /dev/null +++ b/tests/max_level_features/main.rs @@ -0,0 +1,72 @@ +#[macro_use] extern crate log; + +use std::sync::{Arc, Mutex}; +use log::{LogLevel, set_logger, LogLevelFilter, Log, LogRecord, LogMetadata}; +use log::MaxLogLevelFilter; + +struct State { + last_log: Mutex>, + filter: MaxLogLevelFilter, +} + +struct Logger(Arc); + +impl Log for Logger { + fn enabled(&self, _: &LogMetadata) -> bool { + true + } + + fn log(&self, record: &LogRecord) { + *self.0.last_log.lock().unwrap() = Some(record.level()); + } +} + +fn main() { + let mut a = None; + set_logger(|max| { + let me = Arc::new(State { + last_log: Mutex::new(None), + filter: max, + }); + a = Some(me.clone()); + Box::new(Logger(me)) + }).unwrap(); + let a = a.unwrap(); + + test(&a, LogLevelFilter::Off); + test(&a, LogLevelFilter::Error); + test(&a, LogLevelFilter::Warn); + test(&a, LogLevelFilter::Info); + test(&a, LogLevelFilter::Debug); + test(&a, LogLevelFilter::Trace); +} + +fn test(a: &State, filter: LogLevelFilter) { + a.filter.set(filter); + error!(""); + last(&a, t(LogLevel::Error, filter)); + warn!(""); + last(&a, t(LogLevel::Warn, filter)); + info!(""); + last(&a, t(LogLevel::Info, filter)); + + debug!(""); + if cfg!(debug_assertions) { + last(&a, t(LogLevel::Debug, filter)); + } else { + last(&a, None); + } + + trace!(""); + last(&a, None); + + fn t(lvl: LogLevel, filter: LogLevelFilter) -> Option { + if lvl <= filter {Some(lvl)} else {None} + } +} + +fn last(state: &State, expected: Option) { + let mut lvl = state.last_log.lock().unwrap(); + assert_eq!(*lvl, expected); + *lvl = None; +}