Skip to content

Commit

Permalink
subscriber: "implementing FormatEvent" docs (#1727)
Browse files Browse the repository at this point in the history
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 <eliza@buoyant.io>
Co-authored-by: David Barsky <me@davidbarsky.com>
  • Loading branch information
hawkw and davidbarsky committed Nov 20, 2021
1 parent f1e1d99 commit 055aa69
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 28 deletions.
85 changes: 67 additions & 18 deletions tracing-subscriber/src/fmt/format/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,55 @@ pub use pretty::*;

/// A type that can format a tracing [`Event`] to a [`Writer`].
///
/// `FormatEvent` is primarily used in the context of [`fmt::Subscriber`] or [`fmt::Layer`]. Each time an event is
/// dispatched to [`fmt::Subscriber`] or [`fmt::Layer`], the subscriber or layer forwards it to
/// its associated `FormatEvent` to emit a log message.
/// `FormatEvent` is primarily used in the context of [`fmt::Subscriber`] or
/// [`fmt::Layer`]. Each time an event is dispatched to [`fmt::Subscriber`] or
/// [`fmt::Layer`], the subscriber or layer
/// forwards it to its associated `FormatEvent` to emit a log message.
///
/// This trait is already implemented for function pointers with the same
/// signature as `format_event`.
///
/// # Arguments
///
/// The following arguments are passed to `FormatEvent::format_event`:
///
/// * A [`FmtContext`]. This is an extension of the [`layer::Context`] type,
/// which can be used for accessing stored information such as the current
/// span context an event occurred in.
///
/// In addition, [`FmtContext`] exposes access to the [`FormatFields`]
/// implementation that the subscriber was configured to use via the
/// [`FmtContext::field_format`] method. This can be used when the
/// [`FormatEvent`] implementation needs to format the event's fields.
///
/// For convenience, [`FmtContext`] also [implements `FormatFields`],
/// forwarding to the configured [`FormatFields`] type.
///
/// * A [`Writer`] to which the formatted representation of the event is
/// written. This type implements the [`std::fmt::Write`] trait, and therefore
/// can be used with the [`std::write!`] and [`std::writeln!`] macros, as well
/// as calling [`std::fmt::Write`] methods directly.
///
/// The [`Writer`] type also implements additional methods that provide
/// information about how the event should be formatted. The
/// [`Writer::has_ansi_escapes`] method indicates whether [ANSI terminal
/// escape codes] are supported by the underlying I/O writer that the event
/// will be written to. If this returns `true`, the formatter is permitted to
/// use ANSI escape codes to add colors and other text formatting to its
/// output. If it returns `false`, the event will be written to an output that
/// does not support ANSI escape codes (such as a log file), and they should
/// not be emitted.
///
/// Crates like [`ansi_term`] and [`owo-colors`] can be used to add ANSI
/// escape codes to formatted output.
///
/// * The actual [`Event`] to be formatted.
///
/// # Examples
///
/// This example re-implements a simiplified version of this crate's [default
/// formatter]:
///
/// ```rust
/// use std::fmt;
/// use tracing_core::{Subscriber, Event};
Expand All @@ -65,31 +105,25 @@ pub use pretty::*;
/// mut writer: format::Writer<'_>,
/// event: &Event<'_>,
/// ) -> fmt::Result {
/// // Write level and target
/// let level = *event.metadata().level();
/// let target = event.metadata().target();
/// write!(
/// writer,
/// "{} {}: ",
/// level,
/// target,
/// )?;
/// // Format values from the event's's metadata:
/// let metadata = event.metadata();
/// write!(&mut writer, "{} {}: ", metadata.level(), metadata.target())?;
///
/// // Write spans and fields of each span
/// // Format all the spans in the event's span context.
/// ctx.visit_spans(|span| {
/// write!(writer, "{}", span.name())?;
///
/// let ext = span.extensions();
///
/// // `FormattedFields` is a a formatted representation of the span's
/// // `FormattedFields` is a formatted representation of the span's
/// // fields, which is stored in its extensions by the `fmt` layer's
/// // `new_span` method. The fields will have been formatted
/// // by the same field formatter that's provided to the event
/// // formatter in the `FmtContext`.
/// let ext = span.extensions();
/// let fields = &ext
/// .get::<FormattedFields<N>>()
/// .expect("will never be `None`");
///
/// // Skip formatting the fields if the span had no fields.
/// if !fields.is_empty() {
/// write!(writer, "{{{}}}", fields)?;
/// }
Expand All @@ -104,6 +138,13 @@ pub use pretty::*;
/// writeln!(writer)
/// }
/// }
///
/// let _subscriber = tracing_subscriber::fmt()
/// .event_format(MyFormatter)
/// .init();
///
/// let _span = tracing::info_span!("my_span", answer = 42).entered();
/// tracing::info!(question = "life, the universe, and everything", "hello world");
/// ```
///
/// This formatter will print events like this:
Expand All @@ -114,7 +155,13 @@ pub use pretty::*;
///
/// [`fmt::Layer`]: super::Layer
/// [`fmt::Subscriber`]: super::Subscriber
/// [`Event`]: tracing::Event
/// [`layer::Context`]: crate::layer::Context
/// [implements `FormatFields`]: super::FmtContext#impl-FormatFields<'writer>
/// [ANSI terminal escape codes]: https://en.wikipedia.org/wiki/ANSI_escape_code
/// [`Writer::has_ansi_escapes`]: Writer::has_ansi_escapes
/// [`ansi_term`]: https://crates.io/crates/ansi_term
/// [`owo-colors`]: https://crates.io/crates/owo-colors
/// [default formatter]: Full
pub trait FormatEvent<S, N>
where
S: Subscriber + for<'a> LookupSpan<'a>,
Expand Down Expand Up @@ -369,10 +416,12 @@ impl<'writer> Writer<'writer> {
self.writer.write_fmt(args)
}

/// Returns `true` if ANSI escape codes may be used to add colors
/// Returns `true` if [ANSI escape codes] may be used to add colors
/// and other formatting when writing to this `Writer`.
///
/// If this returns `false`, formatters should not emit ANSI escape codes.
///
/// [ANSI escape codes]: https://en.wikipedia.org/wiki/ANSI_escape_code
pub fn has_ansi_escapes(&self) -> bool {
self.is_ansi
}
Expand Down
48 changes: 43 additions & 5 deletions tracing-subscriber/src/fmt/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//! A `Subscriber` for formatting and logging `tracing` data.
//!
//! ## Overview
//! # Overview
//!
//! [`tracing`] is a framework for instrumenting Rust programs with context-aware,
//! structured, event-based diagnostic information. This crate provides an
//! implementation of the [`Subscriber`] trait that records `tracing`'s `Event`s
//! and `Span`s by formatting them as text and logging them to stdout.
//!
//! ## Usage
//! # Usage
//!
//! First, add this to your `Cargo.toml` file:
//!
Expand Down Expand Up @@ -41,7 +41,7 @@
//! **Note**: This should **not** be called by libraries. Libraries should use
//! [`tracing`] to publish `tracing` `Event`s.
//!
//! ## Configuration
//! # Configuration
//!
//! You can configure a subscriber instead of using the defaults with
//! the following functions:
Expand All @@ -60,7 +60,7 @@
//! You can find the configuration methods for [`FmtSubscriber`] in
//! [`SubscriberBuilder`].
//!
//! ### Formatters
//! ## Formatters
//!
//! The output format used by the layer and subscriber in this module is
//! represented by implementing the [`FormatEvent`] trait, and can be
Expand Down Expand Up @@ -195,7 +195,44 @@
//! {&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;}
//! </pre>
//!
//! ### Filters
//! ### Customizing Formatters
//!
//! The formatting of log lines for spans and events is controlled by two
//! traits, [`FormatEvent`] and [`FormatFields`]. The [`FormatEvent`] trait
//! determines the overall formatting of the log line, such as what information
//! from the event's metadata and span context is included and in what order.
//! The [`FormatFields`] trait determines how fields &mdash; both the event's
//! fields and fields on spans &mdash; are formatted.
//!
//! The [`fmt::format`] module provides several types which implement these traits,
//! many of which expose additional configuration options to customize their
//! output. The [`format::Format`] type implements common configuration used by
//! all the formatters provided in this crate, and can be used as a builder to
//! set specific formatting settings. For example:
//!
//! ```
//! use tracing_subscriber::fmt;
//!
//! // Configure a custom event formatter
//! let format = fmt::format()
//! .with_level(false) // don't include levels in formatted output
//! .with_target(false) // don't include targets
//! .with_thread_ids(true) // include the thread ID of the current thread
//! .with_thread_names(true) // include the name of the current thread
//! .compact(); // use the `Compact` formatting style.
//!
//! // Create a `fmt` collector that uses our custom event format, and set it
//! // as the default.
//! tracing_subscriber::fmt()
//! .event_format(format)
//! .init();
//! ```
//!
//! However, if a specific output format is needed, other crates can
//! also implement [`FormatEvent`] and [`FormatFields`]. See those traits'
//! documentation for details on how to implement them.
//!
//! ## Filters
//!
//! If you want to filter the `tracing` `Events` based on environment
//! variables, you can use the [`EnvFilter`] as follows:
Expand Down Expand Up @@ -257,6 +294,7 @@
//! [`Subscriber`]:
//! https://docs.rs/tracing/latest/tracing/trait.Subscriber.html
//! [`tracing`]: https://crates.io/crates/tracing
//! [`fmt::format`]: mod@crate::fmt::format
use std::{any::TypeId, error::Error, io};
use tracing_core::{span, subscriber::Interest, Event, Metadata};

Expand Down
8 changes: 4 additions & 4 deletions tracing-subscriber/src/fmt/time/time_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ impl<F: Formattable> LocalTime<F> {
///
/// If the format description is statically known, then the
/// [`format_description!`] macro should be used. This is identical to the
/// [`time::format_description::parse] method, but runs at compile-time,
/// [`time::format_description::parse`] method, but runs at compile-time,
/// throwing an error if the format description is invalid. If the desired format
/// is not known statically (e.g., a user is providing a format string), then the
/// [`time::format_description::parse]` method should be used. Note that this
/// [`time::format_description::parse`] method should be used. Note that this
/// method is fallible.
///
/// See the [`time` book] for details on the format description syntax.
Expand Down Expand Up @@ -184,10 +184,10 @@ impl<F: Formattable> UtcTime<F> {
///
/// If the format description is statically known, then the
/// [`format_description!`] macro should be used. This is identical to the
/// [`time::format_description::parse] method, but runs at compile-time,
/// [`time::format_description::parse`] method, but runs at compile-time,
/// failing an error if the format description is invalid. If the desired format
/// is not known statically (e.g., a user is providing a format string), then the
/// [`time::format_description::parse]` method should be used. Note that this
/// [`time::format_description::parse`] method should be used. Note that this
/// method is fallible.
///
/// See the [`time` book] for details on the format description syntax.
Expand Down
2 changes: 1 addition & 1 deletion tracing-subscriber/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
//!
//! - [`tracing-log`]: Enables better formatting for events emitted by `log`
//! macros in the `fmt` subscriber. Enabled by default.
//! - [`time`]: Enables support for using the [`time` crate] for timestamp
//! - [`time`][`time` crate]: Enables support for using the [`time` crate] for timestamp
//! formatting in the `fmt` subscriber.
//! - [`smallvec`]: Causes the `EnvFilter` type to use the `smallvec` crate (rather
//! than `Vec`) as a performance optimization. Enabled by default.
Expand Down

0 comments on commit 055aa69

Please sign in to comment.