1 //! Formatters for logging `tracing` events.
2 use super::time::{FormatTime, SystemTime};
3 use crate::{
4 field::{MakeOutput, MakeVisitor, RecordFields, VisitFmt, VisitOutput},
5 fmt::fmt_layer::FmtContext,
6 fmt::fmt_layer::FormattedFields,
7 registry::LookupSpan,
8 };
9
10 use std::fmt::{self, Debug, Display, Write};
11 use tracing_core::{
12 field::{self, Field, Visit},
13 span, Event, Level, Subscriber,
14 };
15
16 #[cfg(feature = "tracing-log")]
17 use tracing_log::NormalizeEvent;
18
19 #[cfg(feature = "ansi")]
20 use ansi_term::{Colour, Style};
21
22 #[cfg(feature = "json")]
23 mod json;
24 #[cfg(feature = "json")]
25 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
26 pub use json::*;
27
28 #[cfg(feature = "ansi")]
29 mod pretty;
30 #[cfg(feature = "ansi")]
31 #[cfg_attr(docsrs, doc(cfg(feature = "ansi")))]
32 pub use pretty::*;
33
34 /// A type that can format a tracing [`Event`] to a [`Writer`].
35 ///
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.
40 ///
41 /// This trait is already implemented for function pointers with the same
42 /// signature as `format_event`.
43 ///
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 ///
80 /// # Examples
81 ///
82 /// This example re-implements a simiplified version of this crate's [default
83 /// formatter]:
84 ///
85 /// ```rust
86 /// use std::fmt;
87 /// use tracing_core::{Subscriber, Event};
88 /// use tracing_subscriber::fmt::{
89 /// format::{self, FormatEvent, FormatFields},
90 /// FmtContext,
91 /// FormattedFields,
92 /// };
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>,
105 /// mut writer: format::Writer<'_>,
106 /// event: &Event<'_>,
107 /// ) -> fmt::Result {
108 /// // Format values from the event's's metadata:
109 /// let metadata = event.metadata();
110 /// write!(&mut writer, "{} {}: ", metadata.level(), metadata.target())?;
111 ///
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())?;
116 ///
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`");
126 ///
127 /// // Skip formatting the fields if the span had no fields.
128 /// if !fields.is_empty() {
129 /// write!(writer, "{{{}}}", fields)?;
130 /// }
131 /// write!(writer, ": ")?;
132 /// }
133 /// }
134 ///
135 /// // Write fields on the event
136 /// ctx.field_format().format_fields(writer.by_ref(), event)?;
137 ///
138 /// writeln!(writer)
139 /// }
140 /// }
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");
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 ///
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
165 pub trait FormatEvent<S, N>
166 where
167 S: Subscriber + for<'a> LookupSpan<'a>,
168 N: for<'a> FormatFields<'a> + 'static,
169 {
170 /// Write a log message for `Event` in `Context` to the given [`Writer`].
format_event( &self, ctx: &FmtContext<'_, S, N>, writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result171 fn format_event(
172 &self,
173 ctx: &FmtContext<'_, S, N>,
174 writer: Writer<'_>,
175 event: &Event<'_>,
176 ) -> fmt::Result;
177 }
178
179 impl<S, N> FormatEvent<S, N>
180 for fn(ctx: &FmtContext<'_, S, N>, Writer<'_>, &Event<'_>) -> fmt::Result
181 where
182 S: Subscriber + for<'a> LookupSpan<'a>,
183 N: for<'a> FormatFields<'a> + 'static,
184 {
format_event( &self, ctx: &FmtContext<'_, S, N>, writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result185 fn format_event(
186 &self,
187 ctx: &FmtContext<'_, S, N>,
188 writer: Writer<'_>,
189 event: &Event<'_>,
190 ) -> fmt::Result {
191 (*self)(ctx, writer, event)
192 }
193 }
194 /// A type that can format a [set of fields] to a [`Writer`].
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
202 pub trait FormatFields<'writer> {
203 /// Format the provided `fields` to the provided [`Writer`], returning a result.
format_fields<R: RecordFields>(&self, writer: Writer<'writer>, fields: R) -> fmt::Result204 fn format_fields<R: RecordFields>(&self, writer: Writer<'writer>, fields: R) -> fmt::Result;
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.
add_fields( &self, current: &'writer mut FormattedFields<Self>, fields: &span::Record<'_>, ) -> fmt::Result211 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(' ');
218 }
219 self.format_fields(current.as_writer(), fields)
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 /// ```
format() -> Format240 pub 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")))]
json() -> Format<Json>247 pub 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
debug_fn<F>(f: F) -> FieldFn<F> where F: Fn(&mut Writer<'_>, &Field, &dyn fmt::Debug) -> fmt::Result + Clone,255 pub fn debug_fn<F>(f: F) -> FieldFn<F>
256 where
257 F: Fn(&mut Writer<'_>, &Field, &dyn fmt::Debug) -> fmt::Result + Clone,
258 {
259 FieldFn(f)
260 }
261
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.
275 pub struct Writer<'writer> {
276 writer: &'writer mut dyn fmt::Write,
277 // TODO(eliza): add ANSI support
278 is_ansi: bool,
279 }
280
281 /// A [`FormatFields`] implementation that formats fields by calling a function
282 /// or closure.
283 ///
284 /// [`FormatFields`]: trait.FormatFields.html
285 #[derive(Debug, Clone)]
286 pub 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
292 pub struct FieldFnVisitor<'a, F> {
293 f: F,
294 writer: Writer<'a>,
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)]
301 pub 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)]
307 pub 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)]
317 pub struct Format<F = Full, T = SystemTime> {
318 format: F,
319 pub(crate) timer: T,
320 pub(crate) ansi: Option<bool>,
321 pub(crate) display_timestamp: bool,
322 pub(crate) display_target: bool,
323 pub(crate) display_level: bool,
324 pub(crate) display_thread_id: bool,
325 pub(crate) display_thread_name: bool,
326 }
327
328 // === impl Writer ===
329
330 impl<'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...?)
new(writer: &'writer mut impl fmt::Write) -> Self335 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?
with_ansi(self, is_ansi: bool) -> Self343 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.
by_ref(&mut self) -> Writer<'_>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]
write_str(&mut self, s: &str) -> fmt::Result377 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]
write_char(&mut self, c: char) -> fmt::Result399 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
write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result415 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
has_ansi_escapes(&self) -> bool425 pub fn has_ansi_escapes(&self) -> bool {
426 self.is_ansi
427 }
428
bold(&self) -> Style429 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
dimmed(&self) -> Style440 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
italic(&self) -> Style451 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
463 impl fmt::Write for Writer<'_> {
464 #[inline]
write_str(&mut self, s: &str) -> fmt::Result465 fn write_str(&mut self, s: &str) -> fmt::Result {
466 Writer::write_str(self, s)
467 }
468
469 #[inline]
write_char(&mut self, c: char) -> fmt::Result470 fn write_char(&mut self, c: char) -> fmt::Result {
471 Writer::write_char(self, c)
472 }
473
474 #[inline]
write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result475 fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
476 Writer::write_fmt(self, args)
477 }
478 }
479
480 impl fmt::Debug for Writer<'_> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result481 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
491 impl Default for Format<Full, SystemTime> {
default() -> Self492 fn default() -> Self {
493 Format {
494 format: Full,
495 timer: SystemTime,
496 ansi: None,
497 display_timestamp: true,
498 display_target: true,
499 display_level: true,
500 display_thread_id: false,
501 display_thread_name: false,
502 }
503 }
504 }
505
506 impl<F, T> Format<F, T> {
507 /// Use a less verbose output format.
508 ///
509 /// See [`Compact`].
compact(self) -> Format<Compact, T>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,
516 display_timestamp: self.display_timestamp,
517 display_level: self.display_level,
518 display_thread_id: self.display_thread_id,
519 display_thread_name: self.display_thread_name,
520 }
521 }
522
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.
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 /// ```
545 #[cfg(feature = "ansi")]
546 #[cfg_attr(docsrs, doc(cfg(feature = "ansi")))]
pretty(self) -> Format<Pretty, T>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,
553 display_timestamp: self.display_timestamp,
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
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")))]
json(self) -> Format<Json, T>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,
584 display_timestamp: self.display_timestamp,
585 display_level: self.display_level,
586 display_thread_id: self.display_thread_id,
587 display_thread_name: self.display_thread_name,
588 }
589 }
590
591 /// Use the given [`timer`] for log message timestamps.
592 ///
593 /// See [`time` module] for the provided timer implementations.
594 ///
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.
599 ///
600 /// [`timer`]: super::time::FormatTime
601 /// [`time` module]: mod@super::time
602 /// [`UtcTime`]: super::time::UtcTime
603 /// [`LocalTime`]: super::time::LocalTime
604 /// [`time` crate]: https://docs.rs/time/0.3
with_timer<T2>(self, timer: T2) -> Format<F, T2>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,
611 display_timestamp: self.display_timestamp,
612 display_level: self.display_level,
613 display_thread_id: self.display_thread_id,
614 display_thread_name: self.display_thread_name,
615 }
616 }
617
618 /// Do not emit timestamps with log messages.
without_time(self) -> Format<F, ()>619 pub fn without_time(self) -> Format<F, ()> {
620 Format {
621 format: self.format,
622 timer: (),
623 ansi: self.ansi,
624 display_timestamp: false,
625 display_target: self.display_target,
626 display_level: self.display_level,
627 display_thread_id: self.display_thread_id,
628 display_thread_name: self.display_thread_name,
629 }
630 }
631
632 /// Enable ANSI terminal colors for formatted output.
with_ansi(self, ansi: bool) -> Format<F, T>633 pub fn with_ansi(self, ansi: bool) -> Format<F, T> {
634 Format {
635 ansi: Some(ansi),
636 ..self
637 }
638 }
639
640 /// Sets whether or not an event's target is displayed.
with_target(self, display_target: bool) -> Format<F, T>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.
with_level(self, display_level: bool) -> Format<F, T>649 pub fn with_level(self, display_level: bool) -> Format<F, T> {
650 Format {
651 display_level,
652 ..self
653 }
654 }
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
with_thread_ids(self, display_thread_id: bool) -> Format<F, T>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
with_thread_names(self, display_thread_name: bool) -> Format<F, T>671 pub fn with_thread_names(self, display_thread_name: bool) -> Format<F, T> {
672 Format {
673 display_thread_name,
674 ..self
675 }
676 }
677
678 #[inline]
format_timestamp(&self, writer: &mut Writer<'_>) -> fmt::Result where T: FormatTime,679 fn format_timestamp(&self, writer: &mut Writer<'_>) -> fmt::Result
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 {
692 if writer.has_ansi_escapes() {
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 }
705 }
706
707 #[cfg(feature = "json")]
708 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
709 impl<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")))]
flatten_event(mut self, flatten_event: bool) -> Format<Json, T>720 pub fn flatten_event(mut self, flatten_event: bool) -> Format<Json, T> {
721 self.format.flatten_event(flatten_event);
722 self
723 }
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")))]
with_current_span(mut self, display_current_span: bool) -> Format<Json, T>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")))]
with_span_list(mut self, display_span_list: bool) -> Format<Json, T>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 }
746 }
747
748 impl<S, N, T> FormatEvent<S, N> for Format<Full, T>
749 where
750 S: Subscriber + for<'a> LookupSpan<'a>,
751 N: for<'a> FormatFields<'a> + 'static,
752 T: FormatTime,
753 {
format_event( &self, ctx: &FmtContext<'_, S, N>, mut writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result754 fn format_event(
755 &self,
756 ctx: &FmtContext<'_, S, N>,
757 mut writer: Writer<'_>,
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();
766
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)?;
776
777 if self.display_level {
778 let fmt_level = {
779 #[cfg(feature = "ansi")]
780 {
781 FmtLevel::new(meta.level(), writer.has_ansi_escapes())
782 }
783 #[cfg(not(feature = "ansi"))]
784 {
785 FmtLevel::new(meta.level())
786 }
787 };
788 write!(writer, "{} ", fmt_level)?;
789 }
790
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
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(":"))?;
827 }
828
829 if seen {
830 writer.write_char(' ')?;
831 }
832 };
833
834 if self.display_target {
835 write!(
836 writer,
837 "{}{} ",
838 dimmed.paint(meta.target()),
839 dimmed.paint(":")
840 )?;
841 }
842
843 ctx.format_fields(writer.by_ref(), event)?;
844 writeln!(writer)
845 }
846 }
847
848 impl<S, N, T> FormatEvent<S, N> for Format<Compact, T>
849 where
850 S: Subscriber + for<'a> LookupSpan<'a>,
851 N: for<'a> FormatFields<'a> + 'static,
852 T: FormatTime,
853 {
format_event( &self, ctx: &FmtContext<'_, S, N>, mut writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result854 fn format_event(
855 &self,
856 ctx: &FmtContext<'_, S, N>,
857 mut writer: Writer<'_>,
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();
866
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)?;
876
877 if self.display_level {
878 let fmt_level = {
879 #[cfg(feature = "ansi")]
880 {
881 FmtLevel::new(meta.level(), writer.has_ansi_escapes())
882 }
883 #[cfg(not(feature = "ansi"))]
884 {
885 FmtLevel::new(meta.level())
886 }
887 };
888 write!(writer, "{} ", fmt_level)?;
889 }
890
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
909 let fmt_ctx = {
910 #[cfg(feature = "ansi")]
911 {
912 FmtCtx::new(ctx, event.parent(), writer.has_ansi_escapes())
913 }
914 #[cfg(not(feature = "ansi"))]
915 {
916 FmtCtx::new(&ctx, event.parent())
917 }
918 };
919 write!(writer, "{}", fmt_ctx)?;
920
921 if self.display_target {
922 write!(
923 writer,
924 "{}{} ",
925 writer.bold().paint(meta.target()),
926 writer.dimmed().paint(":")
927 )?;
928 }
929
930 ctx.format_fields(writer.by_ref(), event)?;
931
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 {
939 let exts = span.extensions();
940 if let Some(fields) = exts.get::<FormattedFields<N>>() {
941 if !fields.is_empty() {
942 write!(writer, " {}", dimmed.paint(&fields.fields))?;
943 }
944 }
945 }
946 writeln!(writer)
947 }
948 }
949
950 // === impl FormatFields ===
951 impl<'writer, M> FormatFields<'writer> for M
952 where
953 M: MakeOutput<Writer<'writer>, fmt::Result>,
954 M::Visitor: VisitFmt + VisitOutput<fmt::Result>,
955 {
format_fields<R: RecordFields>(&self, writer: Writer<'writer>, fields: R) -> fmt::Result956 fn format_fields<R: RecordFields>(&self, writer: Writer<'writer>, fields: R) -> fmt::Result {
957 let mut v = self.make_visitor(writer);
958 fields.record(&mut v);
959 v.finish()
960 }
961 }
962
963 /// The default [`FormatFields`] implementation.
964 ///
965 /// [`FormatFields`]: trait.FormatFields.html
966 #[derive(Debug)]
967 pub 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 ///
975 /// [visitor]: super::super::field::Visit
976 /// [`MakeVisitor`]: super::super::field::MakeVisitor
977 #[derive(Debug)]
978 pub struct DefaultVisitor<'a> {
979 writer: Writer<'a>,
980 is_empty: bool,
981 result: fmt::Result,
982 }
983
984 impl DefaultFields {
985 /// Returns a new default [`FormatFields`] implementation.
986 ///
987 /// [`FormatFields`]: trait.FormatFields.html
new() -> Self988 pub fn new() -> Self {
989 Self { _private: () }
990 }
991 }
992
993 impl Default for DefaultFields {
default() -> Self994 fn default() -> Self {
995 Self::new()
996 }
997 }
998
999 impl<'a> MakeVisitor<Writer<'a>> for DefaultFields {
1000 type Visitor = DefaultVisitor<'a>;
1001
1002 #[inline]
make_visitor(&self, target: Writer<'a>) -> Self::Visitor1003 fn make_visitor(&self, target: Writer<'a>) -> Self::Visitor {
1004 DefaultVisitor::new(target, true)
1005 }
1006 }
1007
1008 // === impl DefaultVisitor ===
1009
1010 impl<'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.
new(writer: Writer<'a>, is_empty: bool) -> Self1017 pub fn new(writer: Writer<'a>, is_empty: bool) -> Self {
1018 Self {
1019 writer,
1020 is_empty,
1021 result: Ok(()),
1022 }
1023 }
1024
maybe_pad(&mut self)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
1034 impl<'a> field::Visit for DefaultVisitor<'a> {
record_str(&mut self, field: &Field, value: &str)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
record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static))1047 fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
1048 if let Some(source) = value.source() {
1049 let italic = self.writer.italic();
1050 self.record_debug(
1051 field,
1052 &format_args!(
1053 "{} {}{}{}{}",
1054 value,
1055 italic.paint(field.name()),
1056 italic.paint(".sources"),
1057 self.writer.dimmed().paint("="),
1058 ErrorSourceList(source)
1059 ),
1060 )
1061 } else {
1062 self.record_debug(field, &format_args!("{}", value))
1063 }
1064 }
1065
record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)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(()),
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 ),
1091 };
1092 }
1093 }
1094
1095 impl<'a> crate::field::VisitOutput<fmt::Result> for DefaultVisitor<'a> {
finish(self) -> fmt::Result1096 fn finish(self) -> fmt::Result {
1097 self.result
1098 }
1099 }
1100
1101 impl<'a> crate::field::VisitFmt for DefaultVisitor<'a> {
writer(&mut self) -> &mut dyn fmt::Write1102 fn writer(&mut self) -> &mut dyn fmt::Write {
1103 &mut self.writer
1104 }
1105 }
1106
1107 /// Renders an error into a list of sources, *including* the error
1108 struct ErrorSourceList<'a>(&'a (dyn std::error::Error + 'static));
1109
1110 impl<'a> Display for ErrorSourceList<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1111 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
1122 struct 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
1129 impl<'a, S, N: 'a> FmtCtx<'a, S, N>
1130 where
1131 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
1132 N: for<'writer> FormatFields<'writer> + 'static,
1133 {
1134 #[cfg(feature = "ansi")]
new( ctx: &'a FmtContext<'_, S, N>, span: Option<&'a span::Id>, ansi: bool, ) -> Self1135 pub(crate) fn new(
1136 ctx: &'a FmtContext<'_, S, N>,
1137 span: Option<&'a span::Id>,
1138 ansi: bool,
1139 ) -> Self {
1140 Self { ctx, span, ansi }
1141 }
1142
1143 #[cfg(not(feature = "ansi"))]
new(ctx: &'a FmtContext<'_, S, N>, span: Option<&'a span::Id>) -> Self1144 pub(crate) fn new(ctx: &'a FmtContext<'_, S, N>, span: Option<&'a span::Id>) -> Self {
1145 Self { ctx, span }
1146 }
1147
bold(&self) -> Style1148 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
1160 impl<'a, S, N: 'a> fmt::Display for FmtCtx<'a, S, N>
1161 where
1162 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
1163 N: for<'writer> FormatFields<'writer> + 'static,
1164 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1165 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
1171 .and_then(|id| self.ctx.ctx.span(id))
1172 .or_else(|| self.ctx.ctx.lookup_current());
1173
1174 let scope = span.into_iter().flat_map(|span| span.scope().from_root());
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
1188 #[cfg(not(feature = "ansi"))]
1189 struct Style;
1190
1191 #[cfg(not(feature = "ansi"))]
1192 impl Style {
new() -> Self1193 fn new() -> Self {
1194 Style
1195 }
1196
bold(self) -> Self1197 fn bold(self) -> Self {
1198 self
1199 }
1200
paint(&self, d: impl fmt::Display) -> impl fmt::Display1201 fn paint(&self, d: impl fmt::Display) -> impl fmt::Display {
1202 d
1203 }
1204 }
1205
1206 struct FmtThreadName<'a> {
1207 name: &'a str,
1208 }
1209
1210 impl<'a> FmtThreadName<'a> {
new(name: &'a str) -> Self1211 pub(crate) fn new(name: &'a str) -> Self {
1212 Self { name }
1213 }
1214 }
1215
1216 impl<'a> fmt::Display for FmtThreadName<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1217 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
1249 struct FmtLevel<'a> {
1250 level: &'a Level,
1251 #[cfg(feature = "ansi")]
1252 ansi: bool,
1253 }
1254
1255 impl<'a> FmtLevel<'a> {
1256 #[cfg(feature = "ansi")]
new(level: &'a Level, ansi: bool) -> Self1257 pub(crate) fn new(level: &'a Level, ansi: bool) -> Self {
1258 Self { level, ansi }
1259 }
1260
1261 #[cfg(not(feature = "ansi"))]
new(level: &'a Level) -> Self1262 pub(crate) fn new(level: &'a Level) -> Self {
1263 Self { level }
1264 }
1265 }
1266
1267 const TRACE_STR: &str = "TRACE";
1268 const DEBUG_STR: &str = "DEBUG";
1269 const INFO_STR: &str = " INFO";
1270 const WARN_STR: &str = " WARN";
1271 const ERROR_STR: &str = "ERROR";
1272
1273 #[cfg(not(feature = "ansi"))]
1274 impl<'a> fmt::Display for FmtLevel<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1275 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")]
1287 impl<'a> fmt::Display for FmtLevel<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1288 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
1311 impl<'a, F> MakeVisitor<Writer<'a>> for FieldFn<F>
1312 where
1313 F: Fn(&mut Writer<'a>, &Field, &dyn fmt::Debug) -> fmt::Result + Clone,
1314 {
1315 type Visitor = FieldFnVisitor<'a, F>;
1316
make_visitor(&self, writer: Writer<'a>) -> Self::Visitor1317 fn make_visitor(&self, writer: Writer<'a>) -> Self::Visitor {
1318 FieldFnVisitor {
1319 writer,
1320 f: self.0.clone(),
1321 result: Ok(()),
1322 }
1323 }
1324 }
1325
1326 impl<'a, F> Visit for FieldFnVisitor<'a, F>
1327 where
1328 F: Fn(&mut Writer<'a>, &Field, &dyn fmt::Debug) -> fmt::Result,
1329 {
record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)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
1337 impl<'a, F> VisitOutput<fmt::Result> for FieldFnVisitor<'a, F>
1338 where
1339 F: Fn(&mut Writer<'a>, &Field, &dyn fmt::Debug) -> fmt::Result,
1340 {
finish(self) -> fmt::Result1341 fn finish(self) -> fmt::Result {
1342 self.result
1343 }
1344 }
1345
1346 impl<'a, F> VisitFmt for FieldFnVisitor<'a, F>
1347 where
1348 F: Fn(&mut Writer<'a>, &Field, &dyn fmt::Debug) -> fmt::Result,
1349 {
writer(&mut self) -> &mut dyn fmt::Write1350 fn writer(&mut self) -> &mut dyn fmt::Write {
1351 &mut self.writer
1352 }
1353 }
1354
1355 impl<'a, F> fmt::Debug for FieldFnVisitor<'a, F> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1356 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1357 f.debug_struct("FieldFnVisitor")
1358 .field("f", &format_args!("{}", std::any::type_name::<F>()))
1359 .field("writer", &self.writer)
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)]
1371 pub struct FmtSpan(u8);
1372
1373 impl FmtSpan {
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
1383 /// spans are ignored (this is the default)
1384 pub const NONE: FmtSpan = FmtSpan(0);
1385 /// one event per enter/exit of a span
1386 pub const ACTIVE: FmtSpan = FmtSpan(FmtSpan::ENTER.0 | FmtSpan::EXIT.0);
1387 /// events at all points (new, enter, exit, drop)
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`]
contains(&self, other: FmtSpan) -> bool1392 fn contains(&self, other: FmtSpan) -> bool {
1393 self.clone() & other.clone() == other
1394 }
1395 }
1396
1397 macro_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
1409 macro_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
1419 impl_fmt_span_bit_op!(BitAnd, bitand, &);
1420 impl_fmt_span_bit_op!(BitOr, bitor, |);
1421 impl_fmt_span_bit_op!(BitXor, bitxor, ^);
1422
1423 impl_fmt_span_bit_assign_op!(BitAndAssign, bitand_assign, &);
1424 impl_fmt_span_bit_assign_op!(BitOrAssign, bitor_assign, |);
1425 impl_fmt_span_bit_assign_op!(BitXorAssign, bitxor_assign, ^);
1426
1427 impl Debug for FmtSpan {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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")?;
1450 }
1451
1452 Ok(())
1453 }
1454 }
1455
1456 pub(super) struct FmtSpanConfig {
1457 pub(super) kind: FmtSpan,
1458 pub(super) fmt_timing: bool,
1459 }
1460
1461 impl FmtSpanConfig {
without_time(self) -> Self1462 pub(super) fn without_time(self) -> Self {
1463 Self {
1464 kind: self.kind,
1465 fmt_timing: false,
1466 }
1467 }
with_kind(self, kind: FmtSpan) -> Self1468 pub(super) fn with_kind(self, kind: FmtSpan) -> Self {
1469 Self {
1470 kind,
1471 fmt_timing: self.fmt_timing,
1472 }
1473 }
trace_new(&self) -> bool1474 pub(super) fn trace_new(&self) -> bool {
1475 self.kind.contains(FmtSpan::NEW)
1476 }
trace_enter(&self) -> bool1477 pub(super) fn trace_enter(&self) -> bool {
1478 self.kind.contains(FmtSpan::ENTER)
1479 }
trace_exit(&self) -> bool1480 pub(super) fn trace_exit(&self) -> bool {
1481 self.kind.contains(FmtSpan::EXIT)
1482 }
trace_close(&self) -> bool1483 pub(super) fn trace_close(&self) -> bool {
1484 self.kind.contains(FmtSpan::CLOSE)
1485 }
1486 }
1487
1488 impl Debug for FmtSpanConfig {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1489 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1490 self.kind.fmt(f)
1491 }
1492 }
1493
1494 impl Default for FmtSpanConfig {
default() -> Self1495 fn default() -> Self {
1496 Self {
1497 kind: FmtSpan::NONE,
1498 fmt_timing: true,
1499 }
1500 }
1501 }
1502
1503 pub(super) struct TimingDisplay(pub(super) u64);
1504 impl Display for TimingDisplay {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1505 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)]
1522 pub(super) mod test {
1523 use crate::fmt::{test::MockMakeWriter, time::FormatTime};
1524 use tracing::{
1525 self,
1526 dispatcher::{set_default, Dispatch},
1527 subscriber::with_default,
1528 };
1529
1530 use super::*;
1531 use std::fmt;
1532
1533 pub(crate) struct MockTime;
1534 impl FormatTime for MockTime {
format_time(&self, w: &mut Writer<'_>) -> fmt::Result1535 fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
1536 write!(w, "fake time")
1537 }
1538 }
1539
1540 #[test]
disable_everything()1541 fn disable_everything() {
1542 // This test reproduces https://github.com/tokio-rs/tracing/issues/1354
1543 let make_writer = MockMakeWriter::default();
1544 let subscriber = crate::fmt::Subscriber::builder()
1545 .with_writer(make_writer.clone())
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);
1553 run_test(subscriber, make_writer, "hello\n")
1554 }
1555
test_ansi<T>( is_ansi: bool, expected: &str, builder: crate::fmt::SubscriberBuilder<DefaultFields, Format<T>>, ) where Format<T, MockTime>: FormatEvent<crate::Registry, DefaultFields>, T: Send + Sync + 'static,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)
1570 }
1571
1572 #[cfg(not(feature = "ansi"))]
test_without_ansi<T>( expected: &str, builder: crate::fmt::SubscriberBuilder<DefaultFields, Format<T>>, ) where Format<T, MockTime>: FormatEvent<crate::Registry, DefaultFields>, T: Send + Sync,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)
1583 }
1584
test_without_level<T>( expected: &str, builder: crate::fmt::SubscriberBuilder<DefaultFields, Format<T>>, ) where Format<T, MockTime>: FormatEvent<crate::Registry, DefaultFields>, T: Send + Sync + 'static,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 }
1600
test_overridden_parents<T>( expected: &str, builder: crate::fmt::SubscriberBuilder<DefaultFields, Format<T>>, ) where Format<T, MockTime>: FormatEvent<crate::Registry, DefaultFields>, T: Send + Sync + 'static,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)
1613 .with_timer(MockTime)
1614 .finish();
1615
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");
1620 });
1621 assert_eq!(expected, make_writer.get_string());
1622 }
1623
test_overridden_parents_in_scope<T>( expected1: &str, expected2: &str, builder: crate::fmt::SubscriberBuilder<DefaultFields, Format<T>>, ) where Format<T, MockTime>: FormatEvent<crate::Registry, DefaultFields>, T: Send + Sync + 'static,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,
1631 {
1632 let make_writer = MockMakeWriter::default();
1633 let subscriber = builder
1634 .with_writer(make_writer.clone())
1635 .with_level(false)
1636 .with_ansi(false)
1637 .with_timer(MockTime)
1638 .finish();
1639
1640 with_default(subscriber, || {
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());
1651 });
1652 }
1653
run_test(subscriber: impl Into<Dispatch>, buf: MockMakeWriter, expected: &str)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())
1658 }
1659
1660 mod default {
1661 use super::*;
1662 #[cfg(feature = "ansi")]
1663 #[test]
with_ansi_true()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());
1667 }
1668
1669 #[cfg(feature = "ansi")]
1670 #[test]
with_ansi_false()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 }
1675
1676 #[cfg(not(feature = "ansi"))]
1677 #[test]
without_ansi()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 }
1682
1683 #[test]
without_level()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())
1687 }
1688
1689 #[test]
overridden_parents()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 }
1694
1695 #[test]
overridden_parents_in_scope()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 }
1703 }
1704
1705 mod compact {
1706 use super::*;
1707
1708 #[cfg(feature = "ansi")]
1709 #[test]
with_ansi_true()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())
1713 }
1714
1715 #[cfg(feature = "ansi")]
1716 #[test]
with_ansi_false()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 }
1721
1722 #[cfg(not(feature = "ansi"))]
1723 #[test]
without_ansi()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 }
1728
1729 #[test]
without_level()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 }
1734
1735 #[test]
overridden_parents()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 }
1740
1741 #[test]
overridden_parents_in_scope()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 }
1749 }
1750
1751 #[test]
format_nanos()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 }
1771
1772 #[test]
fmt_span_combinations()1773 fn fmt_span_combinations() {
1774 let f = FmtSpan::NONE;
1775 assert!(!f.contains(FmtSpan::NEW));
1776 assert!(!f.contains(FmtSpan::ENTER));
1777 assert!(!f.contains(FmtSpan::EXIT));
1778 assert!(!f.contains(FmtSpan::CLOSE));
1779
1780 let f = FmtSpan::ACTIVE;
1781 assert!(!f.contains(FmtSpan::NEW));
1782 assert!(f.contains(FmtSpan::ENTER));
1783 assert!(f.contains(FmtSpan::EXIT));
1784 assert!(!f.contains(FmtSpan::CLOSE));
1785
1786 let f = FmtSpan::FULL;
1787 assert!(f.contains(FmtSpan::NEW));
1788 assert!(f.contains(FmtSpan::ENTER));
1789 assert!(f.contains(FmtSpan::EXIT));
1790 assert!(f.contains(FmtSpan::CLOSE));
1791
1792 let f = FmtSpan::NEW | FmtSpan::CLOSE;
1793 assert!(f.contains(FmtSpan::NEW));
1794 assert!(!f.contains(FmtSpan::ENTER));
1795 assert!(!f.contains(FmtSpan::EXIT));
1796 assert!(f.contains(FmtSpan::CLOSE));
1797 }
1798 }
1799