1use std::sync::OnceLock;
10use std::time::Instant;
11
12pub fn enabled() -> bool {
14 static ON: OnceLock<bool> = OnceLock::new();
15 *ON.get_or_init(|| {
16 std::env::var("ACTL_TRACE")
17 .map(|v| !v.is_empty() && v != "0")
18 .unwrap_or(false)
19 })
20}
21
22pub fn stage(stage: &str, started: Instant) {
24 if enabled() {
25 eprintln!("[actl-trace] {stage} {}ms", started.elapsed().as_millis());
26 }
27}
28
29pub struct TraceScope {
32 stage: &'static str,
33 started: Instant,
34}
35
36pub fn scope(stage: &'static str) -> TraceScope {
37 TraceScope {
38 stage,
39 started: Instant::now(),
40 }
41}
42
43impl Drop for TraceScope {
44 fn drop(&mut self) {
45 stage(self.stage, self.started);
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn disabled_by_default_and_stage_is_silent_noop() {
55 let ok = std::panic::catch_unwind(|| {
57 stage("test.point", Instant::now());
58 let _t = scope("test.scope");
59 });
60 assert!(ok.is_ok());
61 }
62
63 #[test]
64 fn scope_drop_invokes_stage_without_panic() {
65 let _t = scope("test.lifetime");
66 drop(_t);
67 }
68}