tracing_glog/
format.rs

1#[cfg(feature = "ansi")]
2use nu_ansi_term::{Color, Style};
3use std::fmt;
4use tracing::{Level, Metadata};
5use tracing_subscriber::fmt::{format::Writer, time::FormatTime};
6
7use tracing_subscriber::fmt::time::{ChronoLocal, ChronoUtc};
8
9pub(crate) struct FmtLevel {
10    pub level: Level,
11    #[cfg(feature = "ansi")]
12    pub ansi: bool,
13}
14
15impl FmtLevel {
16    const TRACE_STR: &'static str = "T";
17    const DEBUG_STR: &'static str = "D";
18    const INFO_STR: &'static str = "I";
19    const WARN_STR: &'static str = "W";
20    const ERROR_STR: &'static str = "E";
21
22    pub(crate) fn format_level(level: Level, ansi: bool) -> FmtLevel {
23        #[cfg(not(feature = "ansi"))]
24        let _ = ansi;
25        FmtLevel {
26            level,
27            #[cfg(feature = "ansi")]
28            ansi,
29        }
30    }
31}
32
33impl fmt::Display for FmtLevel {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        #[cfg(feature = "ansi")]
36        if self.ansi {
37            return match self.level {
38                Level::TRACE => write!(f, "{}", Color::Purple.paint(Self::TRACE_STR)),
39                Level::DEBUG => write!(f, "{}", Color::Blue.paint(Self::DEBUG_STR)),
40                Level::INFO => write!(f, "{}", Color::Green.paint(Self::INFO_STR)),
41                Level::WARN => write!(f, "{}", Color::Yellow.paint(Self::WARN_STR)),
42                Level::ERROR => write!(f, "{}", Color::Red.paint(Self::ERROR_STR)),
43            };
44        }
45        match self.level {
46            Level::TRACE => f.pad(Self::TRACE_STR),
47            Level::DEBUG => f.pad(Self::DEBUG_STR),
48            Level::INFO => f.pad(Self::INFO_STR),
49            Level::WARN => f.pad(Self::WARN_STR),
50            Level::ERROR => f.pad(Self::ERROR_STR),
51        }
52    }
53}
54
55/// Formats the current [UTC time] using [`chrono` crate].
56///
57/// To format the current local time instead, use the [`LocalTime`]
58/// or the [`LocalTime`] type.
59///
60/// [UTC time]: ChronoUtc
61/// [`chrono` crate]: chrono
62#[derive(Clone, Debug)]
63pub struct UtcTime {
64    time: ChronoUtc,
65}
66
67impl FormatTime for UtcTime {
68    fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
69        #[cfg(feature = "ansi")]
70        if w.has_ansi_escapes() {
71            let style = Style::new().dimmed();
72            write!(w, "{}", style.prefix())?;
73            self.time.format_time(w)?;
74            write!(w, "{}", style.suffix())?;
75            return Ok(());
76        }
77
78        self.time.format_time(w)
79    }
80}
81
82impl Default for UtcTime {
83    fn default() -> Self {
84        let fmt_string = String::from("%m%d %H:%M:%S%.6f");
85        Self {
86            time: ChronoUtc::new(fmt_string),
87        }
88    }
89}
90
91/// Formats the current [`local time`] using [`chrono` crate].
92///
93/// To format the UTC time instead, use the [`UtcTime`]
94/// or the [`crate::time_crate::UtcTime`] type.
95///
96/// [`local time`]: tracing_subscriber::fmt::time::ChronoLocal
97/// [`chrono` crate]: chrono
98pub struct LocalTime {
99    time: ChronoLocal,
100}
101
102impl FormatTime for LocalTime {
103    fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
104        #[cfg(feature = "ansi")]
105        if w.has_ansi_escapes() {
106            let style = Style::new().dimmed();
107            write!(w, "{}", style.prefix())?;
108            self.time.format_time(w)?;
109            write!(w, "{}", style.suffix())?;
110            return Ok(());
111        }
112
113        self.time.format_time(w)
114    }
115}
116
117impl Default for LocalTime {
118    fn default() -> Self {
119        let fmt_string = String::from("%m%d %H:%M:%S%.6f");
120        Self {
121            time: ChronoLocal::new(fmt_string),
122        }
123    }
124}
125
126pub(crate) struct FormatProcessData<'a> {
127    pub(crate) pid: u32,
128    pub(crate) thread_name: Option<&'a str>,
129    pub(crate) with_thread_names: bool,
130    pub(crate) metadata: &'a Metadata<'a>,
131    pub(crate) with_target: bool,
132    #[cfg(feature = "ansi")]
133    pub(crate) ansi: bool,
134}
135
136impl<'a> fmt::Display for FormatProcessData<'a> {
137    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138        let thread_name = self.thread_name;
139        let target = self.metadata.target();
140        let file = self.metadata.file().unwrap_or("");
141        let line = match self.metadata.line() {
142            Some(line) => format!("{}", line),
143            None => String::new(),
144        };
145        // write the always unstyled PID
146        write!(f, " {pid:>5}", pid = self.pid)?;
147
148        #[cfg(feature = "ansi")]
149        if self.ansi {
150            let style = Style::new().bold();
151            // start by bolding all the expected data
152            write!(f, "{}", style.prefix())?;
153            if let Some(name) = thread_name {
154                if self.with_thread_names {
155                    write!(f, " {}", name)?
156                }
157            }
158
159            if self.with_target {
160                write!(f, " [{}]", target)?;
161            }
162
163            write!(f, " {file}:{line}", file = file, line = line)?;
164
165            // end bolding
166            write!(f, "{}", style.suffix())?;
167
168            return Ok(());
169        }
170        if let Some(name) = thread_name {
171            if self.with_thread_names {
172                write!(f, " {}", name)?
173            }
174        }
175
176        if self.with_target {
177            write!(f, " [{}]", target)?;
178        }
179
180        write!(f, " {file}:{line}", file = file, line = line)?;
181        Ok(())
182    }
183}
184
185/// Docs!
186pub(crate) struct FormatSpanFields<'a> {
187    span_name: &'static str,
188    fields: Option<&'a str>,
189    #[cfg(feature = "ansi")]
190    pub ansi: bool,
191    print_span_names: bool,
192}
193
194impl<'a> FormatSpanFields<'a> {
195    pub(crate) fn format_fields(
196        span_name: &'static str,
197        fields: Option<&'a str>,
198        ansi: bool,
199        print_span_names: bool,
200    ) -> Self {
201        #[cfg(not(feature = "ansi"))]
202        let _ = ansi;
203        Self {
204            span_name,
205            fields,
206            #[cfg(feature = "ansi")]
207            ansi,
208            print_span_names,
209        }
210    }
211}
212
213impl<'a> fmt::Display for FormatSpanFields<'a> {
214    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215        #[cfg(feature = "ansi")]
216        if self.ansi {
217            let bold = Style::new().bold();
218
219            if self.print_span_names {
220                write!(f, "{}", bold.paint(self.span_name))?;
221            }
222
223            let italic = Style::new().italic();
224            if let Some(fields) = self.fields {
225                if self.print_span_names {
226                    write!(f, "{{{}}}", italic.paint(fields))?;
227                } else {
228                    write!(f, "{}", italic.paint(fields))?;
229                }
230            };
231            return Ok(());
232        }
233
234        if self.print_span_names {
235            write!(f, "{}", self.span_name)?;
236        }
237        if let Some(fields) = self.fields {
238            if self.print_span_names {
239                write!(f, "{{{}}}", fields)?;
240            } else {
241                write!(f, "{}", fields)?;
242            }
243        };
244
245        Ok(())
246    }
247}