🛈 Note: This is pre-release documentation for the upcoming tracing 0.2.0 ecosystem.

For the release documentation, please see docs.rs, instead.

tracing_subscriber/filter/env/
mod.rs

1//! A `Subscriber` 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    subscribe::{Context, Subscribe},
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    collect::{Collect, Interest},
23    field::Field,
24    span, Metadata,
25};
26
27/// A [`Subscriber`] which filters spans and events based on a set of filter
28/// directives.
29///
30/// `EnvFilter` implements both the [`Subscribe`](#impl-Subscribe<C>) and
31/// [`Filter`] traits, so it may be used for both [global filtering][global] and
32/// [per-subscriber filtering][psf], respectively. See [the documentation on
33/// filtering with `Subscriber`s][filtering]  for details.
34///
35/// The [`Targets`] type implements a similar form of filtering, but without the
36/// ability to dynamically enable events based on the current span context, and
37/// without filtering on field values. When these features are not required,
38/// [`Targets`] provides a lighter-weight alternative to [`EnvFilter`].
39///
40/// # Directives
41///
42/// A filter consists of one or more comma-separated directives which match on [`Span`]s and [`Event`]s.
43/// Each directive may have a corresponding maximum verbosity [`level`] which
44/// enables (e.g., _selects for_) spans and events that match. Like `log`,
45/// `tracing` considers less exclusive levels (like `trace` or `info`) to be more
46/// verbose than more exclusive levels (like `error` or `warn`).
47///
48/// The directive syntax is similar to that of [`env_logger`]'s. At a high level, the syntax for directives
49/// consists of several parts:
50///
51/// ```text
52/// target[span{field=value}]=level
53/// ```
54///
55/// Each component (`target`, `span`, `field`, `value`, and `level`) will be covered in turn.
56///
57/// - `target` matches the event or span's target. In general, this is the module path and/or crate name.
58///   Examples of targets `h2`, `tokio::net`, or `tide::server`. For more information on targets,
59///   please refer to [`Metadata`]'s documentation.
60/// - `span` matches on the span's name. If a `span` directive is provided alongside a `target`,
61///   the `span` directive will match on spans _within_ the `target`.
62/// - `field` matches on [fields] within spans. Field names can also be supplied without a `value`
63///   and will match on any [`Span`] or [`Event`] that has a field with that name.
64///   For example: `[span{field=\"value\"}]=debug`, `[{field}]=trace`.
65/// - `value` matches on the value of a span's field. If a value is a numeric literal or a bool,
66///   it will match _only_ on that value. Otherwise, this filter matches the
67///   [`std::fmt::Debug`] output from the value.
68/// - `level` sets a maximum verbosity level accepted by this directive.
69///
70/// When a field value directive (`[{<FIELD NAME>=<FIELD_VALUE>}]=...`) matches a
71/// value's [`std::fmt::Debug`] output (i.e., the field value in the directive
72/// is not a `bool`, `i64`, `u64`, or `f64` literal), the matched pattern may be
73/// interpreted as either a regular expression or as the precise expected
74/// output of the field's [`std::fmt::Debug`] implementation. By default, these
75/// filters are interpreted as regular expressions, but this can be disabled
76/// using the [`Builder::with_regex`] builder method to use precise matching
77/// instead.
78///
79/// When field value filters are interpreted as regular expressions, the
80/// [`regex-automata` crate's regular expression syntax][re-syntax] is
81/// 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::subscriber())
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::subscriber())
142///     .with(EnvFilter::from_env("MYAPP_LOG"))
143///     .init();
144/// ```
145///
146/// Using `EnvFilter` as a [per-subscriber filter][psf] to filter only a single
147/// [subscriber](crate::subscribe::Subscribe):
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 subscriber *only*.
157/// let filtered_subscriber = fmt::subscriber().with_filter(filter);
158///
159/// // Some other subscriber, whose output we don't want to filter.
160/// let unfiltered_subscriber = // ...
161///     # fmt::subscriber();
162///
163/// tracing_subscriber::registry()
164///     .with(filtered_subscriber)
165///     .with(unfiltered_subscriber)
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/// [`Subscriber`]: Subscribe
184/// [`env_logger`]: https://docs.rs/env_logger/0.7.1/env_logger/#enabling-logging
185/// [`Span`]: tracing_core::span
186/// [fields]: tracing_core::Field
187/// [`Event`]: tracing_core::Event
188/// [`level`]: tracing_core::Level
189/// [`Metadata`]: tracing_core::Metadata
190/// [`Targets`]: crate::filter::Targets
191/// [`Filter`]: #impl-Filter<C>
192/// [global]: crate::subscribe#global-filtering
193/// [psf]: crate::subscribe#per-subscriber-filtering
194/// [filtering]: crate::subscribe#filtering-with-subscribers
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
207type 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)]
213pub struct FromEnvError {
214    kind: ErrorKind,
215}
216
217#[derive(Debug)]
218enum ErrorKind {
219    Parse(ParseError),
220    Env(env::VarError),
221}
222
223impl EnvFilter {
224    /// `RUST_LOG` is the default environment variable used by
225    /// [`EnvFilter::from_default_env`] and [`EnvFilter::try_from_default_env`].
226    ///
227    pub const DEFAULT_ENV: &'static str = "RUST_LOG";
228
229    // === constructors, etc ===
230
231    /// Returns a [builder] that can be used to configure a new [`EnvFilter`]
232    /// instance.
233    ///
234    /// The [`Builder`] type is used to set additional configurations, such as
235    /// [whether regular expressions are enabled](Builder::with_regex) or [the
236    /// default directive](Builder::with_default_directive) before parsing an
237    /// [`EnvFilter`] from a string or environment variable.
238    ///
239    /// [builder]: https://rust-unofficial.github.io/patterns/patterns/creational/builder.html
240    pub fn builder() -> Builder {
241        Builder::default()
242    }
243
244    /// Returns a new `EnvFilter` from the value of the `RUST_LOG` environment
245    /// variable, ignoring any invalid filter directives.
246    ///
247    /// If the environment variable is empty or not set, or if it contains only
248    /// invalid directives, a default directive enabling the [`ERROR`] level is
249    /// added.
250    ///
251    /// To set additional configuration options prior to parsing the filter, use
252    /// the [`Builder`] type instead.
253    ///
254    /// This function is equivalent to the following:
255    ///
256    /// ```rust
257    /// use tracing_subscriber::filter::{EnvFilter, LevelFilter};
258    ///
259    /// # fn docs() -> EnvFilter {
260    /// EnvFilter::builder()
261    ///     .with_default_directive(LevelFilter::ERROR.into())
262    ///     .from_env_lossy()
263    /// # }
264    /// ```
265    ///
266    /// [`ERROR`]: tracing::Level::ERROR
267    pub fn from_default_env() -> Self {
268        Self::builder()
269            .with_default_directive(LevelFilter::ERROR.into())
270            .from_env_lossy()
271    }
272
273    /// Returns a new `EnvFilter` from the value of the given environment
274    /// variable, ignoring any invalid filter directives.
275    ///
276    /// If the environment variable is empty or not set, or if it contains only
277    /// invalid directives, a default directive enabling the [`ERROR`] level is
278    /// added.
279    ///
280    /// To set additional configuration options prior to parsing the filter, use
281    /// the [`Builder`] type instead.
282    ///
283    /// This function is equivalent to the following:
284    ///
285    /// ```rust
286    /// use tracing_subscriber::filter::{EnvFilter, LevelFilter};
287    ///
288    /// # fn docs() -> EnvFilter {
289    /// # let env = "";
290    /// EnvFilter::builder()
291    ///     .with_default_directive(LevelFilter::ERROR.into())
292    ///     .with_env_var(env)
293    ///     .from_env_lossy()
294    /// # }
295    /// ```
296    ///
297    /// [`ERROR`]: tracing::Level::ERROR
298    pub fn from_env<A: AsRef<str>>(env: A) -> Self {
299        Self::builder()
300            .with_default_directive(LevelFilter::ERROR.into())
301            .with_env_var(env.as_ref())
302            .from_env_lossy()
303    }
304
305    /// Returns a new `EnvFilter` from the directives in the given string,
306    /// ignoring any that are invalid.
307    ///
308    /// If the string is empty or contains only invalid directives, a default
309    /// directive enabling the [`ERROR`] level is added.
310    ///
311    /// To set additional configuration options prior to parsing the filter, use
312    /// the [`Builder`] type instead.
313    ///
314    /// This function is equivalent to the following:
315    ///
316    /// ```rust
317    /// use tracing_subscriber::filter::{EnvFilter, LevelFilter};
318    ///
319    /// # fn docs() -> EnvFilter {
320    /// # let directives = "";
321    /// EnvFilter::builder()
322    ///     .with_default_directive(LevelFilter::ERROR.into())
323    ///     .parse_lossy(directives)
324    /// # }
325    /// ```
326    ///
327    /// [`ERROR`]: tracing::Level::ERROR
328    pub fn new<S: AsRef<str>>(directives: S) -> Self {
329        Self::builder()
330            .with_default_directive(LevelFilter::ERROR.into())
331            .parse_lossy(directives)
332    }
333
334    /// Returns a new `EnvFilter` from the directives in the given string,
335    /// or an error if any are invalid.
336    ///
337    /// If the string is empty, a default directive enabling the [`ERROR`] level
338    /// is added.
339    ///
340    /// To set additional configuration options prior to parsing the filter, use
341    /// the [`Builder`] type instead.
342    ///
343    /// This function is equivalent to the following:
344    ///
345    /// ```rust
346    /// use tracing_subscriber::filter::{EnvFilter, LevelFilter};
347    ///
348    /// # fn docs() -> Result<EnvFilter, tracing_subscriber::filter::ParseError> {
349    /// # let directives = "";
350    /// EnvFilter::builder()
351    ///     .with_default_directive(LevelFilter::ERROR.into())
352    ///     .parse(directives)
353    /// # }
354    /// ```
355    ///
356    /// [`ERROR`]: tracing::Level::ERROR
357    pub fn try_new<S: AsRef<str>>(dirs: S) -> Result<Self, directive::ParseError> {
358        Self::builder().parse(dirs)
359    }
360
361    /// Returns a new `EnvFilter` from the value of the `RUST_LOG` environment
362    /// variable, or an error if the environment variable is unset or contains
363    /// any invalid filter directives.
364    ///
365    /// To set additional configuration options prior to parsing the filter, use
366    /// the [`Builder`] type instead.
367    ///
368    /// This function is equivalent to the following:
369    ///
370    /// ```rust
371    /// use tracing_subscriber::EnvFilter;
372    ///
373    /// # fn docs() -> Result<EnvFilter, tracing_subscriber::filter::FromEnvError> {
374    /// EnvFilter::builder().try_from_env()
375    /// # }
376    /// ```
377    pub fn try_from_default_env() -> Result<Self, FromEnvError> {
378        Self::builder().try_from_env()
379    }
380
381    /// Returns a new `EnvFilter` from the value of the given 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    /// # let env = "";
395    /// EnvFilter::builder().with_env_var(env).try_from_env()
396    /// # }
397    /// ```
398    pub fn try_from_env<A: AsRef<str>>(env: A) -> Result<Self, FromEnvError> {
399        Self::builder().with_env_var(env.as_ref()).try_from_env()
400    }
401
402    /// Add a filtering directive to this `EnvFilter`.
403    ///
404    /// The added directive will be used in addition to any previously set
405    /// directives, either added using this method or provided when the filter
406    /// is constructed.
407    ///
408    /// Filters may be created from [`LevelFilter`] or [`Level`], which will
409    /// enable all traces at or below a certain verbosity level, or
410    /// parsed from a string specifying a directive.
411    ///
412    /// If a filter directive is inserted that matches exactly the same spans
413    /// and events as a previous filter, but sets a different level for those
414    /// spans and events, the previous directive is overwritten.
415    ///
416    /// [`Level`]: tracing_core::Level
417    ///
418    /// # Examples
419    ///
420    /// From [`LevelFilter`]:
421    ///
422    /// ```rust
423    /// use tracing_subscriber::filter::{EnvFilter, LevelFilter};
424    /// let mut filter = EnvFilter::from_default_env()
425    ///     .add_directive(LevelFilter::INFO.into());
426    /// ```
427    ///
428    /// Or from [`Level`]:
429    ///
430    /// ```rust
431    /// # use tracing_subscriber::filter::{EnvFilter, LevelFilter};
432    /// # use tracing::Level;
433    /// let mut filter = EnvFilter::from_default_env()
434    ///     .add_directive(Level::INFO.into());
435    /// ```
436    ///
437    /// Parsed from a string:
438    ///
439    /// ```rust
440    /// use tracing_subscriber::filter::{EnvFilter, Directive};
441    ///
442    /// # fn try_mk_filter() -> Result<(), Box<dyn ::std::error::Error>> {
443    /// let mut filter = EnvFilter::try_from_default_env()?
444    ///     .add_directive("my_crate::module=trace".parse()?)
445    ///     .add_directive("my_crate::my_other_module::something=info".parse()?);
446    /// # Ok(())
447    /// # }
448    /// ```
449    /// In the above example, substitute `my_crate`, `module`, etc. with the
450    /// name your target crate/module is imported with. This might be
451    /// different from the package name in Cargo.toml (`-` is replaced by `_`).
452    /// Example, if the package name in your Cargo.toml is `MY-FANCY-LIB`, then
453    /// the corresponding Rust identifier would be `MY_FANCY_LIB`:
454    pub fn add_directive(mut self, mut directive: Directive) -> Self {
455        if !self.regex {
456            directive.deregexify();
457        }
458        if let Some(stat) = directive.to_static() {
459            self.statics.add(stat)
460        } else {
461            self.has_dynamics = true;
462            self.dynamics.add(directive);
463        }
464        self
465    }
466
467    // === filtering methods ===
468
469    /// Returns `true` if this `EnvFilter` would enable the provided `metadata`
470    /// in the current context.
471    ///
472    /// This is equivalent to calling the [`Subscribe::enabled`] or
473    /// [`Filter::enabled`] methods on `EnvFilter`'s implementations of those
474    /// traits, but it does not require the trait to be in scope.
475    pub fn enabled<C>(&self, metadata: &Metadata<'_>, _: Context<'_, C>) -> bool {
476        let level = metadata.level();
477
478        // is it possible for a dynamic filter directive to enable this event?
479        // if not, we can avoid the thread local access + iterating over the
480        // spans in the current scope.
481        if self.has_dynamics && self.dynamics.max_level >= *level {
482            if metadata.is_span() {
483                // If the metadata is a span, see if we care about its callsite.
484                let enabled_by_cs = self
485                    .by_cs
486                    .read()
487                    .ok()
488                    .map(|by_cs| by_cs.contains_key(&metadata.callsite()))
489                    .unwrap_or(false);
490                if enabled_by_cs {
491                    return true;
492                }
493            }
494
495            let enabled_by_scope = {
496                let scope = self.scope.get_or_default().borrow();
497                for filter in &*scope {
498                    if filter >= level {
499                        return true;
500                    }
501                }
502                false
503            };
504            if enabled_by_scope {
505                return true;
506            }
507        }
508
509        // is it possible for a static filter directive to enable this event?
510        if self.statics.max_level >= *level {
511            // Otherwise, fall back to checking if the callsite is
512            // statically enabled.
513            return self.statics.enabled(metadata);
514        }
515
516        false
517    }
518
519    /// Returns an optional hint of the highest [verbosity level][level] that
520    /// this `EnvFilter` will enable.
521    ///
522    /// This is equivalent to calling the [`Subscribe::max_level_hint`] or
523    /// [`Filter::max_level_hint`] methods on `EnvFilter`'s implementations of those
524    /// traits, but it does not require the trait to be in scope.
525    ///
526    /// [level]: tracing_core::metadata::Level
527    pub fn max_level_hint(&self) -> Option<LevelFilter> {
528        if self.dynamics.has_value_filters() {
529            // If we perform any filtering on span field *values*, we will
530            // enable *all* spans, because their field values are not known
531            // until recording.
532            return Some(LevelFilter::TRACE);
533        }
534        std::cmp::max(
535            self.statics.max_level.into(),
536            self.dynamics.max_level.into(),
537        )
538    }
539
540    /// Informs the filter that a new span was created.
541    ///
542    /// This is equivalent to calling the [`Subscribe::on_new_span`] or
543    /// [`Filter::on_new_span`] methods on `EnvFilter`'s implementations of those
544    /// traits, but it does not require the trait to be in scope.
545    pub fn on_new_span<C>(&self, attrs: &span::Attributes<'_>, id: &span::Id, _: Context<'_, C>) {
546        let by_cs = try_lock!(self.by_cs.read());
547        if let Some(cs) = by_cs.get(&attrs.metadata().callsite()) {
548            let span = cs.to_span_match(attrs);
549            try_lock!(self.by_id.write()).insert(id.clone(), span);
550        }
551    }
552
553    /// Informs the filter that the span with the provided `id` was entered.
554    ///
555    /// This is equivalent to calling the [`Subscribe::on_enter`] or
556    /// [`Filter::on_enter`] methods on `EnvFilter`'s implementations of those
557    /// traits, but it does not require the trait to be in scope.
558    pub fn on_enter<C>(&self, id: &span::Id, _: Context<'_, C>) {
559        // XXX: This is where _we_ could push IDs to the stack instead, and use
560        // that to allow changing the filter while a span is already entered.
561        // But that might be much less efficient...
562        if let Some(span) = try_lock!(self.by_id.read()).get(id) {
563            self.scope.get_or_default().borrow_mut().push(span.level());
564        }
565    }
566
567    /// Informs the filter that the span with the provided `id` was exited.
568    ///
569    /// This is equivalent to calling the [`Subscribe::on_exit`] or
570    /// [`Filter::on_exit`] methods on `EnvFilter`'s implementations of those
571    /// traits, but it does not require the trait to be in scope.
572    pub fn on_exit<C>(&self, id: &span::Id, _: Context<'_, C>) {
573        if self.cares_about_span(id) {
574            self.scope.get_or_default().borrow_mut().pop();
575        }
576    }
577
578    /// Informs the filter that the span with the provided `id` was closed.
579    ///
580    /// This is equivalent to calling the [`Subscribe::on_close`] or
581    /// [`Filter::on_close`] methods on `EnvFilter`'s implementations of those
582    /// traits, but it does not require the trait to be in scope.
583    pub fn on_close<C>(&self, id: span::Id, _: Context<'_, C>) {
584        // If we don't need to acquire a write lock, avoid doing so.
585        if !self.cares_about_span(&id) {
586            return;
587        }
588
589        let mut spans = try_lock!(self.by_id.write());
590        spans.remove(&id);
591    }
592
593    /// Informs the filter that the span with the provided `id` recorded the
594    /// provided field `values`.
595    ///
596    /// This is equivalent to calling the [`Subscribe::on_record`] or
597    /// [`Filter::on_record`] methods on `EnvFilter`'s implementations of those
598    /// traits, but it does not require the trait to be in scope
599    pub fn on_record<C>(&self, id: &span::Id, values: &span::Record<'_>, _: Context<'_, C>) {
600        if let Some(span) = try_lock!(self.by_id.read()).get(id) {
601            span.record_update(values);
602        }
603    }
604
605    fn cares_about_span(&self, span: &span::Id) -> bool {
606        let spans = try_lock!(self.by_id.read(), else return false);
607        spans.contains_key(span)
608    }
609
610    fn base_interest(&self) -> Interest {
611        if self.has_dynamics {
612            Interest::sometimes()
613        } else {
614            Interest::never()
615        }
616    }
617
618    fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
619        if self.has_dynamics && metadata.is_span() {
620            // If this metadata describes a span, first, check if there is a
621            // dynamic filter that should be constructed for it. If so, it
622            // should always be enabled, since it influences filtering.
623            if let Some(matcher) = self.dynamics.matcher(metadata) {
624                let mut by_cs = try_lock!(self.by_cs.write(), else return self.base_interest());
625                by_cs.insert(metadata.callsite(), matcher);
626                return Interest::always();
627            }
628        }
629
630        // Otherwise, check if any of our static filters enable this metadata.
631        if self.statics.enabled(metadata) {
632            Interest::always()
633        } else {
634            self.base_interest()
635        }
636    }
637}
638
639impl<C: Collect> Subscribe<C> for EnvFilter {
640    #[inline]
641    fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
642        EnvFilter::register_callsite(self, metadata)
643    }
644
645    #[inline]
646    fn max_level_hint(&self) -> Option<LevelFilter> {
647        EnvFilter::max_level_hint(self)
648    }
649
650    #[inline]
651    fn enabled(&self, metadata: &Metadata<'_>, ctx: Context<'_, C>) -> bool {
652        self.enabled(metadata, ctx)
653    }
654
655    #[inline]
656    fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, C>) {
657        self.on_new_span(attrs, id, ctx)
658    }
659
660    #[inline]
661    fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, C>) {
662        self.on_record(id, values, ctx);
663    }
664
665    #[inline]
666    fn on_enter(&self, id: &span::Id, ctx: Context<'_, C>) {
667        self.on_enter(id, ctx);
668    }
669
670    #[inline]
671    fn on_exit(&self, id: &span::Id, ctx: Context<'_, C>) {
672        self.on_exit(id, ctx);
673    }
674
675    #[inline]
676    fn on_close(&self, id: span::Id, ctx: Context<'_, C>) {
677        self.on_close(id, ctx);
678    }
679}
680
681feature! {
682    #![all(feature = "registry", feature = "std")]
683    use crate::subscribe::Filter;
684
685    impl<C> Filter<C> for EnvFilter {
686        #[inline]
687        fn enabled(&self, meta: &Metadata<'_>, ctx: &Context<'_, C>) -> bool {
688            self.enabled(meta, ctx.clone())
689        }
690
691        #[inline]
692        fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest {
693            self.register_callsite(meta)
694        }
695
696        #[inline]
697        fn max_level_hint(&self) -> Option<LevelFilter> {
698            EnvFilter::max_level_hint(self)
699        }
700
701        #[inline]
702        fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, C>) {
703            self.on_new_span(attrs, id, ctx)
704        }
705
706        #[inline]
707        fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, C>) {
708            self.on_record(id, values, ctx);
709        }
710
711        #[inline]
712        fn on_enter(&self, id: &span::Id, ctx: Context<'_, C>) {
713            self.on_enter(id, ctx);
714        }
715
716        #[inline]
717        fn on_exit(&self, id: &span::Id, ctx: Context<'_, C>) {
718            self.on_exit(id, ctx);
719        }
720
721        #[inline]
722        fn on_close(&self, id: span::Id, ctx: Context<'_, C>) {
723            self.on_close(id, ctx);
724        }
725    }
726}
727
728impl FromStr for EnvFilter {
729    type Err = directive::ParseError;
730
731    fn from_str(spec: &str) -> Result<Self, Self::Err> {
732        Self::try_new(spec)
733    }
734}
735
736impl<S> From<S> for EnvFilter
737where
738    S: AsRef<str>,
739{
740    fn from(s: S) -> Self {
741        Self::new(s)
742    }
743}
744
745impl Default for EnvFilter {
746    fn default() -> Self {
747        Builder::default().from_directives(std::iter::empty())
748    }
749}
750
751impl fmt::Display for EnvFilter {
752    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
753        let mut statics = self.statics.iter();
754        let wrote_statics = if let Some(next) = statics.next() {
755            fmt::Display::fmt(next, f)?;
756            for directive in statics {
757                write!(f, ",{}", directive)?;
758            }
759            true
760        } else {
761            false
762        };
763
764        let mut dynamics = self.dynamics.iter();
765        if let Some(next) = dynamics.next() {
766            if wrote_statics {
767                f.write_str(",")?;
768            }
769            fmt::Display::fmt(next, f)?;
770            for directive in dynamics {
771                write!(f, ",{}", directive)?;
772            }
773        }
774        Ok(())
775    }
776}
777
778// ===== impl FromEnvError =====
779
780impl From<directive::ParseError> for FromEnvError {
781    fn from(p: directive::ParseError) -> Self {
782        Self {
783            kind: ErrorKind::Parse(p),
784        }
785    }
786}
787
788impl From<env::VarError> for FromEnvError {
789    fn from(v: env::VarError) -> Self {
790        Self {
791            kind: ErrorKind::Env(v),
792        }
793    }
794}
795
796impl fmt::Display for FromEnvError {
797    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
798        match self.kind {
799            ErrorKind::Parse(ref p) => p.fmt(f),
800            ErrorKind::Env(ref e) => e.fmt(f),
801        }
802    }
803}
804
805impl Error for FromEnvError {
806    fn source(&self) -> Option<&(dyn Error + 'static)> {
807        match self.kind {
808            ErrorKind::Parse(ref p) => Some(p),
809            ErrorKind::Env(ref e) => Some(e),
810        }
811    }
812}
813
814#[cfg(test)]
815mod tests {
816    use super::*;
817    use tracing_core::field::FieldSet;
818    use tracing_core::*;
819
820    struct NoCollector;
821    impl Collect for NoCollector {
822        #[inline]
823        fn register_callsite(&self, _: &'static Metadata<'static>) -> collect::Interest {
824            collect::Interest::always()
825        }
826        fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
827            span::Id::from_u64(0xDEAD)
828        }
829        fn event(&self, _event: &Event<'_>) {}
830        fn record(&self, _span: &span::Id, _values: &span::Record<'_>) {}
831        fn record_follows_from(&self, _span: &span::Id, _follows: &span::Id) {}
832
833        #[inline]
834        fn enabled(&self, _metadata: &Metadata<'_>) -> bool {
835            true
836        }
837        fn enter(&self, _span: &span::Id) {}
838        fn exit(&self, _span: &span::Id) {}
839        fn current_span(&self) -> span::Current {
840            span::Current::unknown()
841        }
842    }
843
844    struct Cs;
845    impl Callsite for Cs {
846        fn set_interest(&self, _interest: Interest) {}
847        fn metadata(&self) -> &Metadata<'_> {
848            unimplemented!()
849        }
850    }
851
852    #[test]
853    fn callsite_enabled_no_span_directive() {
854        let filter = EnvFilter::new("app=debug").with_collector(NoCollector);
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]
871    fn callsite_off() {
872        let filter = EnvFilter::new("app=off").with_collector(NoCollector);
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]
889    fn callsite_enabled_includes_span_directive() {
890        let filter = EnvFilter::new("app[mySpan]=debug").with_collector(NoCollector);
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]
907    fn callsite_enabled_includes_span_directive_field() {
908        let filter =
909            EnvFilter::new("app[mySpan{field=\"value\"}]=debug").with_collector(NoCollector);
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]
926    fn callsite_enabled_includes_span_directive_multiple_fields() {
927        let filter = EnvFilter::new("app[mySpan{field=\"value\",field2=2}]=debug")
928            .with_collector(NoCollector);
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]
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]
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]
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}