• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::*;
2 use crate::{
3     field::{VisitFmt, VisitOutput},
4     fmt::fmt_layer::{FmtContext, FormattedFields},
5     registry::LookupSpan,
6 };
7 
8 use std::fmt;
9 use tracing_core::{
10     field::{self, Field},
11     Event, Level, Subscriber,
12 };
13 
14 #[cfg(feature = "tracing-log")]
15 use tracing_log::NormalizeEvent;
16 
17 use ansi_term::{Colour, Style};
18 
19 /// An excessively pretty, human-readable event formatter.
20 ///
21 /// Unlike the [`Full`], [`Compact`], and [`Json`] formatters, this is a
22 /// multi-line output format. Each individual event may output multiple lines of
23 /// text.
24 ///
25 /// # Example Output
26 ///
27 /// <pre><font color="#4E9A06"><b>:;</b></font> <font color="#4E9A06">cargo</font> run --example fmt-pretty
28 /// <font color="#4E9A06"><b>    Finished</b></font> dev [unoptimized + debuginfo] target(s) in 0.08s
29 /// <font color="#4E9A06"><b>     Running</b></font> `target/debug/examples/fmt-pretty`
30 ///   2022-02-15T18:44:24.535324Z <font color="#4E9A06"> INFO</font> <font color="#4E9A06"><b>fmt_pretty</b></font><font color="#4E9A06">: preparing to shave yaks, </font><font color="#4E9A06"><b>number_of_yaks</b></font><font color="#4E9A06">: 3</font>
31 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt-pretty.rs:16 <font color="#AAAAAA"><i>on</i></font> main
32 ///
33 ///   2022-02-15T18:44:24.535403Z <font color="#4E9A06"> INFO</font> <font color="#4E9A06"><b>fmt_pretty::yak_shave</b></font><font color="#4E9A06">: shaving yaks</font>
34 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:41 <font color="#AAAAAA"><i>on</i></font> main
35 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
36 ///
37 ///   2022-02-15T18:44:24.535442Z <font color="#75507B">TRACE</font> <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: hello! I&apos;m gonna shave a yak, </font><font color="#75507B"><b>excitement</b></font><font color="#75507B">: &quot;yay!&quot;</font>
38 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:16 <font color="#AAAAAA"><i>on</i></font> main
39 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 1
40 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
41 ///
42 ///   2022-02-15T18:44:24.535469Z <font color="#75507B">TRACE</font> <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: yak shaved successfully</font>
43 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:25 <font color="#AAAAAA"><i>on</i></font> main
44 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 1
45 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
46 ///
47 ///   2022-02-15T18:44:24.535502Z <font color="#3465A4">DEBUG</font> <font color="#3465A4"><b>yak_events</b></font><font color="#3465A4">: </font><font color="#3465A4"><b>yak</b></font><font color="#3465A4">: 1, </font><font color="#3465A4"><b>shaved</b></font><font color="#3465A4">: true</font>
48 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:46 <font color="#AAAAAA"><i>on</i></font> main
49 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
50 ///
51 ///   2022-02-15T18:44:24.535524Z <font color="#75507B">TRACE</font> <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: </font><font color="#75507B"><b>yaks_shaved</b></font><font color="#75507B">: 1</font>
52 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:55 <font color="#AAAAAA"><i>on</i></font> main
53 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
54 ///
55 ///   2022-02-15T18:44:24.535551Z <font color="#75507B">TRACE</font> <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: hello! I&apos;m gonna shave a yak, </font><font color="#75507B"><b>excitement</b></font><font color="#75507B">: &quot;yay!&quot;</font>
56 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:16 <font color="#AAAAAA"><i>on</i></font> main
57 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 2
58 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
59 ///
60 ///   2022-02-15T18:44:24.535573Z <font color="#75507B">TRACE</font> <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: yak shaved successfully</font>
61 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:25 <font color="#AAAAAA"><i>on</i></font> main
62 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 2
63 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
64 ///
65 ///   2022-02-15T18:44:24.535600Z <font color="#3465A4">DEBUG</font> <font color="#3465A4"><b>yak_events</b></font><font color="#3465A4">: </font><font color="#3465A4"><b>yak</b></font><font color="#3465A4">: 2, </font><font color="#3465A4"><b>shaved</b></font><font color="#3465A4">: true</font>
66 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:46 <font color="#AAAAAA"><i>on</i></font> main
67 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
68 ///
69 ///   2022-02-15T18:44:24.535618Z <font color="#75507B">TRACE</font> <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: </font><font color="#75507B"><b>yaks_shaved</b></font><font color="#75507B">: 2</font>
70 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:55 <font color="#AAAAAA"><i>on</i></font> main
71 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
72 ///
73 ///   2022-02-15T18:44:24.535644Z <font color="#75507B">TRACE</font> <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: hello! I&apos;m gonna shave a yak, </font><font color="#75507B"><b>excitement</b></font><font color="#75507B">: &quot;yay!&quot;</font>
74 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:16 <font color="#AAAAAA"><i>on</i></font> main
75 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 3
76 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
77 ///
78 ///   2022-02-15T18:44:24.535670Z <font color="#C4A000"> WARN</font> <font color="#C4A000"><b>fmt_pretty::yak_shave</b></font><font color="#C4A000">: could not locate yak</font>
79 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:18 <font color="#AAAAAA"><i>on</i></font> main
80 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shave</b> <font color="#AAAAAA"><i>with</i></font> <b>yak</b>: 3
81 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
82 ///
83 ///   2022-02-15T18:44:24.535698Z <font color="#3465A4">DEBUG</font> <font color="#3465A4"><b>yak_events</b></font><font color="#3465A4">: </font><font color="#3465A4"><b>yak</b></font><font color="#3465A4">: 3, </font><font color="#3465A4"><b>shaved</b></font><font color="#3465A4">: false</font>
84 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:46 <font color="#AAAAAA"><i>on</i></font> main
85 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
86 ///
87 ///   2022-02-15T18:44:24.535720Z <font color="#CC0000">ERROR</font> <font color="#CC0000"><b>fmt_pretty::yak_shave</b></font><font color="#CC0000">: failed to shave yak, </font><font color="#CC0000"><b>yak</b></font><font color="#CC0000">: 3, </font><font color="#CC0000"><b>error</b></font><font color="#CC0000">: missing yak, </font><font color="#CC0000"><b>error.sources</b></font><font color="#CC0000">: [out of space, out of cash]</font>
88 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:51 <font color="#AAAAAA"><i>on</i></font> main
89 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
90 ///
91 ///   2022-02-15T18:44:24.535742Z <font color="#75507B">TRACE</font> <font color="#75507B"><b>fmt_pretty::yak_shave</b></font><font color="#75507B">: </font><font color="#75507B"><b>yaks_shaved</b></font><font color="#75507B">: 2</font>
92 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt/yak_shave.rs:55 <font color="#AAAAAA"><i>on</i></font> main
93 ///     <font color="#AAAAAA"><i>in</i></font> fmt_pretty::yak_shave::<b>shaving_yaks</b> <font color="#AAAAAA"><i>with</i></font> <b>yaks</b>: 3
94 ///
95 ///   2022-02-15T18:44:24.535765Z <font color="#4E9A06"> INFO</font> <font color="#4E9A06"><b>fmt_pretty</b></font><font color="#4E9A06">: yak shaving completed, </font><font color="#4E9A06"><b>all_yaks_shaved</b></font><font color="#4E9A06">: false</font>
96 ///     <font color="#AAAAAA"><i>at</i></font> examples/examples/fmt-pretty.rs:19 <font color="#AAAAAA"><i>on</i></font> main
97 /// </pre>
98 #[derive(Debug, Clone, Eq, PartialEq)]
99 pub struct Pretty {
100     display_location: bool,
101 }
102 
103 /// The [visitor] produced by [`Pretty`]'s [`MakeVisitor`] implementation.
104 ///
105 /// [visitor]: field::Visit
106 /// [`MakeVisitor`]: crate::field::MakeVisitor
107 #[derive(Debug)]
108 pub struct PrettyVisitor<'a> {
109     writer: Writer<'a>,
110     is_empty: bool,
111     style: Style,
112     result: fmt::Result,
113 }
114 
115 /// An excessively pretty, human-readable [`MakeVisitor`] implementation.
116 ///
117 /// [`MakeVisitor`]: crate::field::MakeVisitor
118 #[derive(Debug)]
119 pub struct PrettyFields {
120     /// A value to override the provided `Writer`'s ANSI formatting
121     /// configuration.
122     ///
123     /// If this is `Some`, we override the `Writer`'s ANSI setting. This is
124     /// necessary in order to continue supporting the deprecated
125     /// `PrettyFields::with_ansi` method. If it is `None`, we don't override the
126     /// ANSI formatting configuration (because the deprecated method was not
127     /// called).
128     // TODO: when `PrettyFields::with_ansi` is removed, we can get rid
129     // of this entirely.
130     ansi: Option<bool>,
131 }
132 
133 // === impl Pretty ===
134 
135 impl Default for Pretty {
default() -> Self136     fn default() -> Self {
137         Self {
138             display_location: true,
139         }
140     }
141 }
142 
143 impl Pretty {
style_for(level: &Level) -> Style144     fn style_for(level: &Level) -> Style {
145         match *level {
146             Level::TRACE => Style::new().fg(Colour::Purple),
147             Level::DEBUG => Style::new().fg(Colour::Blue),
148             Level::INFO => Style::new().fg(Colour::Green),
149             Level::WARN => Style::new().fg(Colour::Yellow),
150             Level::ERROR => Style::new().fg(Colour::Red),
151         }
152     }
153 
154     /// Sets whether the event's source code location is displayed.
155     ///
156     /// This defaults to `true`.
157     #[deprecated(
158         since = "0.3.6",
159         note = "all formatters now support configurable source locations. Use `Format::with_source_location` instead."
160     )]
with_source_location(self, display_location: bool) -> Self161     pub fn with_source_location(self, display_location: bool) -> Self {
162         Self {
163             display_location,
164             ..self
165         }
166     }
167 }
168 
169 impl<C, N, T> FormatEvent<C, N> for Format<Pretty, T>
170 where
171     C: Subscriber + for<'a> LookupSpan<'a>,
172     N: for<'a> FormatFields<'a> + 'static,
173     T: FormatTime,
174 {
format_event( &self, ctx: &FmtContext<'_, C, N>, mut writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result175     fn format_event(
176         &self,
177         ctx: &FmtContext<'_, C, N>,
178         mut writer: Writer<'_>,
179         event: &Event<'_>,
180     ) -> fmt::Result {
181         #[cfg(feature = "tracing-log")]
182         let normalized_meta = event.normalized_metadata();
183         #[cfg(feature = "tracing-log")]
184         let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
185         #[cfg(not(feature = "tracing-log"))]
186         let meta = event.metadata();
187         write!(&mut writer, "  ")?;
188 
189         // if the `Format` struct *also* has an ANSI color configuration,
190         // override the writer...the API for configuring ANSI color codes on the
191         // `Format` struct is deprecated, but we still need to honor those
192         // configurations.
193         if let Some(ansi) = self.ansi {
194             writer = writer.with_ansi(ansi);
195         }
196 
197         self.format_timestamp(&mut writer)?;
198 
199         let style = if self.display_level && writer.has_ansi_escapes() {
200             Pretty::style_for(meta.level())
201         } else {
202             Style::new()
203         };
204 
205         if self.display_level {
206             write!(
207                 writer,
208                 "{} ",
209                 super::FmtLevel::new(meta.level(), writer.has_ansi_escapes())
210             )?;
211         }
212 
213         if self.display_target {
214             let target_style = if writer.has_ansi_escapes() {
215                 style.bold()
216             } else {
217                 style
218             };
219             write!(
220                 writer,
221                 "{}{}{}:",
222                 target_style.prefix(),
223                 meta.target(),
224                 target_style.infix(style)
225             )?;
226         }
227         let line_number = if self.display_line_number {
228             meta.line()
229         } else {
230             None
231         };
232 
233         // If the file name is disabled, format the line number right after the
234         // target. Otherwise, if we also display the file, it'll go on a
235         // separate line.
236         if let (Some(line_number), false, true) = (
237             line_number,
238             self.display_filename,
239             self.format.display_location,
240         ) {
241             write!(
242                 writer,
243                 "{}{}{}:",
244                 style.prefix(),
245                 line_number,
246                 style.infix(style)
247             )?;
248         }
249 
250         writer.write_char(' ')?;
251 
252         let mut v = PrettyVisitor::new(writer.by_ref(), true).with_style(style);
253         event.record(&mut v);
254         v.finish()?;
255         writer.write_char('\n')?;
256 
257         let dimmed = if writer.has_ansi_escapes() {
258             Style::new().dimmed().italic()
259         } else {
260             Style::new()
261         };
262         let thread = self.display_thread_name || self.display_thread_id;
263 
264         if let (Some(file), true, true) = (
265             meta.file(),
266             self.format.display_location,
267             self.display_filename,
268         ) {
269             write!(writer, "    {} {}", dimmed.paint("at"), file,)?;
270 
271             if let Some(line) = line_number {
272                 write!(writer, ":{}", line)?;
273             }
274             writer.write_char(if thread { ' ' } else { '\n' })?;
275         } else if thread {
276             write!(writer, "    ")?;
277         };
278 
279         if thread {
280             write!(writer, "{} ", dimmed.paint("on"))?;
281             let thread = std::thread::current();
282             if self.display_thread_name {
283                 if let Some(name) = thread.name() {
284                     write!(writer, "{}", name)?;
285                     if self.display_thread_id {
286                         writer.write_char(' ')?;
287                     }
288                 }
289             }
290             if self.display_thread_id {
291                 write!(writer, "{:?}", thread.id())?;
292             }
293             writer.write_char('\n')?;
294         }
295 
296         let bold = writer.bold();
297         let span = event
298             .parent()
299             .and_then(|id| ctx.span(id))
300             .or_else(|| ctx.lookup_current());
301 
302         let scope = span.into_iter().flat_map(|span| span.scope());
303 
304         for span in scope {
305             let meta = span.metadata();
306             if self.display_target {
307                 write!(
308                     writer,
309                     "    {} {}::{}",
310                     dimmed.paint("in"),
311                     meta.target(),
312                     bold.paint(meta.name()),
313                 )?;
314             } else {
315                 write!(
316                     writer,
317                     "    {} {}",
318                     dimmed.paint("in"),
319                     bold.paint(meta.name()),
320                 )?;
321             }
322 
323             let ext = span.extensions();
324             let fields = &ext
325                 .get::<FormattedFields<N>>()
326                 .expect("Unable to find FormattedFields in extensions; this is a bug");
327             if !fields.is_empty() {
328                 write!(writer, " {} {}", dimmed.paint("with"), fields)?;
329             }
330             writer.write_char('\n')?;
331         }
332 
333         writer.write_char('\n')
334     }
335 }
336 
337 impl<'writer> FormatFields<'writer> for Pretty {
format_fields<R: RecordFields>(&self, writer: Writer<'writer>, fields: R) -> fmt::Result338     fn format_fields<R: RecordFields>(&self, writer: Writer<'writer>, fields: R) -> fmt::Result {
339         let mut v = PrettyVisitor::new(writer, true);
340         fields.record(&mut v);
341         v.finish()
342     }
343 
add_fields( &self, current: &'writer mut FormattedFields<Self>, fields: &span::Record<'_>, ) -> fmt::Result344     fn add_fields(
345         &self,
346         current: &'writer mut FormattedFields<Self>,
347         fields: &span::Record<'_>,
348     ) -> fmt::Result {
349         let empty = current.is_empty();
350         let writer = current.as_writer();
351         let mut v = PrettyVisitor::new(writer, empty);
352         fields.record(&mut v);
353         v.finish()
354     }
355 }
356 
357 // === impl PrettyFields ===
358 
359 impl Default for PrettyFields {
default() -> Self360     fn default() -> Self {
361         Self::new()
362     }
363 }
364 
365 impl PrettyFields {
366     /// Returns a new default [`PrettyFields`] implementation.
new() -> Self367     pub fn new() -> Self {
368         // By default, don't override the `Writer`'s ANSI colors
369         // configuration. We'll only do this if the user calls the
370         // deprecated `PrettyFields::with_ansi` method.
371         Self { ansi: None }
372     }
373 
374     /// Enable ANSI encoding for formatted fields.
375     #[deprecated(
376         since = "0.3.3",
377         note = "Use `fmt::Subscriber::with_ansi` or `fmt::Layer::with_ansi` instead."
378     )]
with_ansi(self, ansi: bool) -> Self379     pub fn with_ansi(self, ansi: bool) -> Self {
380         Self {
381             ansi: Some(ansi),
382             ..self
383         }
384     }
385 }
386 
387 impl<'a> MakeVisitor<Writer<'a>> for PrettyFields {
388     type Visitor = PrettyVisitor<'a>;
389 
390     #[inline]
make_visitor(&self, mut target: Writer<'a>) -> Self::Visitor391     fn make_visitor(&self, mut target: Writer<'a>) -> Self::Visitor {
392         if let Some(ansi) = self.ansi {
393             target = target.with_ansi(ansi);
394         }
395         PrettyVisitor::new(target, true)
396     }
397 }
398 
399 // === impl PrettyVisitor ===
400 
401 impl<'a> PrettyVisitor<'a> {
402     /// Returns a new default visitor that formats to the provided `writer`.
403     ///
404     /// # Arguments
405     /// - `writer`: the writer to format to.
406     /// - `is_empty`: whether or not any fields have been previously written to
407     ///   that writer.
new(writer: Writer<'a>, is_empty: bool) -> Self408     pub fn new(writer: Writer<'a>, is_empty: bool) -> Self {
409         Self {
410             writer,
411             is_empty,
412             style: Style::default(),
413             result: Ok(()),
414         }
415     }
416 
with_style(self, style: Style) -> Self417     pub(crate) fn with_style(self, style: Style) -> Self {
418         Self { style, ..self }
419     }
420 
write_padded(&mut self, value: &impl fmt::Debug)421     fn write_padded(&mut self, value: &impl fmt::Debug) {
422         let padding = if self.is_empty {
423             self.is_empty = false;
424             ""
425         } else {
426             ", "
427         };
428         self.result = write!(self.writer, "{}{:?}", padding, value);
429     }
430 
bold(&self) -> Style431     fn bold(&self) -> Style {
432         if self.writer.has_ansi_escapes() {
433             self.style.bold()
434         } else {
435             Style::new()
436         }
437     }
438 }
439 
440 impl<'a> field::Visit for PrettyVisitor<'a> {
record_str(&mut self, field: &Field, value: &str)441     fn record_str(&mut self, field: &Field, value: &str) {
442         if self.result.is_err() {
443             return;
444         }
445 
446         if field.name() == "message" {
447             self.record_debug(field, &format_args!("{}", value))
448         } else {
449             self.record_debug(field, &value)
450         }
451     }
452 
record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static))453     fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
454         if let Some(source) = value.source() {
455             let bold = self.bold();
456             self.record_debug(
457                 field,
458                 &format_args!(
459                     "{}, {}{}.sources{}: {}",
460                     value,
461                     bold.prefix(),
462                     field,
463                     bold.infix(self.style),
464                     ErrorSourceList(source),
465                 ),
466             )
467         } else {
468             self.record_debug(field, &format_args!("{}", value))
469         }
470     }
471 
record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)472     fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
473         if self.result.is_err() {
474             return;
475         }
476         let bold = self.bold();
477         match field.name() {
478             "message" => self.write_padded(&format_args!("{}{:?}", self.style.prefix(), value,)),
479             // Skip fields that are actually log metadata that have already been handled
480             #[cfg(feature = "tracing-log")]
481             name if name.starts_with("log.") => self.result = Ok(()),
482             name if name.starts_with("r#") => self.write_padded(&format_args!(
483                 "{}{}{}: {:?}",
484                 bold.prefix(),
485                 &name[2..],
486                 bold.infix(self.style),
487                 value
488             )),
489             name => self.write_padded(&format_args!(
490                 "{}{}{}: {:?}",
491                 bold.prefix(),
492                 name,
493                 bold.infix(self.style),
494                 value
495             )),
496         };
497     }
498 }
499 
500 impl<'a> VisitOutput<fmt::Result> for PrettyVisitor<'a> {
finish(mut self) -> fmt::Result501     fn finish(mut self) -> fmt::Result {
502         write!(&mut self.writer, "{}", self.style.suffix())?;
503         self.result
504     }
505 }
506 
507 impl<'a> VisitFmt for PrettyVisitor<'a> {
writer(&mut self) -> &mut dyn fmt::Write508     fn writer(&mut self) -> &mut dyn fmt::Write {
509         &mut self.writer
510     }
511 }
512