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