tracing_subscriber/filter/
filter_fn.rs

1use crate::{
2    filter::LevelFilter,
3    layer::{Context, Layer},
4};
5use core::{any::type_name, fmt, marker::PhantomData};
6use tracing_core::{Interest, Metadata, Subscriber};
7
8/// A filter implemented by a closure or function pointer that
9/// determines whether a given span or event is enabled, based on its
10/// [`Metadata`].
11///
12/// This type can be used for both [per-layer filtering][plf] (using its
13/// [`Filter`] implementation) and [global filtering][global] (using its
14/// [`Layer`] implementation).
15///
16/// See the [documentation on filtering with layers][filtering] for details.
17///
18/// [`Metadata`]: tracing_core::Metadata
19/// [`Filter`]: crate::layer::Filter
20/// [`Layer`]: crate::layer::Layer
21/// [plf]: crate::layer#per-layer-filtering
22/// [global]: crate::layer#global-filtering
23/// [filtering]: crate::layer#filtering-with-layers
24#[derive(Clone)]
25pub struct FilterFn<F = fn(&Metadata<'_>) -> bool> {
26    enabled: F,
27    max_level_hint: Option<LevelFilter>,
28}
29
30/// A filter implemented by a closure or function pointer that
31/// determines whether a given span or event is enabled _dynamically_,
32/// potentially based on the current [span context].
33///
34/// This type can be used for both [per-layer filtering][plf] (using its
35/// [`Filter`] implementation) and [global filtering][global] (using its
36/// [`Layer`] implementation).
37///
38/// See the [documentation on filtering with layers][filtering] for details.
39///
40/// [span context]: crate::layer::Context
41/// [`Filter`]: crate::layer::Filter
42/// [`Layer`]: crate::layer::Layer
43/// [plf]: crate::layer#per-layer-filtering
44/// [global]: crate::layer#global-filtering
45/// [filtering]: crate::layer#filtering-with-layers
46pub struct DynFilterFn<
47    S,
48    // TODO(eliza): should these just be boxed functions?
49    F = fn(&Metadata<'_>, &Context<'_, S>) -> bool,
50    R = fn(&'static Metadata<'static>) -> Interest,
51> {
52    enabled: F,
53    register_callsite: Option<R>,
54    max_level_hint: Option<LevelFilter>,
55    _s: PhantomData<fn(S)>,
56}
57
58// === impl FilterFn ===
59
60/// Constructs a [`FilterFn`], from a function or closure that returns `true` if
61/// a span or event should be enabled, based on its [`Metadata`].
62///
63/// The returned [`FilterFn`] can be used for both [per-layer filtering][plf]
64/// (using its [`Filter`] implementation) and [global filtering][global] (using
65/// its  [`Layer`] implementation).
66///
67/// See the [documentation on filtering with layers][filtering] for details.
68///
69/// This is equivalent to calling [`FilterFn::new`].
70///
71/// [`Metadata`]: tracing_core::Metadata
72/// [`Filter`]: crate::layer::Filter
73/// [`Layer`]: crate::layer::Layer
74/// [plf]: crate::layer#per-layer-filtering
75/// [global]: crate::layer#global-filtering
76/// [filtering]: crate::layer#filtering-with-layers
77///
78/// # Examples
79///
80/// ```
81/// use tracing_subscriber::{
82///     layer::{Layer, SubscriberExt},
83///     filter,
84///     util::SubscriberInitExt,
85/// };
86///
87/// let my_filter = filter::filter_fn(|metadata| {
88///     // Only enable spans or events with the target "interesting_things"
89///     metadata.target() == "interesting_things"
90/// });
91///
92/// let my_layer = tracing_subscriber::fmt::layer();
93///
94/// tracing_subscriber::registry()
95///     .with(my_layer.with_filter(my_filter))
96///     .init();
97///
98/// // This event will not be enabled.
99/// tracing::warn!("something important but uninteresting happened!");
100///
101/// // This event will be enabled.
102/// tracing::debug!(target: "interesting_things", "an interesting minor detail...");
103/// ```
104pub fn filter_fn<F>(f: F) -> FilterFn<F>
105where
106    F: Fn(&Metadata<'_>) -> bool,
107{
108    FilterFn::new(f)
109}
110
111/// Constructs a [`DynFilterFn`] from a function or closure that returns `true`
112/// if a span or event should be enabled within a particular [span context][`Context`].
113///
114/// This is equivalent to calling [`DynFilterFn::new`].
115///
116/// Unlike [`filter_fn`], this function takes a closure or function pointer
117/// taking the [`Metadata`] for a span or event *and* the current [`Context`].
118/// This means that a [`DynFilterFn`] can choose whether to enable spans or
119/// events based on information about the _current_ span (or its parents).
120///
121/// If this is *not* necessary, use [`filter_fn`] instead.
122///
123/// The returned [`DynFilterFn`] can be used for both [per-layer filtering][plf]
124/// (using its [`Filter`] implementation) and [global filtering][global] (using
125/// its  [`Layer`] implementation).
126///
127/// See the [documentation on filtering with layers][filtering] for details.
128///
129/// # Examples
130///
131/// ```
132/// use tracing_subscriber::{
133///     layer::{Layer, SubscriberExt},
134///     filter,
135///     util::SubscriberInitExt,
136/// };
137///
138/// // Only enable spans or events within a span named "interesting_span".
139/// let my_filter = filter::dynamic_filter_fn(|metadata, cx| {
140///     // If this *is* "interesting_span", make sure to enable it.
141///     if metadata.is_span() && metadata.name() == "interesting_span" {
142///         return true;
143///     }
144///
145///     // Otherwise, are we in an interesting span?
146///     if let Some(current_span) = cx.lookup_current() {
147///         return current_span.name() == "interesting_span";
148///     }
149///
150///     false
151/// });
152///
153/// let my_layer = tracing_subscriber::fmt::layer();
154///
155/// tracing_subscriber::registry()
156///     .with(my_layer.with_filter(my_filter))
157///     .init();
158///
159/// // This event will not be enabled.
160/// tracing::info!("something happened");
161///
162/// tracing::info_span!("interesting_span").in_scope(|| {
163///     // This event will be enabled.
164///     tracing::debug!("something else happened");
165/// });
166/// ```
167///
168/// [`Filter`]: crate::layer::Filter
169/// [`Layer`]: crate::layer::Layer
170/// [plf]: crate::layer#per-layer-filtering
171/// [global]: crate::layer#global-filtering
172/// [filtering]: crate::layer#filtering-with-layers
173/// [`Context`]: crate::layer::Context
174/// [`Metadata`]: tracing_core::Metadata
175pub fn dynamic_filter_fn<S, F>(f: F) -> DynFilterFn<S, F>
176where
177    F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool,
178{
179    DynFilterFn::new(f)
180}
181
182impl<F> FilterFn<F>
183where
184    F: Fn(&Metadata<'_>) -> bool,
185{
186    /// Constructs a [`FilterFn`] from a function or closure that returns `true`
187    /// if a span or event should be enabled, based on its [`Metadata`].
188    ///
189    /// If determining whether a span or event should be enabled also requires
190    /// information about the current span context, use [`DynFilterFn`] instead.
191    ///
192    /// See the [documentation on per-layer filtering][plf] for details on using
193    /// [`Filter`]s.
194    ///
195    /// [`Filter`]: crate::layer::Filter
196    /// [plf]: crate::layer#per-layer-filtering
197    /// [`Metadata`]: tracing_core::Metadata
198    ///
199    /// # Examples
200    ///
201    /// ```
202    /// use tracing_subscriber::{
203    ///     layer::{Layer, SubscriberExt},
204    ///     filter::FilterFn,
205    ///     util::SubscriberInitExt,
206    /// };
207    ///
208    /// let my_filter = FilterFn::new(|metadata| {
209    ///     // Only enable spans or events with the target "interesting_things"
210    ///     metadata.target() == "interesting_things"
211    /// });
212    ///
213    /// let my_layer = tracing_subscriber::fmt::layer();
214    ///
215    /// tracing_subscriber::registry()
216    ///     .with(my_layer.with_filter(my_filter))
217    ///     .init();
218    ///
219    /// // This event will not be enabled.
220    /// tracing::warn!("something important but uninteresting happened!");
221    ///
222    /// // This event will be enabled.
223    /// tracing::debug!(target: "interesting_things", "an interesting minor detail...");
224    /// ```
225    pub fn new(enabled: F) -> Self {
226        Self {
227            enabled,
228            max_level_hint: None,
229        }
230    }
231
232    /// Sets the highest verbosity [`Level`] the filter function will enable.
233    ///
234    /// The value passed to this method will be returned by this `FilterFn`'s
235    /// [`Filter::max_level_hint`] method.
236    ///
237    /// If the provided function will not enable all levels, it is recommended
238    /// to call this method to configure it with the most verbose level it will
239    /// enable.
240    ///
241    /// # Examples
242    ///
243    /// ```
244    /// use tracing_subscriber::{
245    ///     layer::{Layer, SubscriberExt},
246    ///     filter::{filter_fn, LevelFilter},
247    ///     util::SubscriberInitExt,
248    /// };
249    /// use tracing_core::Level;
250    ///
251    /// let my_filter = filter_fn(|metadata| {
252    ///     // Only enable spans or events with targets starting with `my_crate`
253    ///     // and levels at or below `INFO`.
254    ///     metadata.level() <= &Level::INFO && metadata.target().starts_with("my_crate")
255    /// })
256    ///     // Since the filter closure will only enable the `INFO` level and
257    ///     // below, set the max level hint
258    ///     .with_max_level_hint(LevelFilter::INFO);
259    ///
260    /// let my_layer = tracing_subscriber::fmt::layer();
261    ///
262    /// tracing_subscriber::registry()
263    ///     .with(my_layer.with_filter(my_filter))
264    ///     .init();
265    /// ```
266    ///
267    /// [`Level`]: tracing_core::Level
268    /// [`Filter::max_level_hint`]: crate::layer::Filter::max_level_hint
269    pub fn with_max_level_hint(self, max_level_hint: impl Into<LevelFilter>) -> Self {
270        Self {
271            max_level_hint: Some(max_level_hint.into()),
272            ..self
273        }
274    }
275
276    #[inline]
277    pub(in crate::filter) fn is_enabled(&self, metadata: &Metadata<'_>) -> bool {
278        let enabled = (self.enabled)(metadata);
279        debug_assert!(
280            !enabled || self.is_below_max_level(metadata),
281            "FilterFn<{}> claimed it would only enable {:?} and below, \
282            but it enabled metadata with the {:?} level\nmetadata={:#?}",
283            type_name::<F>(),
284            self.max_level_hint.unwrap(),
285            metadata.level(),
286            metadata,
287        );
288
289        enabled
290    }
291
292    #[inline]
293    pub(in crate::filter) fn is_callsite_enabled(
294        &self,
295        metadata: &'static Metadata<'static>,
296    ) -> Interest {
297        // Because `self.enabled` takes a `Metadata` only (and no `Context`
298        // parameter), we can reasonably assume its results are cacheable, and
299        // just return `Interest::always`/`Interest::never`.
300        if (self.enabled)(metadata) {
301            debug_assert!(
302                self.is_below_max_level(metadata),
303                "FilterFn<{}> claimed it was only interested in {:?} and below, \
304                but it enabled metadata with the {:?} level\nmetadata={:#?}",
305                type_name::<F>(),
306                self.max_level_hint.unwrap(),
307                metadata.level(),
308                metadata,
309            );
310            return Interest::always();
311        }
312
313        Interest::never()
314    }
315
316    fn is_below_max_level(&self, metadata: &Metadata<'_>) -> bool {
317        self.max_level_hint
318            .as_ref()
319            .map(|hint| metadata.level() <= hint)
320            .unwrap_or(true)
321    }
322}
323
324impl<S, F> Layer<S> for FilterFn<F>
325where
326    F: Fn(&Metadata<'_>) -> bool + 'static,
327    S: Subscriber,
328{
329    fn enabled(&self, metadata: &Metadata<'_>, _: Context<'_, S>) -> bool {
330        self.is_enabled(metadata)
331    }
332
333    fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
334        self.is_callsite_enabled(metadata)
335    }
336
337    fn max_level_hint(&self) -> Option<LevelFilter> {
338        self.max_level_hint
339    }
340}
341
342impl<F> From<F> for FilterFn<F>
343where
344    F: Fn(&Metadata<'_>) -> bool,
345{
346    fn from(enabled: F) -> Self {
347        Self::new(enabled)
348    }
349}
350
351impl<F> fmt::Debug for FilterFn<F> {
352    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353        f.debug_struct("FilterFn")
354            .field("enabled", &format_args!("{}", type_name::<F>()))
355            .field("max_level_hint", &self.max_level_hint)
356            .finish()
357    }
358}
359
360// === impl DynFilterFn ==
361
362impl<S, F> DynFilterFn<S, F>
363where
364    F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool,
365{
366    /// Constructs a [`Filter`] from a function or closure that returns `true`
367    /// if a span or event should be enabled in the current [span
368    /// context][`Context`].
369    ///
370    /// Unlike [`FilterFn`], a `DynFilterFn` is constructed from a closure or
371    /// function pointer that takes both the [`Metadata`] for a span or event
372    /// *and* the current [`Context`]. This means that a [`DynFilterFn`] can
373    /// choose whether to enable spans or events based on information about the
374    /// _current_ span (or its parents).
375    ///
376    /// If this is *not* necessary, use [`FilterFn`] instead.
377    ///
378    /// See the [documentation on per-layer filtering][plf] for details on using
379    /// [`Filter`]s.
380    ///
381    /// [`Filter`]: crate::layer::Filter
382    /// [plf]: crate::layer#per-layer-filtering
383    /// [`Context`]: crate::layer::Context
384    /// [`Metadata`]: tracing_core::Metadata
385    ///
386    /// # Examples
387    ///
388    /// ```
389    /// use tracing_subscriber::{
390    ///     layer::{Layer, SubscriberExt},
391    ///     filter::DynFilterFn,
392    ///     util::SubscriberInitExt,
393    /// };
394    ///
395    /// // Only enable spans or events within a span named "interesting_span".
396    /// let my_filter = DynFilterFn::new(|metadata, cx| {
397    ///     // If this *is* "interesting_span", make sure to enable it.
398    ///     if metadata.is_span() && metadata.name() == "interesting_span" {
399    ///         return true;
400    ///     }
401    ///
402    ///     // Otherwise, are we in an interesting span?
403    ///     if let Some(current_span) = cx.lookup_current() {
404    ///         return current_span.name() == "interesting_span";
405    ///     }
406    ///
407    ///     false
408    /// });
409    ///
410    /// let my_layer = tracing_subscriber::fmt::layer();
411    ///
412    /// tracing_subscriber::registry()
413    ///     .with(my_layer.with_filter(my_filter))
414    ///     .init();
415    ///
416    /// // This event will not be enabled.
417    /// tracing::info!("something happened");
418    ///
419    /// tracing::info_span!("interesting_span").in_scope(|| {
420    ///     // This event will be enabled.
421    ///     tracing::debug!("something else happened");
422    /// });
423    /// ```
424    pub fn new(enabled: F) -> Self {
425        Self {
426            enabled,
427            register_callsite: None,
428            max_level_hint: None,
429            _s: PhantomData,
430        }
431    }
432}
433
434impl<S, F, R> DynFilterFn<S, F, R>
435where
436    F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool,
437{
438    /// Sets the highest verbosity [`Level`] the filter function will enable.
439    ///
440    /// The value passed to this method will be returned by this `DynFilterFn`'s
441    /// [`Filter::max_level_hint`] method.
442    ///
443    /// If the provided function will not enable all levels, it is recommended
444    /// to call this method to configure it with the most verbose level it will
445    /// enable.
446    ///
447    /// # Examples
448    ///
449    /// ```
450    /// use tracing_subscriber::{
451    ///     layer::{Layer, SubscriberExt},
452    ///     filter::{DynFilterFn, LevelFilter},
453    ///     util::SubscriberInitExt,
454    /// };
455    /// use tracing_core::Level;
456    ///
457    /// // Only enable spans or events with levels at or below `INFO`, if
458    /// // we are inside a span called "interesting_span".
459    /// let my_filter = DynFilterFn::new(|metadata, cx| {
460    ///     // If the level is greater than INFO, disable it.
461    ///     if metadata.level() > &Level::INFO {
462    ///         return false;
463    ///     }
464    ///
465    ///     // If any span in the current scope is named "interesting_span",
466    ///     // enable this span or event.
467    ///     for span in cx.lookup_current().iter().flat_map(|span| span.scope()) {
468    ///         if span.name() == "interesting_span" {
469    ///             return true;
470    ///          }
471    ///     }
472    ///
473    ///     // Otherwise, disable it.
474    ///     false
475    /// })
476    ///     // Since the filter closure will only enable the `INFO` level and
477    ///     // below, set the max level hint
478    ///     .with_max_level_hint(LevelFilter::INFO);
479    ///
480    /// let my_layer = tracing_subscriber::fmt::layer();
481    ///
482    /// tracing_subscriber::registry()
483    ///     .with(my_layer.with_filter(my_filter))
484    ///     .init();
485    /// ```
486    ///
487    /// [`Level`]: tracing_core::Level
488    /// [`Filter::max_level_hint`]: crate::layer::Filter::max_level_hint
489    pub fn with_max_level_hint(self, max_level_hint: impl Into<LevelFilter>) -> Self {
490        Self {
491            max_level_hint: Some(max_level_hint.into()),
492            ..self
493        }
494    }
495
496    /// Adds a function for filtering callsites to this filter.
497    ///
498    /// When this filter's [`Filter::callsite_enabled`][cse] method is called,
499    /// the provided function will be used rather than the default.
500    ///
501    /// By default, `DynFilterFn` assumes that, because the filter _may_ depend
502    /// dynamically on the current [span context], its result should never be
503    /// cached. However, some filtering strategies may require dynamic information
504    /// from the current span context in *some* cases, but are able to make
505    /// static filtering decisions from [`Metadata`] alone in others.
506    ///
507    /// For example, consider the filter given in the example for
508    /// [`DynFilterFn::new`]. That filter enables all spans named
509    /// "interesting_span", and any events and spans that occur inside of an
510    /// interesting span. Since the span's name is part of its static
511    /// [`Metadata`], the "interesting_span" can be enabled in
512    /// [`callsite_enabled`][cse]:
513    ///
514    /// ```
515    /// use tracing_subscriber::{
516    ///     layer::{Layer, SubscriberExt},
517    ///     filter::DynFilterFn,
518    ///     util::SubscriberInitExt,
519    /// };
520    /// use tracing_core::subscriber::Interest;
521    ///
522    /// // Only enable spans or events within a span named "interesting_span".
523    /// let my_filter = DynFilterFn::new(|metadata, cx| {
524    ///     // If this *is* "interesting_span", make sure to enable it.
525    ///     if metadata.is_span() && metadata.name() == "interesting_span" {
526    ///         return true;
527    ///     }
528    ///
529    ///     // Otherwise, are we in an interesting span?
530    ///     if let Some(current_span) = cx.lookup_current() {
531    ///         return current_span.name() == "interesting_span";
532    ///     }
533    ///
534    ///     false
535    /// }).with_callsite_filter(|metadata| {
536    ///     // If this is an "interesting_span", we know we will always
537    ///     // enable it.
538    ///     if metadata.is_span() && metadata.name() == "interesting_span" {
539    ///         return Interest::always();
540    ///     }
541    ///
542    ///     // Otherwise, it depends on whether or not we're in an interesting
543    ///     // span. You'll have to ask us again for each span/event!
544    ///     Interest::sometimes()
545    /// });
546    ///
547    /// let my_layer = tracing_subscriber::fmt::layer();
548    ///
549    /// tracing_subscriber::registry()
550    ///     .with(my_layer.with_filter(my_filter))
551    ///     .init();
552    /// ```
553    ///
554    /// [cse]: crate::layer::Filter::callsite_enabled
555    /// [`enabled`]: crate::layer::Filter::enabled
556    /// [`Metadata`]: tracing_core::Metadata
557    /// [span context]: crate::layer::Context
558    pub fn with_callsite_filter<R2>(self, callsite_enabled: R2) -> DynFilterFn<S, F, R2>
559    where
560        R2: Fn(&'static Metadata<'static>) -> Interest,
561    {
562        let register_callsite = Some(callsite_enabled);
563        let DynFilterFn {
564            enabled,
565            max_level_hint,
566            _s,
567            ..
568        } = self;
569        DynFilterFn {
570            enabled,
571            register_callsite,
572            max_level_hint,
573            _s,
574        }
575    }
576
577    fn default_callsite_enabled(&self, metadata: &Metadata<'_>) -> Interest {
578        // If it's below the configured max level, assume that `enabled` will
579        // never enable it...
580        if !is_below_max_level(&self.max_level_hint, metadata) {
581            debug_assert!(
582                !(self.enabled)(metadata, &Context::none()),
583                "DynFilterFn<{}> claimed it would only enable {:?} and below, \
584                but it enabled metadata with the {:?} level\nmetadata={:#?}",
585                type_name::<F>(),
586                self.max_level_hint.unwrap(),
587                metadata.level(),
588                metadata,
589            );
590            return Interest::never();
591        }
592
593        // Otherwise, since this `enabled` function is dynamic and depends on
594        // the current context, we don't know whether this span or event will be
595        // enabled or not. Ask again every time it's recorded!
596        Interest::sometimes()
597    }
598}
599
600impl<S, F, R> DynFilterFn<S, F, R>
601where
602    F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool,
603    R: Fn(&'static Metadata<'static>) -> Interest,
604{
605    #[inline]
606    fn is_enabled(&self, metadata: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
607        let enabled = (self.enabled)(metadata, cx);
608        debug_assert!(
609            !enabled || is_below_max_level(&self.max_level_hint, metadata),
610            "DynFilterFn<{}> claimed it would only enable {:?} and below, \
611            but it enabled metadata with the {:?} level\nmetadata={:#?}",
612            type_name::<F>(),
613            self.max_level_hint.unwrap(),
614            metadata.level(),
615            metadata,
616        );
617
618        enabled
619    }
620
621    #[inline]
622    fn is_callsite_enabled(&self, metadata: &'static Metadata<'static>) -> Interest {
623        let interest = self
624            .register_callsite
625            .as_ref()
626            .map(|callsite_enabled| callsite_enabled(metadata))
627            .unwrap_or_else(|| self.default_callsite_enabled(metadata));
628        debug_assert!(
629            interest.is_never() || is_below_max_level(&self.max_level_hint, metadata),
630            "DynFilterFn<{}, {}> claimed it was only interested in {:?} and below, \
631            but it enabled metadata with the {:?} level\nmetadata={:#?}",
632            type_name::<F>(),
633            type_name::<R>(),
634            self.max_level_hint.unwrap(),
635            metadata.level(),
636            metadata,
637        );
638
639        interest
640    }
641}
642
643impl<S, F, R> Layer<S> for DynFilterFn<S, F, R>
644where
645    F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool + 'static,
646    R: Fn(&'static Metadata<'static>) -> Interest + 'static,
647    S: Subscriber,
648{
649    fn enabled(&self, metadata: &Metadata<'_>, cx: Context<'_, S>) -> bool {
650        self.is_enabled(metadata, &cx)
651    }
652
653    fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
654        self.is_callsite_enabled(metadata)
655    }
656
657    fn max_level_hint(&self) -> Option<LevelFilter> {
658        self.max_level_hint
659    }
660}
661
662impl<S, F, R> fmt::Debug for DynFilterFn<S, F, R> {
663    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
664        let mut s = f.debug_struct("DynFilterFn");
665        s.field("enabled", &format_args!("{}", type_name::<F>()));
666        if self.register_callsite.is_some() {
667            s.field(
668                "register_callsite",
669                &format_args!("Some({})", type_name::<R>()),
670            );
671        } else {
672            s.field("register_callsite", &format_args!("None"));
673        }
674
675        s.field("max_level_hint", &self.max_level_hint).finish()
676    }
677}
678
679impl<S, F, R> Clone for DynFilterFn<S, F, R>
680where
681    F: Clone,
682    R: Clone,
683{
684    fn clone(&self) -> Self {
685        Self {
686            enabled: self.enabled.clone(),
687            register_callsite: self.register_callsite.clone(),
688            max_level_hint: self.max_level_hint,
689            _s: PhantomData,
690        }
691    }
692}
693
694impl<F, S> From<F> for DynFilterFn<S, F>
695where
696    F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool,
697{
698    fn from(f: F) -> Self {
699        Self::new(f)
700    }
701}
702
703// === PLF impls ===
704
705feature! {
706    #![all(feature = "registry", feature = "std")]
707    use crate::layer::Filter;
708
709    impl<S, F> Filter<S> for FilterFn<F>
710    where
711        F: Fn(&Metadata<'_>) -> bool,
712    {
713        fn enabled(&self, metadata: &Metadata<'_>, _: &Context<'_, S>) -> bool {
714            self.is_enabled(metadata)
715        }
716
717        fn callsite_enabled(&self, metadata: &'static Metadata<'static>) -> Interest {
718            self.is_callsite_enabled(metadata)
719        }
720
721        fn max_level_hint(&self) -> Option<LevelFilter> {
722            self.max_level_hint
723        }
724    }
725
726    impl<S, F, R> Filter<S> for DynFilterFn<S, F, R>
727    where
728        F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool,
729        R: Fn(&'static Metadata<'static>) -> Interest,
730    {
731        fn enabled(&self, metadata: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
732            self.is_enabled(metadata, cx)
733        }
734
735        fn callsite_enabled(&self, metadata: &'static Metadata<'static>) -> Interest {
736            self.is_callsite_enabled(metadata)
737        }
738
739        fn max_level_hint(&self) -> Option<LevelFilter> {
740            self.max_level_hint
741        }
742    }
743}
744
745fn is_below_max_level(hint: &Option<LevelFilter>, metadata: &Metadata<'_>) -> bool {
746    hint.as_ref()
747        .map(|hint| metadata.level() <= hint)
748        .unwrap_or(true)
749}