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