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}