diff --git a/spdlog/src/kv.rs b/spdlog/src/kv.rs index b9ad687..387f106 100644 --- a/spdlog/src/kv.rs +++ b/spdlog/src/kv.rs @@ -4,16 +4,18 @@ use value_bag::{OwnedValueBag, ValueBag}; use crate::helper::ConcreteCow; -#[derive(Debug, Clone)] -enum KeyInner<'a> { +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) enum KeyInner<'a> { Str(&'a str), StaticStr(&'static str), } +// TODO: PartialEq #[derive(Debug, Clone)] pub struct Key<'a>(KeyInner<'a>); impl<'a> Key<'a> { + #[doc(hidden)] pub fn __from_static_str(key: &'static str) -> Self { Key(KeyInner::StaticStr(key)) } @@ -29,6 +31,11 @@ impl<'a> Key<'a> { }; KeyOwned(inner) } + + #[cfg(test)] + pub(crate) fn inner(&self) -> KeyInner<'a> { + self.0.clone() + } } #[derive(Debug, Clone)] diff --git a/spdlog/src/log_macros.rs b/spdlog/src/log_macros.rs index d8bb137..5cdc72c 100644 --- a/spdlog/src/log_macros.rs +++ b/spdlog/src/log_macros.rs @@ -21,15 +21,17 @@ /// [`Level`]: crate::Level #[macro_export] macro_rules! log { - (logger: $logger:expr, $level:expr, $($arg:tt)+) => ({ + (logger: $logger:expr, kv: $kv:tt, $level:expr, $($arg:tt)+) => ({ let logger = &$logger; const LEVEL: $crate::Level = $level; const SHOULD_LOG: bool = $crate::STATIC_LEVEL_FILTER.__test_const(LEVEL); if SHOULD_LOG && logger.should_log(LEVEL) { - $crate::__log(logger, LEVEL, $crate::source_location_current!(), &[], format_args!($($arg)+)); + $crate::__log(logger, LEVEL, $crate::source_location_current!(), $crate::__kv!($kv), format_args!($($arg)+)); } }); - ($level:expr, $($arg:tt)+) => ($crate::log!(logger: $crate::default_logger(), $level, $($arg)+)) + (logger: $logger:expr, $level:expr, $($arg:tt)+) => ($crate::log!(logger: $logger, kv: {}, $level, $($arg)+)); + (kv: $kv:tt, $level:expr, $($arg:tt)+) => ($crate::log!(logger: $crate::default_logger(), kv: $kv, $level, $($arg)+)); + ($level:expr, $($arg:tt)+) => ($crate::log!(logger: $crate::default_logger(), kv: {}, $level, $($arg)+)); } /// Logs a message at the critical level. @@ -50,9 +52,15 @@ macro_rules! log { /// ``` #[macro_export] macro_rules! critical { + (logger: $logger:expr, kv: $kv:tt, $($arg:tt)+) => ( + $crate::log!(logger: $logger, kv: $kv, $crate::Level::Critical, $($arg)+) + ); (logger: $logger:expr, $($arg:tt)+) => ( $crate::log!(logger: $logger, $crate::Level::Critical, $($arg)+) ); + (kv: $kv:tt, $($arg:tt)+) => ( + $crate::log!(kv: $kv, $crate::Level::Critical, $($arg)+) + ); ($($arg:tt)+) => ( $crate::log!($crate::Level::Critical, $($arg)+) ) @@ -76,9 +84,15 @@ macro_rules! critical { /// ``` #[macro_export] macro_rules! error { + (logger: $logger:expr, kv: $kv:tt, $($arg:tt)+) => ( + $crate::log!(logger: $logger, kv: $kv, $crate::Level::Error, $($arg)+) + ); (logger: $logger:expr, $($arg:tt)+) => ( $crate::log!(logger: $logger, $crate::Level::Error, $($arg)+) ); + (kv: $kv:tt, $($arg:tt)+) => ( + $crate::log!(kv: $kv, $crate::Level::Error, $($arg)+) + ); ($($arg:tt)+) => ( $crate::log!($crate::Level::Error, $($arg)+) ) @@ -102,9 +116,15 @@ macro_rules! error { /// ``` #[macro_export] macro_rules! warn { + (logger: $logger:expr, kv: $kv:tt, $($arg:tt)+) => ( + $crate::log!(logger: $logger, kv: $kv, $crate::Level::Warn, $($arg)+) + ); (logger: $logger:expr, $($arg:tt)+) => ( $crate::log!(logger: $logger, $crate::Level::Warn, $($arg)+) ); + (kv: $kv:tt, $($arg:tt)+) => ( + $crate::log!(kv: $kv, $crate::Level::Warn, $($arg)+) + ); ($($arg:tt)+) => ( $crate::log!($crate::Level::Warn, $($arg)+) ) @@ -129,9 +149,15 @@ macro_rules! warn { /// ``` #[macro_export] macro_rules! info { + (logger: $logger:expr, kv: $kv:tt, $($arg:tt)+) => ( + $crate::log!(logger: $logger, kv: $kv, $crate::Level::Info, $($arg)+) + ); (logger: $logger:expr, $($arg:tt)+) => ( $crate::log!(logger: $logger, $crate::Level::Info, $($arg)+) ); + (kv: $kv:tt, $($arg:tt)+) => ( + $crate::log!(kv: $kv, $crate::Level::Info, $($arg)+) + ); ($($arg:tt)+) => ( $crate::log!($crate::Level::Info, $($arg)+) ) @@ -156,9 +182,15 @@ macro_rules! info { /// ``` #[macro_export] macro_rules! debug { + (logger: $logger:expr, kv: $kv:tt, $($arg:tt)+) => ( + $crate::log!(logger: $logger, kv: $kv, $crate::Level::Debug, $($arg)+) + ); (logger: $logger:expr, $($arg:tt)+) => ( $crate::log!(logger: $logger, $crate::Level::Debug, $($arg)+) ); + (kv: $kv:tt, $($arg:tt)+) => ( + $crate::log!(kv: $kv, $crate::Level::Debug, $($arg)+) + ); ($($arg:tt)+) => ( $crate::log!($crate::Level::Debug, $($arg)+) ) @@ -185,10 +217,202 @@ macro_rules! debug { /// ``` #[macro_export] macro_rules! trace { + (logger: $logger:expr, kv: $kv:tt, $($arg:tt)+) => ( + $crate::log!(logger: $logger, kv: $kv, $crate::Level::Trace, $($arg)+) + ); (logger: $logger:expr, $($arg:tt)+) => ( $crate::log!(logger: $logger, $crate::Level::Trace, $($arg)+) ); + (kv: $kv:tt, $($arg:tt)+) => ( + $crate::log!(kv: $kv, $crate::Level::Trace, $($arg)+) + ); ($($arg:tt)+) => ( $crate::log!($crate::Level::Trace, $($arg)+) ) } + +#[doc(hidden)] +#[macro_export] +macro_rules! __kv { + ({}) => (&[]); + ({ $( $k:ident = $v:expr ),+ $(,)? }) => { + &[$(($crate::kv::Key::__from_static_str(stringify!($k)), $v.into())),+] + }; +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use crate::{kv::KeyInner, prelude::*, test_utils::*}; + + #[test] + fn syntax_and_records() { + let test_sink = Arc::new(TestSink::new()); + let test = Arc::new(build_test_logger(|b| { + b.sink(test_sink.clone()).level_filter(LevelFilter::All) + })); + + log!(logger: test, Level::Info, "logger"); + log!(logger: test, kv: {}, Level::Error, "logger, kv(0)"); + log!(logger: test, kv: { k1 = 114 }, Level::Warn, "logger, kv(1)"); + log!(logger: test, kv: { k1 = 114, k2 = 514 }, Level::Critical, "logger, kv(2)"); + critical!(logger: test, "critical: logger"); + critical!(logger: test, kv: {}, "critical: logger, kv(0)"); + critical!(logger: test, kv: { k1 = 114 }, "critical: logger, kv(1)"); + critical!(logger: test, kv: { k1 = 114, k2 = 514 }, "critical: logger, kv(2)"); + error!(logger: test, "error: logger"); + error!(logger: test, kv: {}, "error: logger, kv(0)"); + error!(logger: test, kv: { k1 = 114 }, "error: logger, kv(1)"); + error!(logger: test, kv: { k1 = 114, k2 = 514 }, "error: logger, kv(2)"); + warn!(logger: test, "warn: logger"); + warn!(logger: test, kv: {}, "warn: logger, kv(0)"); + warn!(logger: test, kv: { k1 = 114 }, "warn: logger, kv(1)"); + warn!(logger: test, kv: { k1 = 114, k2 = 514 }, "warn: logger, kv(2)"); + info!(logger: test, "info: logger"); + info!(logger: test, kv: {}, "info: logger, kv(0)"); + info!(logger: test, kv: { k1 = 114 }, "info: logger, kv(1)"); + info!(logger: test, kv: { k1 = 114, k2 = 514 }, "info: logger, kv(2)"); + debug!(logger: test, "debug: logger"); + debug!(logger: test, kv: {}, "debug: logger, kv(0)"); + debug!(logger: test, kv: { k1 = 114 }, "debug: logger, kv(1)"); + debug!(logger: test, kv: { k1 = 114, k2 = 514 }, "debug: logger, kv(2)"); + trace!(logger: test, "trace: logger"); + trace!(logger: test, kv: {}, "trace: logger, kv(0)"); + trace!(logger: test, kv: { k1 = 114 }, "trace: logger, kv(1)"); + trace!(logger: test, kv: { k1 = 114, k2 = 514 }, "trace: logger, kv(2)"); + + let records = test_sink.records(); + let check = records + .iter() + .map(|record| { + ( + record + .key_values() + .into_iter() + .map(|(k, v)| (k.inner(), v.to_i64().unwrap())) + .collect::>(), + record.level(), + record.payload(), + ) + }) + .collect::>(); + + assert_eq!( + check, + vec![ + (vec![], Level::Info, "logger"), + (vec![], Level::Error, "logger, kv(0)"), + ( + vec![(KeyInner::StaticStr("k1"), 114)], + Level::Warn, + "logger, kv(1)" + ), + ( + vec![ + (KeyInner::StaticStr("k1"), 114), + (KeyInner::StaticStr("k2"), 514) + ], + Level::Critical, + "logger, kv(2)" + ), + // + (vec![], Level::Critical, "critical: logger"), + (vec![], Level::Critical, "critical: logger, kv(0)"), + ( + vec![(KeyInner::StaticStr("k1"), 114)], + Level::Critical, + "critical: logger, kv(1)" + ), + ( + vec![ + (KeyInner::StaticStr("k1"), 114), + (KeyInner::StaticStr("k2"), 514) + ], + Level::Critical, + "critical: logger, kv(2)" + ), + // + (vec![], Level::Error, "error: logger"), + (vec![], Level::Error, "error: logger, kv(0)"), + ( + vec![(KeyInner::StaticStr("k1"), 114)], + Level::Error, + "error: logger, kv(1)" + ), + ( + vec![ + (KeyInner::StaticStr("k1"), 114), + (KeyInner::StaticStr("k2"), 514) + ], + Level::Error, + "error: logger, kv(2)" + ), + // + (vec![], Level::Warn, "warn: logger"), + (vec![], Level::Warn, "warn: logger, kv(0)"), + ( + vec![(KeyInner::StaticStr("k1"), 114)], + Level::Warn, + "warn: logger, kv(1)" + ), + ( + vec![ + (KeyInner::StaticStr("k1"), 114), + (KeyInner::StaticStr("k2"), 514) + ], + Level::Warn, + "warn: logger, kv(2)" + ), + // + (vec![], Level::Info, "info: logger"), + (vec![], Level::Info, "info: logger, kv(0)"), + ( + vec![(KeyInner::StaticStr("k1"), 114)], + Level::Info, + "info: logger, kv(1)" + ), + ( + vec![ + (KeyInner::StaticStr("k1"), 114), + (KeyInner::StaticStr("k2"), 514) + ], + Level::Info, + "info: logger, kv(2)" + ), + // + (vec![], Level::Debug, "debug: logger"), + (vec![], Level::Debug, "debug: logger, kv(0)"), + ( + vec![(KeyInner::StaticStr("k1"), 114)], + Level::Debug, + "debug: logger, kv(1)" + ), + ( + vec![ + (KeyInner::StaticStr("k1"), 114), + (KeyInner::StaticStr("k2"), 514) + ], + Level::Debug, + "debug: logger, kv(2)" + ), + // + (vec![], Level::Trace, "trace: logger"), + (vec![], Level::Trace, "trace: logger, kv(0)"), + ( + vec![(KeyInner::StaticStr("k1"), 114)], + Level::Trace, + "trace: logger, kv(1)" + ), + ( + vec![ + (KeyInner::StaticStr("k1"), 114), + (KeyInner::StaticStr("k2"), 514) + ], + Level::Trace, + "trace: logger, kv(2)" + ), + ] + ); + } +}