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