1//! Filter combinators
2use crate::layer::{Context, Filter};
3use std::{cmp, fmt, marker::PhantomData};
4use 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
18pub 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
32pub 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
48pub struct Not<A, S> {
49 a: A,
50 _s: PhantomData<fn(S)>,
51}
52
53// === impl And ===
54
55impl<A, B, S> And<A, B, S>
56where
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
101 pub(crate) fn new(a: A, b: B) -> Self {
102 Self {
103 a,
104 b,
105 _s: PhantomData,
106 }
107 }
108}
109
110impl<A, B, S> Filter<S> for And<A, B, S>
111where
112 A: Filter<S>,
113 B: Filter<S>,
114{
115 #[inline]
116 fn enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
117 self.a.enabled(meta, cx) && self.b.enabled(meta, cx)
118 }
119
120 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
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]
141 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]
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]
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]
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]
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]
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
176impl<A, B, S> Clone for And<A, B, S>
177where
178 A: Clone,
179 B: Clone,
180{
181 fn clone(&self) -> Self {
182 Self {
183 a: self.a.clone(),
184 b: self.b.clone(),
185 _s: PhantomData,
186 }
187 }
188}
189
190impl<A, B, S> fmt::Debug for And<A, B, S>
191where
192 A: fmt::Debug,
193 B: fmt::Debug,
194{
195 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
205impl<A, B, S> Or<A, B, S>
206where
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
284 pub(crate) fn new(a: A, b: B) -> Self {
285 Self {
286 a,
287 b,
288 _s: PhantomData,
289 }
290 }
291}
292
293impl<A, B, S> Filter<S> for Or<A, B, S>
294where
295 A: Filter<S>,
296 B: Filter<S>,
297{
298 #[inline]
299 fn enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
300 self.a.enabled(meta, cx) || self.b.enabled(meta, cx)
301 }
302
303 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
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]
333 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]
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]
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]
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]
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]
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
368impl<A, B, S> Clone for Or<A, B, S>
369where
370 A: Clone,
371 B: Clone,
372{
373 fn clone(&self) -> Self {
374 Self {
375 a: self.a.clone(),
376 b: self.b.clone(),
377 _s: PhantomData,
378 }
379 }
380}
381
382impl<A, B, S> fmt::Debug for Or<A, B, S>
383where
384 A: fmt::Debug,
385 B: fmt::Debug,
386{
387 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
397impl<A, S> Not<A, S>
398where
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
462 pub(crate) fn new(a: A) -> Self {
463 Self { a, _s: PhantomData }
464 }
465}
466
467impl<A, S> Filter<S> for Not<A, S>
468where
469 A: Filter<S>,
470{
471 #[inline]
472 fn enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
473 !self.a.enabled(meta, cx)
474 }
475
476 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
484 fn max_level_hint(&self) -> Option<LevelFilter> {
485 // TODO(eliza): figure this out???
486 None
487 }
488
489 #[inline]
490 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]
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]
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]
508 fn on_enter(&self, id: &Id, ctx: Context<'_, S>) {
509 self.a.on_enter(id, ctx);
510 }
511
512 #[inline]
513 fn on_exit(&self, id: &Id, ctx: Context<'_, S>) {
514 self.a.on_exit(id, ctx);
515 }
516
517 #[inline]
518 fn on_close(&self, id: Id, ctx: Context<'_, S>) {
519 self.a.on_close(id, ctx);
520 }
521}
522
523impl<A, S> Clone for Not<A, S>
524where
525 A: Clone,
526{
527 fn clone(&self) -> Self {
528 Self {
529 a: self.a.clone(),
530 _s: PhantomData,
531 }
532 }
533}
534
535impl<A, S> fmt::Debug for Not<A, S>
536where
537 A: fmt::Debug,
538{
539 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
540 f.debug_tuple("Not").field(&self.a).finish()
541 }
542}
543