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#[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
91pub 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!(f, " {pid:>5}", pid = self.pid)?;
147
148 #[cfg(feature = "ansi")]
149 if self.ansi {
150 let style = Style::new().bold();
151 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 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
185pub(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}