]> git.proxmox.com Git - rustc.git/blame - vendor/tracing-subscriber/src/fmt/format/mod.rs
New upstream version 1.59.0+dfsg1
[rustc.git] / vendor / tracing-subscriber / src / fmt / format / mod.rs
CommitLineData
f035d41b 1//! Formatters for logging `tracing` events.
17df50a5 2use super::time::{FormatTime, SystemTime};
f035d41b
XL
3use crate::{
4 field::{MakeOutput, MakeVisitor, RecordFields, VisitFmt, VisitOutput},
5 fmt::fmt_layer::FmtContext,
6 fmt::fmt_layer::FormattedFields,
7 registry::LookupSpan,
8};
9
a2a8927a 10use std::fmt::{self, Debug, Display, Write};
f035d41b
XL
11use tracing_core::{
12 field::{self, Field, Visit},
13 span, Event, Level, Subscriber,
14};
15
16#[cfg(feature = "tracing-log")]
17use tracing_log::NormalizeEvent;
18
19#[cfg(feature = "ansi")]
20use ansi_term::{Colour, Style};
21
22#[cfg(feature = "json")]
23mod json;
f035d41b
XL
24#[cfg(feature = "json")]
25#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
26pub use json::*;
27
5869c6ff
XL
28#[cfg(feature = "ansi")]
29mod pretty;
30#[cfg(feature = "ansi")]
31#[cfg_attr(docsrs, doc(cfg(feature = "ansi")))]
32pub use pretty::*;
33
a2a8927a 34/// A type that can format a tracing [`Event`] to a [`Writer`].
f035d41b 35///
a2a8927a
XL
36/// `FormatEvent` is primarily used in the context of [`fmt::Subscriber`] or
37/// [`fmt::Layer`]. Each time an event is dispatched to [`fmt::Subscriber`] or
38/// [`fmt::Layer`], the subscriber or layer
39/// forwards it to its associated `FormatEvent` to emit a log message.
f035d41b
XL
40///
41/// This trait is already implemented for function pointers with the same
42/// signature as `format_event`.
43///
a2a8927a
XL
44/// # Arguments
45///
46/// The following arguments are passed to `FormatEvent::format_event`:
47///
48/// * A [`FmtContext`]. This is an extension of the [`layer::Context`] type,
49/// which can be used for accessing stored information such as the current
50/// span context an event occurred in.
51///
52/// In addition, [`FmtContext`] exposes access to the [`FormatFields`]
53/// implementation that the subscriber was configured to use via the
54/// [`FmtContext::field_format`] method. This can be used when the
55/// [`FormatEvent`] implementation needs to format the event's fields.
56///
57/// For convenience, [`FmtContext`] also [implements `FormatFields`],
58/// forwarding to the configured [`FormatFields`] type.
59///
60/// * A [`Writer`] to which the formatted representation of the event is
61/// written. This type implements the [`std::fmt::Write`] trait, and therefore
62/// can be used with the [`std::write!`] and [`std::writeln!`] macros, as well
63/// as calling [`std::fmt::Write`] methods directly.
64///
65/// The [`Writer`] type also implements additional methods that provide
66/// information about how the event should be formatted. The
67/// [`Writer::has_ansi_escapes`] method indicates whether [ANSI terminal
68/// escape codes] are supported by the underlying I/O writer that the event
69/// will be written to. If this returns `true`, the formatter is permitted to
70/// use ANSI escape codes to add colors and other text formatting to its
71/// output. If it returns `false`, the event will be written to an output that
72/// does not support ANSI escape codes (such as a log file), and they should
73/// not be emitted.
74///
75/// Crates like [`ansi_term`] and [`owo-colors`] can be used to add ANSI
76/// escape codes to formatted output.
77///
78/// * The actual [`Event`] to be formatted.
79///
6a06907d
XL
80/// # Examples
81///
a2a8927a
XL
82/// This example re-implements a simiplified version of this crate's [default
83/// formatter]:
84///
6a06907d 85/// ```rust
a2a8927a 86/// use std::fmt;
6a06907d 87/// use tracing_core::{Subscriber, Event};
a2a8927a
XL
88/// use tracing_subscriber::fmt::{
89/// format::{self, FormatEvent, FormatFields},
90/// FmtContext,
91/// FormattedFields,
92/// };
6a06907d
XL
93/// use tracing_subscriber::registry::LookupSpan;
94///
95/// struct MyFormatter;
96///
97/// impl<S, N> FormatEvent<S, N> for MyFormatter
98/// where
99/// S: Subscriber + for<'a> LookupSpan<'a>,
100/// N: for<'a> FormatFields<'a> + 'static,
101/// {
102/// fn format_event(
103/// &self,
104/// ctx: &FmtContext<'_, S, N>,
a2a8927a 105/// mut writer: format::Writer<'_>,
6a06907d
XL
106/// event: &Event<'_>,
107/// ) -> fmt::Result {
a2a8927a
XL
108/// // Format values from the event's's metadata:
109/// let metadata = event.metadata();
110/// write!(&mut writer, "{} {}: ", metadata.level(), metadata.target())?;
6a06907d 111///
a2a8927a
XL
112/// // Format all the spans in the event's span context.
113/// if let Some(scope) = ctx.event_scope() {
114/// for span in scope.from_root() {
115/// write!(writer, "{}", span.name())?;
6a06907d 116///
a2a8927a
XL
117/// // `FormattedFields` is a formatted representation of the span's
118/// // fields, which is stored in its extensions by the `fmt` layer's
119/// // `new_span` method. The fields will have been formatted
120/// // by the same field formatter that's provided to the event
121/// // formatter in the `FmtContext`.
122/// let ext = span.extensions();
123/// let fields = &ext
124/// .get::<FormattedFields<N>>()
125/// .expect("will never be `None`");
6a06907d 126///
a2a8927a
XL
127/// // Skip formatting the fields if the span had no fields.
128/// if !fields.is_empty() {
129/// write!(writer, "{{{}}}", fields)?;
130/// }
131/// write!(writer, ": ")?;
6a06907d 132/// }
a2a8927a 133/// }
6a06907d
XL
134///
135/// // Write fields on the event
a2a8927a 136/// ctx.field_format().format_fields(writer.by_ref(), event)?;
6a06907d
XL
137///
138/// writeln!(writer)
139/// }
140/// }
a2a8927a
XL
141///
142/// let _subscriber = tracing_subscriber::fmt()
143/// .event_format(MyFormatter)
144/// .init();
145///
146/// let _span = tracing::info_span!("my_span", answer = 42).entered();
147/// tracing::info!(question = "life, the universe, and everything", "hello world");
6a06907d
XL
148/// ```
149///
150/// This formatter will print events like this:
151///
152/// ```text
153/// DEBUG yak_shaving::shaver: some-span{field-on-span=foo}: started shaving yak
154/// ```
155///
a2a8927a
XL
156/// [`fmt::Layer`]: super::Layer
157/// [`fmt::Subscriber`]: super::Subscriber
158/// [`Event`]: tracing::Event
159/// [implements `FormatFields`]: super::FmtContext#impl-FormatFields<'writer>
160/// [ANSI terminal escape codes]: https://en.wikipedia.org/wiki/ANSI_escape_code
161/// [`Writer::has_ansi_escapes`]: Writer::has_ansi_escapes
162/// [`ansi_term`]: https://crates.io/crates/ansi_term
163/// [`owo-colors`]: https://crates.io/crates/owo-colors
164/// [default formatter]: Full
f035d41b
XL
165pub trait FormatEvent<S, N>
166where
167 S: Subscriber + for<'a> LookupSpan<'a>,
168 N: for<'a> FormatFields<'a> + 'static,
169{
a2a8927a 170 /// Write a log message for `Event` in `Context` to the given [`Writer`].
f035d41b
XL
171 fn format_event(
172 &self,
173 ctx: &FmtContext<'_, S, N>,
a2a8927a 174 writer: Writer<'_>,
f035d41b
XL
175 event: &Event<'_>,
176 ) -> fmt::Result;
177}
178
179impl<S, N> FormatEvent<S, N>
a2a8927a 180 for fn(ctx: &FmtContext<'_, S, N>, Writer<'_>, &Event<'_>) -> fmt::Result
f035d41b
XL
181where
182 S: Subscriber + for<'a> LookupSpan<'a>,
183 N: for<'a> FormatFields<'a> + 'static,
184{
185 fn format_event(
186 &self,
187 ctx: &FmtContext<'_, S, N>,
a2a8927a 188 writer: Writer<'_>,
f035d41b
XL
189 event: &Event<'_>,
190 ) -> fmt::Result {
191 (*self)(ctx, writer, event)
192 }
193}
a2a8927a 194/// A type that can format a [set of fields] to a [`Writer`].
f035d41b
XL
195///
196/// `FormatFields` is primarily used in the context of [`FmtSubscriber`]. Each
197/// time a span or event with fields is recorded, the subscriber will format
198/// those fields with its associated `FormatFields` implementation.
199///
200/// [set of fields]: ../field/trait.RecordFields.html
201/// [`FmtSubscriber`]: ../fmt/struct.Subscriber.html
202pub trait FormatFields<'writer> {
a2a8927a
XL
203 /// Format the provided `fields` to the provided [`Writer`], returning a result.
204 fn format_fields<R: RecordFields>(&self, writer: Writer<'writer>, fields: R) -> fmt::Result;
f035d41b
XL
205
206 /// Record additional field(s) on an existing span.
207 ///
208 /// By default, this appends a space to the current set of fields if it is
209 /// non-empty, and then calls `self.format_fields`. If different behavior is
210 /// required, the default implementation of this method can be overridden.
a2a8927a
XL
211 fn add_fields(
212 &self,
213 current: &'writer mut FormattedFields<Self>,
214 fields: &span::Record<'_>,
215 ) -> fmt::Result {
216 if !current.fields.is_empty() {
217 current.fields.push(' ');
f035d41b 218 }
a2a8927a 219 self.format_fields(current.as_writer(), fields)
f035d41b
XL
220 }
221}
222
223/// Returns the default configuration for an [event formatter].
224///
225/// Methods on the returned event formatter can be used for further
226/// configuration. For example:
227///
228/// ```rust
229/// let format = tracing_subscriber::fmt::format()
230/// .without_time() // Don't include timestamps
231/// .with_target(false) // Don't include event targets.
232/// .with_level(false) // Don't include event levels.
233/// .compact(); // Use a more compact, abbreviated format.
234///
235/// // Use the configured formatter when building a new subscriber.
236/// tracing_subscriber::fmt()
237/// .event_format(format)
238/// .init();
239/// ```
240pub fn format() -> Format {
241 Format::default()
242}
243
244/// Returns the default configuration for a JSON [event formatter].
245#[cfg(feature = "json")]
246#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
247pub fn json() -> Format<Json> {
248 format().json()
249}
250
251/// Returns a [`FormatFields`] implementation that formats fields using the
252/// provided function or closure.
253///
254/// [`FormatFields`]: trait.FormatFields.html
255pub fn debug_fn<F>(f: F) -> FieldFn<F>
256where
a2a8927a 257 F: Fn(&mut Writer<'_>, &Field, &dyn fmt::Debug) -> fmt::Result + Clone,
f035d41b
XL
258{
259 FieldFn(f)
260}
261
a2a8927a
XL
262/// A writer to which formatted representations of spans and events are written.
263///
264/// This type is provided as input to the [`FormatEvent::format_event`] and
265/// [`FormatFields::format_fields`] methods, which will write formatted
266/// representations of [`Event`]s and [fields] to the `Writer`.
267///
268/// This type implements the [`std::fmt::Write`] trait, allowing it to be used
269/// with any function that takes an instance of [`std::fmt::Write`].
270/// Additionally, it can be used with the standard library's [`std::write!`] and
271/// [`std::writeln!`] macros.
272///
273/// Additionally, a `Writer` may expose additional `tracing`-specific
274/// information to the formatter implementation.
275pub struct Writer<'writer> {
276 writer: &'writer mut dyn fmt::Write,
277 // TODO(eliza): add ANSI support
278 is_ansi: bool,
279}
280
f035d41b
XL
281/// A [`FormatFields`] implementation that formats fields by calling a function
282/// or closure.
283///
284/// [`FormatFields`]: trait.FormatFields.html
285#[derive(Debug, Clone)]
286pub struct FieldFn<F>(F);
287/// The [visitor] produced by [`FieldFn`]'s [`MakeVisitor`] implementation.
288///
289/// [visitor]: ../../field/trait.Visit.html
290/// [`FieldFn`]: struct.FieldFn.html
291/// [`MakeVisitor`]: ../../field/trait.MakeVisitor.html
292pub struct FieldFnVisitor<'a, F> {
293 f: F,
a2a8927a 294 writer: Writer<'a>,
f035d41b
XL
295 result: fmt::Result,
296}
297/// Marker for `Format` that indicates that the compact log format should be used.
298///
299/// The compact format only includes the fields from the most recently entered span.
300#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
301pub struct Compact;
302
303/// Marker for `Format` that indicates that the verbose log format should be used.
304///
305/// The full format includes fields from all entered spans.
306#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
307pub struct Full;
308
309/// A pre-configured event formatter.
310///
311/// You will usually want to use this as the `FormatEvent` for a `FmtSubscriber`.
312///
313/// The default logging format, [`Full`] includes all fields in each event and its containing
314/// spans. The [`Compact`] logging format includes only the fields from the most-recently-entered
315/// span.
316#[derive(Debug, Clone)]
317pub struct Format<F = Full, T = SystemTime> {
318 format: F,
319 pub(crate) timer: T,
a2a8927a 320 pub(crate) ansi: Option<bool>,
17df50a5 321 pub(crate) display_timestamp: bool,
f035d41b
XL
322 pub(crate) display_target: bool,
323 pub(crate) display_level: bool,
3dfed10e
XL
324 pub(crate) display_thread_id: bool,
325 pub(crate) display_thread_name: bool,
f035d41b
XL
326}
327
a2a8927a
XL
328// === impl Writer ===
329
330impl<'writer> Writer<'writer> {
331 // TODO(eliza): consider making this a public API?
332 // We may not want to do that if we choose to expose specialized
333 // constructors instead (e.g. `from_string` that stores whether the string
334 // is empty...?)
335 pub(crate) fn new(writer: &'writer mut impl fmt::Write) -> Self {
336 Self {
337 writer: writer as &mut dyn fmt::Write,
338 is_ansi: false,
339 }
340 }
341
342 // TODO(eliza): consider making this a public API?
343 pub(crate) fn with_ansi(self, is_ansi: bool) -> Self {
344 Self { is_ansi, ..self }
345 }
346
347 /// Return a new `Writer` that mutably borrows `self`.
348 ///
349 /// This can be used to temporarily borrow a `Writer` to pass a new `Writer`
350 /// to a function that takes a `Writer` by value, allowing the original writer
351 /// to still be used once that function returns.
352 pub fn by_ref(&mut self) -> Writer<'_> {
353 let is_ansi = self.is_ansi;
354 Writer {
355 writer: self as &mut dyn fmt::Write,
356 is_ansi,
357 }
358 }
359
360 /// Writes a string slice into this `Writer`, returning whether the write succeeded.
361 ///
362 /// This method can only succeed if the entire string slice was successfully
363 /// written, and this method will not return until all data has been written
364 /// or an error occurs.
365 ///
366 /// This is identical to calling the [`write_str` method] from the `Writer`'s
367 /// [`std::fmt::Write`] implementation. However, it is also provided as an
368 /// inherent method, so that `Writer`s can be used without needing to import the
369 /// [`std::fmt::Write`] trait.
370 ///
371 /// # Errors
372 ///
373 /// This function will return an instance of [`std::fmt::Error`] on error.
374 ///
375 /// [`write_str` method]: std::fmt::Write::write_str
376 #[inline]
377 pub fn write_str(&mut self, s: &str) -> fmt::Result {
378 self.writer.write_str(s)
379 }
380
381 /// Writes a [`char`] into this writer, returning whether the write succeeded.
382 ///
383 /// A single [`char`] may be encoded as more than one byte.
384 /// This method can only succeed if the entire byte sequence was successfully
385 /// written, and this method will not return until all data has been
386 /// written or an error occurs.
387 ///
388 /// This is identical to calling the [`write_char` method] from the `Writer`'s
389 /// [`std::fmt::Write`] implementation. However, it is also provided as an
390 /// inherent method, so that `Writer`s can be used without needing to import the
391 /// [`std::fmt::Write`] trait.
392 ///
393 /// # Errors
394 ///
395 /// This function will return an instance of [`std::fmt::Error`] on error.
396 ///
397 /// [`write_char` method]: std::fmt::Write::write_char
398 #[inline]
399 pub fn write_char(&mut self, c: char) -> fmt::Result {
400 self.writer.write_char(c)
401 }
402
403 /// Glue for usage of the [`write!`] macro with `Writer`s.
404 ///
405 /// This method should generally not be invoked manually, but rather through
406 /// the [`write!`] macro itself.
407 ///
408 /// This is identical to calling the [`write_fmt` method] from the `Writer`'s
409 /// [`std::fmt::Write`] implementation. However, it is also provided as an
410 /// inherent method, so that `Writer`s can be used with the [`write!` macro]
411 /// without needing to import the
412 /// [`std::fmt::Write`] trait.
413 ///
414 /// [`write_fmt` method]: std::fmt::Write::write_fmt
415 pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
416 self.writer.write_fmt(args)
417 }
418
419 /// Returns `true` if [ANSI escape codes] may be used to add colors
420 /// and other formatting when writing to this `Writer`.
421 ///
422 /// If this returns `false`, formatters should not emit ANSI escape codes.
423 ///
424 /// [ANSI escape codes]: https://en.wikipedia.org/wiki/ANSI_escape_code
425 pub fn has_ansi_escapes(&self) -> bool {
426 self.is_ansi
427 }
428
429 pub(in crate::fmt::format) fn bold(&self) -> Style {
430 #[cfg(feature = "ansi")]
431 {
432 if self.is_ansi {
433 return Style::new().bold();
434 }
435 }
436
437 Style::new()
438 }
439
440 pub(in crate::fmt::format) fn dimmed(&self) -> Style {
441 #[cfg(feature = "ansi")]
442 {
443 if self.is_ansi {
444 return Style::new().dimmed();
445 }
446 }
447
448 Style::new()
449 }
450
451 pub(in crate::fmt::format) fn italic(&self) -> Style {
452 #[cfg(feature = "ansi")]
453 {
454 if self.is_ansi {
455 return Style::new().italic();
456 }
457 }
458
459 Style::new()
460 }
461}
462
463impl fmt::Write for Writer<'_> {
464 #[inline]
465 fn write_str(&mut self, s: &str) -> fmt::Result {
466 Writer::write_str(self, s)
467 }
468
469 #[inline]
470 fn write_char(&mut self, c: char) -> fmt::Result {
471 Writer::write_char(self, c)
472 }
473
474 #[inline]
475 fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
476 Writer::write_fmt(self, args)
477 }
478}
479
480impl fmt::Debug for Writer<'_> {
481 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
482 f.debug_struct("Writer")
483 .field("writer", &format_args!("<&mut dyn fmt::Write>"))
484 .field("is_ansi", &self.is_ansi)
485 .finish()
486 }
487}
488
489// === impl Format ===
490
f035d41b
XL
491impl Default for Format<Full, SystemTime> {
492 fn default() -> Self {
493 Format {
494 format: Full,
495 timer: SystemTime,
a2a8927a 496 ansi: None,
17df50a5 497 display_timestamp: true,
f035d41b
XL
498 display_target: true,
499 display_level: true,
3dfed10e
XL
500 display_thread_id: false,
501 display_thread_name: false,
f035d41b
XL
502 }
503 }
504}
505
506impl<F, T> Format<F, T> {
507 /// Use a less verbose output format.
508 ///
509 /// See [`Compact`].
510 pub fn compact(self) -> Format<Compact, T> {
511 Format {
512 format: Compact,
513 timer: self.timer,
514 ansi: self.ansi,
515 display_target: self.display_target,
17df50a5 516 display_timestamp: self.display_timestamp,
f035d41b 517 display_level: self.display_level,
3dfed10e
XL
518 display_thread_id: self.display_thread_id,
519 display_thread_name: self.display_thread_name,
f035d41b
XL
520 }
521 }
522
5869c6ff
XL
523 /// Use an excessively pretty, human-readable output format.
524 ///
525 /// See [`Pretty`].
526 ///
527 /// Note that this requires the "ansi" feature to be enabled.
cdc7bbd5
XL
528 ///
529 /// # Options
530 ///
531 /// [`Format::with_ansi`] can be used to disable ANSI terminal escape codes (which enable
532 /// formatting such as colors, bold, italic, etc) in event formatting. However, a field
533 /// formatter must be manually provided to avoid ANSI in the formatting of parent spans, like
534 /// so:
535 ///
536 /// ```
537 /// # use tracing_subscriber::fmt::format;
538 /// tracing_subscriber::fmt()
539 /// .pretty()
540 /// .with_ansi(false)
541 /// .fmt_fields(format::PrettyFields::new().with_ansi(false))
542 /// // ... other settings ...
543 /// .init();
544 /// ```
5869c6ff
XL
545 #[cfg(feature = "ansi")]
546 #[cfg_attr(docsrs, doc(cfg(feature = "ansi")))]
547 pub fn pretty(self) -> Format<Pretty, T> {
548 Format {
549 format: Pretty::default(),
550 timer: self.timer,
551 ansi: self.ansi,
552 display_target: self.display_target,
17df50a5 553 display_timestamp: self.display_timestamp,
5869c6ff
XL
554 display_level: self.display_level,
555 display_thread_id: self.display_thread_id,
556 display_thread_name: self.display_thread_name,
557 }
558 }
559
f035d41b
XL
560 /// Use the full JSON format.
561 ///
562 /// The full format includes fields from all entered spans.
563 ///
564 /// # Example Output
565 ///
566 /// ```ignore,json
567 /// {"timestamp":"Feb 20 11:28:15.096","level":"INFO","target":"mycrate","fields":{"message":"some message", "key": "value"}}
568 /// ```
569 ///
570 /// # Options
571 ///
572 /// - [`Format::flatten_event`] can be used to enable flattening event fields into the root
573 /// object.
574 ///
575 /// [`Format::flatten_event`]: #method.flatten_event
576 #[cfg(feature = "json")]
577 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
578 pub fn json(self) -> Format<Json, T> {
579 Format {
580 format: Json::default(),
581 timer: self.timer,
582 ansi: self.ansi,
583 display_target: self.display_target,
17df50a5 584 display_timestamp: self.display_timestamp,
f035d41b 585 display_level: self.display_level,
3dfed10e
XL
586 display_thread_id: self.display_thread_id,
587 display_thread_name: self.display_thread_name,
f035d41b
XL
588 }
589 }
590
591 /// Use the given [`timer`] for log message timestamps.
592 ///
17df50a5 593 /// See [`time` module] for the provided timer implementations.
f035d41b 594 ///
a2a8927a
XL
595 /// Note that using the `"time"` feature flag enables the
596 /// additional time formatters [`UtcTime`] and [`LocalTime`], which use the
597 /// [`time` crate] to provide more sophisticated timestamp formatting
598 /// options.
f035d41b 599 ///
17df50a5
XL
600 /// [`timer`]: super::time::FormatTime
601 /// [`time` module]: mod@super::time
a2a8927a
XL
602 /// [`UtcTime`]: super::time::UtcTime
603 /// [`LocalTime`]: super::time::LocalTime
604 /// [`time` crate]: https://docs.rs/time/0.3
f035d41b
XL
605 pub fn with_timer<T2>(self, timer: T2) -> Format<F, T2> {
606 Format {
607 format: self.format,
608 timer,
609 ansi: self.ansi,
610 display_target: self.display_target,
17df50a5 611 display_timestamp: self.display_timestamp,
f035d41b 612 display_level: self.display_level,
3dfed10e
XL
613 display_thread_id: self.display_thread_id,
614 display_thread_name: self.display_thread_name,
f035d41b
XL
615 }
616 }
617
618 /// Do not emit timestamps with log messages.
619 pub fn without_time(self) -> Format<F, ()> {
620 Format {
621 format: self.format,
622 timer: (),
623 ansi: self.ansi,
17df50a5 624 display_timestamp: false,
f035d41b
XL
625 display_target: self.display_target,
626 display_level: self.display_level,
3dfed10e
XL
627 display_thread_id: self.display_thread_id,
628 display_thread_name: self.display_thread_name,
f035d41b
XL
629 }
630 }
631
632 /// Enable ANSI terminal colors for formatted output.
633 pub fn with_ansi(self, ansi: bool) -> Format<F, T> {
a2a8927a
XL
634 Format {
635 ansi: Some(ansi),
636 ..self
637 }
f035d41b
XL
638 }
639
640 /// Sets whether or not an event's target is displayed.
641 pub fn with_target(self, display_target: bool) -> Format<F, T> {
642 Format {
643 display_target,
644 ..self
645 }
646 }
647
648 /// Sets whether or not an event's level is displayed.
649 pub fn with_level(self, display_level: bool) -> Format<F, T> {
650 Format {
651 display_level,
652 ..self
653 }
654 }
3dfed10e
XL
655
656 /// Sets whether or not the [thread ID] of the current thread is displayed
657 /// when formatting events
658 ///
659 /// [thread ID]: https://doc.rust-lang.org/stable/std/thread/struct.ThreadId.html
660 pub fn with_thread_ids(self, display_thread_id: bool) -> Format<F, T> {
661 Format {
662 display_thread_id,
663 ..self
664 }
665 }
666
667 /// Sets whether or not the [name] of the current thread is displayed
668 /// when formatting events
669 ///
670 /// [name]: https://doc.rust-lang.org/stable/std/thread/index.html#naming-threads
671 pub fn with_thread_names(self, display_thread_name: bool) -> Format<F, T> {
672 Format {
673 display_thread_name,
674 ..self
675 }
676 }
17df50a5
XL
677
678 #[inline]
a2a8927a 679 fn format_timestamp(&self, writer: &mut Writer<'_>) -> fmt::Result
17df50a5
XL
680 where
681 T: FormatTime,
682 {
683 // If timestamps are disabled, do nothing.
684 if !self.display_timestamp {
685 return Ok(());
686 }
687
688 // If ANSI color codes are enabled, format the timestamp with ANSI
689 // colors.
690 #[cfg(feature = "ansi")]
691 {
a2a8927a 692 if writer.has_ansi_escapes() {
17df50a5
XL
693 let style = Style::new().dimmed();
694 write!(writer, "{}", style.prefix())?;
695 self.timer.format_time(writer)?;
696 write!(writer, "{} ", style.suffix())?;
697 return Ok(());
698 }
699 }
700
701 // Otherwise, just format the timestamp without ANSI formatting.
702 self.timer.format_time(writer)?;
703 writer.write_char(' ')
704 }
f035d41b
XL
705}
706
707#[cfg(feature = "json")]
708#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
709impl<T> Format<Json, T> {
710 /// Use the full JSON format with the event's event fields flattened.
711 ///
712 /// # Example Output
713 ///
714 /// ```ignore,json
715 /// {"timestamp":"Feb 20 11:28:15.096","level":"INFO","target":"mycrate", "message":"some message", "key": "value"}
716 /// ```
717 /// See [`Json`](../format/struct.Json.html).
718 #[cfg(feature = "json")]
719 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
720 pub fn flatten_event(mut self, flatten_event: bool) -> Format<Json, T> {
721 self.format.flatten_event(flatten_event);
722 self
723 }
3dfed10e
XL
724
725 /// Sets whether or not the formatter will include the current span in
726 /// formatted events.
727 ///
728 /// See [`format::Json`](../fmt/format/struct.Json.html)
729 #[cfg(feature = "json")]
730 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
731 pub fn with_current_span(mut self, display_current_span: bool) -> Format<Json, T> {
732 self.format.with_current_span(display_current_span);
733 self
734 }
735
736 /// Sets whether or not the formatter will include a list (from root to
737 /// leaf) of all currently entered spans in formatted events.
738 ///
739 /// See [`format::Json`](../fmt/format/struct.Json.html)
740 #[cfg(feature = "json")]
741 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
742 pub fn with_span_list(mut self, display_span_list: bool) -> Format<Json, T> {
743 self.format.with_span_list(display_span_list);
744 self
745 }
f035d41b
XL
746}
747
748impl<S, N, T> FormatEvent<S, N> for Format<Full, T>
749where
750 S: Subscriber + for<'a> LookupSpan<'a>,
751 N: for<'a> FormatFields<'a> + 'static,
752 T: FormatTime,
753{
754 fn format_event(
755 &self,
756 ctx: &FmtContext<'_, S, N>,
a2a8927a 757 mut writer: Writer<'_>,
f035d41b
XL
758 event: &Event<'_>,
759 ) -> fmt::Result {
760 #[cfg(feature = "tracing-log")]
761 let normalized_meta = event.normalized_metadata();
762 #[cfg(feature = "tracing-log")]
763 let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
764 #[cfg(not(feature = "tracing-log"))]
765 let meta = event.metadata();
17df50a5 766
a2a8927a
XL
767 // if the `Format` struct *also* has an ANSI color configuration,
768 // override the writer...the API for configuring ANSI color codes on the
769 // `Format` struct is deprecated, but we still need to honor those
770 // configurations.
771 if let Some(ansi) = self.ansi {
772 writer = writer.with_ansi(ansi);
773 }
774
775 self.format_timestamp(&mut writer)?;
f035d41b
XL
776
777 if self.display_level {
778 let fmt_level = {
779 #[cfg(feature = "ansi")]
780 {
a2a8927a 781 FmtLevel::new(meta.level(), writer.has_ansi_escapes())
f035d41b
XL
782 }
783 #[cfg(not(feature = "ansi"))]
784 {
785 FmtLevel::new(meta.level())
786 }
787 };
788 write!(writer, "{} ", fmt_level)?;
789 }
790
3dfed10e
XL
791 if self.display_thread_name {
792 let current_thread = std::thread::current();
793 match current_thread.name() {
794 Some(name) => {
795 write!(writer, "{} ", FmtThreadName::new(name))?;
796 }
797 // fall-back to thread id when name is absent and ids are not enabled
798 None if !self.display_thread_id => {
799 write!(writer, "{:0>2?} ", current_thread.id())?;
800 }
801 _ => {}
802 }
803 }
804
805 if self.display_thread_id {
806 write!(writer, "{:0>2?} ", std::thread::current().id())?;
807 }
808
a2a8927a
XL
809 let dimmed = writer.dimmed();
810
811 if let Some(scope) = ctx.event_scope() {
812 let bold = writer.bold();
813
814 let mut seen = false;
815
816 for span in scope.from_root() {
817 write!(writer, "{}", bold.paint(span.metadata().name()))?;
818 seen = true;
819
820 let ext = span.extensions();
821 if let Some(fields) = &ext.get::<FormattedFields<N>>() {
822 if !fields.is_empty() {
823 write!(writer, "{}{}{}", bold.paint("{"), fields, bold.paint("}"))?;
824 }
825 }
826 write!(writer, "{}", dimmed.paint(":"))?;
f035d41b 827 }
a2a8927a
XL
828
829 if seen {
830 writer.write_char(' ')?;
f035d41b
XL
831 }
832 };
833
f035d41b 834 if self.display_target {
a2a8927a
XL
835 write!(
836 writer,
837 "{}{} ",
838 dimmed.paint(meta.target()),
839 dimmed.paint(":")
840 )?;
f035d41b 841 }
a2a8927a
XL
842
843 ctx.format_fields(writer.by_ref(), event)?;
f035d41b
XL
844 writeln!(writer)
845 }
846}
847
848impl<S, N, T> FormatEvent<S, N> for Format<Compact, T>
849where
850 S: Subscriber + for<'a> LookupSpan<'a>,
851 N: for<'a> FormatFields<'a> + 'static,
852 T: FormatTime,
853{
854 fn format_event(
855 &self,
856 ctx: &FmtContext<'_, S, N>,
a2a8927a 857 mut writer: Writer<'_>,
f035d41b
XL
858 event: &Event<'_>,
859 ) -> fmt::Result {
860 #[cfg(feature = "tracing-log")]
861 let normalized_meta = event.normalized_metadata();
862 #[cfg(feature = "tracing-log")]
863 let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
864 #[cfg(not(feature = "tracing-log"))]
865 let meta = event.metadata();
17df50a5 866
a2a8927a
XL
867 // if the `Format` struct *also* has an ANSI color configuration,
868 // override the writer...the API for configuring ANSI color codes on the
869 // `Format` struct is deprecated, but we still need to honor those
870 // configurations.
871 if let Some(ansi) = self.ansi {
872 writer = writer.with_ansi(ansi);
873 }
874
875 self.format_timestamp(&mut writer)?;
f035d41b
XL
876
877 if self.display_level {
878 let fmt_level = {
879 #[cfg(feature = "ansi")]
880 {
a2a8927a 881 FmtLevel::new(meta.level(), writer.has_ansi_escapes())
f035d41b
XL
882 }
883 #[cfg(not(feature = "ansi"))]
884 {
885 FmtLevel::new(meta.level())
886 }
887 };
888 write!(writer, "{} ", fmt_level)?;
889 }
890
3dfed10e
XL
891 if self.display_thread_name {
892 let current_thread = std::thread::current();
893 match current_thread.name() {
894 Some(name) => {
895 write!(writer, "{} ", FmtThreadName::new(name))?;
896 }
897 // fall-back to thread id when name is absent and ids are not enabled
898 None if !self.display_thread_id => {
899 write!(writer, "{:0>2?} ", current_thread.id())?;
900 }
901 _ => {}
902 }
903 }
904
905 if self.display_thread_id {
906 write!(writer, "{:0>2?} ", std::thread::current().id())?;
907 }
908
f035d41b
XL
909 let fmt_ctx = {
910 #[cfg(feature = "ansi")]
911 {
a2a8927a 912 FmtCtx::new(ctx, event.parent(), writer.has_ansi_escapes())
f035d41b
XL
913 }
914 #[cfg(not(feature = "ansi"))]
915 {
916 FmtCtx::new(&ctx, event.parent())
917 }
918 };
919 write!(writer, "{}", fmt_ctx)?;
a2a8927a 920
f035d41b 921 if self.display_target {
a2a8927a
XL
922 write!(
923 writer,
924 "{}{} ",
925 writer.bold().paint(meta.target()),
926 writer.dimmed().paint(":")
927 )?;
f035d41b 928 }
c295e0f8 929
a2a8927a 930 ctx.format_fields(writer.by_ref(), event)?;
c295e0f8 931
a2a8927a
XL
932 let dimmed = writer.dimmed();
933 for span in ctx
934 .event_scope()
935 .into_iter()
936 .map(crate::registry::Scope::from_root)
937 .flatten()
938 {
c295e0f8
XL
939 let exts = span.extensions();
940 if let Some(fields) = exts.get::<FormattedFields<N>>() {
941 if !fields.is_empty() {
a2a8927a 942 write!(writer, " {}", dimmed.paint(&fields.fields))?;
c295e0f8 943 }
f035d41b
XL
944 }
945 }
946 writeln!(writer)
947 }
948}
949
950// === impl FormatFields ===
951impl<'writer, M> FormatFields<'writer> for M
952where
a2a8927a 953 M: MakeOutput<Writer<'writer>, fmt::Result>,
f035d41b
XL
954 M::Visitor: VisitFmt + VisitOutput<fmt::Result>,
955{
a2a8927a 956 fn format_fields<R: RecordFields>(&self, writer: Writer<'writer>, fields: R) -> fmt::Result {
f035d41b
XL
957 let mut v = self.make_visitor(writer);
958 fields.record(&mut v);
959 v.finish()
960 }
961}
a2a8927a 962
f035d41b
XL
963/// The default [`FormatFields`] implementation.
964///
965/// [`FormatFields`]: trait.FormatFields.html
966#[derive(Debug)]
967pub struct DefaultFields {
968 // reserve the ability to add fields to this without causing a breaking
969 // change in the future.
970 _private: (),
971}
972
973/// The [visitor] produced by [`DefaultFields`]'s [`MakeVisitor`] implementation.
974///
a2a8927a
XL
975/// [visitor]: super::super::field::Visit
976/// [`MakeVisitor`]: super::super::field::MakeVisitor
977#[derive(Debug)]
f035d41b 978pub struct DefaultVisitor<'a> {
a2a8927a 979 writer: Writer<'a>,
f035d41b
XL
980 is_empty: bool,
981 result: fmt::Result,
982}
983
984impl DefaultFields {
985 /// Returns a new default [`FormatFields`] implementation.
986 ///
987 /// [`FormatFields`]: trait.FormatFields.html
988 pub fn new() -> Self {
989 Self { _private: () }
990 }
991}
992
993impl Default for DefaultFields {
994 fn default() -> Self {
995 Self::new()
996 }
997}
998
a2a8927a 999impl<'a> MakeVisitor<Writer<'a>> for DefaultFields {
f035d41b
XL
1000 type Visitor = DefaultVisitor<'a>;
1001
1002 #[inline]
a2a8927a 1003 fn make_visitor(&self, target: Writer<'a>) -> Self::Visitor {
f035d41b
XL
1004 DefaultVisitor::new(target, true)
1005 }
1006}
1007
1008// === impl DefaultVisitor ===
1009
1010impl<'a> DefaultVisitor<'a> {
1011 /// Returns a new default visitor that formats to the provided `writer`.
1012 ///
1013 /// # Arguments
1014 /// - `writer`: the writer to format to.
1015 /// - `is_empty`: whether or not any fields have been previously written to
1016 /// that writer.
a2a8927a 1017 pub fn new(writer: Writer<'a>, is_empty: bool) -> Self {
f035d41b
XL
1018 Self {
1019 writer,
1020 is_empty,
1021 result: Ok(()),
1022 }
1023 }
1024
1025 fn maybe_pad(&mut self) {
1026 if self.is_empty {
1027 self.is_empty = false;
1028 } else {
1029 self.result = write!(self.writer, " ");
1030 }
1031 }
1032}
1033
1034impl<'a> field::Visit for DefaultVisitor<'a> {
1035 fn record_str(&mut self, field: &Field, value: &str) {
1036 if self.result.is_err() {
1037 return;
1038 }
1039
1040 if field.name() == "message" {
1041 self.record_debug(field, &format_args!("{}", value))
1042 } else {
1043 self.record_debug(field, &value)
1044 }
1045 }
1046
1047 fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
1048 if let Some(source) = value.source() {
a2a8927a 1049 let italic = self.writer.italic();
c295e0f8
XL
1050 self.record_debug(
1051 field,
a2a8927a
XL
1052 &format_args!(
1053 "{} {}{}{}{}",
1054 value,
1055 italic.paint(field.name()),
1056 italic.paint(".sources"),
1057 self.writer.dimmed().paint("="),
1058 ErrorSourceList(source)
1059 ),
c295e0f8 1060 )
f035d41b
XL
1061 } else {
1062 self.record_debug(field, &format_args!("{}", value))
1063 }
1064 }
1065
1066 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
1067 if self.result.is_err() {
1068 return;
1069 }
1070
1071 self.maybe_pad();
1072 self.result = match field.name() {
1073 "message" => write!(self.writer, "{:?}", value),
1074 // Skip fields that are actually log metadata that have already been handled
1075 #[cfg(feature = "tracing-log")]
1076 name if name.starts_with("log.") => Ok(()),
a2a8927a
XL
1077 name if name.starts_with("r#") => write!(
1078 self.writer,
1079 "{}{}{:?}",
1080 self.writer.italic().paint(&name[2..]),
1081 self.writer.dimmed().paint("="),
1082 value
1083 ),
1084 name => write!(
1085 self.writer,
1086 "{}{}{:?}",
1087 self.writer.italic().paint(name),
1088 self.writer.dimmed().paint("="),
1089 value
1090 ),
f035d41b
XL
1091 };
1092 }
1093}
1094
1095impl<'a> crate::field::VisitOutput<fmt::Result> for DefaultVisitor<'a> {
1096 fn finish(self) -> fmt::Result {
1097 self.result
1098 }
1099}
1100
1101impl<'a> crate::field::VisitFmt for DefaultVisitor<'a> {
1102 fn writer(&mut self) -> &mut dyn fmt::Write {
a2a8927a 1103 &mut self.writer
f035d41b
XL
1104 }
1105}
1106
c295e0f8
XL
1107/// Renders an error into a list of sources, *including* the error
1108struct ErrorSourceList<'a>(&'a (dyn std::error::Error + 'static));
1109
1110impl<'a> Display for ErrorSourceList<'a> {
1111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1112 let mut list = f.debug_list();
1113 let mut curr = Some(self.0);
1114 while let Some(curr_err) = curr {
1115 list.entry(&format_args!("{}", curr_err));
1116 curr = curr_err.source();
1117 }
1118 list.finish()
1119 }
1120}
1121
f035d41b
XL
1122struct FmtCtx<'a, S, N> {
1123 ctx: &'a FmtContext<'a, S, N>,
1124 span: Option<&'a span::Id>,
1125 #[cfg(feature = "ansi")]
1126 ansi: bool,
1127}
1128
1129impl<'a, S, N: 'a> FmtCtx<'a, S, N>
1130where
1131 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
1132 N: for<'writer> FormatFields<'writer> + 'static,
1133{
1134 #[cfg(feature = "ansi")]
1135 pub(crate) fn new(
1136 ctx: &'a FmtContext<'_, S, N>,
1137 span: Option<&'a span::Id>,
1138 ansi: bool,
1139 ) -> Self {
136023e0 1140 Self { ctx, span, ansi }
f035d41b
XL
1141 }
1142
1143 #[cfg(not(feature = "ansi"))]
1144 pub(crate) fn new(ctx: &'a FmtContext<'_, S, N>, span: Option<&'a span::Id>) -> Self {
1145 Self { ctx, span }
1146 }
1147
1148 fn bold(&self) -> Style {
1149 #[cfg(feature = "ansi")]
1150 {
1151 if self.ansi {
1152 return Style::new().bold();
1153 }
1154 }
1155
1156 Style::new()
1157 }
1158}
1159
1160impl<'a, S, N: 'a> fmt::Display for FmtCtx<'a, S, N>
1161where
1162 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
1163 N: for<'writer> FormatFields<'writer> + 'static,
1164{
1165 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1166 let bold = self.bold();
1167 let mut seen = false;
1168
1169 let span = self
1170 .span
c295e0f8 1171 .and_then(|id| self.ctx.ctx.span(id))
f035d41b
XL
1172 .or_else(|| self.ctx.ctx.lookup_current());
1173
136023e0 1174 let scope = span.into_iter().flat_map(|span| span.scope().from_root());
f035d41b
XL
1175
1176 for span in scope {
1177 seen = true;
1178 write!(f, "{}:", bold.paint(span.metadata().name()))?;
1179 }
1180
1181 if seen {
1182 f.write_char(' ')?;
1183 }
1184 Ok(())
1185 }
1186}
1187
f035d41b
XL
1188#[cfg(not(feature = "ansi"))]
1189struct Style;
1190
1191#[cfg(not(feature = "ansi"))]
1192impl Style {
1193 fn new() -> Self {
1194 Style
1195 }
a2a8927a
XL
1196
1197 fn bold(self) -> Self {
1198 self
1199 }
1200
f035d41b
XL
1201 fn paint(&self, d: impl fmt::Display) -> impl fmt::Display {
1202 d
1203 }
1204}
1205
3dfed10e
XL
1206struct FmtThreadName<'a> {
1207 name: &'a str,
1208}
1209
1210impl<'a> FmtThreadName<'a> {
1211 pub(crate) fn new(name: &'a str) -> Self {
1212 Self { name }
1213 }
1214}
1215
1216impl<'a> fmt::Display for FmtThreadName<'a> {
1217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1218 use std::sync::atomic::{
1219 AtomicUsize,
1220 Ordering::{AcqRel, Acquire, Relaxed},
1221 };
1222
1223 // Track the longest thread name length we've seen so far in an atomic,
1224 // so that it can be updated by any thread.
1225 static MAX_LEN: AtomicUsize = AtomicUsize::new(0);
1226 let len = self.name.len();
1227 // Snapshot the current max thread name length.
1228 let mut max_len = MAX_LEN.load(Relaxed);
1229
1230 while len > max_len {
1231 // Try to set a new max length, if it is still the value we took a
1232 // snapshot of.
1233 match MAX_LEN.compare_exchange(max_len, len, AcqRel, Acquire) {
1234 // We successfully set the new max value
1235 Ok(_) => break,
1236 // Another thread set a new max value since we last observed
1237 // it! It's possible that the new length is actually longer than
1238 // ours, so we'll loop again and check whether our length is
1239 // still the longest. If not, we'll just use the newer value.
1240 Err(actual) => max_len = actual,
1241 }
1242 }
1243
1244 // pad thread name using `max_len`
1245 write!(f, "{:>width$}", self.name, width = max_len)
1246 }
1247}
1248
f035d41b
XL
1249struct FmtLevel<'a> {
1250 level: &'a Level,
1251 #[cfg(feature = "ansi")]
1252 ansi: bool,
1253}
1254
1255impl<'a> FmtLevel<'a> {
1256 #[cfg(feature = "ansi")]
1257 pub(crate) fn new(level: &'a Level, ansi: bool) -> Self {
1258 Self { level, ansi }
1259 }
1260
1261 #[cfg(not(feature = "ansi"))]
1262 pub(crate) fn new(level: &'a Level) -> Self {
1263 Self { level }
1264 }
1265}
1266
1267const TRACE_STR: &str = "TRACE";
1268const DEBUG_STR: &str = "DEBUG";
1269const INFO_STR: &str = " INFO";
1270const WARN_STR: &str = " WARN";
1271const ERROR_STR: &str = "ERROR";
1272
1273#[cfg(not(feature = "ansi"))]
1274impl<'a> fmt::Display for FmtLevel<'a> {
1275 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1276 match *self.level {
1277 Level::TRACE => f.pad(TRACE_STR),
1278 Level::DEBUG => f.pad(DEBUG_STR),
1279 Level::INFO => f.pad(INFO_STR),
1280 Level::WARN => f.pad(WARN_STR),
1281 Level::ERROR => f.pad(ERROR_STR),
1282 }
1283 }
1284}
1285
1286#[cfg(feature = "ansi")]
1287impl<'a> fmt::Display for FmtLevel<'a> {
1288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1289 if self.ansi {
1290 match *self.level {
1291 Level::TRACE => write!(f, "{}", Colour::Purple.paint(TRACE_STR)),
1292 Level::DEBUG => write!(f, "{}", Colour::Blue.paint(DEBUG_STR)),
1293 Level::INFO => write!(f, "{}", Colour::Green.paint(INFO_STR)),
1294 Level::WARN => write!(f, "{}", Colour::Yellow.paint(WARN_STR)),
1295 Level::ERROR => write!(f, "{}", Colour::Red.paint(ERROR_STR)),
1296 }
1297 } else {
1298 match *self.level {
1299 Level::TRACE => f.pad(TRACE_STR),
1300 Level::DEBUG => f.pad(DEBUG_STR),
1301 Level::INFO => f.pad(INFO_STR),
1302 Level::WARN => f.pad(WARN_STR),
1303 Level::ERROR => f.pad(ERROR_STR),
1304 }
1305 }
1306 }
1307}
1308
1309// === impl FieldFn ===
1310
a2a8927a 1311impl<'a, F> MakeVisitor<Writer<'a>> for FieldFn<F>
f035d41b 1312where
a2a8927a 1313 F: Fn(&mut Writer<'a>, &Field, &dyn fmt::Debug) -> fmt::Result + Clone,
f035d41b
XL
1314{
1315 type Visitor = FieldFnVisitor<'a, F>;
1316
a2a8927a 1317 fn make_visitor(&self, writer: Writer<'a>) -> Self::Visitor {
f035d41b
XL
1318 FieldFnVisitor {
1319 writer,
1320 f: self.0.clone(),
1321 result: Ok(()),
1322 }
1323 }
1324}
1325
1326impl<'a, F> Visit for FieldFnVisitor<'a, F>
1327where
a2a8927a 1328 F: Fn(&mut Writer<'a>, &Field, &dyn fmt::Debug) -> fmt::Result,
f035d41b
XL
1329{
1330 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
1331 if self.result.is_ok() {
1332 self.result = (self.f)(&mut self.writer, field, value)
1333 }
1334 }
1335}
1336
1337impl<'a, F> VisitOutput<fmt::Result> for FieldFnVisitor<'a, F>
1338where
a2a8927a 1339 F: Fn(&mut Writer<'a>, &Field, &dyn fmt::Debug) -> fmt::Result,
f035d41b
XL
1340{
1341 fn finish(self) -> fmt::Result {
1342 self.result
1343 }
1344}
1345
1346impl<'a, F> VisitFmt for FieldFnVisitor<'a, F>
1347where
a2a8927a 1348 F: Fn(&mut Writer<'a>, &Field, &dyn fmt::Debug) -> fmt::Result,
f035d41b
XL
1349{
1350 fn writer(&mut self) -> &mut dyn fmt::Write {
a2a8927a 1351 &mut self.writer
f035d41b
XL
1352 }
1353}
1354
1355impl<'a, F> fmt::Debug for FieldFnVisitor<'a, F> {
1356 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1357 f.debug_struct("FieldFnVisitor")
a2a8927a
XL
1358 .field("f", &format_args!("{}", std::any::type_name::<F>()))
1359 .field("writer", &self.writer)
f035d41b
XL
1360 .field("result", &self.result)
1361 .finish()
1362 }
1363}
1364
1365// === printing synthetic Span events ===
1366
1367/// Configures what points in the span lifecycle are logged as events.
1368///
1369/// See also [`with_span_events`](../struct.SubscriberBuilder.html#method.with_span_events).
1370#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
cdc7bbd5 1371pub struct FmtSpan(u8);
f035d41b
XL
1372
1373impl FmtSpan {
cdc7bbd5
XL
1374 /// one event when span is created
1375 pub const NEW: FmtSpan = FmtSpan(1 << 0);
1376 /// one event per enter of a span
1377 pub const ENTER: FmtSpan = FmtSpan(1 << 1);
1378 /// one event per exit of a span
1379 pub const EXIT: FmtSpan = FmtSpan(1 << 2);
1380 /// one event when the span is dropped
1381 pub const CLOSE: FmtSpan = FmtSpan(1 << 3);
1382
f035d41b 1383 /// spans are ignored (this is the default)
cdc7bbd5 1384 pub const NONE: FmtSpan = FmtSpan(0);
f035d41b 1385 /// one event per enter/exit of a span
cdc7bbd5 1386 pub const ACTIVE: FmtSpan = FmtSpan(FmtSpan::ENTER.0 | FmtSpan::EXIT.0);
f035d41b 1387 /// events at all points (new, enter, exit, drop)
cdc7bbd5
XL
1388 pub const FULL: FmtSpan =
1389 FmtSpan(FmtSpan::NEW.0 | FmtSpan::ENTER.0 | FmtSpan::EXIT.0 | FmtSpan::CLOSE.0);
1390
1391 /// Check whether or not a certain flag is set for this [`FmtSpan`]
1392 fn contains(&self, other: FmtSpan) -> bool {
1393 self.clone() & other.clone() == other
1394 }
f035d41b
XL
1395}
1396
cdc7bbd5
XL
1397macro_rules! impl_fmt_span_bit_op {
1398 ($trait:ident, $func:ident, $op:tt) => {
1399 impl std::ops::$trait for FmtSpan {
1400 type Output = FmtSpan;
1401
1402 fn $func(self, rhs: Self) -> Self::Output {
1403 FmtSpan(self.0 $op rhs.0)
1404 }
1405 }
1406 };
1407}
1408
1409macro_rules! impl_fmt_span_bit_assign_op {
1410 ($trait:ident, $func:ident, $op:tt) => {
1411 impl std::ops::$trait for FmtSpan {
1412 fn $func(&mut self, rhs: Self) {
1413 *self = FmtSpan(self.0 $op rhs.0)
1414 }
1415 }
1416 };
1417}
1418
1419impl_fmt_span_bit_op!(BitAnd, bitand, &);
1420impl_fmt_span_bit_op!(BitOr, bitor, |);
1421impl_fmt_span_bit_op!(BitXor, bitxor, ^);
1422
1423impl_fmt_span_bit_assign_op!(BitAndAssign, bitand_assign, &);
1424impl_fmt_span_bit_assign_op!(BitOrAssign, bitor_assign, |);
1425impl_fmt_span_bit_assign_op!(BitXorAssign, bitxor_assign, ^);
1426
f035d41b
XL
1427impl Debug for FmtSpan {
1428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cdc7bbd5
XL
1429 let mut wrote_flag = false;
1430 let mut write_flags = |flag, flag_str| -> fmt::Result {
1431 if self.contains(flag) {
1432 if wrote_flag {
1433 f.write_str(" | ")?;
1434 }
1435
1436 f.write_str(flag_str)?;
1437 wrote_flag = true;
1438 }
1439
1440 Ok(())
1441 };
1442
1443 if FmtSpan::NONE | self.clone() == FmtSpan::NONE {
1444 f.write_str("FmtSpan::NONE")?;
1445 } else {
1446 write_flags(FmtSpan::NEW, "FmtSpan::NEW")?;
1447 write_flags(FmtSpan::ENTER, "FmtSpan::ENTER")?;
1448 write_flags(FmtSpan::EXIT, "FmtSpan::EXIT")?;
1449 write_flags(FmtSpan::CLOSE, "FmtSpan::CLOSE")?;
f035d41b 1450 }
f035d41b 1451
cdc7bbd5
XL
1452 Ok(())
1453 }
f035d41b
XL
1454}
1455
1456pub(super) struct FmtSpanConfig {
1457 pub(super) kind: FmtSpan,
1458 pub(super) fmt_timing: bool,
1459}
1460
1461impl FmtSpanConfig {
1462 pub(super) fn without_time(self) -> Self {
1463 Self {
1464 kind: self.kind,
1465 fmt_timing: false,
1466 }
1467 }
1468 pub(super) fn with_kind(self, kind: FmtSpan) -> Self {
1469 Self {
1470 kind,
1471 fmt_timing: self.fmt_timing,
1472 }
1473 }
1474 pub(super) fn trace_new(&self) -> bool {
cdc7bbd5
XL
1475 self.kind.contains(FmtSpan::NEW)
1476 }
1477 pub(super) fn trace_enter(&self) -> bool {
1478 self.kind.contains(FmtSpan::ENTER)
f035d41b 1479 }
cdc7bbd5
XL
1480 pub(super) fn trace_exit(&self) -> bool {
1481 self.kind.contains(FmtSpan::EXIT)
f035d41b
XL
1482 }
1483 pub(super) fn trace_close(&self) -> bool {
cdc7bbd5 1484 self.kind.contains(FmtSpan::CLOSE)
f035d41b
XL
1485 }
1486}
1487
1488impl Debug for FmtSpanConfig {
1489 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1490 self.kind.fmt(f)
1491 }
1492}
1493
1494impl Default for FmtSpanConfig {
1495 fn default() -> Self {
1496 Self {
1497 kind: FmtSpan::NONE,
1498 fmt_timing: true,
1499 }
1500 }
1501}
1502
f035d41b
XL
1503pub(super) struct TimingDisplay(pub(super) u64);
1504impl Display for TimingDisplay {
1505 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1506 let mut t = self.0 as f64;
1507 for unit in ["ns", "µs", "ms", "s"].iter() {
1508 if t < 10.0 {
1509 return write!(f, "{:.2}{}", t, unit);
1510 } else if t < 100.0 {
1511 return write!(f, "{:.1}{}", t, unit);
1512 } else if t < 1000.0 {
1513 return write!(f, "{:.0}{}", t, unit);
1514 }
1515 t /= 1000.0;
1516 }
1517 write!(f, "{:.0}s", t * 1000.0)
1518 }
1519}
1520
1521#[cfg(test)]
1522pub(super) mod test {
a2a8927a
XL
1523 use crate::fmt::{test::MockMakeWriter, time::FormatTime};
1524 use tracing::{
1525 self,
1526 dispatcher::{set_default, Dispatch},
1527 subscriber::with_default,
1528 };
f035d41b 1529
a2a8927a
XL
1530 use super::*;
1531 use std::fmt;
f035d41b
XL
1532
1533 pub(crate) struct MockTime;
1534 impl FormatTime for MockTime {
a2a8927a 1535 fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
f035d41b
XL
1536 write!(w, "fake time")
1537 }
1538 }
1539
17df50a5
XL
1540 #[test]
1541 fn disable_everything() {
1542 // This test reproduces https://github.com/tokio-rs/tracing/issues/1354
a2a8927a 1543 let make_writer = MockMakeWriter::default();
17df50a5 1544 let subscriber = crate::fmt::Subscriber::builder()
a2a8927a 1545 .with_writer(make_writer.clone())
17df50a5
XL
1546 .without_time()
1547 .with_level(false)
1548 .with_target(false)
1549 .with_thread_ids(false)
1550 .with_thread_names(false);
1551 #[cfg(feature = "ansi")]
1552 let subscriber = subscriber.with_ansi(false);
a2a8927a 1553 run_test(subscriber, make_writer, "hello\n")
17df50a5
XL
1554 }
1555
a2a8927a
XL
1556 fn test_ansi<T>(
1557 is_ansi: bool,
1558 expected: &str,
1559 builder: crate::fmt::SubscriberBuilder<DefaultFields, Format<T>>,
1560 ) where
1561 Format<T, MockTime>: FormatEvent<crate::Registry, DefaultFields>,
1562 T: Send + Sync + 'static,
1563 {
1564 let make_writer = MockMakeWriter::default();
1565 let subscriber = builder
1566 .with_writer(make_writer.clone())
1567 .with_ansi(is_ansi)
1568 .with_timer(MockTime);
1569 run_test(subscriber, make_writer, expected)
f035d41b
XL
1570 }
1571
a2a8927a
XL
1572 #[cfg(not(feature = "ansi"))]
1573 fn test_without_ansi<T>(
1574 expected: &str,
1575 builder: crate::fmt::SubscriberBuilder<DefaultFields, Format<T>>,
1576 ) where
1577 Format<T, MockTime>: FormatEvent<crate::Registry, DefaultFields>,
1578 T: Send + Sync,
1579 {
1580 let make_writer = MockMakeWriter::default();
1581 let subscriber = builder.with_writer(make_writer).with_timer(MockTime);
1582 run_test(subscriber, make_writer, expected)
f035d41b
XL
1583 }
1584
a2a8927a
XL
1585 fn test_without_level<T>(
1586 expected: &str,
1587 builder: crate::fmt::SubscriberBuilder<DefaultFields, Format<T>>,
1588 ) where
1589 Format<T, MockTime>: FormatEvent<crate::Registry, DefaultFields>,
1590 T: Send + Sync + 'static,
1591 {
1592 let make_writer = MockMakeWriter::default();
1593 let subscriber = builder
1594 .with_writer(make_writer.clone())
1595 .with_level(false)
1596 .with_ansi(false)
1597 .with_timer(MockTime);
1598 run_test(subscriber, make_writer, expected);
1599 }
f035d41b 1600
a2a8927a
XL
1601 fn test_overridden_parents<T>(
1602 expected: &str,
1603 builder: crate::fmt::SubscriberBuilder<DefaultFields, Format<T>>,
1604 ) where
1605 Format<T, MockTime>: FormatEvent<crate::Registry, DefaultFields>,
1606 T: Send + Sync + 'static,
1607 {
1608 let make_writer = MockMakeWriter::default();
1609 let collector = builder
1610 .with_writer(make_writer.clone())
1611 .with_level(false)
1612 .with_ansi(false)
f035d41b
XL
1613 .with_timer(MockTime)
1614 .finish();
1615
a2a8927a
XL
1616 with_default(collector, || {
1617 let span1 = tracing::info_span!("span1", span = 1);
1618 let span2 = tracing::info_span!(parent: &span1, "span2", span = 2);
1619 tracing::info!(parent: &span2, "hello");
f035d41b 1620 });
a2a8927a 1621 assert_eq!(expected, make_writer.get_string());
f035d41b
XL
1622 }
1623
a2a8927a
XL
1624 fn test_overridden_parents_in_scope<T>(
1625 expected1: &str,
1626 expected2: &str,
1627 builder: crate::fmt::SubscriberBuilder<DefaultFields, Format<T>>,
1628 ) where
1629 Format<T, MockTime>: FormatEvent<crate::Registry, DefaultFields>,
1630 T: Send + Sync + 'static,
f035d41b 1631 {
a2a8927a
XL
1632 let make_writer = MockMakeWriter::default();
1633 let subscriber = builder
1634 .with_writer(make_writer.clone())
1635 .with_level(false)
1636 .with_ansi(false)
f035d41b
XL
1637 .with_timer(MockTime)
1638 .finish();
1639
1640 with_default(subscriber, || {
a2a8927a
XL
1641 let span1 = tracing::info_span!("span1", span = 1);
1642 let span2 = tracing::info_span!(parent: &span1, "span2", span = 2);
1643 let span3 = tracing::info_span!("span3", span = 3);
1644 let _e3 = span3.enter();
1645
1646 tracing::info!("hello");
1647 assert_eq!(expected1, make_writer.get_string().as_str());
1648
1649 tracing::info!(parent: &span2, "hello");
1650 assert_eq!(expected2, make_writer.get_string().as_str());
f035d41b 1651 });
a2a8927a 1652 }
f035d41b 1653
a2a8927a
XL
1654 fn run_test(subscriber: impl Into<Dispatch>, buf: MockMakeWriter, expected: &str) {
1655 let _default = set_default(&subscriber.into());
1656 tracing::info!("hello");
1657 assert_eq!(expected, buf.get_string())
f035d41b
XL
1658 }
1659
a2a8927a
XL
1660 mod default {
1661 use super::*;
1662 #[cfg(feature = "ansi")]
1663 #[test]
1664 fn with_ansi_true() {
1665 let expected = "\u{1b}[2mfake time\u{1b}[0m \u{1b}[32m INFO\u{1b}[0m \u{1b}[2mtracing_subscriber::fmt::format::test\u{1b}[0m\u{1b}[2m:\u{1b}[0m hello\n";
1666 test_ansi(true, expected, crate::fmt::Subscriber::builder());
f035d41b
XL
1667 }
1668
a2a8927a
XL
1669 #[cfg(feature = "ansi")]
1670 #[test]
1671 fn with_ansi_false() {
1672 let expected = "fake time INFO tracing_subscriber::fmt::format::test: hello\n";
1673 test_ansi(false, expected, crate::fmt::Subscriber::builder());
1674 }
f035d41b 1675
a2a8927a
XL
1676 #[cfg(not(feature = "ansi"))]
1677 #[test]
1678 fn without_ansi() {
1679 let expected = "fake time INFO tracing_subscriber::fmt::format::test: hello\n";
1680 test_without_ansi(expected, crate::fmt::Subscriber::builder())
1681 }
f035d41b 1682
a2a8927a
XL
1683 #[test]
1684 fn without_level() {
1685 let expected = "fake time tracing_subscriber::fmt::format::test: hello\n";
1686 test_without_level(expected, crate::fmt::Subscriber::builder())
f035d41b
XL
1687 }
1688
a2a8927a
XL
1689 #[test]
1690 fn overridden_parents() {
1691 let expected = "fake time span1{span=1}:span2{span=2}: tracing_subscriber::fmt::format::test: hello\n";
1692 test_overridden_parents(expected, crate::fmt::Subscriber::builder())
1693 }
f035d41b 1694
a2a8927a
XL
1695 #[test]
1696 fn overridden_parents_in_scope() {
1697 test_overridden_parents_in_scope(
1698 "fake time span3{span=3}: tracing_subscriber::fmt::format::test: hello\n",
1699 "fake time span1{span=1}:span2{span=2}: tracing_subscriber::fmt::format::test: hello\n",
1700 crate::fmt::Subscriber::builder(),
1701 )
1702 }
f035d41b
XL
1703 }
1704
a2a8927a
XL
1705 mod compact {
1706 use super::*;
1707
1708 #[cfg(feature = "ansi")]
1709 #[test]
1710 fn with_ansi_true() {
1711 let expected = "\u{1b}[2mfake time\u{1b}[0m \u{1b}[32m INFO\u{1b}[0m \u{1b}[1mtracing_subscriber::fmt::format::test\u{1b}[0m\u{1b}[2m:\u{1b}[0m hello\n";
1712 test_ansi(true, expected, crate::fmt::Subscriber::builder().compact())
f035d41b
XL
1713 }
1714
a2a8927a
XL
1715 #[cfg(feature = "ansi")]
1716 #[test]
1717 fn with_ansi_false() {
1718 let expected = "fake time INFO tracing_subscriber::fmt::format::test: hello\n";
1719 test_ansi(false, expected, crate::fmt::Subscriber::builder().compact());
1720 }
f035d41b 1721
a2a8927a
XL
1722 #[cfg(not(feature = "ansi"))]
1723 #[test]
1724 fn without_ansi() {
1725 let expected = "fake time INFO tracing_subscriber::fmt::format::test: hello\n";
1726 test_without_ansi(expected, crate::fmt::Subscriber::builder().compact())
1727 }
f035d41b 1728
a2a8927a
XL
1729 #[test]
1730 fn without_level() {
1731 let expected = "fake time tracing_subscriber::fmt::format::test: hello\n";
1732 test_without_level(expected, crate::fmt::Subscriber::builder().compact());
1733 }
f035d41b 1734
a2a8927a
XL
1735 #[test]
1736 fn overridden_parents() {
1737 let expected = "fake time span1:span2: tracing_subscriber::fmt::format::test: hello span=1 span=2\n";
1738 test_overridden_parents(expected, crate::fmt::Subscriber::builder().compact())
1739 }
f035d41b 1740
a2a8927a
XL
1741 #[test]
1742 fn overridden_parents_in_scope() {
1743 test_overridden_parents_in_scope(
1744 "fake time span3: tracing_subscriber::fmt::format::test: hello span=3\n",
1745 "fake time span1:span2: tracing_subscriber::fmt::format::test: hello span=1 span=2\n",
1746 crate::fmt::Subscriber::builder().compact(),
1747 )
1748 }
f035d41b
XL
1749 }
1750
1751 #[test]
1752 fn format_nanos() {
1753 fn fmt(t: u64) -> String {
1754 TimingDisplay(t).to_string()
1755 }
1756
1757 assert_eq!(fmt(1), "1.00ns");
1758 assert_eq!(fmt(12), "12.0ns");
1759 assert_eq!(fmt(123), "123ns");
1760 assert_eq!(fmt(1234), "1.23µs");
1761 assert_eq!(fmt(12345), "12.3µs");
1762 assert_eq!(fmt(123456), "123µs");
1763 assert_eq!(fmt(1234567), "1.23ms");
1764 assert_eq!(fmt(12345678), "12.3ms");
1765 assert_eq!(fmt(123456789), "123ms");
1766 assert_eq!(fmt(1234567890), "1.23s");
1767 assert_eq!(fmt(12345678901), "12.3s");
1768 assert_eq!(fmt(123456789012), "123s");
1769 assert_eq!(fmt(1234567890123), "1235s");
1770 }
cdc7bbd5
XL
1771
1772 #[test]
1773 fn fmt_span_combinations() {
1774 let f = FmtSpan::NONE;
136023e0
XL
1775 assert!(!f.contains(FmtSpan::NEW));
1776 assert!(!f.contains(FmtSpan::ENTER));
1777 assert!(!f.contains(FmtSpan::EXIT));
1778 assert!(!f.contains(FmtSpan::CLOSE));
cdc7bbd5
XL
1779
1780 let f = FmtSpan::ACTIVE;
136023e0
XL
1781 assert!(!f.contains(FmtSpan::NEW));
1782 assert!(f.contains(FmtSpan::ENTER));
1783 assert!(f.contains(FmtSpan::EXIT));
1784 assert!(!f.contains(FmtSpan::CLOSE));
cdc7bbd5
XL
1785
1786 let f = FmtSpan::FULL;
136023e0
XL
1787 assert!(f.contains(FmtSpan::NEW));
1788 assert!(f.contains(FmtSpan::ENTER));
1789 assert!(f.contains(FmtSpan::EXIT));
1790 assert!(f.contains(FmtSpan::CLOSE));
cdc7bbd5
XL
1791
1792 let f = FmtSpan::NEW | FmtSpan::CLOSE;
136023e0
XL
1793 assert!(f.contains(FmtSpan::NEW));
1794 assert!(!f.contains(FmtSpan::ENTER));
1795 assert!(!f.contains(FmtSpan::EXIT));
1796 assert!(f.contains(FmtSpan::CLOSE));
cdc7bbd5 1797 }
f035d41b 1798}