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 struct FormatLevelChars {
10 pub trace: &'static str,
11 pub debug: &'static str,
12 pub info: &'static str,
13 pub warn: &'static str,
14 pub error: &'static str,
15}
16
17impl FormatLevelChars {
18 pub const fn const_default() -> FormatLevelChars {
19 FormatLevelChars {
20 trace: "T",
21 debug: "D",
22 info: "I",
23 warn: "W",
24 error: "E",
25 }
26 }
27}
28
29impl Default for FormatLevelChars {
30 fn default() -> FormatLevelChars {
31 FormatLevelChars::const_default()
32 }
33}
34
35pub(crate) const DEFAULT_FORMAT_LEVEL_CHARS: FormatLevelChars = FormatLevelChars::const_default();
36
37pub(crate) struct FmtLevel {
38 pub level: Level,
39 pub chars: &'static FormatLevelChars,
40 #[cfg(feature = "ansi")]
41 pub ansi: bool,
42}
43
44impl FmtLevel {
45 pub(crate) fn format_level(
46 level: Level,
47 chars: &'static FormatLevelChars,
48 ansi: bool,
49 ) -> FmtLevel {
50 #[cfg(not(feature = "ansi"))]
51 let _ = ansi;
52 FmtLevel {
53 level,
54 chars,
55 #[cfg(feature = "ansi")]
56 ansi,
57 }
58 }
59}
60
61impl fmt::Display for FmtLevel {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 let chars = self.chars;
64 #[cfg(feature = "ansi")]
65 if self.ansi {
66 return match self.level {
67 Level::TRACE => write!(f, "{}", Color::Purple.paint(chars.trace)),
68 Level::DEBUG => write!(f, "{}", Color::Blue.paint(chars.debug)),
69 Level::INFO => write!(f, "{}", Color::Green.paint(chars.info)),
70 Level::WARN => write!(f, "{}", Color::Yellow.paint(chars.warn)),
71 Level::ERROR => write!(f, "{}", Color::Red.paint(chars.error)),
72 };
73 }
74 match self.level {
75 Level::TRACE => f.pad(chars.trace),
76 Level::DEBUG => f.pad(chars.debug),
77 Level::INFO => f.pad(chars.info),
78 Level::WARN => f.pad(chars.warn),
79 Level::ERROR => f.pad(chars.error),
80 }
81 }
82}
83
84#[derive(Clone, Debug)]
92pub struct UtcTime {
93 time: ChronoUtc,
94}
95
96impl FormatTime for UtcTime {
97 fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
98 #[cfg(feature = "ansi")]
99 if w.has_ansi_escapes() {
100 let style = Style::new().dimmed();
101 write!(w, "{}", style.prefix())?;
102 self.time.format_time(w)?;
103 write!(w, "{}", style.suffix())?;
104 return Ok(());
105 }
106
107 self.time.format_time(w)
108 }
109}
110
111impl Default for UtcTime {
112 fn default() -> Self {
113 let fmt_string = String::from("%m%d %H:%M:%S%.6f");
114 Self {
115 time: ChronoUtc::new(fmt_string),
116 }
117 }
118}
119
120pub struct LocalTime {
128 time: ChronoLocal,
129}
130
131impl FormatTime for LocalTime {
132 fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
133 #[cfg(feature = "ansi")]
134 if w.has_ansi_escapes() {
135 let style = Style::new().dimmed();
136 write!(w, "{}", style.prefix())?;
137 self.time.format_time(w)?;
138 write!(w, "{}", style.suffix())?;
139 return Ok(());
140 }
141
142 self.time.format_time(w)
143 }
144}
145
146impl Default for LocalTime {
147 fn default() -> Self {
148 let fmt_string = String::from("%m%d %H:%M:%S%.6f");
149 Self {
150 time: ChronoLocal::new(fmt_string),
151 }
152 }
153}
154
155pub(crate) struct FormatProcessData<'a> {
156 pub(crate) pid: u32,
157 pub(crate) thread_name: Option<&'a str>,
158 pub(crate) with_thread_names: bool,
159 pub(crate) metadata: &'a Metadata<'a>,
160 pub(crate) with_target: bool,
161 #[cfg(feature = "ansi")]
162 pub(crate) ansi: bool,
163}
164
165impl<'a> fmt::Display for FormatProcessData<'a> {
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 let thread_name = self.thread_name;
168 let target = self.metadata.target();
169 let file = self.metadata.file().unwrap_or("");
170 let line = match self.metadata.line() {
171 Some(line) => format!("{line}"),
172 None => String::new(),
173 };
174 write!(f, " {pid:>5}", pid = self.pid)?;
176
177 #[cfg(feature = "ansi")]
178 if self.ansi {
179 let style = Style::new().bold();
180 write!(f, "{}", style.prefix())?;
182 if let Some(name) = thread_name {
183 if self.with_thread_names {
184 write!(f, " {name}")?
185 }
186 }
187
188 if self.with_target {
189 write!(f, " [{target}]")?;
190 }
191
192 write!(f, " {file}:{line}")?;
193
194 write!(f, "{}", style.suffix())?;
196
197 return Ok(());
198 }
199 if let Some(name) = thread_name {
200 if self.with_thread_names {
201 write!(f, " {name}")?
202 }
203 }
204
205 if self.with_target {
206 write!(f, " [{target}]")?;
207 }
208
209 write!(f, " {file}:{line}")?;
210 Ok(())
211 }
212}
213
214pub(crate) struct FormatSpanFields<'a> {
216 span_name: &'static str,
217 fields: Option<&'a str>,
218 #[cfg(feature = "ansi")]
219 pub ansi: bool,
220 print_span_names: bool,
221}
222
223impl<'a> FormatSpanFields<'a> {
224 pub(crate) fn format_fields(
225 span_name: &'static str,
226 fields: Option<&'a str>,
227 ansi: bool,
228 print_span_names: bool,
229 ) -> Self {
230 #[cfg(not(feature = "ansi"))]
231 let _ = ansi;
232 Self {
233 span_name,
234 fields,
235 #[cfg(feature = "ansi")]
236 ansi,
237 print_span_names,
238 }
239 }
240}
241
242impl<'a> fmt::Display for FormatSpanFields<'a> {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 #[cfg(feature = "ansi")]
245 if self.ansi {
246 let bold = Style::new().bold();
247
248 if self.print_span_names {
249 write!(f, "{}", bold.paint(self.span_name))?;
250 }
251
252 let italic = Style::new().italic();
253 if let Some(fields) = self.fields {
254 if self.print_span_names {
255 write!(f, "{{{}}}", italic.paint(fields))?;
256 } else {
257 write!(f, "{}", italic.paint(fields))?;
258 }
259 };
260 return Ok(());
261 }
262
263 if self.print_span_names {
264 write!(f, "{}", self.span_name)?;
265 }
266 if let Some(fields) = self.fields {
267 if self.print_span_names {
268 write!(f, "{{{fields}}}")?;
269 } else {
270 write!(f, "{fields}")?;
271 }
272 };
273
274 Ok(())
275 }
276}