diff --git a/CHANGELOG.md b/CHANGELOG.md index 11cfaea37..87a98937e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ ## [Unreleased] +## [0.4.27] - 2025-03-24 + +## What's Changed +* A few minor lint fixes by @nyurik in https://github.com/rust-lang/log/pull/671 +* Enable clippy support for format-like macros by @nyurik in https://github.com/rust-lang/log/pull/665 +* Add an optional logger param by @tisonkun in https://github.com/rust-lang/log/pull/664 +* Pass global logger by value, supplied logger by ref by @KodrAus in https://github.com/rust-lang/log/pull/673 + + +**Full Changelog**: https://github.com/rust-lang/log/compare/0.4.26...0.4.27 + ## [0.4.26] - 2025-02-18 ## What's Changed @@ -347,7 +358,8 @@ version using log 0.4.x to avoid losing module and file information. Look at the [release tags] for information about older releases. -[Unreleased]: https://github.com/rust-lang-nursery/log/compare/0.4.26...HEAD +[Unreleased]: https://github.com/rust-lang-nursery/log/compare/0.4.27...HEAD +[0.4.27]: https://github.com/rust-lang/log/compare/0.4.26...0.4.27 [0.4.26]: https://github.com/rust-lang/log/compare/0.4.25...0.4.26 [0.4.25]: https://github.com/rust-lang/log/compare/0.4.24...0.4.25 [0.4.24]: https://github.com/rust-lang/log/compare/0.4.23...0.4.24 diff --git a/Cargo.toml b/Cargo.toml index 0c8b53763..00d3a7ce3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "log" -version = "0.4.26" # remember to update html_root_url +version = "0.4.27" # remember to update html_root_url authors = ["The Rust Project Developers"] license = "MIT OR Apache-2.0" readme = "README.md" diff --git a/src/__private_api.rs b/src/__private_api.rs index 11bc2fc1c..58d4c0fab 100644 --- a/src/__private_api.rs +++ b/src/__private_api.rs @@ -1,7 +1,7 @@ //! WARNING: this is not part of the crate's public API and is subject to change at any time use self::sealed::KVs; -use crate::{Level, Metadata, Record}; +use crate::{logger, Level, Log, Metadata, Record}; use std::fmt::Arguments; use std::panic::Location; pub use std::{format_args, module_path, stringify}; @@ -34,7 +34,27 @@ impl<'a> KVs<'a> for () { // Log implementation. -fn log_impl( +/// The global logger proxy. +#[derive(Debug)] +pub struct GlobalLogger; + +impl Log for GlobalLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + logger().enabled(metadata) + } + + fn log(&self, record: &Record) { + logger().log(record) + } + + fn flush(&self) { + logger().flush() + } +} + +// Split from `log` to reduce generics and code size +fn log_impl( + logger: L, args: Arguments, level: Level, &(target, module_path, loc): &(&str, &'static str, &'static Location), @@ -58,22 +78,30 @@ fn log_impl( #[cfg(feature = "kv")] builder.key_values(&kvs); - crate::logger().log(&builder.build()); + logger.log(&builder.build()); } -pub fn log<'a, K>( +pub fn log<'a, K, L>( + logger: L, args: Arguments, level: Level, target_module_path_and_loc: &(&str, &'static str, &'static Location), kvs: K, ) where K: KVs<'a>, + L: Log, { - log_impl(args, level, target_module_path_and_loc, kvs.into_kvs()) + log_impl( + logger, + args, + level, + target_module_path_and_loc, + kvs.into_kvs(), + ) } -pub fn enabled(level: Level, target: &str) -> bool { - crate::logger().enabled(&Metadata::builder().level(level).target(target).build()) +pub fn enabled(logger: L, level: Level, target: &str) -> bool { + logger.enabled(&Metadata::builder().level(level).target(target).build()) } #[track_caller] diff --git a/src/lib.rs b/src/lib.rs index 843893d01..eb37f55cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -292,7 +292,7 @@ //! configured in your `Cargo.toml`. //! //! * `std` allows use of `std` crate instead of the default `core`. Enables using `std::error` and -//! `set_boxed_logger` functionality. +//! `set_boxed_logger` functionality. //! * `serde` enables support for serialization and deserialization of `Level` and `LevelFilter`. //! //! ```toml @@ -344,7 +344,7 @@ #![doc( html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", - html_root_url = "https://docs.rs/log/0.4.26" + html_root_url = "https://docs.rs/log/0.4.27" )] #![warn(missing_docs)] #![deny(missing_debug_implementations, unconditional_recursion)] @@ -1035,7 +1035,7 @@ impl<'a> RecordBuilder<'a> { } } -impl<'a> Default for RecordBuilder<'a> { +impl Default for RecordBuilder<'_> { fn default() -> Self { Self::new() } @@ -1164,7 +1164,7 @@ impl<'a> MetadataBuilder<'a> { } } -impl<'a> Default for MetadataBuilder<'a> { +impl Default for MetadataBuilder<'_> { fn default() -> Self { Self::new() } @@ -1204,7 +1204,7 @@ pub trait Log: Sync + Send { fn flush(&self); } -// Just used as a dummy initial value for LOGGER +/// A dummy initial value for LOGGER. struct NopLogger; impl Log for NopLogger { diff --git a/src/macros.rs b/src/macros.rs index 87693f2b1..14e4ac64b 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -13,40 +13,130 @@ /// This macro will generically log with the specified `Level` and `format!` /// based argument list. /// -/// # Examples -/// /// ``` /// use log::{log, Level}; /// -/// # fn main() { /// let data = (42, "Forty-two"); /// let private_data = "private"; /// /// log!(Level::Error, "Received errors: {}, {}", data.0, data.1); -/// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}", -/// data.0, data.1, private_data); +/// ``` +/// +/// Optionally, you can specify a `target` argument to attach a specific target +/// to the log record. By default, the target is the module path of the caller. +/// +/// ``` +/// use log::{log, Level}; +/// +/// let data = (42, "Forty-two"); +/// let private_data = "private"; +/// +/// log!( +/// target: "app_events", +/// Level::Error, +/// "Received errors: {}, {}", +/// data.0, data.1 +/// ); +/// ``` +/// +/// And optionally, you can specify a `logger` argument to use a specific logger +/// instead of the default global logger. +/// +/// ``` +/// # struct MyLogger {} +/// # impl Log for MyLogger { +/// # fn enabled(&self, _metadata: &log::Metadata) -> bool { +/// # false +/// # } +/// # fn log(&self, _record: &log::Record) {} +/// # fn flush(&self) {} /// # } +/// use log::{log, Level, Log}; +/// +/// let data = (42, "Forty-two"); +/// let private_data = "private"; +/// +/// let my_logger = MyLogger {}; +/// log!( +/// logger: my_logger, +/// Level::Error, +/// "Received errors: {}, {}", +/// data.0, data.1 +/// ); /// ``` +/// +/// The `logger` argument accepts a value that implements the `Log` trait. The value +/// will be borrowed within the macro. +/// +/// Note that the global level set via Cargo features, or through `set_max_level` will +/// still apply, even when a custom logger is supplied with the `logger` argument. #[macro_export] +#[clippy::format_args] macro_rules! log { - // log!(target: "my_target", Level::Info, key1:? = 42, key2 = true; "a {} event", "log"); - (target: $target:expr, $lvl:expr, $($key:tt $(:$capture:tt)? $(= $value:expr)?),+; $($arg:tt)+) => ({ + // log!(logger: my_logger, target: "my_target", Level::Info, "a {} event", "log"); + (logger: $logger:expr, target: $target:expr, $lvl:expr, $($arg:tt)+) => ({ + $crate::__log!( + logger: $crate::__log_logger!($logger), + target: $target, + $lvl, + $($arg)+ + ) + }); + + // log!(logger: my_logger, Level::Info, "a log event") + (logger: $logger:expr, $lvl:expr, $($arg:tt)+) => ({ + $crate::__log!( + logger: $crate::__log_logger!($logger), + target: $crate::__private_api::module_path!(), + $lvl, + $($arg)+ + ) + }); + + // log!(target: "my_target", Level::Info, "a log event") + (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({ + $crate::__log!( + logger: $crate::__log_logger!(__log_global_logger), + target: $target, + $lvl, + $($arg)+ + ) + }); + + // log!(Level::Info, "a log event") + ($lvl:expr, $($arg:tt)+) => ({ + $crate::__log!( + logger: $crate::__log_logger!(__log_global_logger), + target: $crate::__private_api::module_path!(), + $lvl, + $($arg)+ + ) + }); +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __log { + // log!(logger: my_logger, target: "my_target", Level::Info, key1:? = 42, key2 = true; "a {} event", "log"); + (logger: $logger:expr, target: $target:expr, $lvl:expr, $($key:tt $(:$capture:tt)? $(= $value:expr)?),+; $($arg:tt)+) => ({ let lvl = $lvl; if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() { - $crate::__private_api::log::<&_>( + $crate::__private_api::log( + $logger, $crate::__private_api::format_args!($($arg)+), lvl, &($target, $crate::__private_api::module_path!(), $crate::__private_api::loc()), - &[$(($crate::__log_key!($key), $crate::__log_value!($key $(:$capture)* = $($value)*))),+] + &[$(($crate::__log_key!($key), $crate::__log_value!($key $(:$capture)* = $($value)*))),+] as &[_], ); } }); - // log!(target: "my_target", Level::Info, "a {} event", "log"); - (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({ + // log!(logger: my_logger, target: "my_target", Level::Info, "a {} event", "log"); + (logger: $logger:expr, target: $target:expr, $lvl:expr, $($arg:tt)+) => ({ let lvl = $lvl; if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() { $crate::__private_api::log( + $logger, $crate::__private_api::format_args!($($arg)+), lvl, &($target, $crate::__private_api::module_path!(), $crate::__private_api::loc()), @@ -54,9 +144,6 @@ macro_rules! log { ); } }); - - // log!(Level::Info, "a log event") - ($lvl:expr, $($arg:tt)+) => ($crate::log!(target: $crate::__private_api::module_path!(), $lvl, $($arg)+)); } /// Logs a message at the error level. @@ -66,18 +153,33 @@ macro_rules! log { /// ``` /// use log::error; /// -/// # fn main() { +/// # let my_logger = log::__private_api::GlobalLogger; /// let (err_info, port) = ("No connection", 22); /// /// error!("Error: {err_info} on port {port}"); /// error!(target: "app_events", "App Error: {err_info}, Port: {port}"); -/// # } +/// error!(logger: my_logger, "App Error: {err_info}, Port: {port}"); /// ``` #[macro_export] +#[clippy::format_args] macro_rules! error { + // error!(logger: my_logger, target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // error!(logger: my_logger, target: "my_target", "a {} event", "log") + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), target: $target, $crate::Level::Error, $($arg)+) + }); + + // error!(logger: my_logger, key1 = 42, key2 = true; "a {} event", "log") + // error!(logger: my_logger, "a {} event", "log") + (logger: $logger:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), $crate::Level::Error, $($arg)+) + }); + // error!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") // error!(target: "my_target", "a {} event", "log") - (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Error, $($arg)+)); + (target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(target: $target, $crate::Level::Error, $($arg)+) + }); // error!("a {} event", "log") ($($arg:tt)+) => ($crate::log!($crate::Level::Error, $($arg)+)) @@ -90,18 +192,33 @@ macro_rules! error { /// ``` /// use log::warn; /// -/// # fn main() { +/// # let my_logger = log::__private_api::GlobalLogger; /// let warn_description = "Invalid Input"; /// /// warn!("Warning! {warn_description}!"); /// warn!(target: "input_events", "App received warning: {warn_description}"); -/// # } +/// warn!(logger: my_logger, "App received warning: {warn_description}"); /// ``` #[macro_export] +#[clippy::format_args] macro_rules! warn { + // warn!(logger: my_logger, target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // warn!(logger: my_logger, target: "my_target", "a {} event", "log") + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), target: $target, $crate::Level::Warn, $($arg)+) + }); + + // warn!(logger: my_logger, key1 = 42, key2 = true; "a {} event", "log") + // warn!(logger: my_logger, "a {} event", "log") + (logger: $logger:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), $crate::Level::Warn, $($arg)+) + }); + // warn!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") // warn!(target: "my_target", "a {} event", "log") - (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Warn, $($arg)+)); + (target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(target: $target, $crate::Level::Warn, $($arg)+) + }); // warn!("a {} event", "log") ($($arg:tt)+) => ($crate::log!($crate::Level::Warn, $($arg)+)) @@ -114,20 +231,42 @@ macro_rules! warn { /// ``` /// use log::info; /// -/// # fn main() { +/// # let my_logger = log::__private_api::GlobalLogger; /// # struct Connection { port: u32, speed: f32 } /// let conn_info = Connection { port: 40, speed: 3.20 }; /// /// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed); -/// info!(target: "connection_events", "Successful connection, port: {}, speed: {}", -/// conn_info.port, conn_info.speed); -/// # } +/// info!( +/// target: "connection_events", +/// "Successful connection, port: {}, speed: {}", +/// conn_info.port, conn_info.speed +/// ); +/// info!( +/// logger: my_logger, +/// "Successful connection, port: {}, speed: {}", +/// conn_info.port, conn_info.speed +/// ); /// ``` #[macro_export] +#[clippy::format_args] macro_rules! info { + // info!(logger: my_logger, target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // info!(logger: my_logger, target: "my_target", "a {} event", "log") + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), target: $target, $crate::Level::Info, $($arg)+) + }); + + // info!(logger: my_logger, key1 = 42, key2 = true; "a {} event", "log") + // info!(logger: my_logger, "a {} event", "log") + (logger: $logger:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), $crate::Level::Info, $($arg)+) + }); + // info!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") // info!(target: "my_target", "a {} event", "log") - (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Info, $($arg)+)); + (target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(target: $target, $crate::Level::Info, $($arg)+) + }); // info!("a {} event", "log") ($($arg:tt)+) => ($crate::log!($crate::Level::Info, $($arg)+)) @@ -140,19 +279,34 @@ macro_rules! info { /// ``` /// use log::debug; /// -/// # fn main() { +/// # let my_logger = log::__private_api::GlobalLogger; /// # struct Position { x: f32, y: f32 } /// let pos = Position { x: 3.234, y: -1.223 }; /// /// debug!("New position: x: {}, y: {}", pos.x, pos.y); /// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y); -/// # } +/// debug!(logger: my_logger, "New position: x: {}, y: {}", pos.x, pos.y); /// ``` #[macro_export] +#[clippy::format_args] macro_rules! debug { + // debug!(logger: my_logger, target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // debug!(logger: my_logger, target: "my_target", "a {} event", "log") + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), target: $target, $crate::Level::Debug, $($arg)+) + }); + + // debug!(logger: my_logger, key1 = 42, key2 = true; "a {} event", "log") + // debug!(logger: my_logger, "a {} event", "log") + (logger: $logger:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), $crate::Level::Debug, $($arg)+) + }); + // debug!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") // debug!(target: "my_target", "a {} event", "log") - (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Debug, $($arg)+)); + (target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(target: $target, $crate::Level::Debug, $($arg)+) + }); // debug!("a {} event", "log") ($($arg:tt)+) => ($crate::log!($crate::Level::Debug, $($arg)+)) @@ -165,7 +319,7 @@ macro_rules! debug { /// ``` /// use log::trace; /// -/// # fn main() { +/// # let my_logger = log::__private_api::GlobalLogger; /// # struct Position { x: f32, y: f32 } /// let pos = Position { x: 3.234, y: -1.223 }; /// @@ -173,13 +327,30 @@ macro_rules! debug { /// trace!(target: "app_events", "x is {} and y is {}", /// if pos.x >= 0.0 { "positive" } else { "negative" }, /// if pos.y >= 0.0 { "positive" } else { "negative" }); -/// # } +/// trace!(logger: my_logger, "x is {} and y is {}", +/// if pos.x >= 0.0 { "positive" } else { "negative" }, +/// if pos.y >= 0.0 { "positive" } else { "negative" }); /// ``` #[macro_export] +#[clippy::format_args] macro_rules! trace { + // trace!(logger: my_logger, target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // trace!(logger: my_logger, target: "my_target", "a {} event", "log") + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), target: $target, $crate::Level::Trace, $($arg)+) + }); + + // trace!(logger: my_logger, key1 = 42, key2 = true; "a {} event", "log") + // trace!(logger: my_logger, "a {} event", "log") + (logger: $logger:expr, $($arg:tt)+) => ({ + $crate::log!(logger: $crate::__log_logger!($logger), $crate::Level::Trace, $($arg)+) + }); + // trace!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") // trace!(target: "my_target", "a {} event", "log") - (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Trace, $($arg)+)); + (target: $target:expr, $($arg:tt)+) => ({ + $crate::log!(target: $target, $crate::Level::Trace, $($arg)+) + }); // trace!("a {} event", "log") ($($arg:tt)+) => ($crate::log!($crate::Level::Trace, $($arg)+)) @@ -194,34 +365,75 @@ macro_rules! trace { /// # Examples /// /// ``` -/// use log::Level::Debug; -/// use log::{debug, log_enabled}; +/// use log::{debug, log_enabled, Level}; /// -/// # fn foo() { -/// if log_enabled!(Debug) { +/// # struct Data { x: u32, y: u32 } +/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } } +/// # let my_logger = log::__private_api::GlobalLogger; +/// if log_enabled!(Level::Debug) { /// let data = expensive_call(); /// debug!("expensive debug data: {} {}", data.x, data.y); /// } -/// if log_enabled!(target: "Global", Debug) { +/// +/// if log_enabled!(target: "Global", Level::Debug) { +/// let data = expensive_call(); +/// debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y); +/// } +/// +/// if log_enabled!(logger: my_logger, Level::Debug) { /// let data = expensive_call(); /// debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y); /// } -/// # } -/// # struct Data { x: u32, y: u32 } -/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } } -/// # fn main() {} /// ``` +/// +/// This macro accepts the same `target` and `logger` arguments as [`macro@log`]. #[macro_export] macro_rules! log_enabled { - (target: $target:expr, $lvl:expr) => {{ + // log_enabled!(logger: my_logger, target: "my_target", Level::Info) + (logger: $logger:expr, target: $target:expr, $lvl:expr) => ({ + $crate::__log_enabled!(logger: $crate::__log_logger!($logger), target: $target, $lvl) + }); + + // log_enabled!(logger: my_logger, Level::Info) + (logger: $logger:expr, $lvl:expr) => ({ + $crate::__log_enabled!(logger: $crate::__log_logger!($logger), target: $crate::__private_api::module_path!(), $lvl) + }); + + // log_enabled!(target: "my_target", Level::Info) + (target: $target:expr, $lvl:expr) => ({ + $crate::__log_enabled!(logger: $crate::__log_logger!(__log_global_logger), target: $target, $lvl) + }); + + // log_enabled!(Level::Info) + ($lvl:expr) => ({ + $crate::__log_enabled!(logger: $crate::__log_logger!(__log_global_logger), target: $crate::__private_api::module_path!(), $lvl) + }); +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __log_enabled { + // log_enabled!(logger: my_logger, target: "my_target", Level::Info) + (logger: $logger:expr, target: $target:expr, $lvl:expr) => {{ let lvl = $lvl; lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() - && $crate::__private_api::enabled(lvl, $target) + && $crate::__private_api::enabled($logger, lvl, $target) + }}; +} + +// Determine the logger to use, and whether to take it by-value or by reference + +#[doc(hidden)] +#[macro_export] +macro_rules! __log_logger { + (__log_global_logger) => {{ + $crate::__private_api::GlobalLogger + }}; + + ($logger:expr) => {{ + &($logger) }}; - ($lvl:expr) => { - $crate::log_enabled!(target: $crate::__private_api::module_path!(), $lvl) - }; } // These macros use a pattern of #[cfg]s to produce nicer error diff --git a/tests/integration.rs b/tests/integration.rs index 7bf456e02..0b8522d71 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -3,14 +3,6 @@ use log::{debug, error, info, trace, warn, Level, LevelFilter, Log, Metadata, Record}; use std::sync::{Arc, Mutex}; -#[cfg(feature = "std")] -use log::set_boxed_logger; - -#[cfg(not(feature = "std"))] -fn set_boxed_logger(logger: Box) -> Result<(), log::SetLoggerError> { - log::set_logger(Box::leak(logger)) -} - struct State { last_log_level: Mutex>, last_log_location: Mutex>, @@ -53,31 +45,31 @@ fn main() { last_log_location: Mutex::new(None), }); let a = me.clone(); - set_boxed_logger(Box::new(Logger(me))).unwrap(); + let logger = Logger(me); - test_filter(&a, LevelFilter::Off); - test_filter(&a, LevelFilter::Error); - test_filter(&a, LevelFilter::Warn); - test_filter(&a, LevelFilter::Info); - test_filter(&a, LevelFilter::Debug); - test_filter(&a, LevelFilter::Trace); + test_filter(&logger, &a, LevelFilter::Off); + test_filter(&logger, &a, LevelFilter::Error); + test_filter(&logger, &a, LevelFilter::Warn); + test_filter(&logger, &a, LevelFilter::Info); + test_filter(&logger, &a, LevelFilter::Debug); + test_filter(&logger, &a, LevelFilter::Trace); - test_line_numbers(&a); + test_line_numbers(&logger, &a); } } -fn test_filter(a: &State, filter: LevelFilter) { +fn test_filter(logger: &dyn Log, a: &State, filter: LevelFilter) { // tests to ensure logs with a level beneath 'max_level' are filtered out log::set_max_level(filter); - error!(""); + error!(logger: logger, ""); last(a, t(Level::Error, filter)); - warn!(""); + warn!(logger: logger, ""); last(a, t(Level::Warn, filter)); - info!(""); + info!(logger: logger, ""); last(a, t(Level::Info, filter)); - debug!(""); + debug!(logger: logger, ""); last(a, t(Level::Debug, filter)); - trace!(""); + trace!(logger: logger, ""); last(a, t(Level::Trace, filter)); fn t(lvl: Level, filter: LevelFilter) -> Option { @@ -93,11 +85,11 @@ fn test_filter(a: &State, filter: LevelFilter) { } } -fn test_line_numbers(state: &State) { +fn test_line_numbers(logger: &dyn Log, state: &State) { log::set_max_level(LevelFilter::Trace); - info!(""); // ensure check_line function follows log macro - check_log_location(&state); + info!(logger: logger, ""); // ensure check_line function follows log macro + check_log_location(state); #[track_caller] fn check_log_location(state: &State) { diff --git a/tests/macros.rs b/tests/macros.rs index 20da6ac44..dded475c1 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -1,4 +1,4 @@ -use log::{log, log_enabled}; +use log::{log, log_enabled, Log, Metadata, Record}; macro_rules! all_log_macros { ($($arg:tt)*) => ({ @@ -10,8 +10,21 @@ macro_rules! all_log_macros { }); } +// Not `Copy` +struct Logger; + +impl Log for Logger { + fn enabled(&self, _: &Metadata) -> bool { + false + } + fn log(&self, _: &Record) {} + fn flush(&self) {} +} + #[test] fn no_args() { + let logger = Logger; + for lvl in log::Level::iter() { log!(lvl, "hello"); log!(lvl, "hello",); @@ -19,8 +32,11 @@ fn no_args() { log!(target: "my_target", lvl, "hello"); log!(target: "my_target", lvl, "hello",); - log!(lvl, "hello"); - log!(lvl, "hello",); + log!(logger: logger, lvl, "hello"); + log!(logger: logger, lvl, "hello",); + + log!(logger: logger, target: "my_target", lvl, "hello"); + log!(logger: logger, target: "my_target", lvl, "hello",); } all_log_macros!("hello"); @@ -28,6 +44,12 @@ fn no_args() { all_log_macros!(target: "my_target", "hello"); all_log_macros!(target: "my_target", "hello",); + + all_log_macros!(logger: logger, "hello"); + all_log_macros!(logger: logger, "hello",); + + all_log_macros!(logger: logger, target: "my_target", "hello"); + all_log_macros!(logger: logger, target: "my_target", "hello",); } #[test] @@ -48,6 +70,14 @@ fn anonymous_args() { all_log_macros!(target: "my_target", "hello {}", "world"); all_log_macros!(target: "my_target", "hello {}", "world",); + + let logger = Logger; + + all_log_macros!(logger: logger, "hello {}", "world"); + all_log_macros!(logger: logger, "hello {}", "world",); + + all_log_macros!(logger: logger, target: "my_target", "hello {}", "world"); + all_log_macros!(logger: logger, target: "my_target", "hello {}", "world",); } #[test] @@ -68,6 +98,14 @@ fn named_args() { all_log_macros!(target: "my_target", "hello {world}", world = "world"); all_log_macros!(target: "my_target", "hello {world}", world = "world",); + + let logger = Logger; + + all_log_macros!(logger: logger, "hello {world}", world = "world"); + all_log_macros!(logger: logger, "hello {world}", world = "world",); + + all_log_macros!(logger: logger, target: "my_target", "hello {world}", world = "world"); + all_log_macros!(logger: logger, target: "my_target", "hello {world}", world = "world",); } #[test] @@ -90,79 +128,136 @@ fn inlined_args() { all_log_macros!(target: "my_target", "hello {world}"); all_log_macros!(target: "my_target", "hello {world}",); + + let logger = Logger; + + all_log_macros!(logger: logger, "hello {world}"); + all_log_macros!(logger: logger, "hello {world}",); + + all_log_macros!(logger: logger, target: "my_target", "hello {world}"); + all_log_macros!(logger: logger, target: "my_target", "hello {world}",); } #[test] fn enabled() { + let logger = Logger; + for lvl in log::Level::iter() { + let _enabled = log_enabled!(lvl); let _enabled = log_enabled!(target: "my_target", lvl); + let _enabled = log_enabled!(logger: logger, target: "my_target", lvl); + let _enabled = log_enabled!(logger: logger, lvl); } } #[test] fn expr() { + let logger = Logger; + for lvl in log::Level::iter() { log!(lvl, "hello"); + + log!(logger: logger, lvl, "hello"); } } #[test] #[cfg(feature = "kv")] fn kv_no_args() { + let logger = Logger; + for lvl in log::Level::iter() { log!(target: "my_target", lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); - log!(lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); + + log!(logger: logger, target: "my_target", lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); + log!(logger: logger, lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); } all_log_macros!(target: "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); all_log_macros!(target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); all_log_macros!(cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); + + all_log_macros!(logger: logger, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); + all_log_macros!(logger: logger, target: "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello"); } #[test] #[cfg(feature = "kv")] fn kv_expr_args() { + let logger = Logger; + for lvl in log::Level::iter() { log!(target: "my_target", lvl, cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); log!(lvl, target = "my_target", cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); log!(lvl, cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + + log!(logger: logger, target: "my_target", lvl, cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + + log!(logger: logger, lvl, target = "my_target", cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + log!(logger: logger, lvl, cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); } all_log_macros!(target: "my_target", cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); all_log_macros!(target = "my_target", cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); all_log_macros!(cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + + all_log_macros!(logger: logger, target: "my_target", cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + all_log_macros!(logger: logger, target = "my_target", cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); + all_log_macros!(logger: logger, cat_math = { let mut x = 0; x += 1; x + 1 }; "hello"); } #[test] #[cfg(feature = "kv")] fn kv_anonymous_args() { + let logger = Logger; + for lvl in log::Level::iter() { log!(target: "my_target", lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); log!(lvl, target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); log!(lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + + log!(logger: logger, target: "my_target", lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + log!(logger: logger, lvl, target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + + log!(logger: logger, lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); } all_log_macros!(target: "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); all_log_macros!(target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); all_log_macros!(cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + + all_log_macros!(logger: logger, target: "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + all_log_macros!(logger: logger, target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); + all_log_macros!(logger: logger, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {}", "world"); } #[test] #[cfg(feature = "kv")] fn kv_named_args() { + let logger = Logger; + for lvl in log::Level::iter() { log!(target: "my_target", lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); log!(lvl, target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); log!(lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + + log!(logger: logger, target: "my_target", lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + log!(logger: logger, lvl, target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + + log!(logger: logger, lvl, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); } all_log_macros!(target: "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); all_log_macros!(target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); all_log_macros!(cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + + all_log_macros!(logger: logger, target: "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + all_log_macros!(logger: logger, target = "my_target", cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); + all_log_macros!(logger: logger, cat_1 = "chashu", cat_2 = "nori", cat_count = 2; "hello {world}", world = "world"); } #[test] @@ -306,6 +401,20 @@ fn kv_serde() { ); } +#[test] +fn logger_short_lived() { + all_log_macros!(logger: Logger, "hello"); + all_log_macros!(logger: &Logger, "hello"); +} + +#[test] +fn logger_expr() { + all_log_macros!(logger: { + let logger = Logger; + logger + }, "hello"); +} + /// Some and None (from Option) are used in the macros. #[derive(Debug)] enum Type { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy