• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Filter combinators
2 use crate::layer::{Context, Filter};
3 use std::{cmp, fmt, marker::PhantomData};
4 use tracing_core::{
5     span::{Attributes, Id, Record},
6     subscriber::Interest,
7     LevelFilter, Metadata,
8 };
9 
10 /// Combines two [`Filter`]s so that spans and events are enabled if and only if
11 /// *both* filters return `true`.
12 ///
13 /// This type is typically returned by the [`FilterExt::and`] method. See that
14 /// method's documentation for details.
15 ///
16 /// [`Filter`]: crate::layer::Filter
17 /// [`FilterExt::and`]: crate::filter::FilterExt::and
18 pub struct And<A, B, S> {
19     a: A,
20     b: B,
21     _s: PhantomData<fn(S)>,
22 }
23 
24 /// Combines two [`Filter`]s so that spans and events are enabled if *either* filter
25 /// returns `true`.
26 ///
27 /// This type is typically returned by the [`FilterExt::or`] method. See that
28 /// method's documentation for details.
29 ///
30 /// [`Filter`]: crate::layer::Filter
31 /// [`FilterExt::or`]: crate::filter::FilterExt::or
32 pub struct Or<A, B, S> {
33     a: A,
34     b: B,
35     _s: PhantomData<fn(S)>,
36 }
37 
38 /// Inverts the result of a [`Filter`].
39 ///
40 /// If the wrapped filter would enable a span or event, it will be disabled. If
41 /// it would disable a span or event, that span or event will be enabled.
42 ///
43 /// This type is typically returned by the [`FilterExt::not`] method. See that
44 /// method's documentation for details.
45 ///
46 /// [`Filter`]: crate::layer::Filter
47 /// [`FilterExt::not`]: crate::filter::FilterExt::not
48 pub struct Not<A, S> {
49     a: A,
50     _s: PhantomData<fn(S)>,
51 }
52 
53 // === impl And ===
54 
55 impl<A, B, S> And<A, B, S>
56 where
57     A: Filter<S>,
58     B: Filter<S>,
59 {
60     /// Combines two [`Filter`]s so that spans and events are enabled if and only if
61     /// *both* filters return `true`.
62     ///
63     /// # Examples
64     ///
65     /// Enabling spans or events if they have both a particular target *and* are
66     /// above a certain level:
67     ///
68     /// ```ignore
69     /// use tracing_subscriber::{
70     ///     filter::{filter_fn, LevelFilter, combinator::And},
71     ///     prelude::*,
72     /// };
73     ///
74     /// // Enables spans and events with targets starting with `interesting_target`:
75     /// let target_filter = filter_fn(|meta| {
76     ///     meta.target().starts_with("interesting_target")
77     /// });
78     ///
79     /// // Enables spans and events with levels `INFO` and below:
80     /// let level_filter = LevelFilter::INFO;
81     ///
82     /// // Combine the two filters together so that a span or event is only enabled
83     /// // if *both* filters would enable it:
84     /// let filter = And::new(level_filter, target_filter);
85     ///
86     /// tracing_subscriber::registry()
87     ///     .with(tracing_subscriber::fmt::layer().with_filter(filter))
88     ///     .init();
89     ///
90     /// // This event will *not* be enabled:
91     /// tracing::info!("an event with an uninteresting target");
92     ///
93     /// // This event *will* be enabled:
94     /// tracing::info!(target: "interesting_target", "a very interesting event");
95     ///
96     /// // This event will *not* be enabled:
97     /// tracing::debug!(target: "interesting_target", "interesting debug event...");
98     /// ```
99     ///
100     /// [`Filter`]: crate::layer::Filter
new(a: A, b: B) -> Self101     pub(crate) fn new(a: A, b: B) -> Self {
102         Self {
103             a,
104             b,
105             _s: PhantomData,
106         }
107     }
108 }
109 
110 impl<A, B, S> Filter<S> for And<A, B, S>
111 where
112     A: Filter<S>,
113     B: Filter<S>,
114 {
115     #[inline]
enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool116     fn enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
117         self.a.enabled(meta, cx) && self.b.enabled(meta, cx)
118     }
119 
callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest120     fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest {
121         let a = self.a.callsite_enabled(meta);
122         if a.is_never() {
123             return a;
124         }
125 
126         let b = self.b.callsite_enabled(meta);
127 
128         if !b.is_always() {
129             return b;
130         }
131 
132         a
133     }
134 
max_level_hint(&self) -> Option<LevelFilter>135     fn max_level_hint(&self) -> Option<LevelFilter> {
136         // If either hint is `None`, return `None`. Otherwise, return the most restrictive.
137         cmp::min(self.a.max_level_hint(), self.b.max_level_hint())
138     }
139 
140     #[inline]
event_enabled(&self, event: &tracing_core::Event<'_>, cx: &Context<'_, S>) -> bool141     fn event_enabled(&self, event: &tracing_core::Event<'_>, cx: &Context<'_, S>) -> bool {
142         self.a.event_enabled(event, cx) && self.b.event_enabled(event, cx)
143     }
144 
145     #[inline]
on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>)146     fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
147         self.a.on_new_span(attrs, id, ctx.clone());
148         self.b.on_new_span(attrs, id, ctx)
149     }
150 
151     #[inline]
on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>)152     fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {
153         self.a.on_record(id, values, ctx.clone());
154         self.b.on_record(id, values, ctx);
155     }
156 
157     #[inline]
on_enter(&self, id: &Id, ctx: Context<'_, S>)158     fn on_enter(&self, id: &Id, ctx: Context<'_, S>) {
159         self.a.on_enter(id, ctx.clone());
160         self.b.on_enter(id, ctx);
161     }
162 
163     #[inline]
on_exit(&self, id: &Id, ctx: Context<'_, S>)164     fn on_exit(&self, id: &Id, ctx: Context<'_, S>) {
165         self.a.on_exit(id, ctx.clone());
166         self.b.on_exit(id, ctx);
167     }
168 
169     #[inline]
on_close(&self, id: Id, ctx: Context<'_, S>)170     fn on_close(&self, id: Id, ctx: Context<'_, S>) {
171         self.a.on_close(id.clone(), ctx.clone());
172         self.b.on_close(id, ctx);
173     }
174 }
175 
176 impl<A, B, S> Clone for And<A, B, S>
177 where
178     A: Clone,
179     B: Clone,
180 {
clone(&self) -> Self181     fn clone(&self) -> Self {
182         Self {
183             a: self.a.clone(),
184             b: self.b.clone(),
185             _s: PhantomData,
186         }
187     }
188 }
189 
190 impl<A, B, S> fmt::Debug for And<A, B, S>
191 where
192     A: fmt::Debug,
193     B: fmt::Debug,
194 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result195     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196         f.debug_struct("And")
197             .field("a", &self.a)
198             .field("b", &self.b)
199             .finish()
200     }
201 }
202 
203 // === impl Or ===
204 
205 impl<A, B, S> Or<A, B, S>
206 where
207     A: Filter<S>,
208     B: Filter<S>,
209 {
210     /// Combines two [`Filter`]s so that spans and events are enabled if *either* filter
211     /// returns `true`.
212     ///
213     /// # Examples
214     ///
215     /// Enabling spans and events at the `INFO` level and above, and all spans
216     /// and events with a particular target:
217     ///
218     /// ```ignore
219     /// use tracing_subscriber::{
220     ///     filter::{filter_fn, LevelFilter, combinator::Or},
221     ///     prelude::*,
222     /// };
223     ///
224     /// // Enables spans and events with targets starting with `interesting_target`:
225     /// let target_filter = filter_fn(|meta| {
226     ///     meta.target().starts_with("interesting_target")
227     /// });
228     ///
229     /// // Enables spans and events with levels `INFO` and below:
230     /// let level_filter = LevelFilter::INFO;
231     ///
232     /// // Combine the two filters together so that a span or event is enabled
233     /// // if it is at INFO or lower, or if it has a target starting with
234     /// // `interesting_target`.
235     /// let filter = Or::new(level_filter, target_filter);
236     ///
237     /// tracing_subscriber::registry()
238     ///     .with(tracing_subscriber::fmt::layer().with_filter(filter))
239     ///     .init();
240     ///
241     /// // This event will *not* be enabled:
242     /// tracing::debug!("an uninteresting event");
243     ///
244     /// // This event *will* be enabled:
245     /// tracing::info!("an uninteresting INFO event");
246     ///
247     /// // This event *will* be enabled:
248     /// tracing::info!(target: "interesting_target", "a very interesting event");
249     ///
250     /// // This event *will* be enabled:
251     /// tracing::debug!(target: "interesting_target", "interesting debug event...");
252     /// ```
253     ///
254     /// Enabling a higher level for a particular target by using `Or` in
255     /// conjunction with the [`And`] combinator:
256     ///
257     /// ```ignore
258     /// use tracing_subscriber::{
259     ///     filter::{filter_fn, LevelFilter, combinator},
260     ///     prelude::*,
261     /// };
262     ///
263     /// // This filter will enable spans and events with targets beginning with
264     /// // `my_crate`:
265     /// let my_crate = filter_fn(|meta| {
266     ///     meta.target().starts_with("my_crate")
267     /// });
268     ///
269     /// // Combine the `my_crate` filter with a `LevelFilter` to produce a filter
270     /// // that will enable the `INFO` level and lower for spans and events with
271     /// // `my_crate` targets:
272     /// let filter = combinator::And::new(my_crate, LevelFilter::INFO);
273     ///
274     /// // If a span or event *doesn't* have a target beginning with
275     /// // `my_crate`, enable it if it has the `WARN` level or lower:
276     /// // let filter = combinator::Or::new(filter, LevelFilter::WARN);
277     ///
278     /// tracing_subscriber::registry()
279     ///     .with(tracing_subscriber::fmt::layer().with_filter(filter))
280     ///     .init();
281     /// ```
282     ///
283     /// [`Filter`]: crate::layer::Filter
new(a: A, b: B) -> Self284     pub(crate) fn new(a: A, b: B) -> Self {
285         Self {
286             a,
287             b,
288             _s: PhantomData,
289         }
290     }
291 }
292 
293 impl<A, B, S> Filter<S> for Or<A, B, S>
294 where
295     A: Filter<S>,
296     B: Filter<S>,
297 {
298     #[inline]
enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool299     fn enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
300         self.a.enabled(meta, cx) || self.b.enabled(meta, cx)
301     }
302 
callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest303     fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest {
304         let a = self.a.callsite_enabled(meta);
305         let b = self.b.callsite_enabled(meta);
306 
307         // If either filter will always enable the span or event, return `always`.
308         if a.is_always() || b.is_always() {
309             return Interest::always();
310         }
311 
312         // Okay, if either filter will sometimes enable the span or event,
313         // return `sometimes`.
314         if a.is_sometimes() || b.is_sometimes() {
315             return Interest::sometimes();
316         }
317 
318         debug_assert!(
319             a.is_never() && b.is_never(),
320             "if neither filter was `always` or `sometimes`, both must be `never` (a={:?}; b={:?})",
321             a,
322             b,
323         );
324         Interest::never()
325     }
326 
max_level_hint(&self) -> Option<LevelFilter>327     fn max_level_hint(&self) -> Option<LevelFilter> {
328         // If either hint is `None`, return `None`. Otherwise, return the less restrictive.
329         Some(cmp::max(self.a.max_level_hint()?, self.b.max_level_hint()?))
330     }
331 
332     #[inline]
event_enabled(&self, event: &tracing_core::Event<'_>, cx: &Context<'_, S>) -> bool333     fn event_enabled(&self, event: &tracing_core::Event<'_>, cx: &Context<'_, S>) -> bool {
334         self.a.event_enabled(event, cx) || self.b.event_enabled(event, cx)
335     }
336 
337     #[inline]
on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>)338     fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
339         self.a.on_new_span(attrs, id, ctx.clone());
340         self.b.on_new_span(attrs, id, ctx)
341     }
342 
343     #[inline]
on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>)344     fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {
345         self.a.on_record(id, values, ctx.clone());
346         self.b.on_record(id, values, ctx);
347     }
348 
349     #[inline]
on_enter(&self, id: &Id, ctx: Context<'_, S>)350     fn on_enter(&self, id: &Id, ctx: Context<'_, S>) {
351         self.a.on_enter(id, ctx.clone());
352         self.b.on_enter(id, ctx);
353     }
354 
355     #[inline]
on_exit(&self, id: &Id, ctx: Context<'_, S>)356     fn on_exit(&self, id: &Id, ctx: Context<'_, S>) {
357         self.a.on_exit(id, ctx.clone());
358         self.b.on_exit(id, ctx);
359     }
360 
361     #[inline]
on_close(&self, id: Id, ctx: Context<'_, S>)362     fn on_close(&self, id: Id, ctx: Context<'_, S>) {
363         self.a.on_close(id.clone(), ctx.clone());
364         self.b.on_close(id, ctx);
365     }
366 }
367 
368 impl<A, B, S> Clone for Or<A, B, S>
369 where
370     A: Clone,
371     B: Clone,
372 {
clone(&self) -> Self373     fn clone(&self) -> Self {
374         Self {
375             a: self.a.clone(),
376             b: self.b.clone(),
377             _s: PhantomData,
378         }
379     }
380 }
381 
382 impl<A, B, S> fmt::Debug for Or<A, B, S>
383 where
384     A: fmt::Debug,
385     B: fmt::Debug,
386 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result387     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388         f.debug_struct("Or")
389             .field("a", &self.a)
390             .field("b", &self.b)
391             .finish()
392     }
393 }
394 
395 // === impl Not ===
396 
397 impl<A, S> Not<A, S>
398 where
399     A: Filter<S>,
400 {
401     /// Inverts the result of a [`Filter`].
402     ///
403     /// If the wrapped filter would enable a span or event, it will be disabled. If
404     /// it would disable a span or event, that span or event will be enabled.
405     ///
406     /// This inverts the values returned by the [`enabled`] and [`callsite_enabled`]
407     /// methods on the wrapped filter; it does *not* invert [`event_enabled`], as
408     /// filters which do not implement filtering on event field values will return
409     /// the default `true` even for events that their [`enabled`] method disables.
410     ///
411     /// Consider a normal filter defined as:
412     ///
413     /// ```ignore (pseudo-code)
414     /// // for spans
415     /// match callsite_enabled() {
416     ///     ALWAYS => on_span(),
417     ///     SOMETIMES => if enabled() { on_span() },
418     ///     NEVER => (),
419     /// }
420     /// // for events
421     /// match callsite_enabled() {
422     ///    ALWAYS => on_event(),
423     ///    SOMETIMES => if enabled() && event_enabled() { on_event() },
424     ///    NEVER => (),
425     /// }
426     /// ```
427     ///
428     /// and an inverted filter defined as:
429     ///
430     /// ```ignore (pseudo-code)
431     /// // for spans
432     /// match callsite_enabled() {
433     ///     ALWAYS => (),
434     ///     SOMETIMES => if !enabled() { on_span() },
435     ///     NEVER => on_span(),
436     /// }
437     /// // for events
438     /// match callsite_enabled() {
439     ///     ALWAYS => (),
440     ///     SOMETIMES => if !enabled() { on_event() },
441     ///     NEVER => on_event(),
442     /// }
443     /// ```
444     ///
445     /// A proper inversion would do `!(enabled() && event_enabled())` (or
446     /// `!enabled() || !event_enabled()`), but because of the implicit `&&`
447     /// relation between `enabled` and `event_enabled`, it is difficult to
448     /// short circuit and not call the wrapped `event_enabled`.
449     ///
450     /// A combinator which remembers the result of `enabled` in order to call
451     /// `event_enabled` only when `enabled() == true` is possible, but requires
452     /// additional thread-local mutable state to support a very niche use case.
453     //
454     //  Also, it'd mean the wrapped layer's `enabled()` always gets called and
455     //  globally applied to events where it doesn't today, since we can't know
456     //  what `event_enabled` will say until we have the event to call it with.
457     ///
458     /// [`Filter`]: crate::layer::Filter
459     /// [`enabled`]: crate::layer::Filter::enabled
460     /// [`event_enabled`]: crate::layer::Filter::event_enabled
461     /// [`callsite_enabled`]: crate::layer::Filter::callsite_enabled
new(a: A) -> Self462     pub(crate) fn new(a: A) -> Self {
463         Self { a, _s: PhantomData }
464     }
465 }
466 
467 impl<A, S> Filter<S> for Not<A, S>
468 where
469     A: Filter<S>,
470 {
471     #[inline]
enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool472     fn enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
473         !self.a.enabled(meta, cx)
474     }
475 
callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest476     fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest {
477         match self.a.callsite_enabled(meta) {
478             i if i.is_always() => Interest::never(),
479             i if i.is_never() => Interest::always(),
480             _ => Interest::sometimes(),
481         }
482     }
483 
max_level_hint(&self) -> Option<LevelFilter>484     fn max_level_hint(&self) -> Option<LevelFilter> {
485         // TODO(eliza): figure this out???
486         None
487     }
488 
489     #[inline]
event_enabled(&self, event: &tracing_core::Event<'_>, cx: &Context<'_, S>) -> bool490     fn event_enabled(&self, event: &tracing_core::Event<'_>, cx: &Context<'_, S>) -> bool {
491         // Never disable based on event_enabled; we "disabled" it in `enabled`,
492         // so the `not` has already been applied and filtered this not out.
493         let _ = (event, cx);
494         true
495     }
496 
497     #[inline]
on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>)498     fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
499         self.a.on_new_span(attrs, id, ctx);
500     }
501 
502     #[inline]
on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>)503     fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {
504         self.a.on_record(id, values, ctx.clone());
505     }
506 
507     #[inline]
on_enter(&self, id: &Id, ctx: Context<'_, S>)508     fn on_enter(&self, id: &Id, ctx: Context<'_, S>) {
509         self.a.on_enter(id, ctx);
510     }
511 
512     #[inline]
on_exit(&self, id: &Id, ctx: Context<'_, S>)513     fn on_exit(&self, id: &Id, ctx: Context<'_, S>) {
514         self.a.on_exit(id, ctx);
515     }
516 
517     #[inline]
on_close(&self, id: Id, ctx: Context<'_, S>)518     fn on_close(&self, id: Id, ctx: Context<'_, S>) {
519         self.a.on_close(id, ctx);
520     }
521 }
522 
523 impl<A, S> Clone for Not<A, S>
524 where
525     A: Clone,
526 {
clone(&self) -> Self527     fn clone(&self) -> Self {
528         Self {
529             a: self.a.clone(),
530             _s: PhantomData,
531         }
532     }
533 }
534 
535 impl<A, S> fmt::Debug for Not<A, S>
536 where
537     A: fmt::Debug,
538 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result539     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
540         f.debug_tuple("Not").field(&self.a).finish()
541     }
542 }
543