diff --git a/README.md b/README.md index d456111..327fe82 100644 --- a/README.md +++ b/README.md @@ -41,19 +41,19 @@ use log_once::{info_once, warn_once}; pub fn shave_the_yak(yaks: &[Yak]) { for yak in yaks { - info!(target: "yak_events", "Commencing yak shaving for {:?}", yak); + info!(target: "yak_events", "Commencing yak shaving for {yak:?}"); loop { match find_a_razor() { Ok(razor) => { // This will only appear once in the logger output for each razor - info_once!("Razor located: {}", razor); + info_once!("Razor located: {razor}"); yak.shave(razor); break; } Err(err) => { // This will only appear once in the logger output for each error - warn_once!("Unable to locate a razor: {}, retrying", err); + warn_once!("Unable to locate a razor: {err}, retrying"); } } } diff --git a/src/lib.rs b/src/lib.rs index fc94e41..5e82f70 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,19 +26,19 @@ //! # fn find_a_razor() -> Result { Ok(1) } //! pub fn shave_the_yak(yaks: &[Yak]) { //! for yak in yaks { -//! info!(target: "yak_events", "Commencing yak shaving for {:?}", yak); +//! info!(target: "yak_events", "Commencing yak shaving for {yak:?}"); //! //! loop { //! match find_a_razor() { //! Ok(razor) => { //! // This will only appear once in the logger output for each razor -//! info_once!("Razor located: {}", razor); +//! info_once!("Razor located: {razor}"); //! yak.shave(razor); //! break; //! } //! Err(err) => { //! // This will only appear once in the logger output for each error -//! warn_once!("Unable to locate a razor: {}, retrying", err); +//! warn_once!("Unable to locate a razor: {err}, retrying"); //! } //! } //! } @@ -48,7 +48,11 @@ //! # fn main() {} //! ``` -extern crate log; +// We re-export the log crate so that the log_once macros can use it directly. +// That way users don't need to depend on `log` explicitly. +// This is especially nice for people who use `tracing` for logging, but still use `log_once`. +pub use log; + pub use log::Level; use std::collections::BTreeSet; @@ -56,17 +60,22 @@ use std::sync::{Mutex, MutexGuard, PoisonError}; #[doc(hidden)] pub struct __MessagesSet { - inner: Mutex> + inner: Mutex>, } impl __MessagesSet { - pub fn new() -> __MessagesSet { - __MessagesSet { - inner: Mutex::new(BTreeSet::new()) + #[must_use] + pub fn new() -> Self { + Self { + inner: Mutex::new(BTreeSet::new()), } } - pub fn lock(&self) -> Result>, PoisonError>>> { + /// # Errors + /// Mutex poisoning. + pub fn lock( + &self, + ) -> Result>, PoisonError>>> { self.inner.lock() } } @@ -94,21 +103,21 @@ macro_rules! log_once { &(*__SEEN_MESSAGES) } }); - (target: $target:expr, $lvl:expr, $message:expr) => ({ + + // log_once!(target: "my_target", Level::Info, "Some {}", "logging") + (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({ + let message = format!($($arg)+); #[allow(non_snake_case)] let __SEEN_MESSAGES = $crate::log_once!(@CREATE STATIC); let mut seen_messages = __SEEN_MESSAGES.lock().expect("Mutex was poisonned"); - let event = String::from(stringify!($target)) + stringify!($lvl) + $message.as_ref(); + let event = String::from(stringify!($target)) + stringify!($lvl) + message.as_ref(); if seen_messages.insert(event) { - log::log!(target: $target, $lvl, "{}", $message); + $crate::log::log!(target: $target, $lvl, "{}", message); } }); - (target: $target:expr, $lvl:expr, $format:expr, $($arg:tt)+) => ({ - let message = format!($format, $($arg)+); - $crate::log_once!(target: $target, $lvl, message); - }); - ($lvl:expr, $message:expr) => ($crate::log_once!(target: module_path!(), $lvl, $message)); - ($lvl:expr, $format:expr, $($arg:tt)+) => ($crate::log_once!(target: module_path!(), $lvl, $format, $($arg)+)); + + // log_once!(Level::Info, "Some {}", "logging") + ($lvl:expr, $($arg:tt)+) => ($crate::log_once!(target: module_path!(), $lvl, $($arg)+)); } /// Logs a message once at the error level. @@ -214,13 +223,15 @@ macro_rules! trace_once { #[cfg(test)] mod tests { + use log::{LevelFilter, Log, Metadata, Record}; use std::cell::Cell; use std::sync::Once; - use log::{Log, Record, Metadata, LevelFilter}; struct SimpleLogger; impl Log for SimpleLogger { - fn enabled(&self, _: &Metadata) -> bool {true} + fn enabled(&self, _: &Metadata) -> bool { + true + } fn log(&self, _: &Record) {} fn flush(&self) {} } @@ -231,8 +242,8 @@ mod tests { fn called_once() { static START: Once = Once::new(); START.call_once(|| { - ::log::set_logger(&LOGGER).expect("Could not set the logger"); - ::log::set_max_level(LevelFilter::Trace); + log::set_logger(&LOGGER).expect("Could not set the logger"); + log::set_max_level(LevelFilter::Trace); }); let counter = Cell::new(0); diff --git a/tests/captured-identifiers-format-strings.rs b/tests/captured-identifiers-format-strings.rs new file mode 100644 index 0000000..b7c6ed0 --- /dev/null +++ b/tests/captured-identifiers-format-strings.rs @@ -0,0 +1,33 @@ +//! Test that we can support capture identifiers in format strings introduced in Rust 1.58.0. +//! See https://blog.rust-lang.org/2022/01/13/Rust-1.58.0.html#captured-identifiers-in-format-strings + +mod logger; + +#[test] +fn info() { + logger::init(); + + let value = "FOO"; + + for _ in 0..2 { + log::info!("This is logged twice {value}!"); + } + + for _ in 0..2 { + log_once::info_once!("This is only logged once {value}!"); + } + + for i in 0..2 { + log_once::info_once!("This will be logged twice {i}!"); + } + + let data = logger::logged_data(); + let expected = "\ +This is logged twice FOO! +This is logged twice FOO! +This is only logged once FOO! +This will be logged twice 0! +This will be logged twice 1! +"; + assert_eq!(data, expected); +} diff --git a/tests/debug.rs b/tests/debug.rs index 820ad6c..27887fa 100644 --- a/tests/debug.rs +++ b/tests/debug.rs @@ -21,8 +21,8 @@ fn debug() { } let data = logger::logged_data(); - let expected = -"Here 42! + let expected = "\ +Here 42! Here 42! Here 42! Here 42! diff --git a/tests/error.rs b/tests/error.rs index 1b22547..2dc3523 100644 --- a/tests/error.rs +++ b/tests/error.rs @@ -21,8 +21,8 @@ fn error() { } let data = logger::logged_data(); - let expected = -"Here 42! + let expected = "\ +Here 42! Here 42! Here 42! Here 42! diff --git a/tests/info.rs b/tests/info.rs index 8f41b3d..7196811 100644 --- a/tests/info.rs +++ b/tests/info.rs @@ -21,8 +21,8 @@ fn info() { } let data = logger::logged_data(); - let expected = -"Here 42! + let expected = "\ +Here 42! Here 42! Here 42! Here 42! diff --git a/tests/logger/mod.rs b/tests/logger/mod.rs index 4cdda43..33d21f5 100644 --- a/tests/logger/mod.rs +++ b/tests/logger/mod.rs @@ -1,8 +1,8 @@ -use log::{Record, LevelFilter, Metadata}; -use std::sync::{Mutex, Once}; +use log::{LevelFilter, Metadata, Record}; use std::fmt::Write; +use std::sync::{Mutex, Once}; -lazy_static::lazy_static!{ +lazy_static::lazy_static! { static ref LOGGED_DATA: Mutex = Mutex::new(String::new()); } @@ -33,5 +33,8 @@ pub fn init() { } pub fn logged_data() -> String { - LOGGED_DATA.lock().expect("Mutex has been poisonned").clone() + LOGGED_DATA + .lock() + .expect("Mutex has been poisonned") + .clone() } diff --git a/tests/trace.rs b/tests/trace.rs index c3b43e1..1c54dcd 100644 --- a/tests/trace.rs +++ b/tests/trace.rs @@ -21,8 +21,8 @@ fn trace() { } let data = logger::logged_data(); - let expected = -"Here 42! + let expected = "\ +Here 42! Here 42! Here 42! Here 42! diff --git a/tests/warn.rs b/tests/warn.rs index 11b6aba..fa97309 100644 --- a/tests/warn.rs +++ b/tests/warn.rs @@ -21,8 +21,8 @@ fn warn() { } let data = logger::logged_data(); - let expected = -"Here 42! + let expected = "\ +Here 42! Here 42! Here 42! Here 42!