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