#[doc(hidden)]
#[derive(Default)]
pub struct LogOnceSet(parking_lot::Mutex<std::collections::BTreeSet<String>>);
impl LogOnceSet {
#[doc(hidden)]
pub fn insert(&self, message: String) -> bool {
self.0.lock().insert(message)
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! __log_once {
($level:expr, target: $target:expr, $($arg:tt)+) => {{
static SEEN_MESSAGES: std::sync::LazyLock<$crate::LogOnceSet> =
std::sync::LazyLock::new($crate::LogOnceSet::default);
let message = format!($($arg)+);
if SEEN_MESSAGES.insert(message.clone()) {
$crate::event!(target: $target, $level, "{message}");
}
}};
($level:expr, $($arg:tt)+) => {{
static SEEN_MESSAGES: std::sync::LazyLock<$crate::LogOnceSet> =
std::sync::LazyLock::new($crate::LogOnceSet::default);
let message = format!($($arg)+);
if SEEN_MESSAGES.insert(message.clone()) {
$crate::event!($level, "{message}");
}
}};
}
#[macro_export]
macro_rules! trace_once {
($($arg:tt)+) => {
$crate::__log_once!($crate::Level::TRACE, $($arg)+)
};
}
#[macro_export]
macro_rules! debug_once {
($($arg:tt)+) => {
$crate::__log_once!($crate::Level::DEBUG, $($arg)+)
};
}
#[macro_export]
macro_rules! info_once {
($($arg:tt)+) => {
$crate::__log_once!($crate::Level::INFO, $($arg)+)
};
}
#[macro_export]
macro_rules! warn_once {
($($arg:tt)+) => {
$crate::__log_once!($crate::Level::WARN, $($arg)+)
};
}
#[macro_export]
macro_rules! error_once {
($($arg:tt)+) => {
$crate::__log_once!($crate::Level::ERROR, $($arg)+)
};
}
#[macro_export]
macro_rules! log_once {
($level:expr, $($arg:tt)+) => {
match $level {
$crate::Level::ERROR => $crate::error_once!($($arg)+),
$crate::Level::WARN => $crate::warn_once!($($arg)+),
$crate::Level::INFO => $crate::info_once!($($arg)+),
$crate::Level::DEBUG => $crate::debug_once!($($arg)+),
$crate::Level::TRACE => $crate::trace_once!($($arg)+),
}
};
}