1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//! A span based profiler, utilizing the [tracing](https://docs.rs/tracing/latest/tracing/) crate.
//!
//! # Overview  
//! This implementation of `tracing_subscriber::Layer<S>` records the time
//! a span took to execute, along with any user supplied metadata and
//! information necessary to construct a call graph from the resulting logs.
//!
//! Two Layer implementations are provided:
//!     `CsvLayer`: logs data in CSV format
//!     `PrintTreeLayer`: prints a call graph
//!
//! ```
//! use tracing::instrument;
//! use tracing::debug_span;
//! use tracing_subscriber::prelude::*;
//! use tracing_profile::*;
//!
//! #[instrument(skip_all, name= "graph_root", fields(a="b", c="d"))]
//! fn entry_point() {
//!     let span = debug_span!("some_span");
//!     let _scope1 = span.enter();
//!     
//!     let span2 = debug_span!("another_span", field1 = "value1");
//!     let _scope2 = span2.enter();
//! }
//!
//! fn main() {
//!     tracing_subscriber::registry()
//!         .with(PrintTreeLayer::new())
//!         .with(CsvLayer::new("/tmp/output.csv"))
//!         .init();
//!     entry_point();
//! }
//! ```
//!
//! Note that if `#[instrument]` is used, `skip_all` is recommended. Omitting this will result in
//! all the function arguments being included as fields.
//!
//! # Features  
//! The `panic` feature will turn eprintln! into panic!, causing the program to halt on errors.

mod data;
mod layers;
pub use layers::{csv::Layer as CsvLayer, graph::Layer as PrintTreeLayer};

// use this instead of eprintln!
macro_rules! err_msg {
    ($($arg:tt)*) => {{
        eprintln!($($arg)*);
        assert!(cfg!(not(feature = "panic")))
    }};
}

pub(crate) use err_msg;

#[cfg(test)]
mod tests {
    use tracing::debug_span;
    use tracing_subscriber::prelude::*;

    use super::*;

    fn make_spans() {
        let span = debug_span!("root span");
        let _scope1 = span.enter();

        // child spans 1 and 2 are siblings
        let span2 = debug_span!("child span1", field1 = "value1");
        let scope2 = span2.enter();
        drop(scope2);

        let span3 = debug_span!("child span2", field2 = "value2");
        let _scope3 = span3.enter();

        // child spans 3 and 4 are siblings
        let span = debug_span!("child span3", field3 = "value3");
        let scope = span.enter();
        drop(scope);

        let span = debug_span!("child span4", field4 = "value4");
        let scope = span.enter();
        drop(scope);
    }

    #[test]
    fn all_layers() {
        tracing_subscriber::registry()
            .with(PrintTreeLayer::new())
            .with(CsvLayer::new("/tmp/output.csv"))
            .init();
        make_spans();
    }
}