Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: add a brief docs section on comparing levels #1446

Merged
merged 5 commits into from
Jun 25, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 138 additions & 4 deletions tracing-core/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ use core::{
/// 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 @@ -91,18 +93,150 @@ 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
///
/// `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 [collector] could implement filtering through
/// a [`LevelFilter`]. When a span or event is recorded, the [`Collect::enabled`] method
/// compares 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,
/// often improving performance in short-lived programs.
///
/// ```
/// 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() }
/// }
/// ```
///
/// 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
/// [`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