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 19, 2021
1 parent 0512245 commit 772290d
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 28 deletions.
86 changes: 68 additions & 18 deletions tracing-subscriber/src/fmt/format/mod.rs
Expand Up @@ -35,15 +35,55 @@ use fmt::{Debug, Display};

/// A type that can format a tracing [`Event`] to a [`Writer`].
///
/// `FormatEvent` is primarily used in the context of [`fmt::Collector`] or [`fmt::Subscriber`].
/// Each time an event is dispatched to [`fmt::Collector`] or [`fmt::Subscriber`],
/// the collector or subscriber forwards it to its associated `FormatEvent` to emit a log message.
/// `FormatEvent` is primarily used in the context of [`fmt::Collector`] or
/// [`fmt::Subscriber`]. Each time an event is dispatched to [`fmt::Collector`]
/// or [`fmt::Subscriber`], the collector or subscriber 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 [`subscribe::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::{Collect, Event};
Expand All @@ -67,31 +107,25 @@ use fmt::{Debug, Display};
/// 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 @@ -106,6 +140,13 @@ use fmt::{Debug, Display};
/// 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 @@ -116,7 +157,14 @@ use fmt::{Debug, Display};
///
/// [`fmt::Collector`]: super::Collector
/// [`fmt::Subscriber`]: super::Subscriber
/// [`subscribe::Context`]: crate::subscribe::Context
/// [`Event`]: tracing::Event
/// [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<C, N>
where
C: Collect + for<'a> LookupSpan<'a>,
Expand Down Expand Up @@ -373,14 +421,16 @@ 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
}

pub(in crate::fmt::format) fn bold(&self) -> Style {
#[cfg(feature = "ansi")]
{
Expand Down
55 changes: 46 additions & 9 deletions tracing-subscriber/src/fmt/mod.rs
@@ -1,13 +1,13 @@
//! A Collector 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 [`Collect`] 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 @@ -43,12 +43,12 @@
//! **Note**: This should **not** be called by libraries. Libraries should use
//! [`tracing`] to publish `tracing` `Event`s.
//!
//! ## Configuration
//! # Configuration
//!
//! You can configure a collector instead of using the defaults with
//! the following functions:
//!
//! ### Collector
//! ## Collector
//!
//! The [`FmtCollector`] formats and records `tracing` events as line-oriented logs.
//! You can create one by calling:
Expand All @@ -62,7 +62,7 @@
//! The configuration methods for [`FmtCollector`] can be found in
//! [`fmtBuilder`].
//!
//! ### Formatters
//! ## Formatters
//!
//! The output format used by the subscriber and collector in this module is
//! represented by implementing the [`FormatEvent`] trait, and can be
Expand Down Expand Up @@ -223,7 +223,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,7 +294,7 @@
//! // collector multiple times
//! ```
//!
//! ### Composing Subscribers
//! ## Composing Subscribers
//!
//! Composing an [`EnvFilter`] `Subscribe` and a [format `Subscribe`](super::fmt::Subscriber):
//!
Expand All @@ -283,9 +320,9 @@
//! [`filter`]: super::filter
//! [`fmtBuilder`]: CollectorBuilder
//! [`FmtCollector`]: Collector
//! [`Collect`]:
//! https://docs.rs/tracing/latest/tracing/trait.Collect.html
//! [`Collect`]: https://docs.rs/tracing/latest/tracing/trait.Collect.html
//! [`tracing`]: https://crates.io/crates/tracing
//! [`fmt::format`]: mod@crate::fmt::format
use std::{any::TypeId, error::Error, io, ptr::NonNull};
use tracing_core::{collect::Interest, span, Event, Metadata};

Expand Down
2 changes: 1 addition & 1 deletion tracing-subscriber/src/lib.rs
Expand Up @@ -43,7 +43,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 772290d

Please sign in to comment.