1 //! A `Layer` that enables or disables spans and events based on a set of 2 //! filtering directives. 3 4 // these are publicly re-exported, but the compiler doesn't realize 5 // that for some reason. 6 #[allow(unreachable_pub)] 7 pub use self::{builder::Builder, directive::Directive, field::BadName as BadFieldName}; 8 mod builder; 9 mod directive; 10 mod field; 11 12 use crate::{ 13 filter::LevelFilter, 14 layer::{Context, Layer}, 15 sync::RwLock, 16 }; 17 use directive::ParseError; 18 use std::{cell::RefCell, collections::HashMap, env, error::Error, fmt, str::FromStr}; 19 use thread_local::ThreadLocal; 20 use tracing_core::{ 21 callsite, 22 field::Field, 23 span, 24 subscriber::{Interest, Subscriber}, 25 Metadata, 26 }; 27 28 /// A [`Layer`] which filters spans and events based on a set of filter 29 /// directives. 30 /// 31 /// `EnvFilter` implements both the [`Layer`](#impl-Layer<S>) and [`Filter`] traits, so it may 32 /// be used for both [global filtering][global] and [per-layer filtering][plf], 33 /// respectively. See [the documentation on filtering with `Layer`s][filtering] 34 /// for details. 35 /// 36 /// The [`Targets`] type implements a similar form of filtering, but without the 37 /// ability to dynamically enable events based on the current span context, and 38 /// without filtering on field values. When these features are not required, 39 /// [`Targets`] provides a lighter-weight alternative to [`EnvFilter`]. 40 /// 41 /// # Directives 42 /// 43 /// A filter consists of one or more comma-separated directives which match on [`Span`]s and [`Event`]s. 44 /// Each directive may have a corresponding maximum verbosity [`level`] which 45 /// enables (e.g., _selects for_) spans and events that match. Like `log`, 46 /// `tracing` considers less exclusive levels (like `trace` or `info`) to be more 47 /// verbose than more exclusive levels (like `error` or `warn`). 48 /// 49 /// The directive syntax is similar to that of [`env_logger`]'s. At a high level, the syntax for directives 50 /// consists of several parts: 51 /// 52 /// ```text 53 /// target[span{field=value}]=level 54 /// ``` 55 /// 56 /// Each component (`target`, `span`, `field`, `value`, and `level`) will be covered in turn. 57 /// 58 /// - `target` matches the event or span's target. In general, this is the module path and/or crate name. 59 /// Examples of targets `h2`, `tokio::net`, or `tide::server`. For more information on targets, 60 /// please refer to [`Metadata`]'s documentation. 61 /// - `span` matches on the span's name. If a `span` directive is provided alongside a `target`, 62 /// the `span` directive will match on spans _within_ the `target`. 63 /// - `field` matches on [fields] within spans. Field names can also be supplied without a `value` 64 /// and will match on any [`Span`] or [`Event`] that has a field with that name. 65 /// For example: `[span{field=\"value\"}]=debug`, `[{field}]=trace`. 66 /// - `value` matches on the value of a span's field. If a value is a numeric literal or a bool, 67 /// it will match _only_ on that value. Otherwise, this filter matches the 68 /// [`std::fmt::Debug`] output from the value. 69 /// - `level` sets a maximum verbosity level accepted by this directive. 70 /// 71 /// When a field value directive (`[{<FIELD NAME>=<FIELD_VALUE>}]=...`) matches a 72 /// value's [`std::fmt::Debug`] output (i.e., the field value in the directive 73 /// is not a `bool`, `i64`, `u64`, or `f64` literal), the matched pattern may be 74 /// interpreted as either a regular expression or as the precise expected 75 /// output of the field's [`std::fmt::Debug`] implementation. By default, these 76 /// filters are interpreted as regular expressions, but this can be disabled 77 /// using the [`Builder::with_regex`] builder method to use precise matching 78 /// instead. 79 /// 80 /// When field value filters are interpreted as regular expressions, the 81 /// [`regex-automata` crate's regular expression syntax][re-syntax] is 82 /// supported. 83 /// 84 /// **Note**: When filters are constructed from potentially untrusted inputs, 85 /// [disabling regular expression matching](Builder::with_regex) is strongly 86 /// recommended. 87 /// 88 /// ## Usage Notes 89 /// 90 /// - The portion of the directive which is included within the square brackets is `tracing`-specific. 91 /// - Any portion of the directive can be omitted. 92 /// - The sole exception are the `field` and `value` directives. If a `value` is provided, 93 /// a `field` must _also_ be provided. However, the converse does not hold, as fields can 94 /// be matched without a value. 95 /// - If only a level is provided, it will set the maximum level for all `Span`s and `Event`s 96 /// that are not enabled by other filters. 97 /// - A directive without a level will enable anything that it matches. This is equivalent to `=trace`. 98 /// - When a crate has a dash in its name, the default target for events will be the 99 /// crate's module path as it appears in Rust. This means every dash will be replaced 100 /// with an underscore. 101 /// - A dash in a target will only appear when being specified explicitly: 102 /// `tracing::info!(target: "target-name", ...);` 103 /// 104 /// ## Example Syntax 105 /// 106 /// - `tokio::net=info` will enable all spans or events that: 107 /// - have the `tokio::net` target, 108 /// - at the level `info` or above. 109 /// - `warn,tokio::net=info` will enable all spans and events that: 110 /// - are at the level `warn` or above, *or* 111 /// - have the `tokio::net` target at the level `info` or above. 112 /// - `my_crate[span_a]=trace` will enable all spans and events that: 113 /// - are within the `span_a` span or named `span_a` _if_ `span_a` has the target `my_crate`, 114 /// - at the level `trace` or above. 115 /// - `[span_b{name=\"bob\"}]` will enable all spans or event that: 116 /// - have _any_ target, 117 /// - are inside a span named `span_b`, 118 /// - which has a field named `name` with value `bob`, 119 /// - at _any_ level. 120 /// 121 /// # Examples 122 /// 123 /// Parsing an `EnvFilter` from the [default environment 124 /// variable](EnvFilter::from_default_env) (`RUST_LOG`): 125 /// 126 /// ``` 127 /// use tracing_subscriber::{EnvFilter, fmt, prelude::*}; 128 /// 129 /// tracing_subscriber::registry() 130 /// .with(fmt::layer()) 131 /// .with(EnvFilter::from_default_env()) 132 /// .init(); 133 /// ``` 134 /// 135 /// Parsing an `EnvFilter` [from a user-provided environment 136 /// variable](EnvFilter::from_env): 137 /// 138 /// ``` 139 /// use tracing_subscriber::{EnvFilter, fmt, prelude::*}; 140 /// 141 /// tracing_subscriber::registry() 142 /// .with(fmt::layer()) 143 /// .with(EnvFilter::from_env("MYAPP_LOG")) 144 /// .init(); 145 /// ``` 146 /// 147 /// Using `EnvFilter` as a [per-layer filter][plf] to filter only a single 148 /// [`Layer`]: 149 /// 150 /// ``` 151 /// use tracing_subscriber::{EnvFilter, fmt, prelude::*}; 152 /// 153 /// // Parse an `EnvFilter` configuration from the `RUST_LOG` 154 /// // environment variable. 155 /// let filter = EnvFilter::from_default_env(); 156 /// 157 /// // Apply the filter to this layer *only*. 158 /// let filtered_layer = fmt::layer().with_filter(filter); 159 /// 160 /// // Some other layer, whose output we don't want to filter. 161 /// let unfiltered_layer = // ... 162 /// # fmt::layer(); 163 /// 164 /// tracing_subscriber::registry() 165 /// .with(filtered_layer) 166 /// .with(unfiltered_layer) 167 /// .init(); 168 /// ``` 169 /// # Constructing `EnvFilter`s 170 /// 171 /// An `EnvFilter` is be constructed by parsing a string containing one or more 172 /// directives. The [`EnvFilter::new`] constructor parses an `EnvFilter` from a 173 /// string, ignoring any invalid directives, while [`EnvFilter::try_new`] 174 /// returns an error if invalid directives are encountered. Similarly, the 175 /// [`EnvFilter::from_env`] and [`EnvFilter::try_from_env`] constructors parse 176 /// an `EnvFilter` from the value of the provided environment variable, with 177 /// lossy and strict validation, respectively. 178 /// 179 /// A [builder](EnvFilter::builder) interface is available to set additional 180 /// configuration options prior to parsing an `EnvFilter`. See the [`Builder` 181 /// type's documentation](Builder) for details on the options that can be 182 /// configured using the builder. 183 /// 184 /// [`Span`]: tracing_core::span 185 /// [fields]: tracing_core::Field 186 /// [`Event`]: tracing_core::Event 187 /// [`level`]: tracing_core::Level 188 /// [`Metadata`]: tracing_core::Metadata 189 /// [`Targets`]: crate::filter::Targets 190 /// [`env_logger`]: https://crates.io/crates/env_logger 191 /// [`Filter`]: #impl-Filter<S> 192 /// [global]: crate::layer#global-filtering 193 /// [plf]: crate::layer#per-layer-filtering 194 /// [filtering]: crate::layer#filtering-with-layers 195 #[cfg_attr(docsrs, doc(cfg(all(feature = "env-filter", feature = "std"))))] 196 #[derive(Debug)] 197 pub struct EnvFilter { 198 statics: directive::Statics, 199 dynamics: directive::Dynamics, 200 has_dynamics: bool, 201 by_id: RwLock<HashMap<span::Id, directive::SpanMatcher>>, 202 by_cs: RwLock<HashMap<callsite::Identifier, directive::CallsiteMatcher>>, 203 scope: ThreadLocal<RefCell<Vec<LevelFilter>>>, 204 regex: bool, 205 } 206 207 type FieldMap<T> = HashMap<Field, T>; 208 209 /// Indicates that an error occurred while parsing a `EnvFilter` from an 210 /// environment variable. 211 #[cfg_attr(docsrs, doc(cfg(all(feature = "env-filter", feature = "std"))))] 212 #[derive(Debug)] 213 pub struct FromEnvError { 214 kind: ErrorKind, 215 } 216 217 #[derive(Debug)] 218 enum ErrorKind { 219 Parse(ParseError), 220 Env(env::VarError), 221 } 222 223 impl EnvFilter { 224 /// `RUST_LOG` is the default environment variable used by 225 /// [`EnvFilter::from_default_env`] and [`EnvFilter::try_from_default_env`]. 226 /// 227 /// [`EnvFilter::from_default_env`]: EnvFilter::from_default_env() 228 /// [`EnvFilter::try_from_default_env`]: EnvFilter::try_from_default_env() 229 pub const DEFAULT_ENV: &'static str = "RUST_LOG"; 230 231 // === constructors, etc === 232 233 /// Returns a [builder] that can be used to configure a new [`EnvFilter`] 234 /// instance. 235 /// 236 /// The [`Builder`] type is used to set additional configurations, such as 237 /// [whether regular expressions are enabled](Builder::with_regex) or [the 238 /// default directive](Builder::with_default_directive) before parsing an 239 /// [`EnvFilter`] from a string or environment variable. 240 /// 241 /// [builder]: https://rust-unofficial.github.io/patterns/patterns/creational/builder.html builder() -> Builder242 pub fn builder() -> Builder { 243 Builder::default() 244 } 245 246 /// Returns a new `EnvFilter` from the value of the `RUST_LOG` environment 247 /// variable, ignoring any invalid filter directives. 248 /// 249 /// If the environment variable is empty or not set, or if it contains only 250 /// invalid directives, a default directive enabling the [`ERROR`] level is 251 /// added. 252 /// 253 /// To set additional configuration options prior to parsing the filter, use 254 /// the [`Builder`] type instead. 255 /// 256 /// This function is equivalent to the following: 257 /// 258 /// ```rust 259 /// use tracing_subscriber::filter::{EnvFilter, LevelFilter}; 260 /// 261 /// # fn docs() -> EnvFilter { 262 /// EnvFilter::builder() 263 /// .with_default_directive(LevelFilter::ERROR.into()) 264 /// .from_env_lossy() 265 /// # } 266 /// ``` 267 /// 268 /// [`ERROR`]: tracing::Level::ERROR from_default_env() -> Self269 pub fn from_default_env() -> Self { 270 Self::builder() 271 .with_default_directive(LevelFilter::ERROR.into()) 272 .from_env_lossy() 273 } 274 275 /// Returns a new `EnvFilter` from the value of the given environment 276 /// variable, ignoring any invalid filter directives. 277 /// 278 /// If the environment variable is empty or not set, or if it contains only 279 /// invalid directives, a default directive enabling the [`ERROR`] level is 280 /// added. 281 /// 282 /// To set additional configuration options prior to parsing the filter, use 283 /// the [`Builder`] type instead. 284 /// 285 /// This function is equivalent to the following: 286 /// 287 /// ```rust 288 /// use tracing_subscriber::filter::{EnvFilter, LevelFilter}; 289 /// 290 /// # fn docs() -> EnvFilter { 291 /// # let env = ""; 292 /// EnvFilter::builder() 293 /// .with_default_directive(LevelFilter::ERROR.into()) 294 /// .with_env_var(env) 295 /// .from_env_lossy() 296 /// # } 297 /// ``` 298 /// 299 /// [`ERROR`]: tracing::Level::ERROR from_env<A: AsRef<str>>(env: A) -> Self300 pub fn from_env<A: AsRef<str>>(env: A) -> Self { 301 Self::builder() 302 .with_default_directive(LevelFilter::ERROR.into()) 303 .with_env_var(env.as_ref()) 304 .from_env_lossy() 305 } 306 307 /// Returns a new `EnvFilter` from the directives in the given string, 308 /// ignoring any that are invalid. 309 /// 310 /// If the string is empty or contains only invalid directives, a default 311 /// directive enabling the [`ERROR`] level is added. 312 /// 313 /// To set additional configuration options prior to parsing the filter, use 314 /// the [`Builder`] type instead. 315 /// 316 /// This function is equivalent to the following: 317 /// 318 /// ```rust 319 /// use tracing_subscriber::filter::{EnvFilter, LevelFilter}; 320 /// 321 /// # fn docs() -> EnvFilter { 322 /// # let directives = ""; 323 /// EnvFilter::builder() 324 /// .with_default_directive(LevelFilter::ERROR.into()) 325 /// .parse_lossy(directives) 326 /// # } 327 /// ``` 328 /// 329 /// [`ERROR`]: tracing::Level::ERROR new<S: AsRef<str>>(directives: S) -> Self330 pub fn new<S: AsRef<str>>(directives: S) -> Self { 331 Self::builder() 332 .with_default_directive(LevelFilter::ERROR.into()) 333 .parse_lossy(directives) 334 } 335 336 /// Returns a new `EnvFilter` from the directives in the given string, 337 /// or an error if any are invalid. 338 /// 339 /// If the string is empty, a default directive enabling the [`ERROR`] level 340 /// is added. 341 /// 342 /// To set additional configuration options prior to parsing the filter, use 343 /// the [`Builder`] type instead. 344 /// 345 /// This function is equivalent to the following: 346 /// 347 /// ```rust 348 /// use tracing_subscriber::filter::{EnvFilter, LevelFilter}; 349 /// 350 /// # fn docs() -> Result<EnvFilter, tracing_subscriber::filter::ParseError> { 351 /// # let directives = ""; 352 /// EnvFilter::builder() 353 /// .with_default_directive(LevelFilter::ERROR.into()) 354 /// .parse(directives) 355 /// # } 356 /// ``` 357 /// 358 /// [`ERROR`]: tracing::Level::ERROR try_new<S: AsRef<str>>(dirs: S) -> Result<Self, directive::ParseError>359 pub fn try_new<S: AsRef<str>>(dirs: S) -> Result<Self, directive::ParseError> { 360 Self::builder().parse(dirs) 361 } 362 363 /// Returns a new `EnvFilter` from the value of the `RUST_LOG` environment 364 /// variable, or an error if the environment variable is unset or contains 365 /// any invalid filter directives. 366 /// 367 /// To set additional configuration options prior to parsing the filter, use 368 /// the [`Builder`] type instead. 369 /// 370 /// This function is equivalent to the following: 371 /// 372 /// ```rust 373 /// use tracing_subscriber::EnvFilter; 374 /// 375 /// # fn docs() -> Result<EnvFilter, tracing_subscriber::filter::FromEnvError> { 376 /// EnvFilter::builder().try_from_env() 377 /// # } 378 /// ``` try_from_default_env() -> Result<Self, FromEnvError>379 pub fn try_from_default_env() -> Result<Self, FromEnvError> { 380 Self::builder().try_from_env() 381 } 382 383 /// Returns a new `EnvFilter` from the value of the given environment 384 /// variable, or an error if the environment variable is unset or contains 385 /// any invalid filter directives. 386 /// 387 /// To set additional configuration options prior to parsing the filter, use 388 /// the [`Builder`] type instead. 389 /// 390 /// This function is equivalent to the following: 391 /// 392 /// ```rust 393 /// use tracing_subscriber::EnvFilter; 394 /// 395 /// # fn docs() -> Result<EnvFilter, tracing_subscriber::filter::FromEnvError> { 396 /// # let env = ""; 397 /// EnvFilter::builder().with_env_var(env).try_from_env() 398 /// # } 399 /// ``` try_from_env<A: AsRef<str>>(env: A) -> Result<Self, FromEnvError>400 pub fn try_from_env<A: AsRef<str>>(env: A) -> Result<Self, FromEnvError> { 401 Self::builder().with_env_var(env.as_ref()).try_from_env() 402 } 403 404 /// Add a filtering directive to this `EnvFilter`. 405 /// 406 /// The added directive will be used in addition to any previously set 407 /// directives, either added using this method or provided when the filter 408 /// is constructed. 409 /// 410 /// Filters may be created from [`LevelFilter`] or [`Level`], which will 411 /// enable all traces at or below a certain verbosity level, or 412 /// parsed from a string specifying a directive. 413 /// 414 /// If a filter directive is inserted that matches exactly the same spans 415 /// and events as a previous filter, but sets a different level for those 416 /// spans and events, the previous directive is overwritten. 417 /// 418 /// [`LevelFilter`]: super::LevelFilter 419 /// [`Level`]: tracing_core::Level 420 /// 421 /// # Examples 422 /// 423 /// From [`LevelFilter`]: 424 /// 425 /// ```rust 426 /// use tracing_subscriber::filter::{EnvFilter, LevelFilter}; 427 /// let mut filter = EnvFilter::from_default_env() 428 /// .add_directive(LevelFilter::INFO.into()); 429 /// ``` 430 /// 431 /// Or from [`Level`]: 432 /// 433 /// ```rust 434 /// # use tracing_subscriber::filter::{EnvFilter, LevelFilter}; 435 /// # use tracing::Level; 436 /// let mut filter = EnvFilter::from_default_env() 437 /// .add_directive(Level::INFO.into()); 438 /// ``` 439 /// 440 /// Parsed from a string: 441 /// 442 /// ```rust 443 /// use tracing_subscriber::filter::{EnvFilter, Directive}; 444 /// 445 /// # fn try_mk_filter() -> Result<(), Box<dyn ::std::error::Error>> { 446 /// let mut filter = EnvFilter::try_from_default_env()? 447 /// .add_directive("my_crate::module=trace".parse()?) 448 /// .add_directive("my_crate::my_other_module::something=info".parse()?); 449 /// # Ok(()) 450 /// # } 451 /// ``` 452 /// In the above example, substitute `my_crate`, `module`, etc. with the 453 /// name your target crate/module is imported with. This might be 454 /// different from the package name in Cargo.toml (`-` is replaced by `_`). 455 /// Example, if the package name in your Cargo.toml is `MY-FANCY-LIB`, then 456 /// the corresponding Rust identifier would be `MY_FANCY_LIB`: add_directive(mut self, mut directive: Directive) -> Self457 pub fn add_directive(mut self, mut directive: Directive) -> Self { 458 if !self.regex { 459 directive.deregexify(); 460 } 461 if let Some(stat) = directive.to_static() { 462 self.statics.add(stat) 463 } else { 464 self.has_dynamics = true; 465 self.dynamics.add(directive); 466 } 467 self 468 } 469 470 // === filtering methods === 471 472 /// Returns `true` if this `EnvFilter` would enable the provided `metadata` 473 /// in the current context. 474 /// 475 /// This is equivalent to calling the [`Layer::enabled`] or 476 /// [`Filter::enabled`] methods on `EnvFilter`'s implementations of those 477 /// traits, but it does not require the trait to be in scope. enabled<S>(&self, metadata: &Metadata<'_>, _: Context<'_, S>) -> bool478 pub fn enabled<S>(&self, metadata: &Metadata<'_>, _: Context<'_, S>) -> bool { 479 let level = metadata.level(); 480 481 // is it possible for a dynamic filter directive to enable this event? 482 // if not, we can avoid the thread loca'l access + iterating over the 483 // spans in the current scope. 484 if self.has_dynamics && self.dynamics.max_level >= *level { 485 if metadata.is_span() { 486 // If the metadata is a span, see if we care about its callsite. 487 let enabled_by_cs = self 488 .by_cs 489 .read() 490 .ok() 491 .map(|by_cs| by_cs.contains_key(&metadata.callsite())) 492 .unwrap_or(false); 493 if enabled_by_cs { 494 return true; 495 } 496 } 497 498 let enabled_by_scope = { 499 let scope = self.scope.get_or_default().borrow(); 500 for filter in &*scope { 501 if filter >= level { 502 return true; 503 } 504 } 505 false 506 }; 507 if enabled_by_scope { 508 return true; 509 } 510 } 511 512 // is it possible for a static filter directive to enable this event? 513 if self.statics.max_level >= *level { 514 // Otherwise, fall back to checking if the callsite is 515 // statically enabled. 516 return self.statics.enabled(metadata); 517 } 518 519 false 520 } 521 522 /// Returns an optional hint of the highest [verbosity level][level] that 523 /// this `EnvFilter` will enable. 524 /// 525 /// This is equivalent to calling the [`Layer::max_level_hint`] or 526 /// [`Filter::max_level_hint`] methods on `EnvFilter`'s implementations of those 527 /// traits, but it does not require the trait to be in scope. 528 /// 529 /// [level]: tracing_core::metadata::Level max_level_hint(&self) -> Option<LevelFilter>530 pub fn max_level_hint(&self) -> Option<LevelFilter> { 531 if self.dynamics.has_value_filters() { 532 // If we perform any filtering on span field *values*, we will 533 // enable *all* spans, because their field values are not known 534 // until recording. 535 return Some(LevelFilter::TRACE); 536 } 537 std::cmp::max( 538 self.statics.max_level.into(), 539 self.dynamics.max_level.into(), 540 ) 541 } 542 543 /// Informs the filter that a new span was created. 544 /// 545 /// This is equivalent to calling the [`Layer::on_new_span`] or 546 /// [`Filter::on_new_span`] methods on `EnvFilter`'s implementations of those 547 /// traits, but it does not require the trait to be in scope. on_new_span<S>(&self, attrs: &span::Attributes<'_>, id: &span::Id, _: Context<'_, S>)548 pub fn on_new_span<S>(&self, attrs: &span::Attributes<'_>, id: &span::Id, _: Context<'_, S>) { 549 let by_cs = try_lock!(self.by_cs.read()); 550 if let Some(cs) = by_cs.get(&attrs.metadata().callsite()) { 551 let span = cs.to_span_match(attrs); 552 try_lock!(self.by_id.write()).insert(id.clone(), span); 553 } 554 } 555 556 /// Informs the filter that the span with the provided `id` was entered. 557 /// 558 /// This is equivalent to calling the [`Layer::on_enter`] or 559 /// [`Filter::on_enter`] methods on `EnvFilter`'s implementations of those 560 /// traits, but it does not require the trait to be in scope. on_enter<S>(&self, id: &span::Id, _: Context<'_, S>)561 pub fn on_enter<S>(&self, id: &span::Id, _: Context<'_, S>) { 562 // XXX: This is where _we_ could push IDs to the stack instead, and use 563 // that to allow changing the filter while a span is already entered. 564 // But that might be much less efficient... 565 if let Some(span) = try_lock!(self.by_id.read()).get(id) { 566 self.scope.get_or_default().borrow_mut().push(span.level()); 567 } 568 } 569 570 /// Informs the filter that the span with the provided `id` was exited. 571 /// 572 /// This is equivalent to calling the [`Layer::on_exit`] or 573 /// [`Filter::on_exit`] methods on `EnvFilter`'s implementations of those 574 /// traits, but it does not require the trait to be in scope. on_exit<S>(&self, id: &span::Id, _: Context<'_, S>)575 pub fn on_exit<S>(&self, id: &span::Id, _: Context<'_, S>) { 576 if self.cares_about_span(id) { 577 self.scope.get_or_default().borrow_mut().pop(); 578 } 579 } 580 581 /// Informs the filter that the span with the provided `id` was closed. 582 /// 583 /// This is equivalent to calling the [`Layer::on_close`] or 584 /// [`Filter::on_close`] methods on `EnvFilter`'s implementations of those 585 /// traits, but it does not require the trait to be in scope. on_close<S>(&self, id: span::Id, _: Context<'_, S>)586 pub fn on_close<S>(&self, id: span::Id, _: Context<'_, S>) { 587 // If we don't need to acquire a write lock, avoid doing so. 588 if !self.cares_about_span(&id) { 589 return; 590 } 591 592 let mut spans = try_lock!(self.by_id.write()); 593 spans.remove(&id); 594 } 595 596 /// Informs the filter that the span with the provided `id` recorded the 597 /// provided field `values`. 598 /// 599 /// This is equivalent to calling the [`Layer::on_record`] or 600 /// [`Filter::on_record`] methods on `EnvFilter`'s implementations of those 601 /// traits, but it does not require the trait to be in scope on_record<S>(&self, id: &span::Id, values: &span::Record<'_>, _: Context<'_, S>)602 pub fn on_record<S>(&self, id: &span::Id, values: &span::Record<'_>, _: Context<'_, S>) { 603 if let Some(span) = try_lock!(self.by_id.read()).get(id) { 604 span.record_update(values); 605 } 606 } 607 cares_about_span(&self, span: &span::Id) -> bool608 fn cares_about_span(&self, span: &span::Id) -> bool { 609 let spans = try_lock!(self.by_id.read(), else return false); 610 spans.contains_key(span) 611 } 612 base_interest(&self) -> Interest613 fn base_interest(&self) -> Interest { 614 if self.has_dynamics { 615 Interest::sometimes() 616 } else { 617 Interest::never() 618 } 619 } 620 register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest621 fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest { 622 if self.has_dynamics && metadata.is_span() { 623 // If this metadata describes a span, first, check if there is a 624 // dynamic filter that should be constructed for it. If so, it 625 // should always be enabled, since it influences filtering. 626 if let Some(matcher) = self.dynamics.matcher(metadata) { 627 let mut by_cs = try_lock!(self.by_cs.write(), else return self.base_interest()); 628 by_cs.insert(metadata.callsite(), matcher); 629 return Interest::always(); 630 } 631 } 632 633 // Otherwise, check if any of our static filters enable this metadata. 634 if self.statics.enabled(metadata) { 635 Interest::always() 636 } else { 637 self.base_interest() 638 } 639 } 640 } 641 642 impl<S: Subscriber> Layer<S> for EnvFilter { 643 #[inline] register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest644 fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest { 645 EnvFilter::register_callsite(self, metadata) 646 } 647 648 #[inline] max_level_hint(&self) -> Option<LevelFilter>649 fn max_level_hint(&self) -> Option<LevelFilter> { 650 EnvFilter::max_level_hint(self) 651 } 652 653 #[inline] enabled(&self, metadata: &Metadata<'_>, ctx: Context<'_, S>) -> bool654 fn enabled(&self, metadata: &Metadata<'_>, ctx: Context<'_, S>) -> bool { 655 self.enabled(metadata, ctx) 656 } 657 658 #[inline] on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>)659 fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) { 660 self.on_new_span(attrs, id, ctx) 661 } 662 663 #[inline] on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>)664 fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) { 665 self.on_record(id, values, ctx); 666 } 667 668 #[inline] on_enter(&self, id: &span::Id, ctx: Context<'_, S>)669 fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) { 670 self.on_enter(id, ctx); 671 } 672 673 #[inline] on_exit(&self, id: &span::Id, ctx: Context<'_, S>)674 fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) { 675 self.on_exit(id, ctx); 676 } 677 678 #[inline] on_close(&self, id: span::Id, ctx: Context<'_, S>)679 fn on_close(&self, id: span::Id, ctx: Context<'_, S>) { 680 self.on_close(id, ctx); 681 } 682 } 683 684 feature! { 685 #![all(feature = "registry", feature = "std")] 686 use crate::layer::Filter; 687 688 impl<S> Filter<S> for EnvFilter { 689 #[inline] 690 fn enabled(&self, meta: &Metadata<'_>, ctx: &Context<'_, S>) -> bool { 691 self.enabled(meta, ctx.clone()) 692 } 693 694 #[inline] 695 fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest { 696 self.register_callsite(meta) 697 } 698 699 #[inline] 700 fn max_level_hint(&self) -> Option<LevelFilter> { 701 EnvFilter::max_level_hint(self) 702 } 703 704 #[inline] 705 fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) { 706 self.on_new_span(attrs, id, ctx) 707 } 708 709 #[inline] 710 fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) { 711 self.on_record(id, values, ctx); 712 } 713 714 #[inline] 715 fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) { 716 self.on_enter(id, ctx); 717 } 718 719 #[inline] 720 fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) { 721 self.on_exit(id, ctx); 722 } 723 724 #[inline] 725 fn on_close(&self, id: span::Id, ctx: Context<'_, S>) { 726 self.on_close(id, ctx); 727 } 728 } 729 } 730 731 impl FromStr for EnvFilter { 732 type Err = directive::ParseError; 733 from_str(spec: &str) -> Result<Self, Self::Err>734 fn from_str(spec: &str) -> Result<Self, Self::Err> { 735 Self::try_new(spec) 736 } 737 } 738 739 impl<S> From<S> for EnvFilter 740 where 741 S: AsRef<str>, 742 { from(s: S) -> Self743 fn from(s: S) -> Self { 744 Self::new(s) 745 } 746 } 747 748 impl Default for EnvFilter { default() -> Self749 fn default() -> Self { 750 Builder::default().from_directives(std::iter::empty()) 751 } 752 } 753 754 impl fmt::Display for EnvFilter { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result755 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 756 let mut statics = self.statics.iter(); 757 let wrote_statics = if let Some(next) = statics.next() { 758 fmt::Display::fmt(next, f)?; 759 for directive in statics { 760 write!(f, ",{}", directive)?; 761 } 762 true 763 } else { 764 false 765 }; 766 767 let mut dynamics = self.dynamics.iter(); 768 if let Some(next) = dynamics.next() { 769 if wrote_statics { 770 f.write_str(",")?; 771 } 772 fmt::Display::fmt(next, f)?; 773 for directive in dynamics { 774 write!(f, ",{}", directive)?; 775 } 776 } 777 Ok(()) 778 } 779 } 780 781 // ===== impl FromEnvError ===== 782 783 impl From<directive::ParseError> for FromEnvError { from(p: directive::ParseError) -> Self784 fn from(p: directive::ParseError) -> Self { 785 Self { 786 kind: ErrorKind::Parse(p), 787 } 788 } 789 } 790 791 impl From<env::VarError> for FromEnvError { from(v: env::VarError) -> Self792 fn from(v: env::VarError) -> Self { 793 Self { 794 kind: ErrorKind::Env(v), 795 } 796 } 797 } 798 799 impl fmt::Display for FromEnvError { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result800 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 801 match self.kind { 802 ErrorKind::Parse(ref p) => p.fmt(f), 803 ErrorKind::Env(ref e) => e.fmt(f), 804 } 805 } 806 } 807 808 impl Error for FromEnvError { source(&self) -> Option<&(dyn Error + 'static)>809 fn source(&self) -> Option<&(dyn Error + 'static)> { 810 match self.kind { 811 ErrorKind::Parse(ref p) => Some(p), 812 ErrorKind::Env(ref e) => Some(e), 813 } 814 } 815 } 816 817 #[cfg(test)] 818 mod tests { 819 use super::*; 820 use tracing_core::field::FieldSet; 821 use tracing_core::*; 822 823 struct NoSubscriber; 824 impl Subscriber for NoSubscriber { 825 #[inline] register_callsite(&self, _: &'static Metadata<'static>) -> subscriber::Interest826 fn register_callsite(&self, _: &'static Metadata<'static>) -> subscriber::Interest { 827 subscriber::Interest::always() 828 } new_span(&self, _: &span::Attributes<'_>) -> span::Id829 fn new_span(&self, _: &span::Attributes<'_>) -> span::Id { 830 span::Id::from_u64(0xDEAD) 831 } event(&self, _event: &Event<'_>)832 fn event(&self, _event: &Event<'_>) {} record(&self, _span: &span::Id, _values: &span::Record<'_>)833 fn record(&self, _span: &span::Id, _values: &span::Record<'_>) {} record_follows_from(&self, _span: &span::Id, _follows: &span::Id)834 fn record_follows_from(&self, _span: &span::Id, _follows: &span::Id) {} 835 836 #[inline] enabled(&self, _metadata: &Metadata<'_>) -> bool837 fn enabled(&self, _metadata: &Metadata<'_>) -> bool { 838 true 839 } enter(&self, _span: &span::Id)840 fn enter(&self, _span: &span::Id) {} exit(&self, _span: &span::Id)841 fn exit(&self, _span: &span::Id) {} 842 } 843 844 struct Cs; 845 impl Callsite for Cs { set_interest(&self, _interest: Interest)846 fn set_interest(&self, _interest: Interest) {} metadata(&self) -> &Metadata<'_>847 fn metadata(&self) -> &Metadata<'_> { 848 unimplemented!() 849 } 850 } 851 852 #[test] callsite_enabled_no_span_directive()853 fn callsite_enabled_no_span_directive() { 854 let filter = EnvFilter::new("app=debug").with_subscriber(NoSubscriber); 855 static META: &Metadata<'static> = &Metadata::new( 856 "mySpan", 857 "app", 858 Level::TRACE, 859 None, 860 None, 861 None, 862 FieldSet::new(&[], identify_callsite!(&Cs)), 863 Kind::SPAN, 864 ); 865 866 let interest = filter.register_callsite(META); 867 assert!(interest.is_never()); 868 } 869 870 #[test] callsite_off()871 fn callsite_off() { 872 let filter = EnvFilter::new("app=off").with_subscriber(NoSubscriber); 873 static META: &Metadata<'static> = &Metadata::new( 874 "mySpan", 875 "app", 876 Level::ERROR, 877 None, 878 None, 879 None, 880 FieldSet::new(&[], identify_callsite!(&Cs)), 881 Kind::SPAN, 882 ); 883 884 let interest = filter.register_callsite(META); 885 assert!(interest.is_never()); 886 } 887 888 #[test] callsite_enabled_includes_span_directive()889 fn callsite_enabled_includes_span_directive() { 890 let filter = EnvFilter::new("app[mySpan]=debug").with_subscriber(NoSubscriber); 891 static META: &Metadata<'static> = &Metadata::new( 892 "mySpan", 893 "app", 894 Level::TRACE, 895 None, 896 None, 897 None, 898 FieldSet::new(&[], identify_callsite!(&Cs)), 899 Kind::SPAN, 900 ); 901 902 let interest = filter.register_callsite(META); 903 assert!(interest.is_always()); 904 } 905 906 #[test] callsite_enabled_includes_span_directive_field()907 fn callsite_enabled_includes_span_directive_field() { 908 let filter = 909 EnvFilter::new("app[mySpan{field=\"value\"}]=debug").with_subscriber(NoSubscriber); 910 static META: &Metadata<'static> = &Metadata::new( 911 "mySpan", 912 "app", 913 Level::TRACE, 914 None, 915 None, 916 None, 917 FieldSet::new(&["field"], identify_callsite!(&Cs)), 918 Kind::SPAN, 919 ); 920 921 let interest = filter.register_callsite(META); 922 assert!(interest.is_always()); 923 } 924 925 #[test] callsite_enabled_includes_span_directive_multiple_fields()926 fn callsite_enabled_includes_span_directive_multiple_fields() { 927 let filter = EnvFilter::new("app[mySpan{field=\"value\",field2=2}]=debug") 928 .with_subscriber(NoSubscriber); 929 static META: &Metadata<'static> = &Metadata::new( 930 "mySpan", 931 "app", 932 Level::TRACE, 933 None, 934 None, 935 None, 936 FieldSet::new(&["field"], identify_callsite!(&Cs)), 937 Kind::SPAN, 938 ); 939 940 let interest = filter.register_callsite(META); 941 assert!(interest.is_never()); 942 } 943 944 #[test] roundtrip()945 fn roundtrip() { 946 let f1: EnvFilter = 947 "[span1{foo=1}]=error,[span2{bar=2 baz=false}],crate2[{quux=\"quuux\"}]=debug" 948 .parse() 949 .unwrap(); 950 let f2: EnvFilter = format!("{}", f1).parse().unwrap(); 951 assert_eq!(f1.statics, f2.statics); 952 assert_eq!(f1.dynamics, f2.dynamics); 953 } 954 955 #[test] size_of_filters()956 fn size_of_filters() { 957 fn print_sz(s: &str) { 958 let filter = s.parse::<EnvFilter>().expect("filter should parse"); 959 println!( 960 "size_of_val({:?})\n -> {}B", 961 s, 962 std::mem::size_of_val(&filter) 963 ); 964 } 965 966 print_sz("info"); 967 968 print_sz("foo=debug"); 969 970 print_sz( 971 "crate1::mod1=error,crate1::mod2=warn,crate1::mod2::mod3=info,\ 972 crate2=debug,crate3=trace,crate3::mod2::mod1=off", 973 ); 974 975 print_sz("[span1{foo=1}]=error,[span2{bar=2 baz=false}],crate2[{quux=\"quuux\"}]=debug"); 976 977 print_sz( 978 "crate1::mod1=error,crate1::mod2=warn,crate1::mod2::mod3=info,\ 979 crate2=debug,crate3=trace,crate3::mod2::mod1=off,[span1{foo=1}]=error,\ 980 [span2{bar=2 baz=false}],crate2[{quux=\"quuux\"}]=debug", 981 ); 982 } 983 984 #[test] parse_empty_string()985 fn parse_empty_string() { 986 // There is no corresponding test for [`Builder::parse_lossy`] as failed 987 // parsing does not produce any observable side effects. If this test fails 988 // check that [`Builder::parse_lossy`] is behaving correctly as well. 989 assert!(EnvFilter::builder().parse("").is_ok()); 990 } 991 } 992