use log::Record;
use std::{
fmt::Display,
sync::atomic::{AtomicUsize, Ordering},
};
use crate::constants;
static ID: AtomicUsize = AtomicUsize::new(0);
pub fn profile_core<L, F, T>(label: L, location: &'static str, func: F, quiet: bool) -> T
where
L: Display,
F: FnOnce() -> T,
{
profile_core_with_level(label, location, func, log::Level::Info, quiet)
}
pub fn profile_core_with_level<L, F, T>(
label: L,
location: &'static str,
func: F,
level: log::Level,
quiet: bool,
) -> T
where
L: Display,
F: FnOnce() -> T,
{
let id = ID.fetch_add(1, Ordering::SeqCst); log::logger().log(
&Record::builder()
.key_values(&[(constants::INCREMENT, ())])
.build(),
);
log::logger().log(
&Record::builder()
.level(level)
.key_values(&[
(constants::ID, id),
(constants::QUIET, if quiet { 1 } else { 0 }),
])
.target(location)
.args(format_args!("{label}"))
.build(),
);
let now = std::time::Instant::now();
log::logger().log(
&Record::builder()
.key_values(&[(constants::INCREMENT, ())])
.build(),
);
let rv = func();
log::logger().log(
&Record::builder()
.key_values(&[(constants::DECREMENT, ())])
.build(),
);
let elapsed = now.elapsed().as_millis();
log::logger().log(
&Record::builder()
.key_values(&[
(constants::SET_TIME, ""),
(constants::TIME, &elapsed.to_string()),
(constants::ID, &id.to_string()),
])
.build(),
);
log::logger().log(
&Record::builder()
.key_values(&[(constants::DECREMENT, ())])
.build(),
);
rv
}
#[macro_export]
macro_rules! profile {
($label:expr, $func:expr, $level:expr) => {
tree_logger::profile::profile_core_with_level($label, file!(), $func, $level, false)
};
($label:expr, $func:expr) => {
tree_logger::profile::profile_core($label, file!(), $func, false)
};
}
#[macro_export]
macro_rules! profile_quiet {
($label:expr, $func:expr, $level:expr) => {
tree_logger::profile::profile_core_with_level($label, file!(), $func, $level, true)
};
($label:expr, $func:expr) => {
tree_logger::profile::profile_core($label, file!(), $func, true)
};
}
#[cfg(test)]
mod test {
use crate as tree_logger;
#[test]
fn logging_compiles() {
crate::profile!("test", || {});
crate::profile!("test", || {}, log::Level::Error);
crate::profile_quiet!("test", || {}, log::Level::Error);
}
}