Skip to content

Commit f86322a

Browse files
hawkwdavidbarsky
andcommitted
subscriber: "implementing FormatEvent" docs (#1727)
This branch adds some documentation to the `FormatEvent` trait in `tracing_subscriber::fmt` on how to write user-provided `FormatEvent` implementations. There's probably room for additional improvement here, but I just wanted to get something written down for now. I also fixed a broken link I noticed while I was here. Signed-off-by: Eliza Weisman <[email protected]> Co-authored-by: David Barsky <[email protected]>
1 parent 8c2852a commit f86322a

File tree

4 files changed

+115
-28
lines changed

4 files changed

+115
-28
lines changed

Diff for: tracing-subscriber/src/fmt/format/mod.rs

+67-18
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,55 @@ pub use pretty::*;
3333

3434
/// A type that can format a tracing [`Event`] to a [`Writer`].
3535
///
36-
/// `FormatEvent` is primarily used in the context of [`fmt::Subscriber`] or [`fmt::Layer`]. Each time an event is
37-
/// dispatched to [`fmt::Subscriber`] or [`fmt::Layer`], the subscriber or layer forwards it to
38-
/// its associated `FormatEvent` to emit a log message.
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.
3940
///
4041
/// This trait is already implemented for function pointers with the same
4142
/// signature as `format_event`.
4243
///
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+
///
4380
/// # Examples
4481
///
82+
/// This example re-implements a simiplified version of this crate's [default
83+
/// formatter]:
84+
///
4585
/// ```rust
4686
/// use std::fmt;
4787
/// use tracing_core::{Subscriber, Event};
@@ -65,31 +105,25 @@ pub use pretty::*;
65105
/// mut writer: format::Writer<'_>,
66106
/// event: &Event<'_>,
67107
/// ) -> fmt::Result {
68-
/// // Write level and target
69-
/// let level = *event.metadata().level();
70-
/// let target = event.metadata().target();
71-
/// write!(
72-
/// writer,
73-
/// "{} {}: ",
74-
/// level,
75-
/// target,
76-
/// )?;
108+
/// // Format values from the event's's metadata:
109+
/// let metadata = event.metadata();
110+
/// write!(&mut writer, "{} {}: ", metadata.level(), metadata.target())?;
77111
///
78-
/// // Write spans and fields of each span
112+
/// // Format all the spans in the event's span context.
79113
/// ctx.visit_spans(|span| {
80114
/// write!(writer, "{}", span.name())?;
81115
///
82-
/// let ext = span.extensions();
83-
///
84-
/// // `FormattedFields` is a a formatted representation of the span's
116+
/// // `FormattedFields` is a formatted representation of the span's
85117
/// // fields, which is stored in its extensions by the `fmt` layer's
86118
/// // `new_span` method. The fields will have been formatted
87119
/// // by the same field formatter that's provided to the event
88120
/// // formatter in the `FmtContext`.
121+
/// let ext = span.extensions();
89122
/// let fields = &ext
90123
/// .get::<FormattedFields<N>>()
91124
/// .expect("will never be `None`");
92125
///
126+
/// // Skip formatting the fields if the span had no fields.
93127
/// if !fields.is_empty() {
94128
/// write!(writer, "{{{}}}", fields)?;
95129
/// }
@@ -104,6 +138,13 @@ pub use pretty::*;
104138
/// writeln!(writer)
105139
/// }
106140
/// }
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");
107148
/// ```
108149
///
109150
/// This formatter will print events like this:
@@ -114,7 +155,13 @@ pub use pretty::*;
114155
///
115156
/// [`fmt::Layer`]: super::Layer
116157
/// [`fmt::Subscriber`]: super::Subscriber
117-
/// [`Event`]: tracing::Event
158+
/// [`layer::Context`]: crate::layer::Context
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
118165
pub trait FormatEvent<S, N>
119166
where
120167
S: Subscriber + for<'a> LookupSpan<'a>,
@@ -369,10 +416,12 @@ impl<'writer> Writer<'writer> {
369416
self.writer.write_fmt(args)
370417
}
371418

372-
/// Returns `true` if ANSI escape codes may be used to add colors
419+
/// Returns `true` if [ANSI escape codes] may be used to add colors
373420
/// and other formatting when writing to this `Writer`.
374421
///
375422
/// If this returns `false`, formatters should not emit ANSI escape codes.
423+
///
424+
/// [ANSI escape codes]: https://en.wikipedia.org/wiki/ANSI_escape_code
376425
pub fn has_ansi_escapes(&self) -> bool {
377426
self.is_ansi
378427
}

Diff for: tracing-subscriber/src/fmt/mod.rs

+43-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
//! A `Subscriber` for formatting and logging `tracing` data.
22
//!
3-
//! ## Overview
3+
//! # Overview
44
//!
55
//! [`tracing`] is a framework for instrumenting Rust programs with context-aware,
66
//! structured, event-based diagnostic information. This crate provides an
77
//! implementation of the [`Subscriber`] trait that records `tracing`'s `Event`s
88
//! and `Span`s by formatting them as text and logging them to stdout.
99
//!
10-
//! ## Usage
10+
//! # Usage
1111
//!
1212
//! First, add this to your `Cargo.toml` file:
1313
//!
@@ -41,7 +41,7 @@
4141
//! **Note**: This should **not** be called by libraries. Libraries should use
4242
//! [`tracing`] to publish `tracing` `Event`s.
4343
//!
44-
//! ## Configuration
44+
//! # Configuration
4545
//!
4646
//! You can configure a subscriber instead of using the defaults with
4747
//! the following functions:
@@ -60,7 +60,7 @@
6060
//! You can find the configuration methods for [`FmtSubscriber`] in
6161
//! [`SubscriberBuilder`].
6262
//!
63-
//! ### Formatters
63+
//! ## Formatters
6464
//!
6565
//! The output format used by the layer and subscriber in this module is
6666
//! represented by implementing the [`FormatEvent`] trait, and can be
@@ -195,7 +195,44 @@
195195
//! {&quot;timestamp&quot;:&quot;Oct 24 13:00:00.875&quot;,&quot;level&quot;:&quot;INFO&quot;,&quot;fields&quot;:{&quot;message&quot;:&quot;yak shaving completed&quot;,&quot;all_yaks_shaved&quot;:false},&quot;target&quot;:&quot;fmt_json&quot;}
196196
//! </pre>
197197
//!
198-
//! ### Filters
198+
//! ### Customizing Formatters
199+
//!
200+
//! The formatting of log lines for spans and events is controlled by two
201+
//! traits, [`FormatEvent`] and [`FormatFields`]. The [`FormatEvent`] trait
202+
//! determines the overall formatting of the log line, such as what information
203+
//! from the event's metadata and span context is included and in what order.
204+
//! The [`FormatFields`] trait determines how fields &mdash; both the event's
205+
//! fields and fields on spans &mdash; are formatted.
206+
//!
207+
//! The [`fmt::format`] module provides several types which implement these traits,
208+
//! many of which expose additional configuration options to customize their
209+
//! output. The [`format::Format`] type implements common configuration used by
210+
//! all the formatters provided in this crate, and can be used as a builder to
211+
//! set specific formatting settings. For example:
212+
//!
213+
//! ```
214+
//! use tracing_subscriber::fmt;
215+
//!
216+
//! // Configure a custom event formatter
217+
//! let format = fmt::format()
218+
//! .with_level(false) // don't include levels in formatted output
219+
//! .with_target(false) // don't include targets
220+
//! .with_thread_ids(true) // include the thread ID of the current thread
221+
//! .with_thread_names(true) // include the name of the current thread
222+
//! .compact(); // use the `Compact` formatting style.
223+
//!
224+
//! // Create a `fmt` collector that uses our custom event format, and set it
225+
//! // as the default.
226+
//! tracing_subscriber::fmt()
227+
//! .event_format(format)
228+
//! .init();
229+
//! ```
230+
//!
231+
//! However, if a specific output format is needed, other crates can
232+
//! also implement [`FormatEvent`] and [`FormatFields`]. See those traits'
233+
//! documentation for details on how to implement them.
234+
//!
235+
//! ## Filters
199236
//!
200237
//! If you want to filter the `tracing` `Events` based on environment
201238
//! variables, you can use the [`EnvFilter`] as follows:
@@ -257,6 +294,7 @@
257294
//! [`Subscriber`]:
258295
//! https://docs.rs/tracing/latest/tracing/trait.Subscriber.html
259296
//! [`tracing`]: https://crates.io/crates/tracing
297+
//! [`fmt::format`]: mod@crate::fmt::format
260298
use std::{any::TypeId, error::Error, io};
261299
use tracing_core::{span, subscriber::Interest, Event, Metadata};
262300

Diff for: tracing-subscriber/src/fmt/time/time_crate.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ impl<F: Formattable> LocalTime<F> {
6767
///
6868
/// If the format description is statically known, then the
6969
/// [`format_description!`] macro should be used. This is identical to the
70-
/// [`time::format_description::parse] method, but runs at compile-time,
70+
/// [`time::format_description::parse`] method, but runs at compile-time,
7171
/// throwing an error if the format description is invalid. If the desired format
7272
/// is not known statically (e.g., a user is providing a format string), then the
73-
/// [`time::format_description::parse]` method should be used. Note that this
73+
/// [`time::format_description::parse`] method should be used. Note that this
7474
/// method is fallible.
7575
///
7676
/// See the [`time` book] for details on the format description syntax.
@@ -184,10 +184,10 @@ impl<F: Formattable> UtcTime<F> {
184184
///
185185
/// If the format description is statically known, then the
186186
/// [`format_description!`] macro should be used. This is identical to the
187-
/// [`time::format_description::parse] method, but runs at compile-time,
187+
/// [`time::format_description::parse`] method, but runs at compile-time,
188188
/// failing an error if the format description is invalid. If the desired format
189189
/// is not known statically (e.g., a user is providing a format string), then the
190-
/// [`time::format_description::parse]` method should be used. Note that this
190+
/// [`time::format_description::parse`] method should be used. Note that this
191191
/// method is fallible.
192192
///
193193
/// See the [`time` book] for details on the format description syntax.

Diff for: tracing-subscriber/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
//!
6868
//! - [`tracing-log`]: Enables better formatting for events emitted by `log`
6969
//! macros in the `fmt` subscriber. Enabled by default.
70-
//! - [`time`]: Enables support for using the [`time` crate] for timestamp
70+
//! - [`time`][`time` crate]: Enables support for using the [`time` crate] for timestamp
7171
//! formatting in the `fmt` subscriber.
7272
//! - [`smallvec`]: Causes the `EnvFilter` type to use the `smallvec` crate (rather
7373
//! than `Vec`) as a performance optimization. Enabled by default.

0 commit comments

Comments
 (0)