tracing_tree/
lib.rs

1pub(crate) mod format;
2pub mod time;
3
4use crate::time::FormatTime;
5use format::{write_span_mode, Buffers, ColorLevel, Config, FmtEvent, SpanMode};
6
7use nu_ansi_term::{Color, Style};
8use std::{
9    fmt::{self, Write},
10    io::{self, IsTerminal},
11    iter::Fuse,
12    mem,
13    sync::{
14        atomic::{AtomicBool, Ordering},
15        Mutex,
16    },
17    thread::LocalKey,
18    time::Instant,
19};
20use tracing_core::{
21    field::{Field, Visit},
22    span::{Attributes, Id},
23    Event, Subscriber,
24};
25#[cfg(feature = "tracing-log")]
26use tracing_log::NormalizeEvent;
27use tracing_subscriber::{
28    fmt::MakeWriter,
29    layer::{Context, Layer},
30    registry::{LookupSpan, ScopeFromRoot, SpanRef},
31};
32
33// Span extension data
34pub(crate) struct Data {
35    start: Instant,
36    kvs: Vec<(&'static str, String)>,
37    written: bool,
38}
39
40impl Data {
41    pub fn new(attrs: &Attributes<'_>, written: bool) -> Self {
42        let mut span = Self {
43            start: Instant::now(),
44            kvs: Vec::new(),
45            written,
46        };
47        attrs.record(&mut span);
48        span
49    }
50}
51
52impl Visit for Data {
53    fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
54        self.kvs.push((field.name(), format!("{:?}", value)))
55    }
56}
57
58#[derive(Debug)]
59pub struct HierarchicalLayer<W = fn() -> io::Stderr, FT = ()>
60where
61    W: for<'writer> MakeWriter<'writer> + 'static,
62    FT: FormatTime,
63{
64    make_writer: W,
65    bufs: Mutex<Buffers>,
66    config: Config,
67    timer: FT,
68}
69
70impl Default for HierarchicalLayer {
71    fn default() -> Self {
72        Self::new(2)
73    }
74}
75
76impl HierarchicalLayer<fn() -> io::Stderr> {
77    pub fn new(indent_amount: usize) -> Self {
78        let ansi = io::stderr().is_terminal();
79        let config = Config {
80            ansi,
81            indent_amount,
82            ..Default::default()
83        };
84        Self {
85            make_writer: io::stderr,
86            bufs: Mutex::new(Buffers::new()),
87            config,
88            timer: (),
89        }
90    }
91}
92
93impl<W, FT> HierarchicalLayer<W, FT>
94where
95    W: for<'writer> MakeWriter<'writer> + 'static,
96    FT: FormatTime,
97{
98    /// Enables terminal colors, boldness and italics.
99    pub fn with_ansi(self, ansi: bool) -> Self {
100        Self {
101            config: self.config.with_ansi(ansi),
102            ..self
103        }
104    }
105
106    pub fn with_writer<W2>(self, make_writer: W2) -> HierarchicalLayer<W2, FT>
107    where
108        W2: for<'writer> MakeWriter<'writer>,
109    {
110        HierarchicalLayer {
111            make_writer,
112            config: self.config,
113            bufs: self.bufs,
114            timer: self.timer,
115        }
116    }
117
118    pub fn with_indent_amount(self, indent_amount: usize) -> Self {
119        let config = Config {
120            indent_amount,
121            ..self.config
122        };
123        Self { config, ..self }
124    }
125
126    /// Renders an ascii art tree instead of just using whitespace indentation.
127    pub fn with_indent_lines(self, indent_lines: bool) -> Self {
128        Self {
129            config: self.config.with_indent_lines(indent_lines),
130            ..self
131        }
132    }
133
134    /// Specifies how to measure and format time at which event has occurred.
135    pub fn with_timer<FT2: FormatTime>(self, timer: FT2) -> HierarchicalLayer<W, FT2> {
136        HierarchicalLayer {
137            make_writer: self.make_writer,
138            config: self.config,
139            bufs: self.bufs,
140            timer,
141        }
142    }
143
144    /// Whether to render the event and span targets. Usually targets are the module path to the
145    /// event/span macro invocation.
146    pub fn with_targets(self, targets: bool) -> Self {
147        Self {
148            config: self.config.with_targets(targets),
149            ..self
150        }
151    }
152
153    /// Whether to render the thread id in the beginning of every line. This is helpful to
154    /// untangle the tracing statements emitted by each thread.
155    pub fn with_thread_ids(self, thread_ids: bool) -> Self {
156        Self {
157            config: self.config.with_thread_ids(thread_ids),
158            ..self
159        }
160    }
161
162    /// Whether to render the thread name in the beginning of every line. Not all threads have
163    /// names, but if they do, this may be more helpful than the generic thread ids.
164    pub fn with_thread_names(self, thread_names: bool) -> Self {
165        Self {
166            config: self.config.with_thread_names(thread_names),
167            ..self
168        }
169    }
170
171    /// Resets the indentation to zero after `wraparound` indentation levels.
172    /// This is helpful if you expect very deeply nested spans as otherwise the indentation
173    /// just runs out of your screen.
174    pub fn with_wraparound(self, wraparound: usize) -> Self {
175        Self {
176            config: self.config.with_wraparound(wraparound),
177            ..self
178        }
179    }
180
181    /// Whether to print the currently active span's message again before entering a new span.
182    /// This helps if the entry to the current span was quite a while back (and with scrolling
183    /// upwards in logs).
184    pub fn with_verbose_entry(self, verbose_entry: bool) -> Self {
185        Self {
186            config: self.config.with_verbose_entry(verbose_entry),
187            ..self
188        }
189    }
190
191    /// Whether to print the currently active span's message again before dropping it.
192    /// This helps if the entry to the current span was quite a while back (and with scrolling
193    /// upwards in logs).
194    pub fn with_verbose_exit(self, verbose_exit: bool) -> Self {
195        Self {
196            config: self.config.with_verbose_exit(verbose_exit),
197            ..self
198        }
199    }
200
201    /// Whether to print the currently active span's message again if another span was entered in
202    /// the meantime
203    /// This helps during concurrent or multi-threaded events where threads are entered, but not
204    /// necessarily *exited* before other *divergent* spans are entered and generating events.
205    pub fn with_span_retrace(self, enabled: bool) -> Self {
206        Self {
207            config: self.config.with_span_retrace(enabled),
208            ..self
209        }
210    }
211
212    /// Defers printing span opening until an event is generated within the span.
213    ///
214    /// Avoids printing empty spans with no generated events.
215    pub fn with_deferred_spans(self, enabled: bool) -> Self {
216        Self {
217            config: self.config.with_deferred_spans(enabled),
218            ..self
219        }
220    }
221
222    /// Prefixes each branch with the event mode, such as `open`, or `close`
223    pub fn with_span_modes(self, enabled: bool) -> Self {
224        Self {
225            config: self.config.with_span_modes(enabled),
226            ..self
227        }
228    }
229
230    /// Whether to print `{}` around the fields when printing a span.
231    /// This can help visually distinguish fields from the rest of the message.
232    pub fn with_bracketed_fields(self, bracketed_fields: bool) -> Self {
233        Self {
234            config: self.config.with_bracketed_fields(bracketed_fields),
235            ..self
236        }
237    }
238
239    fn styled(&self, style: Style, text: impl AsRef<str>) -> String {
240        styled(self.config.ansi, style, text)
241    }
242
243    fn print_kvs<'a, I, V>(&self, buf: &mut impl fmt::Write, kvs: I) -> fmt::Result
244    where
245        I: IntoIterator<Item = (&'a str, V)>,
246        V: fmt::Display + 'a,
247    {
248        let mut kvs = kvs.into_iter();
249        if let Some((k, v)) = kvs.next() {
250            if k == "message" {
251                write!(buf, "{}", v)?;
252            } else {
253                write!(buf, "{}={}", k, v)?;
254            }
255        }
256        for (k, v) in kvs {
257            write!(buf, ", {}={}", k, v)?;
258        }
259        Ok(())
260    }
261
262    /// Ensures that `new_span` and all its ancestors are properly printed before an event
263    fn write_retrace_span<'a, S>(
264        &self,
265        new_span: &SpanRef<'a, S>,
266        bufs: &mut Buffers,
267        ctx: &'a Context<S>,
268        pre_open: bool,
269    ) where
270        S: Subscriber + for<'new_span> LookupSpan<'new_span>,
271    {
272        // Also handle deferred spans along with retrace since deferred spans may need to print
273        // multiple spans at once as a whole tree can be deferred
274        //
275        // If a another event occurs right after a previous event in the same span, this will
276        // simply print nothing since the path to the common lowest ancestor is empty
277        // if self.config.span_retrace || self.config.deferred_spans {
278        let old_span_id = bufs.current_span.replace((new_span.id()).clone());
279        let old_span_id = old_span_id.as_ref();
280        let new_span_id = new_span.id();
281
282        if Some(&new_span_id) != old_span_id {
283            let old_span = old_span_id.as_ref().and_then(|v| ctx.span(v));
284            let old_path = old_span.as_ref().map(scope_path).into_iter().flatten();
285
286            let new_path = scope_path(new_span);
287
288            // Print the path from the common base of the two spans
289            let new_path = DifferenceIter::new(old_path, new_path, |v| v.id());
290
291            for (i, span) in new_path.enumerate() {
292                // Mark traversed spans as *written*
293                let was_written = if let Some(data) = span.extensions_mut().get_mut::<Data>() {
294                    mem::replace(&mut data.written, true)
295                } else {
296                    // `on_new_span` was not called, before
297                    // Consider if this should panic instead, which is *technically* correct but is
298                    // bad behavior for a logging layer in production.
299                    false
300                };
301
302                // Print the parent of the first span
303                let mut verbose = false;
304                if i == 0 && pre_open {
305                    if let Some(span) = span.parent() {
306                        verbose = true;
307                        self.write_span_info(&span, bufs, SpanMode::PreOpen);
308                    }
309                }
310
311                self.write_span_info(
312                    &span,
313                    bufs,
314                    if was_written {
315                        SpanMode::Retrace { verbose }
316                    } else {
317                        SpanMode::Open { verbose }
318                    },
319                )
320            }
321        }
322    }
323
324    fn write_span_info<S>(&self, span: &SpanRef<S>, bufs: &mut Buffers, style: SpanMode)
325    where
326        S: Subscriber + for<'span> LookupSpan<'span>,
327    {
328        let ext = span.extensions();
329        let data = ext.get::<Data>().expect("span does not have data");
330
331        let mut current_buf = &mut bufs.current_buf;
332
333        if self.config.span_modes {
334            write_span_mode(current_buf, style)
335        }
336
337        let indent = scope_path(span).skip(1).count();
338
339        let should_write = match style {
340            SpanMode::Open { .. } | SpanMode::Event => true,
341            // Print the parent of a new span again before entering the child
342            SpanMode::PreOpen { .. } if self.config.verbose_entry => true,
343            SpanMode::Close { verbose } => verbose,
344            // Generated if `span_retrace` is enabled
345            SpanMode::Retrace { .. } => true,
346            // Generated if `verbose_exit` is enabled
347            SpanMode::PostClose => true,
348            _ => false,
349        };
350
351        if should_write {
352            if self.config.targets {
353                let target = span.metadata().target();
354                write!(
355                    &mut current_buf,
356                    "{}::",
357                    self.styled(Style::new().dimmed(), target,),
358                )
359                .expect("Unable to write to buffer");
360            }
361
362            write!(
363                current_buf,
364                "{name}",
365                name = self.styled(Style::new().fg(Color::Green).bold(), span.metadata().name())
366            )
367            .unwrap();
368            if self.config.bracketed_fields {
369                write!(
370                    current_buf,
371                    "{}",
372                    self.styled(Style::new().fg(Color::Green).bold(), "{") // Style::new().fg(Color::Green).dimmed().paint("{")
373                )
374                .unwrap();
375            } else {
376                write!(current_buf, " ").unwrap();
377            }
378            self.print_kvs(&mut current_buf, data.kvs.iter().map(|(k, v)| (*k, v)))
379                .unwrap();
380            if self.config.bracketed_fields {
381                write!(
382                    current_buf,
383                    "{}",
384                    self.styled(Style::new().fg(Color::Green).bold(), "}") // Style::new().dimmed().paint("}")
385                )
386                .unwrap();
387            }
388        }
389
390        bufs.indent_current(indent, &self.config, style);
391        let writer = self.make_writer.make_writer();
392        bufs.flush_current_buf(writer)
393    }
394
395    fn write_timestamp<S>(&self, span: SpanRef<S>, buf: &mut String)
396    where
397        S: Subscriber + for<'span> LookupSpan<'span>,
398    {
399        let ext = span.extensions();
400        let data = ext
401            .get::<Data>()
402            .expect("Data cannot be found in extensions");
403
404        self.timer
405            .style_timestamp(self.config.ansi, data.start.elapsed(), buf)
406            .unwrap()
407    }
408
409    fn is_recursive() -> Option<RecursiveGuard> {
410        thread_local! {
411            pub static IS_EMPTY: AtomicBool = const { AtomicBool::new(true) };
412        }
413
414        IS_EMPTY.with(|is_empty| {
415            is_empty
416                .compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
417                .ok()
418                .map(|_| RecursiveGuard(&IS_EMPTY))
419        })
420    }
421}
422
423fn styled(ansi: bool, style: Style, text: impl AsRef<str>) -> String {
424    if ansi {
425        style.paint(text.as_ref()).to_string()
426    } else {
427        text.as_ref().to_string()
428    }
429}
430
431struct RecursiveGuard(&'static LocalKey<AtomicBool>);
432
433impl Drop for RecursiveGuard {
434    fn drop(&mut self) {
435        self.0
436            .with(|is_empty| is_empty.store(true, Ordering::Relaxed));
437    }
438}
439
440impl<S, W, FT> Layer<S> for HierarchicalLayer<W, FT>
441where
442    S: Subscriber + for<'span> LookupSpan<'span>,
443    W: for<'writer> MakeWriter<'writer> + 'static,
444    FT: FormatTime + 'static,
445{
446    fn on_new_span(&self, attrs: &Attributes, id: &Id, ctx: Context<S>) {
447        let Some(_guard) = Self::is_recursive() else {
448            return;
449        };
450
451        let span = ctx.span(id).expect("in new_span but span does not exist");
452
453        if span.extensions().get::<Data>().is_none() {
454            let data = Data::new(attrs, !self.config.deferred_spans);
455            span.extensions_mut().insert(data);
456        }
457
458        // Entry will be printed in on_event along with retrace
459        if self.config.deferred_spans {
460            return;
461        }
462
463        let bufs = &mut *self.bufs.lock().unwrap();
464
465        if self.config.span_retrace {
466            self.write_retrace_span(&span, bufs, &ctx, self.config.verbose_entry);
467        } else {
468            if self.config.verbose_entry {
469                if let Some(span) = span.parent() {
470                    self.write_span_info(&span, bufs, SpanMode::PreOpen);
471                }
472            }
473            // Store the most recently entered span
474            bufs.current_span = Some(span.id());
475            self.write_span_info(
476                &span,
477                bufs,
478                SpanMode::Open {
479                    verbose: self.config.verbose_entry,
480                },
481            );
482        }
483    }
484
485    fn on_event(&self, event: &Event<'_>, ctx: Context<S>) {
486        let Some(_guard) = Self::is_recursive() else {
487            return;
488        };
489
490        let span = ctx.current_span();
491        let span_id = span.id();
492        let span = span_id.and_then(|id| ctx.span(id));
493
494        let mut guard = self.bufs.lock().unwrap();
495        let bufs = &mut *guard;
496
497        if let Some(new_span) = &span {
498            if self.config.span_retrace || self.config.deferred_spans {
499                self.write_retrace_span(new_span, bufs, &ctx, self.config.verbose_entry);
500            }
501        }
502
503        let mut event_buf = &mut bufs.current_buf;
504
505        // Time.
506
507        {
508            let prev_buffer_len = event_buf.len();
509
510            self.timer
511                .format_time(&mut event_buf)
512                .expect("Unable to write time to buffer");
513
514            // Something was written to the buffer, pad it with a space.
515            if prev_buffer_len < event_buf.len() {
516                write!(event_buf, " ").expect("Unable to write to buffer");
517            }
518        }
519
520        let deindent = if self.config.indent_lines { 0 } else { 1 };
521        // printing the indentation
522        let indent = ctx
523            .event_scope(event)
524            .map(|scope| scope.count() - deindent)
525            .unwrap_or(0);
526
527        // check if this event occurred in the context of a span.
528        // if it has, get the start time of this span.
529        if let Some(span) = span {
530            self.write_timestamp(span, event_buf);
531            event_buf.push(' ');
532        }
533
534        #[cfg(feature = "tracing-log")]
535        let normalized_meta = event.normalized_metadata();
536        #[cfg(feature = "tracing-log")]
537        let metadata = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
538        #[cfg(not(feature = "tracing-log"))]
539        let metadata = event.metadata();
540
541        let level = metadata.level();
542        let level = if self.config.ansi {
543            ColorLevel(level).to_string()
544        } else {
545            level.to_string()
546        };
547
548        write!(&mut event_buf, "{level}", level = level).expect("Unable to write to buffer");
549
550        if self.config.targets {
551            let target = metadata.target();
552            write!(
553                &mut event_buf,
554                " {}",
555                self.styled(Style::new().dimmed(), target,),
556            )
557            .expect("Unable to write to buffer");
558        }
559
560        let mut visitor = FmtEvent { comma: false, bufs };
561        event.record(&mut visitor);
562        visitor
563            .bufs
564            .indent_current(indent, &self.config, SpanMode::Event);
565        let writer = self.make_writer.make_writer();
566        bufs.flush_current_buf(writer)
567    }
568
569    fn on_close(&self, id: Id, ctx: Context<S>) {
570        let Some(_guard) = Self::is_recursive() else {
571            return;
572        };
573
574        let bufs = &mut *self.bufs.lock().unwrap();
575
576        let span = ctx.span(&id).expect("invalid span in on_close");
577
578        // Span was not printed, so don't print an exit
579        if self.config.deferred_spans
580            && span.extensions().get::<Data>().map(|v| v.written) != Some(true)
581        {
582            return;
583        }
584
585        // self.write_retrace_span(&span, bufs, &ctx);
586
587        self.write_span_info(
588            &span,
589            bufs,
590            SpanMode::Close {
591                verbose: self.config.verbose_exit,
592            },
593        );
594
595        if let Some(parent_span) = span.parent() {
596            bufs.current_span = Some(parent_span.id());
597            if self.config.verbose_exit {
598                // Consider parent as entered
599
600                self.write_span_info(&parent_span, bufs, SpanMode::PostClose);
601            }
602        }
603    }
604}
605
606fn scope_path<'a, R: LookupSpan<'a>>(span: &SpanRef<'a, R>) -> ScopeFromRoot<'a, R> {
607    span.scope().from_root()
608}
609
610/// Runs `A` and `B` side by side and only yields items present in `B`
611struct DifferenceIter<L, R, F> {
612    left: Fuse<L>,
613    right: R,
614    compare: F,
615}
616
617impl<L: Iterator<Item = T>, R: Iterator<Item = T>, T, U: PartialEq, F: Fn(&T) -> U>
618    DifferenceIter<L, R, F>
619{
620    fn new(left: L, right: R, compare: F) -> Self {
621        Self {
622            left: left.fuse(),
623            right,
624            compare,
625        }
626    }
627}
628
629impl<L: Iterator<Item = T>, R: Iterator<Item = T>, T, U: PartialEq, F: Fn(&T) -> U> Iterator
630    for DifferenceIter<L, R, F>
631{
632    type Item = T;
633
634    fn next(&mut self) -> Option<Self::Item> {
635        loop {
636            let left = self.left.next();
637            let right = self.right.next()?;
638
639            if left.as_ref().map(&self.compare) != Some((self.compare)(&right)) {
640                return Some(right);
641            }
642        }
643    }
644}