Skip to content

Commit 204077f

Browse files
hawkwdavidbarsky
andcommitted
core: add a brief docs section on comparing levels (#1446)
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]>
1 parent 4bf3d00 commit 204077f

File tree

1 file changed

+137
-5
lines changed

1 file changed

+137
-5
lines changed

tracing-core/src/metadata.rs

Lines changed: 137 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ use crate::stdlib::{
1414
/// or event occurred. The `tracing` macros default to using the module
1515
/// path where the span or event originated as the target, but it may be
1616
/// overridden.
17-
/// - A [verbosity level].
17+
/// - A [verbosity level]. This determines how verbose a given span or event
18+
/// is, and allows enabling or disabling more verbose diagnostics
19+
/// situationally. See the documentation for the [`Level`] type for details.
1820
/// - The names of the [fields] defined by the span or event.
1921
/// - Whether the metadata corresponds to a span or event.
2022
///
@@ -89,20 +91,150 @@ pub struct Metadata<'a> {
8991
/// Indicates whether the callsite is a span or event.
9092
#[derive(Clone, Debug, Eq, PartialEq)]
9193
pub struct Kind(KindInner);
92-
9394
/// Describes the level of verbosity of a span or event.
95+
///
96+
/// # Comparing Levels
97+
///
98+
/// `Level` implements the [`PartialOrd`] and [`Ord`] traits, allowing two
99+
/// `Level`s to be compared to determine which is considered more or less
100+
/// verbose. Levels which are more verbose are considered "greater than" levels
101+
/// which are less verbose, with [`Level::ERROR`] considered the lowest, and
102+
/// [`Level::TRACE`] considered the highest.
103+
///
104+
/// For example:
105+
/// ```
106+
/// use tracing_core::Level;
107+
///
108+
/// assert!(Level::TRACE > Level::DEBUG);
109+
/// assert!(Level::ERROR < Level::WARN);
110+
/// assert!(Level::INFO <= Level::DEBUG);
111+
/// assert_eq!(Level::TRACE, Level::TRACE);
112+
/// ```
113+
///
114+
/// # Filtering
115+
///
116+
/// `Level`s are typically used to implement filtering that determines which
117+
/// spans and events are enabled. Depending on the use case, more or less
118+
/// verbose diagnostics may be desired. For example, when running in
119+
/// development, [`DEBUG`]-level traces may be enabled by default. When running in
120+
/// production, only [`INFO`]-level and lower traces might be enabled. Libraries
121+
/// may include very verbose diagnostics at the [`DEBUG`] and/or [`TRACE`] levels.
122+
/// Applications using those libraries typically chose to ignore those traces. However, when
123+
/// debugging an issue involving said libraries, it may be useful to temporarily
124+
/// enable the more verbose traces.
125+
///
126+
/// The [`LevelFilter`] type is provided to enable filtering traces by
127+
/// verbosity. `Level`s can be compared against [`LevelFilter`]s, and
128+
/// [`LevelFilter`] has a variant for each `Level`, which compares analogously
129+
/// to that level. In addition, [`LevelFilter`] adds a [`LevelFilter::OFF`]
130+
/// variant, which is considered "less verbose" than every other `Level. This is
131+
/// intended to allow filters to completely disable tracing in a particular context.
132+
///
133+
/// For example:
134+
/// ```
135+
/// use tracing_core::{Level, LevelFilter};
136+
///
137+
/// assert!(LevelFilter::OFF < Level::TRACE);
138+
/// assert!(LevelFilter::TRACE > Level::DEBUG);
139+
/// assert!(LevelFilter::ERROR < Level::WARN);
140+
/// assert!(LevelFilter::INFO <= Level::DEBUG);
141+
/// assert!(LevelFilter::INFO >= Level::INFO);
142+
/// ```
143+
///
144+
/// ## Examples
145+
///
146+
/// Below is a simple example of how a [`Subscriber`] could implement filtering through
147+
/// a [`LevelFilter`]. When a span or event is recorded, the [`Subscriber::enabled`] method
148+
/// compares the span or event's `Level` against the configured [`LevelFilter`].
149+
/// The optional [`Subscriber::max_level_hint`] method can also be implemented to allow spans
150+
/// and events above a maximum verbosity level to be skipped more efficiently,
151+
/// often improving performance in short-lived programs.
152+
///
153+
/// ```
154+
/// use tracing_core::{span, Event, Level, LevelFilter, Subscriber, Metadata};
155+
/// # use tracing_core::span::{Id, Record, Current};
156+
///
157+
/// #[derive(Debug)]
158+
/// pub struct MySubscriber {
159+
/// /// The most verbose level that this subscriber will enable.
160+
/// max_level: LevelFilter,
161+
///
162+
/// // ...
163+
/// }
164+
///
165+
/// impl MySubscriber {
166+
/// /// Returns a new `MySubscriber` which will record spans and events up to
167+
/// /// `max_level`.
168+
/// pub fn with_max_level(max_level: LevelFilter) -> Self {
169+
/// Self {
170+
/// max_level,
171+
/// // ...
172+
/// }
173+
/// }
174+
/// }
175+
/// impl Subscriber for MySubscriber {
176+
/// fn enabled(&self, meta: &Metadata<'_>) -> bool {
177+
/// // A span or event is enabled if it is at or below the configured
178+
/// // maximum level.
179+
/// meta.level() <= &self.max_level
180+
/// }
181+
///
182+
/// // This optional method returns the most verbose level that this
183+
/// // subscriber will enable. Although implementing this method is not
184+
/// // *required*, it permits additional optimizations when it is provided,
185+
/// // allowing spans and events above the max level to be skipped
186+
/// // more efficiently.
187+
/// fn max_level_hint(&self) -> Option<LevelFilter> {
188+
/// Some(self.max_level)
189+
/// }
190+
///
191+
/// // Implement the rest of the subscriber...
192+
/// fn new_span(&self, span: &span::Attributes<'_>) -> span::Id {
193+
/// // ...
194+
/// # drop(span); Id::from_u64(1)
195+
/// }
196+
197+
/// fn event(&self, event: &Event<'_>) {
198+
/// // ...
199+
/// # drop(event);
200+
/// }
201+
///
202+
/// // ...
203+
/// # fn enter(&self, _: &Id) {}
204+
/// # fn exit(&self, _: &Id) {}
205+
/// # fn record(&self, _: &Id, _: &Record<'_>) {}
206+
/// # fn record_follows_from(&self, _: &Id, _: &Id) {}
207+
/// }
208+
/// ```
209+
///
210+
/// It is worth noting that the `tracing-subscriber` crate provides [additional
211+
/// APIs][envfilter] for performing more sophisticated filtering, such as
212+
/// enabling different levels based on which module or crate a span or event is
213+
/// recorded in.
214+
///
215+
/// [`DEBUG`]: Level::DEBUG
216+
/// [`INFO`]: Level::INFO
217+
/// [`TRACE`]: Level::TRACE
218+
/// [`Subscriber::enabled`]: crate::subscriber::Subscriber::enabled
219+
/// [`Subscriber::max_level_hint`]: crate::subscriber::Subscriber::max_level_hint
220+
/// [subscriber]: crate::subscriber::Subscriber
221+
/// [envfilter]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html
94222
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
95223
pub struct Level(LevelInner);
96224

97-
/// A filter comparable to a verbosity `Level`.
225+
/// A filter comparable to a verbosity [`Level`].
98226
///
99-
/// If a `Level` is considered less than a `LevelFilter`, it should be
227+
/// If a [`Level`] is considered less than a `LevelFilter`, it should be
100228
/// considered disabled; if greater than or equal to the `LevelFilter`, that
101229
/// level is enabled.
102230
///
103231
/// Note that this is essentially identical to the `Level` type, but with the
104-
/// addition of an `OFF` level that completely disables all trace
232+
/// addition of an [`OFF`] level that completely disables all trace
105233
/// instrumentation.
234+
///
235+
/// See the documentation for the [`Level`] type for more details.
236+
///
237+
/// [`OFF`]: LevelFilter::OFF
106238
#[repr(transparent)]
107239
#[derive(Copy, Clone, Eq, PartialEq)]
108240
pub struct LevelFilter(Option<Level>);

0 commit comments

Comments
 (0)