Skip to content

Commit

Permalink
core: add a brief docs section on comparing levels
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.

See #1274 (comment)

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
  • Loading branch information
hawkw committed Jun 25, 2021
1 parent c919f7a commit a777fe1
Showing 1 changed file with 134 additions and 3 deletions.
137 changes: 134 additions & 3 deletions tracing-core/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,18 +91,149 @@ pub struct Metadata<'a> {
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
///
/// Typically, `Level`s are 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 &mdash; for example, when running in
/// development, [`DEBUG`]-level traces may be enabled by default, and when
/// running in production, we might choose to enable only [`INFO`]-level and
/// lower. Libraries may include very verbose diagnostics at the [`DEBUG`]
/// and/or [`TRACE`] levels, which applications using those libraries might
/// typically choose to ignore. However, when debugging an issue involving those
/// libraries, it may be useful to temporarily enable those 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);
/// ```
///
/// As a simple example of how a [collector] could implement filtering, a
/// [`LevelFilter`] is provided when the collector is constructed. Then, when a
/// span or event is recorded, the [`Collect::enabled`] method would compare the
/// span or event's `Level` against the configured [`LevelFilter`]. The optional
/// [`Collect::max_level_hint`] method can also be implemented to allow spans and
/// events above a maximum verbosity level to be skipped more efficiently,
/// improving performance.
///
/// ```
/// use tracing_core::{span, Event, Level, LevelFilter, Collect, Metadata};
/// # use tracing_core::span::{Id, Record, Current};
///
/// #[derive(Debug)]
/// pub struct MyCollector {
/// /// The most verbose level that this collector will enable.
/// max_level: LevelFilter,
///
/// // ...
/// }
///
/// impl MyCollector {
/// /// Returns a new `MyCollector` which will record spans and events up to
/// /// `max_level`.
/// pub fn with_max_level(max_level: LevelFilter) -> Self {
/// Self {
/// max_level,
/// // ...
/// }
/// }
/// }
/// impl Collect for MyCollector {
/// 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
/// // collector 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 collector...
/// 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) {}
/// # fn current_span(&self) -> Current { Current::unknown() }
/// }
/// ```
///
/// In addition, 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
/// [`Collect::enabled`]: crate::collect::Collect::enabled
/// [`Collect::max_level_hint`]: crate::collect::Collect::max_level_hint
/// [collector]: crate::collect::Collect
/// [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 a777fe1

Please sign in to comment.