3 field
::{VisitFmt, VisitOutput}
,
4 fmt
::fmt_layer
::{FmtContext, FormattedFields}
,
8 use std
::fmt
::{self, Write}
;
11 Event
, Level
, Subscriber
,
14 #[cfg(feature = "tracing-log")]
15 use tracing_log
::NormalizeEvent
;
17 use ansi_term
::{Colour, Style}
;
19 /// An excessively pretty, human-readable event formatter.
20 #[derive(Debug, Clone, Eq, PartialEq)]
22 display_location
: bool
,
25 /// The [visitor] produced by [`Pretty`]'s [`MakeVisitor`] implementation.
27 /// [visitor]: ../../field/trait.Visit.html
28 /// [`DefaultFields`]: struct.DefaultFields.html
29 /// [`MakeVisitor`]: ../../field/trait.MakeVisitor.html
30 pub struct PrettyVisitor
<'a
> {
31 writer
: &'a
mut dyn Write
,
38 /// An excessively pretty, human-readable [`MakeVisitor`] implementation.
40 /// [`MakeVisitor`]: crate::field::MakeVisitor
42 pub struct PrettyFields
{
46 // === impl Pretty ===
48 impl Default
for Pretty
{
49 fn default() -> Self {
51 display_location
: true,
57 fn style_for(level
: &Level
) -> Style
{
59 Level
::TRACE
=> Style
::new().fg(Colour
::Purple
),
60 Level
::DEBUG
=> Style
::new().fg(Colour
::Blue
),
61 Level
::INFO
=> Style
::new().fg(Colour
::Green
),
62 Level
::WARN
=> Style
::new().fg(Colour
::Yellow
),
63 Level
::ERROR
=> Style
::new().fg(Colour
::Red
),
67 /// Sets whether the event's source code location is displayed.
69 /// This defaults to `true`.
70 pub fn with_source_location(self, display_location
: bool
) -> Self {
78 impl<T
> Format
<Pretty
, T
> {
79 /// Sets whether or not the source code location from which an event
80 /// originated is displayed.
82 /// This defaults to `true`.
83 pub fn with_source_location(mut self, display_location
: bool
) -> Self {
84 self.format
= self.format
.with_source_location(display_location
);
89 impl<C
, N
, T
> FormatEvent
<C
, N
> for Format
<Pretty
, T
>
91 C
: Subscriber
+ for<'a
> LookupSpan
<'a
>,
92 N
: for<'a
> FormatFields
<'a
> + '
static,
97 ctx
: &FmtContext
<'_
, C
, N
>,
98 writer
: &mut dyn fmt
::Write
,
101 #[cfg(feature = "tracing-log")]
102 let normalized_meta
= event
.normalized_metadata();
103 #[cfg(feature = "tracing-log")]
104 let meta
= normalized_meta
.as_ref().unwrap_or_else(|| event
.metadata());
105 #[cfg(not(feature = "tracing-log"))]
106 let meta
= event
.metadata();
107 write
!(writer
, " ")?
;
109 self.format_timestamp(writer
)?
;
111 let style
= if self.display_level
&& self.ansi
{
112 Pretty
::style_for(meta
.level())
117 if self.display_level
{
118 write
!(writer
, "{}", super::FmtLevel
::new(meta
.level(), self.ansi
))?
;
121 if self.display_target
{
122 let target_style
= if self.ansi { style.bold() }
else { style }
;
126 target_style
.prefix(),
128 target_style
.infix(style
)
131 let mut v
= PrettyVisitor
::new(writer
, true)
133 .with_ansi(self.ansi
);
134 event
.record(&mut v
);
136 writer
.write_char('
\n'
)?
;
138 let dimmed
= if self.ansi
{
139 Style
::new().dimmed().italic()
143 let thread
= self.display_thread_name
|| self.display_thread_id
;
144 if let (true, Some(file
), Some(line
)) =
145 (self.format
.display_location
, meta
.file(), meta
.line())
153 dimmed
.paint(if thread { " " }
else { "\n" }
)
156 write
!(writer
, " ")?
;
160 write
!(writer
, "{} ", dimmed
.paint("on"))?
;
161 let thread
= std
::thread
::current();
162 if self.display_thread_name
{
163 if let Some(name
) = thread
.name() {
164 write
!(writer
, "{}", name
)?
;
165 if self.display_thread_id
{
166 write
!(writer
, " ({:?})", thread
.id())?
;
168 } else if !self.display_thread_id
{
169 write
!(writer
, " {:?}", thread
.id())?
;
171 } else if self.display_thread_id
{
172 write
!(writer
, " {:?}", thread
.id())?
;
174 writer
.write_char('
\n'
)?
;
177 let bold
= if self.ansi
{
184 .and_then(|id
| ctx
.span(&id
))
185 .or_else(|| ctx
.lookup_current());
187 let scope
= span
.into_iter().flat_map(|span
| span
.scope());
190 let meta
= span
.metadata();
191 if self.display_target
{
197 bold
.paint(meta
.name()),
204 bold
.paint(meta
.name()),
208 let ext
= span
.extensions();
210 .get
::<FormattedFields
<N
>>()
211 .expect("Unable to find FormattedFields in extensions; this is a bug");
212 if !fields
.is_empty() {
213 write
!(writer
, " {} {}", dimmed
.paint("with"), fields
)?
;
215 writer
.write_char('
\n'
)?
;
218 writer
.write_char('
\n'
)
222 impl<'writer
> FormatFields
<'writer
> for Pretty
{
223 fn format_fields
<R
: RecordFields
>(
225 writer
: &'writer
mut dyn fmt
::Write
,
228 let mut v
= PrettyVisitor
::new(writer
, true);
229 fields
.record(&mut v
);
233 fn add_fields(&self, current
: &'writer
mut String
, fields
: &span
::Record
<'_
>) -> fmt
::Result
{
234 let empty
= current
.is_empty();
235 let mut v
= PrettyVisitor
::new(current
, empty
);
236 fields
.record(&mut v
);
241 // === impl PrettyFields ===
243 impl Default
for PrettyFields
{
244 fn default() -> Self {
250 /// Returns a new default [`PrettyFields`] implementation.
251 pub fn new() -> Self {
255 /// Enable ANSI encoding for formatted fields.
256 pub fn with_ansi(self, ansi
: bool
) -> Self {
257 Self { ansi, ..self }
261 impl<'a
> MakeVisitor
<&'a
mut dyn Write
> for PrettyFields
{
262 type Visitor
= PrettyVisitor
<'a
>;
265 fn make_visitor(&self, target
: &'a
mut dyn Write
) -> Self::Visitor
{
266 PrettyVisitor
::new(target
, true).with_ansi(self.ansi
)
270 // === impl PrettyVisitor ===
272 impl<'a
> PrettyVisitor
<'a
> {
273 /// Returns a new default visitor that formats to the provided `writer`.
276 /// - `writer`: the writer to format to.
277 /// - `is_empty`: whether or not any fields have been previously written to
279 pub fn new(writer
: &'a
mut dyn Write
, is_empty
: bool
) -> Self {
284 style
: Style
::default(),
289 pub(crate) fn with_style(self, style
: Style
) -> Self {
290 Self { style, ..self }
293 pub(crate) fn with_ansi(self, ansi
: bool
) -> Self {
294 Self { ansi, ..self }
297 fn write_padded(&mut self, value
: &impl fmt
::Debug
) {
298 let padding
= if self.is_empty
{
299 self.is_empty
= false;
304 self.result
= write
!(self.writer
, "{}{:?}", padding
, value
);
307 fn bold(&self) -> Style
{
316 impl<'a
> field
::Visit
for PrettyVisitor
<'a
> {
317 fn record_str(&mut self, field
: &Field
, value
: &str) {
318 if self.result
.is_err() {
322 if field
.name() == "message" {
323 self.record_debug(field
, &format_args
!("{}", value
))
325 self.record_debug(field
, &value
)
329 fn record_error(&mut self, field
: &Field
, value
: &(dyn std
::error
::Error
+ '
static)) {
330 if let Some(source
) = value
.source() {
331 let bold
= self.bold();
335 "{}, {}{}.source{}: {}",
339 bold
.infix(self.style
),
344 self.record_debug(field
, &format_args
!("{}", value
))
348 fn record_debug(&mut self, field
: &Field
, value
: &dyn fmt
::Debug
) {
349 if self.result
.is_err() {
352 let bold
= self.bold();
354 "message" => self.write_padded(&format_args
!("{}{:?}", self.style
.prefix(), value
,)),
355 // Skip fields that are actually log metadata that have already been handled
356 #[cfg(feature = "tracing-log")]
357 name
if name
.starts_with("log.") => self.result
= Ok(()),
358 name
if name
.starts_with("r#") => self.write_padded(&format_args
!(
362 bold
.infix(self.style
),
365 name
=> self.write_padded(&format_args
!(
369 bold
.infix(self.style
),
376 impl<'a
> VisitOutput
<fmt
::Result
> for PrettyVisitor
<'a
> {
377 fn finish(self) -> fmt
::Result
{
378 write
!(self.writer
, "{}", self.style
.suffix())?
;
383 impl<'a
> VisitFmt
for PrettyVisitor
<'a
> {
384 fn writer(&mut self) -> &mut dyn fmt
::Write
{
389 impl<'a
> fmt
::Debug
for PrettyVisitor
<'a
> {
390 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
391 f
.debug_struct("PrettyVisitor")
392 .field("writer", &format_args
!("<dyn fmt::Write>"))
393 .field("is_empty", &self.is_empty
)
394 .field("result", &self.result
)
395 .field("style", &self.style
)
396 .field("ansi", &self.ansi
)