tree_logger/
profile.rs

1use log::Record;
2use std::{
3    fmt::Display,
4    sync::atomic::{AtomicUsize, Ordering},
5};
6
7use crate::constants;
8
9static ID: AtomicUsize = AtomicUsize::new(0);
10
11pub fn profile_core<L, F, T>(label: L, location: &'static str, func: F, quiet: bool) -> T
12where
13    L: Display,
14    F: FnOnce() -> T,
15{
16    let id = ID.fetch_add(1, Ordering::SeqCst); // TODO: is this correct?
17    log::logger().log(
18        &Record::builder()
19            .key_values(&[(constants::INCREMENT, ())])
20            .build(),
21    );
22    log::logger().log(
23        &Record::builder()
24            .level(log::Level::Info)
25            .key_values(&[
26                (constants::ID, id),
27                (constants::QUIET, if quiet { 1 } else { 0 }),
28            ])
29            .target(location)
30            .args(format_args!("{label}"))
31            .build(),
32    );
33
34    let now = std::time::Instant::now();
35
36    log::logger().log(
37        &Record::builder()
38            .key_values(&[(constants::INCREMENT, ())])
39            .build(),
40    );
41    let rv = func();
42    log::logger().log(
43        &Record::builder()
44            .key_values(&[(constants::DECREMENT, ())])
45            .build(),
46    );
47
48    let elapsed = now.elapsed().as_millis();
49    log::logger().log(
50        &Record::builder()
51            .key_values(&[
52                (constants::SET_TIME, ""),
53                (constants::TIME, &elapsed.to_string()),
54                (constants::ID, &id.to_string()),
55            ])
56            .build(),
57    );
58    log::logger().log(
59        &Record::builder()
60            .key_values(&[(constants::DECREMENT, ())])
61            .build(),
62    );
63    rv
64}
65
66/// Utility macro that profiles code and nests the logging output.
67///
68/// ```no_run
69/// use tree_logger::TreeLogger;
70/// TreeLogger::new().with_colors(true).with_threads(true).init().unwrap();
71/// log::warn!("This is an example message.");
72/// ```
73///
74#[macro_export]
75macro_rules! profile {
76    ($label:expr, $func:expr) => {
77        tree_logger::profile::profile_core($label, file!(), $func, false)
78    };
79}
80
81#[macro_export]
82macro_rules! profile_quiet {
83    ($label:literal, $func:expr) => {
84        tree_logger::profile::profile_core($label, file!(), $func, true)
85    };
86}