diff --git a/tracing-core/src/collect.rs b/tracing-core/src/collect.rs index 4bafc00d92..8c5ae3ff8a 100644 --- a/tracing-core/src/collect.rs +++ b/tracing-core/src/collect.rs @@ -57,6 +57,9 @@ use core::ptr::NonNull; /// See also the [documentation on the callsite registry][cs-reg] for details /// on [`register_callsite`]. /// +/// - [`event_enabled`] is called once before every call to the [`event`] +/// method. This can be used to implement filtering on events once their field +/// values are known, but before any processing is done in the `event` method. /// - [`clone_span`] is called every time a span ID is cloned, and [`try_close`] /// is called when a span ID is dropped. By default, these functions do /// nothing. However, they can be used to implement reference counting for @@ -72,6 +75,8 @@ use core::ptr::NonNull; /// [`clone_span`]: Collect::clone_span /// [`try_close`]: Collect::try_close /// [cs-reg]: crate::callsite#registering-callsites +/// [`event`]: Collect::event +/// [`event_enabled`]: Collect::event_enabled pub trait Collect: 'static { // === Span registry methods ============================================== @@ -288,6 +293,17 @@ pub trait Collect: 'static { /// follow from _b_), it may silently do nothing. fn record_follows_from(&self, span: &span::Id, follows: &span::Id); + /// Determine if an [`Event`] should be recorded. + /// + /// By default, this returns `true` and collectors can filter events in + /// [`event`][Self::event] without any penalty. However, when `event` is + /// more complicated, this can be used to determine if `event` should be + /// called at all, separating out the decision from the processing. + fn event_enabled(&self, event: &Event<'_>) -> bool { + let _ = event; + true + } + /// Records that an [`Event`] has occurred. /// /// This method will be invoked when an Event is constructed by @@ -688,6 +704,11 @@ where self.as_ref().record_follows_from(span, follows) } + #[inline] + fn event_enabled(&self, event: &Event<'_>) -> bool { + self.as_ref().event_enabled(event) + } + #[inline] fn event(&self, event: &Event<'_>) { self.as_ref().event(event) @@ -762,6 +783,11 @@ where self.as_ref().record_follows_from(span, follows) } + #[inline] + fn event_enabled(&self, event: &Event<'_>) -> bool { + self.as_ref().event_enabled(event) + } + #[inline] fn event(&self, event: &Event<'_>) { self.as_ref().event(event) diff --git a/tracing-core/src/dispatch.rs b/tracing-core/src/dispatch.rs index 5b85dcde35..e95969037b 100644 --- a/tracing-core/src/dispatch.rs +++ b/tracing-core/src/dispatch.rs @@ -682,7 +682,10 @@ impl Dispatch { /// [`event`]: super::collect::Collect::event #[inline] pub fn event(&self, event: &Event<'_>) { - self.collector().event(event) + let collector = self.collector(); + if collector.event_enabled(event) { + collector.event(event); + } } /// Records that a span has been can_enter. diff --git a/tracing-subscriber/src/fmt/mod.rs b/tracing-subscriber/src/fmt/mod.rs index 34fd7ed497..d7abce1635 100644 --- a/tracing-subscriber/src/fmt/mod.rs +++ b/tracing-subscriber/src/fmt/mod.rs @@ -393,6 +393,11 @@ where self.inner.record_follows_from(span, follows) } + #[inline] + fn event_enabled(&self, event: &Event<'_>) -> bool { + self.inner.event_enabled(event) + } + #[inline] fn event(&self, event: &Event<'_>) { self.inner.event(event); diff --git a/tracing-subscriber/src/reload.rs b/tracing-subscriber/src/reload.rs index f2f875b77b..eb87630b99 100644 --- a/tracing-subscriber/src/reload.rs +++ b/tracing-subscriber/src/reload.rs @@ -106,6 +106,11 @@ where try_lock!(self.inner.read()).on_follows_from(span, follows, ctx) } + #[inline] + fn event_enabled(&self, event: &Event<'_>, ctx: subscribe::Context<'_, C>) -> bool { + try_lock!(self.inner.read(), else return false).event_enabled(event, ctx) + } + #[inline] fn on_event(&self, event: &Event<'_>, ctx: subscribe::Context<'_, C>) { try_lock!(self.inner.read()).on_event(event, ctx) diff --git a/tracing-subscriber/src/subscribe/layered.rs b/tracing-subscriber/src/subscribe/layered.rs index 813bafebba..c601996b9e 100644 --- a/tracing-subscriber/src/subscribe/layered.rs +++ b/tracing-subscriber/src/subscribe/layered.rs @@ -138,6 +138,16 @@ where self.subscriber.on_follows_from(span, follows, self.ctx()); } + fn event_enabled(&self, event: &Event<'_>) -> bool { + if self.subscriber.event_enabled(event, self.ctx()) { + // if the outer subscriber enables the event, ask the inner collector. + self.inner.event_enabled(event) + } else { + // otherwise, the event is disabled by this subscriber + false + } + } + fn event(&self, event: &Event<'_>) { self.inner.event(event); self.subscriber.on_event(event, self.ctx()); @@ -280,6 +290,17 @@ where self.subscriber.on_follows_from(span, follows, ctx); } + #[inline] + fn event_enabled(&self, event: &Event<'_>, ctx: Context<'_, C>) -> bool { + if self.subscriber.event_enabled(event, ctx.clone()) { + // if the outer subscriber enables the event, ask the inner collector. + self.inner.event_enabled(event, ctx) + } else { + // otherwise, the event is disabled by this subscriber + false + } + } + #[inline] fn on_event(&self, event: &Event<'_>, ctx: Context<'_, C>) { self.inner.on_event(event, ctx.clone()); diff --git a/tracing-subscriber/src/subscribe/mod.rs b/tracing-subscriber/src/subscribe/mod.rs index f8d3edf52f..1715437028 100644 --- a/tracing-subscriber/src/subscribe/mod.rs +++ b/tracing-subscriber/src/subscribe/mod.rs @@ -417,6 +417,28 @@ //! [`Interest::never()`] from its [`register_callsite`] method, filter //! evaluation will short-circuit and the span or event will be disabled. //! +//! ### Enabling Interest +//! +//! Whenever an tracing event (or span) is emitted, it goes through a number of +//! steps to determine how and how much it should be processed. The earlier an +//! event is disabled, the less work has to be done to process the event, so +//! subscribers that implement filtering should attempt to disable unwanted +//! events as early as possible. In order, each event checks: +//! +//! - [`register_callsite`], once per callsite (roughly: once per time that +//! `event!` or `span!` is written in the source code; this is cached at the +//! callsite). See [`Collect::register_callsite`] and +//! [`tracing_core::callsite`] for a summary of how this behaves. +//! - [`enabled`], once per emitted event (roughly: once per time that `event!` +//! or `span!` is *executed*), and only if `register_callsite` regesters an +//! [`Interest::sometimes`]. This is the main customization point to globally +//! filter events based on their [`Metadata`]. If an event can be disabled +//! based only on [`Metadata`], it should be, as this allows the construction +//! of the actual `Event`/`Span` to be skipped. +//! - For events only (and not spans), [`event_enabled`] is called just before +//! processing the event. This gives subscribers one last chance to say that +//! an event should be filtered out, now that the event's fields are known. +//! //! ## Per-Subscriber Filtering //! //! **Note**: per-subscriber filtering APIs currently require the [`"registry"` crate @@ -639,6 +661,7 @@ //! [the current span]: Context::current_span //! [`register_callsite`]: Subscribe::register_callsite //! [`enabled`]: Subscribe::enabled +//! [`event_enabled`]: Subscribe::event_enabled //! [`on_enter`]: Subscribe::on_enter //! [`Subscribe::register_callsite`]: Subscribe::register_callsite //! [`Subscribe::enabled`]: Subscribe::enabled @@ -827,6 +850,31 @@ where // seems like a good future-proofing measure as it may grow other methods later... fn on_follows_from(&self, _span: &span::Id, _follows: &span::Id, _ctx: Context<'_, C>) {} + /// Called before [`on_event`], to determine if `on_event` should be called. + /// + ///
+ /// + /// **Note**: This method determines whether an event is globally enabled, + /// *not* whether the individual subscriber will be notified about the + /// event. This is intended to be used by subscibers that implement + /// filtering for the entire stack. Subscribers which do not wish to be + /// notified about certain events but do not wish to globally disable them + /// should ignore those events in their [on_event][Self::on_event]. + /// + ///