#[doc = include_str!("./include/doc/log-macro-named-opt-params.md")]
#[macro_export]
macro_rules! log {
($($input:tt)+) => {
$crate::__normalize_forward!(__log_impl => default[logger: $crate::default_logger(), kv: {}], $($input)+)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __log_impl {
(logger: $logger:expr, kv: $kv:tt, $level:expr, $($arg:tt)+) => ({
let logger = &$logger;
if $crate::STATIC_LEVEL_FILTER.__test_const($level) && logger.should_log($level) {
$crate::__log(logger, $level, $crate::source_location_current!(), $crate::__kv!($kv), format_args!($($arg)+));
}
});
}
#[doc = include_str!("./include/doc/log-macro-named-opt-params.md")]
#[macro_export]
macro_rules! critical {
($($input:tt)+) => {
$crate::__normalize_forward!(__log_impl => default[logger: $crate::default_logger(), kv: {}, $crate::Level::Critical], $($input)+)
};
}
#[doc = include_str!("./include/doc/log-macro-named-opt-params.md")]
#[macro_export]
macro_rules! error {
($($input:tt)+) => {
$crate::__normalize_forward!(__log_impl => default[logger: $crate::default_logger(), kv: {}, $crate::Level::Error], $($input)+)
};
}
#[doc = include_str!("./include/doc/log-macro-named-opt-params.md")]
#[macro_export]
macro_rules! warn {
($($input:tt)+) => {
$crate::__normalize_forward!(__log_impl => default[logger: $crate::default_logger(), kv: {}, $crate::Level::Warn], $($input)+)
};
}
#[doc = include_str!("./include/doc/log-macro-named-opt-params.md")]
#[macro_export]
macro_rules! info {
($($input:tt)+) => {
$crate::__normalize_forward!(__log_impl => default[logger: $crate::default_logger(), kv: {}, $crate::Level::Info], $($input)+)
};
}
#[doc = include_str!("./include/doc/log-macro-named-opt-params.md")]
#[macro_export]
macro_rules! debug {
($($input:tt)+) => {
$crate::__normalize_forward!(__log_impl => default[logger: $crate::default_logger(), kv: {}, $crate::Level::Debug], $($input)+)
};
}
#[doc = include_str!("./include/doc/log-macro-named-opt-params.md")]
#[macro_export]
macro_rules! trace {
($($input:tt)+) => {
$crate::__normalize_forward!(__log_impl => default[logger: $crate::default_logger(), kv: {}, $crate::Level::Trace], $($input)+)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __kv {
({}) => (&[]);
({ $($ttm:tt)+ }) => {
$crate::__kv!(@{} $($ttm)+)
};
(@{$($done:tt)*} $k:ident $(= $v:expr)? $(,$($rest:tt)*)?) => ($crate::__kv!(@{$($done)* $k [ ] $(= $v)?,} $($($rest)*)?));
(@{$($done:tt)*} $k:ident : $(= $v:expr)? $(,$($rest:tt)*)?) => ($crate::__kv!(@{$($done)* $k [: ] $(= $v)?,} $($($rest)*)?));
(@{$($done:tt)*} $k:ident :? $(= $v:expr)? $(,$($rest:tt)*)?) => ($crate::__kv!(@{$($done)* $k [:?] $(= $v)?,} $($($rest)*)?));
(@{$($done:tt)*} $k:ident :sval $(= $v:expr)? $(,$($rest:tt)*)?) => ($crate::__kv!(@{$($done)* $k [:sval] $(= $v)?,} $($($rest)*)?));
(@{$($done:tt)*} $k:ident :serde $(= $v:expr)? $(,$($rest:tt)*)?) => ($crate::__kv!(@{$($done)* $k [:serde] $(= $v)?,} $($($rest)*)?));
(@{$( $k:ident [$($modifier:tt)*] $(= $v:expr)? ),+ $(,)?}) => {
&[$(($crate::kv::Key::__from_static_str(stringify!($k)), $crate::__kv_value!($k [$($modifier)*] $(= $v)?))),+]
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __kv_value {
($k:ident [$($modifier:tt)*]) => { $crate::__kv_value!($k [$($modifier)*] = $k) };
($k:ident [ ] = $v:expr) => { $crate::kv::Value::from(&$v) };
($k:ident [: ] = $v:expr) => { $crate::kv::Value::from_display(&$v) };
($k:ident [:?] = $v:expr) => { $crate::kv::Value::from_debug(&$v) };
($k:ident [:sval] = $v:expr) => { $crate::kv::Value::from_sval2(&$v) };
($k:ident [:serde] = $v:expr) => { $crate::kv::Value::from_serde1(&$v) };
}
#[cfg(test)]
mod tests {
use std::{
fmt::{self, Debug, Display},
sync::Arc,
vec,
};
use crate::{
kv::Key,
prelude::*,
sink::{GetSinkProp, Sink, SinkProp},
test_utils::{self, *},
utils::RefStr,
Record,
};
#[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)
}));
struct Mods;
impl Debug for Mods {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "debug")
}
}
impl Display for Mods {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "display")
}
}
let (int, mod1, mod2) = (114514, Mods, Mods);
const LEVEL_ARG: Level = Level::Info;
let assert_records = |kv: &[(&'static str, &str)], payload| {
let records = test_sink.records();
assert_eq!(records.len(), Level::count() + 1);
test_sink.clear();
records
.into_iter()
.zip([
LEVEL_ARG,
Level::Trace,
Level::Debug,
Level::Info,
Level::Warn,
Level::Error,
Level::Critical,
])
.for_each(|(record, expected_level)| {
assert_eq!(record.level(), expected_level);
assert_eq!(
record
.key_values()
.into_iter()
.map(|(k, v)| (k.inner(), v.to_string()))
.collect::<Vec<_>>(),
kv.iter()
.map(|(k, v)| (RefStr::new_ref(k), v.to_string()))
.collect::<Vec<_>>()
);
assert_eq!(record.payload(), payload);
});
};
log!(logger: test, LEVEL_ARG, "logger param only");
trace!(logger: test, "logger param only");
debug!(logger: test, "logger param only");
info!(logger: test, "logger param only");
warn!(logger: test, "logger param only");
error!(logger: test, "logger param only");
critical!(logger: test, "logger param only");
assert_records(&[], "logger param only");
log!(logger: test, kv: {}, LEVEL_ARG, "empty kv param");
trace!(logger: test, kv: {}, "empty kv param");
debug!(logger: test, kv: {}, "empty kv param");
info!(logger: test, kv: {}, "empty kv param");
warn!(logger: test, kv: {}, "empty kv param");
error!(logger: test, kv: {}, "empty kv param");
critical!(logger: test, kv: {}, "empty kv param");
assert_records(&[], "empty kv param");
log!(logger: test, kv: { int = 114514 }, LEVEL_ARG, "kv capture value directly");
trace!(logger: test, kv: { int = 114514 }, "kv capture value directly");
debug!(logger: test, kv: { int = 114514 }, "kv capture value directly");
info!(logger: test, kv: { int = 114514 }, "kv capture value directly");
warn!(logger: test, kv: { int = 114514 }, "kv capture value directly");
error!(logger: test, kv: { int = 114514 }, "kv capture value directly");
critical!(logger: test, kv: { int = 114514 }, "kv capture value directly");
assert_records(&[("int", "114514")], "kv capture value directly");
log!(logger: test, kv: { int = 114514, mod1: = Mods, mod2:? = Mods }, LEVEL_ARG, "kv capture value using modifiers");
trace!(logger: test, kv: { int = 114514, mod1: = Mods, mod2:? = Mods }, "kv capture value using modifiers");
debug!(logger: test, kv: { int = 114514, mod1: = Mods, mod2:? = Mods }, "kv capture value using modifiers");
info!(logger: test, kv: { int = 114514, mod1: = Mods, mod2:? = Mods }, "kv capture value using modifiers");
warn!(logger: test, kv: { int = 114514, mod1: = Mods, mod2:? = Mods }, "kv capture value using modifiers");
error!(logger: test, kv: { int = 114514, mod1: = Mods, mod2:? = Mods }, "kv capture value using modifiers");
critical!(logger: test, kv: { int = 114514, mod1: = Mods, mod2:? = Mods }, "kv capture value using modifiers");
assert_records(
&[("int", "114514"), ("mod1", "display"), ("mod2", "debug")],
"kv capture value using modifiers",
);
log!(logger: test, kv: { int }, LEVEL_ARG, "kv shorthand");
trace!(logger: test, kv: { int }, "kv shorthand");
debug!(logger: test, kv: { int }, "kv shorthand");
info!(logger: test, kv: { int }, "kv shorthand");
warn!(logger: test, kv: { int }, "kv shorthand");
error!(logger: test, kv: { int }, "kv shorthand");
critical!(logger: test, kv: { int }, "kv shorthand");
assert_records(&[("int", "114514")], "kv shorthand");
log!(logger: test, kv: { int, mod1:, mod2:? }, LEVEL_ARG, "kv shorthand modifiers");
trace!(logger: test, kv: { int, mod1:, mod2:? }, "kv shorthand modifiers");
debug!(logger: test, kv: { int, mod1:, mod2:? }, "kv shorthand modifiers");
info!(logger: test, kv: { int, mod1:, mod2:? }, "kv shorthand modifiers");
warn!(logger: test, kv: { int, mod1:, mod2:? }, "kv shorthand modifiers");
error!(logger: test, kv: { int, mod1:, mod2:? }, "kv shorthand modifiers");
critical!(logger: test, kv: { int, mod1:, mod2:? }, "kv shorthand modifiers");
assert_records(
&[("int", "114514"), ("mod1", "display"), ("mod2", "debug")],
"kv shorthand modifiers",
);
log!(logger: test, LEVEL_ARG, "params arbitrary order: logger, format, kv", kv: { mod1: });
trace!(logger: test, "params arbitrary order: logger, format, kv", kv: { mod1: });
debug!(logger: test, "params arbitrary order: logger, format, kv", kv: { mod1: });
info!(logger: test, "params arbitrary order: logger, format, kv", kv: { mod1: });
warn!(logger: test, "params arbitrary order: logger, format, kv", kv: { mod1: });
error!(logger: test, "params arbitrary order: logger, format, kv", kv: { mod1: });
critical!(logger: test, "params arbitrary order: logger, format, kv", kv: { mod1: });
assert_records(
&[("mod1", "display")],
"params arbitrary order: logger, format, kv",
);
log!(LEVEL_ARG, "params arbitrary order = format, kv, logger", kv: { mod1:? }, logger: test);
trace!("params arbitrary order = format, kv, logger", kv: { mod1:? }, logger: test);
debug!("params arbitrary order = format, kv, logger", kv: { mod1:? }, logger: test);
info!("params arbitrary order = format, kv, logger", kv: { mod1:? }, logger: test);
warn!("params arbitrary order = format, kv, logger", kv: { mod1:? }, logger: test);
error!("params arbitrary order = format, kv, logger", kv: { mod1:? }, logger: test);
critical!("params arbitrary order = format, kv, logger", kv: { mod1:? }, logger: test);
assert_records(
&[("mod1", "debug")],
"params arbitrary order = format, kv, logger",
);
let runtime_level = Level::Info;
log!(logger: test, runtime_level, "runtime level");
}
#[test]
fn kv_types() {
struct Asserter {
prop: SinkProp,
}
impl GetSinkProp for Asserter {
fn prop(&self) -> &SinkProp {
&self.prop
}
}
impl Sink for Asserter {
fn should_log(&self, _: Level) -> bool {
true
}
fn flush(&self) -> crate::Result<()> {
Ok(())
}
fn log(&self, record: &Record) -> crate::Result<()> {
let kvs = record.key_values();
let value = kvs.get(Key::from_str("v")).unwrap();
assert_eq!(kvs.len(), 1);
match record.payload() {
"1" => assert!(value.to_i64().is_some()),
"2" => assert!(value.to_str().is_some()),
"3" => assert_eq!(value.to_string(), "1"),
"4" => assert_eq!(value.to_string(), "1"),
"5" => assert_eq!(value.to_string(), "[1, 2]"),
"6" => assert_eq!(value.to_string(), "Data { i: 1, v: [1, 2] }"),
"7" => assert_eq!(value.to_string(), "Data { i: 1, v: [1, 2] }"),
_ => panic!(),
}
Ok(())
}
}
let asserter = test_utils::build_test_logger(|b| {
b.sink(Arc::new(Asserter {
prop: SinkProp::default(),
}))
});
#[cfg_attr(feature = "sval", derive(sval_derive::Value))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
struct Data {
i: i32,
v: Vec<i32>,
}
let data = Data {
i: 1,
v: vec![1, 2],
};
info!(logger: asserter, "1", kv: { v = 1 });
info!(logger: asserter, "2", kv: { v = "string" });
info!(logger: asserter, "3", kv: { v: = 1 });
info!(logger: asserter, "3", kv: { v: = &1 });
info!(logger: asserter, "4", kv: { v:? = 1 });
info!(logger: asserter, "4", kv: { v:? = &1 });
#[cfg(feature = "sval")]
info!(logger: asserter, "5", kv: { v:sval = vec![1, 2] });
#[cfg(feature = "sval")]
info!(logger: asserter, "5", kv: { v:sval = &vec![1, 2] });
#[cfg(feature = "sval")]
info!(logger: asserter, "6", kv: { v:sval = data });
#[cfg(feature = "sval")]
info!(logger: asserter, "6", kv: { v:sval = &data });
#[cfg(feature = "serde")]
info!(logger: asserter, "7", kv: { v:serde = data });
#[cfg(feature = "serde")]
info!(logger: asserter, "7", kv: { v:serde = &data });
}
}