tracing_setup/
buffered_layer.rs

1crate::ix!();
2
3#[derive(Getters, Setters, Debug)]
4#[getset(get = "pub", set = "pub")]
5pub struct BufferedLayer {
6    tag: Option<String>,
7    buffer: Arc<Mutex<Vec<String>>>,
8
9    /// The single source of truth for how we print events:
10    event_printer: EventPrinter,
11}
12
13impl BufferedLayer {
14    pub fn new_with_tag(tag: &str) -> Self {
15        Self {
16            tag: Some(tag.to_string()),
17            buffer: Arc::new(Mutex::new(Vec::new())),
18            event_printer: EventPrinter::default(),
19        }
20    }
21}
22
23impl<S: Subscriber> tracing_subscriber::Layer<S> for BufferedLayer {
24    fn on_event(&self, event: &tracing::Event<'_>, _ctx: Context<'_, S>) {
25        use tracing::{trace, debug, info, warn, error};
26
27        trace!("on_event called for BufferedLayer");
28
29        if let Ok(mut buf) = self.buffer.lock() {
30            trace!("successfully acquired buffer lock, building event log line");
31
32            match &self.event_printer {
33                EventPrinter::FullWithHeader => {
34                    // Original approach: debug-print the entire event
35                    let mut msg = String::new();
36                    let _ = write!(&mut msg, "{:#?}", event);
37
38                    debug!("pushing fully detailed event log line");
39                    buf.push(msg);
40                }
41
42                EventPrinter::LogLineAndContents {
43                    show_timestamp,
44                    show_loglevel,
45                    show_location,
46                } => {
47                    // Single-line approach with optional timestamp/level, but
48                    // place the location info after the message with alignment
49                    use chrono::{Local, SecondsFormat};
50
51                    let now  = Local::now().to_rfc3339_opts(SecondsFormat::Millis, true);
52                    let meta = event.metadata();
53
54                    let mut line = String::new();
55
56                    if *show_loglevel {
57                        let desired = 6;
58                        let level   = meta.level().to_string();
59                        let pad     = desired - level.len();
60                        line.push_str(&level);
61                        line.push_str(&" ".repeat(pad));
62                    }
63
64                    if *show_location {
65                        // we place the location (and level, if requested) at a fixed column
66                        // for consistent right-bracket alignment across lines
67                        let location = format!(" [{}] ", meta.target());
68                        let max_len = 60;
69                        if location.len() > max_len {
70                            let prefix = &location[0..max_len];
71                            line.push_str(&prefix);
72                        } else {
73                            line.push_str(&location);
74                            let pad = max_len - location.len();
75                            line.push_str(&" ".repeat(pad));
76                        }
77                        line.push_str(&" ");
78                    }
79
80                    // optional timestamp
81                    if *show_timestamp {
82                        line.push_str(&now);
83                        line.push(' ');
84                    }
85
86                    // collect field data
87                    struct FieldCollector(String);
88                    impl tracing::field::Visit for FieldCollector {
89                        fn record_debug(
90                            &mut self,
91                            f: &tracing::field::Field,
92                            v: &dyn std::fmt::Debug
93                        ) {
94                            if f.name() == "message" {
95                                let _ = write!(self.0, "{:?}, ", v);
96                            } else {
97                                let _ = write!(self.0, "{} = {:?}, ", f.name(), v);
98                            }
99                        }
100                    }
101                    let mut visitor = FieldCollector(String::new());
102                    event.record(&mut visitor);
103
104                    // trim trailing comma, if any
105                    if !visitor.0.is_empty() {
106                        visitor.0.truncate(visitor.0.len().saturating_sub(2));
107                    }
108
109                    // build the main part of the line (timestamp + message fields)
110                    line.push_str(&visitor.0);
111
112                    trace!("pushing single-line log event with aligned location bracket");
113                    buf.push(line);
114                }
115
116                EventPrinter::JustTheContents => {
117                    // Minimal approach: only the field values
118                    let mut message = String::new();
119                    struct FieldCollector(String);
120                    impl tracing::field::Visit for FieldCollector {
121                        fn record_debug(
122                            &mut self,
123                            _f: &tracing::field::Field,
124                            v: &dyn std::fmt::Debug
125                        ) {
126                            let _ = write!(self.0, "{:?}, ", v);
127                        }
128                    }
129                    let mut visitor = FieldCollector(String::new());
130                    event.record(&mut visitor);
131
132                    if !visitor.0.is_empty() {
133                        visitor.0.truncate(visitor.0.len().saturating_sub(2));
134                        message.push_str(&visitor.0);
135                    }
136
137                    debug!("pushing minimal event fields");
138                    buf.push(message);
139                }
140            }
141        } else {
142            warn!("failed to acquire buffer lock in BufferedLayer::on_event");
143        }
144    }
145}
146
147// The flush logic remains as-is (unchanged):
148impl Flushable for BufferedLayer {
149    fn flush(&self) {
150        use colored::Colorize;
151
152        if let Ok(mut buf) = self.buffer.lock() {
153            if let Some(tag) = &self.tag {
154                let msg = format!("---------------------------------------------------------[trace_events: {}]", tag);
155                println!("{}", msg.bright_blue());
156            }
157
158            for message in &*buf {
159                println!("{}", message);
160            }
161            buf.clear();
162        }
163    }
164}
165
166impl Clone for BufferedLayer {
167
168    fn clone(&self) -> Self {
169        Self {
170            tag:            self.tag.clone(),
171            buffer:         Arc::clone(&self.buffer),
172            event_printer:  self.event_printer.clone(),
173        }
174    }
175}
176
177impl Default for BufferedLayer {
178
179    fn default() -> Self {
180        Self {
181            tag:           None,
182            buffer:        Arc::new(Mutex::new(Vec::new())),
183            event_printer: EventPrinter::default(),
184        }
185    }
186}