Skip to content

Commit

Permalink
core: add a brief docs section on comparing levels (#1446)
Browse files Browse the repository at this point in the history
This adds a section to the `Level` docs explaining the comparison rules
for `Level` and `LevelFilter`. It turns out this wasn't really
explicitly documented anywhere.

I may have gone a bit overboard on this, but I think the new docs should
be helpful...

See #1274 (comment)

Signed-off-by: Eliza Weisman <[email protected]>
Co-authored-by: David Barsky <[email protected]>
  • Loading branch information
hawkw and davidbarsky committed Jun 26, 2021
1 parent 4bf3d00 commit 204077f
Showing 1 changed file with 137 additions and 5 deletions.
142 changes: 137 additions & 5 deletions tracing-core/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ use crate::stdlib::{
/// or event occurred. The `tracing` macros default to using the module
/// path where the span or event originated as the target, but it may be
/// overridden.
/// - A [verbosity level].
/// - A [verbosity level]. This determines how verbose a given span or event
/// is, and allows enabling or disabling more verbose diagnostics
/// situationally. See the documentation for the [`Level`] type for details.
/// - The names of the [fields] defined by the span or event.
/// - Whether the metadata corresponds to a span or event.
///
Expand Down Expand Up @@ -89,20 +91,150 @@ pub struct Metadata<'a> {
/// Indicates whether the callsite is a span or event.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Kind(KindInner);

/// Describes the level of verbosity of a span or event.
///
/// # Comparing Levels
///
/// `Level` implements the [`PartialOrd`] and [`Ord`] traits, allowing two
/// `Level`s to be compared to determine which is considered more or less
/// verbose. Levels which are more verbose are considered "greater than" levels
/// which are less verbose, with [`Level::ERROR`] considered the lowest, and
/// [`Level::TRACE`] considered the highest.
///
/// For example:
/// ```
/// use tracing_core::Level;
///
/// assert!(Level::TRACE > Level::DEBUG);
/// assert!(Level::ERROR < Level::WARN);
/// assert!(Level::INFO <= Level::DEBUG);
/// assert_eq!(Level::TRACE, Level::TRACE);
/// ```
///
/// # Filtering
///
/// `Level`s are typically used to implement filtering that determines which
/// spans and events are enabled. Depending on the use case, more or less
/// verbose diagnostics may be desired. For example, when running in
/// development, [`DEBUG`]-level traces may be enabled by default. When running in
/// production, only [`INFO`]-level and lower traces might be enabled. Libraries
/// may include very verbose diagnostics at the [`DEBUG`] and/or [`TRACE`] levels.
/// Applications using those libraries typically chose to ignore those traces. However, when
/// debugging an issue involving said libraries, it may be useful to temporarily
/// enable the more verbose traces.
///
/// The [`LevelFilter`] type is provided to enable filtering traces by
/// verbosity. `Level`s can be compared against [`LevelFilter`]s, and
/// [`LevelFilter`] has a variant for each `Level`, which compares analogously
/// to that level. In addition, [`LevelFilter`] adds a [`LevelFilter::OFF`]
/// variant, which is considered "less verbose" than every other `Level. This is
/// intended to allow filters to completely disable tracing in a particular context.
///
/// For example:
/// ```
/// use tracing_core::{Level, LevelFilter};
///
/// assert!(LevelFilter::OFF < Level::TRACE);
/// assert!(LevelFilter::TRACE > Level::DEBUG);
/// assert!(LevelFilter::ERROR < Level::WARN);
/// assert!(LevelFilter::INFO <= Level::DEBUG);
/// assert!(LevelFilter::INFO >= Level::INFO);
/// ```
///
/// ## Examples
///
/// Below is a simple example of how a [`Subscriber`] could implement filtering through
/// a [`LevelFilter`]. When a span or event is recorded, the [`Subscriber::enabled`] method
/// compares the span or event's `Level` against the configured [`LevelFilter`].
/// The optional [`Subscriber::max_level_hint`] method can also be implemented to allow spans
/// and events above a maximum verbosity level to be skipped more efficiently,
/// often improving performance in short-lived programs.
///
/// ```
/// use tracing_core::{span, Event, Level, LevelFilter, Subscriber, Metadata};
/// # use tracing_core::span::{Id, Record, Current};
///
/// #[derive(Debug)]
/// pub struct MySubscriber {
/// /// The most verbose level that this subscriber will enable.
/// max_level: LevelFilter,
///
/// // ...
/// }
///
/// impl MySubscriber {
/// /// Returns a new `MySubscriber` which will record spans and events up to
/// /// `max_level`.
/// pub fn with_max_level(max_level: LevelFilter) -> Self {
/// Self {
/// max_level,
/// // ...
/// }
/// }
/// }
/// impl Subscriber for MySubscriber {
/// fn enabled(&self, meta: &Metadata<'_>) -> bool {
/// // A span or event is enabled if it is at or below the configured
/// // maximum level.
/// meta.level() <= &self.max_level
/// }
///
/// // This optional method returns the most verbose level that this
/// // subscriber will enable. Although implementing this method is not
/// // *required*, it permits additional optimizations when it is provided,
/// // allowing spans and events above the max level to be skipped
/// // more efficiently.
/// fn max_level_hint(&self) -> Option<LevelFilter> {
/// Some(self.max_level)
/// }
///
/// // Implement the rest of the subscriber...
/// fn new_span(&self, span: &span::Attributes<'_>) -> span::Id {
/// // ...
/// # drop(span); Id::from_u64(1)
/// }
/// fn event(&self, event: &Event<'_>) {
/// // ...
/// # drop(event);
/// }
///
/// // ...
/// # fn enter(&self, _: &Id) {}
/// # fn exit(&self, _: &Id) {}
/// # fn record(&self, _: &Id, _: &Record<'_>) {}
/// # fn record_follows_from(&self, _: &Id, _: &Id) {}
/// }
/// ```
///
/// It is worth noting that the `tracing-subscriber` crate provides [additional
/// APIs][envfilter] for performing more sophisticated filtering, such as
/// enabling different levels based on which module or crate a span or event is
/// recorded in.
///
/// [`DEBUG`]: Level::DEBUG
/// [`INFO`]: Level::INFO
/// [`TRACE`]: Level::TRACE
/// [`Subscriber::enabled`]: crate::subscriber::Subscriber::enabled
/// [`Subscriber::max_level_hint`]: crate::subscriber::Subscriber::max_level_hint
/// [subscriber]: crate::subscriber::Subscriber
/// [envfilter]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Level(LevelInner);

/// A filter comparable to a verbosity `Level`.
/// A filter comparable to a verbosity [`Level`].
///
/// If a `Level` is considered less than a `LevelFilter`, it should be
/// If a [`Level`] is considered less than a `LevelFilter`, it should be
/// considered disabled; if greater than or equal to the `LevelFilter`, that
/// level is enabled.
///
/// Note that this is essentially identical to the `Level` type, but with the
/// addition of an `OFF` level that completely disables all trace
/// addition of an [`OFF`] level that completely disables all trace
/// instrumentation.
///
/// See the documentation for the [`Level`] type for more details.
///
/// [`OFF`]: LevelFilter::OFF
#[repr(transparent)]
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct LevelFilter(Option<Level>);
Expand Down

0 comments on commit 204077f

Please sign in to comment.