Skip to main content

jigs_trace/
lib.rs

1#![warn(missing_docs)]
2//! Per-jig execution tracing.
3//!
4//! Wires into `#[jig]` when the `trace` feature is enabled on the `jigs`
5//! umbrella crate (or on `jigs-macros` directly). Each instrumented jig
6//! records its name, depth, wall-clock duration and outcome into a
7//! thread-local buffer that callers can drain with [`take`].
8
9use std::cell::{Cell, RefCell};
10use std::time::Duration;
11
12pub use jigs_core::Status;
13
14/// One recorded jig invocation.
15pub struct Entry {
16    /// Function name of the jig.
17    pub name: &'static str,
18    /// Nesting depth at the time of entry (top-level jigs are depth 0).
19    pub depth: usize,
20    /// Wall-clock time spent inside the jig.
21    pub duration: Duration,
22    /// `true` if the jig produced a successful outcome.
23    pub ok: bool,
24    /// Error message captured from the jig's output, if any.
25    pub error: Option<String>,
26}
27
28thread_local! {
29    static DEPTH: Cell<usize> = const { Cell::new(0) };
30    static BUFFER: RefCell<Vec<Entry>> = const { RefCell::new(Vec::new()) };
31}
32
33/// Record the start of a jig invocation. Returns an index used by [`exit`]
34/// to close the same entry. Called by code generated from `#[jig]`.
35pub fn enter(name: &'static str) -> usize {
36    let depth = DEPTH.with(|d| {
37        let v = d.get();
38        d.set(v + 1);
39        v
40    });
41    BUFFER.with(|b| {
42        let mut buf = b.borrow_mut();
43        let idx = buf.len();
44        buf.push(Entry {
45            name,
46            depth,
47            duration: Duration::ZERO,
48            ok: true,
49            error: None,
50        });
51        idx
52    })
53}
54
55/// Close the entry at `idx` with its measured duration and outcome.
56/// Called by code generated from `#[jig]`.
57pub fn exit(idx: usize, duration: Duration, ok: bool, error: Option<String>) {
58    DEPTH.with(|d| d.set(d.get().saturating_sub(1)));
59    BUFFER.with(|b| {
60        let mut buf = b.borrow_mut();
61        buf[idx].duration = duration;
62        buf[idx].ok = ok;
63        buf[idx].error = error;
64    });
65}
66
67/// Drain the current thread's trace buffer and reset depth tracking.
68/// Call once per request after the pipeline finishes.
69pub fn take() -> Vec<Entry> {
70    DEPTH.with(|d| d.set(0));
71    BUFFER.with(|b| std::mem::take(&mut *b.borrow_mut()))
72}