1 | use crate::{ |
2 | filter::LevelFilter, |
3 | layer::{Context, Layer}, |
4 | }; |
5 | use core::{any::type_name, fmt, marker::PhantomData}; |
6 | use 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)] |
25 | pub 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 |
46 | pub 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 | /// ``` |
104 | pub fn filter_fn<F>(f: F) -> FilterFn<F> |
105 | where |
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 |
175 | pub fn dynamic_filter_fn<S, F>(f: F) -> DynFilterFn<S, F> |
176 | where |
177 | F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool, |
178 | { |
179 | DynFilterFn::new(f) |
180 | } |
181 | |
182 | impl<F> FilterFn<F> |
183 | where |
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 cachable, 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 | |
324 | impl<S, F> Layer<S> for FilterFn<F> |
325 | where |
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 | |
342 | impl<F> From<F> for FilterFn<F> |
343 | where |
344 | F: Fn(&Metadata<'_>) -> bool, |
345 | { |
346 | fn from(enabled: F) -> Self { |
347 | Self::new(enabled) |
348 | } |
349 | } |
350 | |
351 | impl<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 | |
362 | impl<S, F> DynFilterFn<S, F> |
363 | where |
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 | |
434 | impl<S, F, R> DynFilterFn<S, F, R> |
435 | where |
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 | |
600 | impl<S, F, R> DynFilterFn<S, F, R> |
601 | where |
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 | |
643 | impl<S, F, R> Layer<S> for DynFilterFn<S, F, R> |
644 | where |
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 | |
662 | impl<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 | |
679 | impl<S, F, R> Clone for DynFilterFn<S, F, R> |
680 | where |
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 | |
694 | impl<F, S> From<F> for DynFilterFn<S, F> |
695 | where |
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 | |
705 | feature! { |
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 | |
745 | fn 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 | } |
750 | |