3 field
::{VisitFmt, VisitOutput}
,
4 fmt
::fmt_layer
::{FmtContext, FormattedFields}
,
14 Event
, Level
, Subscriber
,
17 #[cfg(feature = "tracing-log")]
18 use tracing_log
::NormalizeEvent
;
20 use ansi_term
::{Colour, Style}
;
22 /// An excessively pretty, human-readable event formatter.
23 #[derive(Debug, Clone, Eq, PartialEq)]
25 display_location
: bool
,
28 /// The [visitor] produced by [`Pretty`]'s [`MakeVisitor`] implementation.
30 /// [visitor]: ../../field/trait.Visit.html
31 /// [`DefaultFields`]: struct.DefaultFields.html
32 /// [`MakeVisitor`]: ../../field/trait.MakeVisitor.html
33 pub struct PrettyVisitor
<'a
> {
34 writer
: &'a
mut dyn Write
,
41 /// An excessively pretty, human-readable [`MakeVisitor`] implementation.
43 /// [`MakeVisitor`]: crate::field::MakeVisitor
45 pub struct PrettyFields
{
49 // === impl Pretty ===
51 impl Default
for Pretty
{
52 fn default() -> Self {
54 display_location
: true,
60 fn style_for(level
: &Level
) -> Style
{
62 Level
::TRACE
=> Style
::new().fg(Colour
::Purple
),
63 Level
::DEBUG
=> Style
::new().fg(Colour
::Blue
),
64 Level
::INFO
=> Style
::new().fg(Colour
::Green
),
65 Level
::WARN
=> Style
::new().fg(Colour
::Yellow
),
66 Level
::ERROR
=> Style
::new().fg(Colour
::Red
),
70 /// Sets whether the event's source code location is displayed.
72 /// This defaults to `true`.
73 pub fn with_source_location(self, display_location
: bool
) -> Self {
81 impl<T
> Format
<Pretty
, T
> {
82 /// Sets whether or not the source code location from which an event
83 /// originated is displayed.
85 /// This defaults to `true`.
86 pub fn with_source_location(mut self, display_location
: bool
) -> Self {
87 self.format
= self.format
.with_source_location(display_location
);
92 impl<C
, N
, T
> FormatEvent
<C
, N
> for Format
<Pretty
, T
>
94 C
: Subscriber
+ for<'a
> LookupSpan
<'a
>,
95 N
: for<'a
> FormatFields
<'a
> + '
static,
100 ctx
: &FmtContext
<'_
, C
, N
>,
101 writer
: &mut dyn fmt
::Write
,
104 #[cfg(feature = "tracing-log")]
105 let normalized_meta
= event
.normalized_metadata();
106 #[cfg(feature = "tracing-log")]
107 let meta
= normalized_meta
.as_ref().unwrap_or_else(|| event
.metadata());
108 #[cfg(not(feature = "tracing-log"))]
109 let meta
= event
.metadata();
110 write
!(writer
, " ")?
;
111 time
::write(&self.timer
, writer
, self.ansi
)?
;
113 let style
= if self.display_level
&& self.ansi
{
114 Pretty
::style_for(meta
.level())
119 if self.display_level
{
120 write
!(writer
, "{}", super::FmtLevel
::new(meta
.level(), self.ansi
))?
;
123 if self.display_target
{
124 let target_style
= if self.ansi { style.bold() }
else { style }
;
128 target_style
.prefix(),
130 target_style
.infix(style
)
133 let mut v
= PrettyVisitor
::new(writer
, true)
135 .with_ansi(self.ansi
);
136 event
.record(&mut v
);
138 writer
.write_char('
\n'
)?
;
140 let dimmed
= if self.ansi
{
141 Style
::new().dimmed().italic()
145 let thread
= self.display_thread_name
|| self.display_thread_id
;
146 if let (true, Some(file
), Some(line
)) =
147 (self.format
.display_location
, meta
.file(), meta
.line())
155 dimmed
.paint(if thread { " " }
else { "\n" }
)
158 write
!(writer
, " ")?
;
162 write
!(writer
, "{} ", dimmed
.paint("on"))?
;
163 let thread
= std
::thread
::current();
164 if self.display_thread_name
{
165 if let Some(name
) = thread
.name() {
166 write
!(writer
, "{}", name
)?
;
167 if self.display_thread_id
{
168 write
!(writer
, " ({:?})", thread
.id())?
;
170 } else if !self.display_thread_id
{
171 write
!(writer
, " {:?}", thread
.id())?
;
173 } else if self.display_thread_id
{
174 write
!(writer
, " {:?}", thread
.id())?
;
176 writer
.write_char('
\n'
)?
;
179 let bold
= if self.ansi
{
186 .and_then(|id
| ctx
.span(&id
))
187 .or_else(|| ctx
.lookup_current());
189 let scope
= span
.into_iter().flat_map(|span
| {
190 let parents
= span
.parents();
191 iter
::once(span
).chain(parents
)
195 let meta
= span
.metadata();
196 if self.display_target
{
202 bold
.paint(meta
.name()),
209 bold
.paint(meta
.name()),
213 let ext
= span
.extensions();
215 .get
::<FormattedFields
<N
>>()
216 .expect("Unable to find FormattedFields in extensions; this is a bug");
217 if !fields
.is_empty() {
218 write
!(writer
, " {} {}", dimmed
.paint("with"), fields
)?
;
220 writer
.write_char('
\n'
)?
;
223 writer
.write_char('
\n'
)
227 impl<'writer
> FormatFields
<'writer
> for Pretty
{
228 fn format_fields
<R
: RecordFields
>(
230 writer
: &'writer
mut dyn fmt
::Write
,
233 let mut v
= PrettyVisitor
::new(writer
, true);
234 fields
.record(&mut v
);
238 fn add_fields(&self, current
: &'writer
mut String
, fields
: &span
::Record
<'_
>) -> fmt
::Result
{
239 let empty
= current
.is_empty();
240 let mut v
= PrettyVisitor
::new(current
, empty
);
241 fields
.record(&mut v
);
246 // === impl PrettyFields ===
248 impl Default
for PrettyFields
{
249 fn default() -> Self {
255 /// Returns a new default [`PrettyFields`] implementation.
256 pub fn new() -> Self {
260 /// Enable ANSI encoding for formatted fields.
261 pub fn with_ansi(self, ansi
: bool
) -> Self {
262 Self { ansi, ..self }
266 impl<'a
> MakeVisitor
<&'a
mut dyn Write
> for PrettyFields
{
267 type Visitor
= PrettyVisitor
<'a
>;
270 fn make_visitor(&self, target
: &'a
mut dyn Write
) -> Self::Visitor
{
271 PrettyVisitor
::new(target
, true).with_ansi(self.ansi
)
275 // === impl PrettyVisitor ===
277 impl<'a
> PrettyVisitor
<'a
> {
278 /// Returns a new default visitor that formats to the provided `writer`.
281 /// - `writer`: the writer to format to.
282 /// - `is_empty`: whether or not any fields have been previously written to
284 pub fn new(writer
: &'a
mut dyn Write
, is_empty
: bool
) -> Self {
289 style
: Style
::default(),
294 pub(crate) fn with_style(self, style
: Style
) -> Self {
295 Self { style, ..self }
298 pub(crate) fn with_ansi(self, ansi
: bool
) -> Self {
299 Self { ansi, ..self }
302 fn write_padded(&mut self, value
: &impl fmt
::Debug
) {
303 let padding
= if self.is_empty
{
304 self.is_empty
= false;
309 self.result
= write
!(self.writer
, "{}{:?}", padding
, value
);
312 fn bold(&self) -> Style
{
321 impl<'a
> field
::Visit
for PrettyVisitor
<'a
> {
322 fn record_str(&mut self, field
: &Field
, value
: &str) {
323 if self.result
.is_err() {
327 if field
.name() == "message" {
328 self.record_debug(field
, &format_args
!("{}", value
))
330 self.record_debug(field
, &value
)
334 fn record_error(&mut self, field
: &Field
, value
: &(dyn std
::error
::Error
+ '
static)) {
335 if let Some(source
) = value
.source() {
336 let bold
= self.bold();
340 "{}, {}{}.source{}: {}",
344 bold
.infix(self.style
),
349 self.record_debug(field
, &format_args
!("{}", value
))
353 fn record_debug(&mut self, field
: &Field
, value
: &dyn fmt
::Debug
) {
354 if self.result
.is_err() {
357 let bold
= self.bold();
359 "message" => self.write_padded(&format_args
!("{}{:?}", self.style
.prefix(), value
,)),
360 // Skip fields that are actually log metadata that have already been handled
361 #[cfg(feature = "tracing-log")]
362 name
if name
.starts_with("log.") => self.result
= Ok(()),
363 name
if name
.starts_with("r#") => self.write_padded(&format_args
!(
367 bold
.infix(self.style
),
370 name
=> self.write_padded(&format_args
!(
374 bold
.infix(self.style
),
381 impl<'a
> VisitOutput
<fmt
::Result
> for PrettyVisitor
<'a
> {
382 fn finish(self) -> fmt
::Result
{
383 write
!(self.writer
, "{}", self.style
.suffix())?
;
388 impl<'a
> VisitFmt
for PrettyVisitor
<'a
> {
389 fn writer(&mut self) -> &mut dyn fmt
::Write
{
394 impl<'a
> fmt
::Debug
for PrettyVisitor
<'a
> {
395 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
396 f
.debug_struct("PrettyVisitor")
397 .field("writer", &format_args
!("<dyn fmt::Write>"))
398 .field("is_empty", &self.is_empty
)
399 .field("result", &self.result
)
400 .field("style", &self.style
)
401 .field("ansi", &self.ansi
)