Skip to main content

uv_logging/
lib.rs

1use std::fmt;
2
3use jiff::Timestamp;
4use owo_colors::OwoColorize;
5use tracing::{Event, Subscriber};
6use tracing_subscriber::fmt::format::Writer;
7use tracing_subscriber::fmt::{FmtContext, FormatEvent, FormatFields};
8use tracing_subscriber::registry::LookupSpan;
9
10/// The style of a uv logging line.
11pub struct UvFormat {
12    pub display_timestamp: bool,
13    pub display_level: bool,
14    pub show_spans: bool,
15}
16
17impl Default for UvFormat {
18    /// Regardless of the tracing level, show messages without any adornment.
19    fn default() -> Self {
20        Self {
21            display_timestamp: false,
22            display_level: true,
23            show_spans: false,
24        }
25    }
26}
27
28/// See <https://docs.rs/tracing-subscriber/0.3.18/src/tracing_subscriber/fmt/format/mod.rs.html#1026-1156>
29impl<S, N> FormatEvent<S, N> for UvFormat
30where
31    S: Subscriber + for<'a> LookupSpan<'a>,
32    N: for<'a> FormatFields<'a> + 'static,
33{
34    fn format_event(
35        &self,
36        ctx: &FmtContext<'_, S, N>,
37        mut writer: Writer<'_>,
38        event: &Event<'_>,
39    ) -> fmt::Result {
40        let meta = event.metadata();
41        let ansi = writer.has_ansi_escapes();
42
43        if self.display_timestamp {
44            if ansi {
45                write!(writer, "{} ", Timestamp::now().dimmed())?;
46            } else {
47                write!(writer, "{} ", Timestamp::now())?;
48            }
49        }
50
51        if self.display_level {
52            let level = meta.level();
53            // Same colors as tracing
54            if ansi {
55                match *level {
56                    tracing::Level::TRACE => write!(writer, "{} ", level.purple())?,
57                    tracing::Level::DEBUG => write!(writer, "{} ", level.blue())?,
58                    tracing::Level::INFO => write!(writer, "{} ", level.green())?,
59                    tracing::Level::WARN => write!(writer, "{} ", level.yellow())?,
60                    tracing::Level::ERROR => write!(writer, "{} ", level.red())?,
61                }
62            } else {
63                write!(writer, "{level} ")?;
64            }
65        }
66
67        if self.show_spans {
68            let span = event.parent();
69            let mut seen = false;
70
71            let span = span
72                .and_then(|id| ctx.span(id))
73                .or_else(|| ctx.lookup_current());
74
75            let scope = span.into_iter().flat_map(|span| span.scope().from_root());
76
77            for span in scope {
78                seen = true;
79                if ansi {
80                    write!(writer, "{}:", span.metadata().name().bold())?;
81                } else {
82                    write!(writer, "{}:", span.metadata().name())?;
83                }
84            }
85
86            if seen {
87                writer.write_char(' ')?;
88            }
89        }
90
91        ctx.field_format().format_fields(writer.by_ref(), event)?;
92
93        writeln!(writer)
94    }
95}