1 //! A `Layer` that enables or disables spans and events based on a set of
2 //! filtering directives.
3 
4 // these are publicly re-exported, but the compiler doesn't realize
5 // that for some reason.
6 #[allow(unreachable_pub)]
7 pub use self::{
8     directive::{Directive, ParseError},
9     field::BadName as BadFieldName,
10 };
11 mod directive;
12 mod field;
13 
14 use crate::{
15     filter::LevelFilter,
16     layer::{Context, Layer},
17     sync::RwLock,
18 };
19 use std::{cell::RefCell, collections::HashMap, env, error::Error, fmt, str::FromStr};
20 use tracing_core::{
21     callsite,
22     field::Field,
23     span,
24     subscriber::{Interest, Subscriber},
25     Metadata,
26 };
27 
28 /// A [`Layer`] which filters spans and events based on a set of filter
29 /// directives.
30 ///
31 /// # Directives
32 ///
33 /// A filter consists of one or more directives which match on [`Span`]s and [`Event`]s.
34 /// Each directive may have a corresponding maximum verbosity [`level`] which
35 /// enables (e.g., _selects for_) spans and events that match. Like `log`,
36 /// `tracing` considers less exclusive levels (like `trace` or `info`) to be more
37 /// verbose than more exclusive levels (like `error` or `warn`).
38 ///
39 /// The directive syntax is similar to that of [`env_logger`]'s. At a high level, the syntax for directives
40 /// consists of several parts:
41 ///
42 /// ```text
43 /// target[span{field=value}]=level
44 /// ```
45 ///
46 /// Each component (`target`, `span`, `field`, `value`, and `level`) will be covered in turn.
47 ///
48 /// - `target` matches the event or span's target. In general, this is the module path and/or crate name.
49 ///    Examples of targets `h2`, `tokio::net`, or `tide::server`. For more information on targets,
50 ///    please refer to [`Metadata`]'s documentation.
51 /// - `span` matches on the span's name. If a `span` directive is provided alongside a `target`,
52 ///    the `span` directive will match on spans _within_ the `target`.
53 /// - `field` matches on [fields] within spans. Field names can also be supplied without a `value`
54 ///    and will match on any [`Span`] or [`Event`] that has a field with that name.
55 ///    For example: `[span{field=\"value\"}]=debug`, `[{field}]=trace`.
56 /// - `value` matches on the value of a span's field. If a value is a numeric literal or a bool,
57 ///    it will match _only_ on that value. Otherwise, this filter acts as a regex on
58 ///    the `std::fmt::Debug` output from the value.
59 /// - `level` sets a maximum verbosity level accepted by this directive.
60 ///
61 /// ## Usage Notes
62 ///
63 /// - The portion of the directive which is included within the square brackets is `tracing`-specific.
64 /// - Any portion of the directive can be omitted.
65 ///     - The sole exception are the `field` and `value` directives. If a `value` is provided,
66 ///       a `field` must _also_ be provided. However, the converse does not hold, as fields can
67 ///       be matched without a value.
68 /// - If only a level is provided, it will set the maximum level for all `Span`s and `Event`s
69 ///   that are not enabled by other filters.
70 /// - A directive without a level will enable anything that it matches. This is equivalent to `=trace`.
71 /// - When a crate has a dash in its name, the default target for events will be the
72 ///   crate's module path as it appears in Rust. This means every dash will be replaced
73 ///   with an underscore.
74 /// - A dash in a target will only appear when being specified explicitly:
75 ///   `tracing::info!(target: "target-name", ...);`
76 ///
77 /// ## Examples
78 ///
79 /// - `tokio::net=info` will enable all spans or events that:
80 ///    - have the `tokio::net` target,
81 ///    - at the level `info` or above.
82 /// - `my_crate[span_a]=trace` will enable all spans and events that:
83 ///    - are within the `span_a` span or named `span_a` _if_ `span_a` has the target `my_crate`,
84 ///    - at the level `trace` or above.
85 /// - `[span_b{name=\"bob\"}]` will enable all spans or event that:
86 ///    - have _any_ target,
87 ///    - are inside a span named `span_b`,
88 ///    - which has a field named `name` with value `bob`,
89 ///    - at _any_ level.
90 ///
91 /// [`Layer`]: ../layer/trait.Layer.html
92 /// [`env_logger`]: https://docs.rs/env_logger/0.7.1/env_logger/#enabling-logging
93 /// [`Span`]: https://docs.rs/tracing-core/latest/tracing_core/span/index.html
94 /// [fields]: https://docs.rs/tracing-core/latest/tracing_core/struct.Field.html
95 /// [`Event`]: https://docs.rs/tracing-core/latest/tracing_core/struct.Event.html
96 /// [`level`]: https://docs.rs/tracing-core/latest/tracing_core/struct.Level.html
97 /// [`Metadata`]: https://docs.rs/tracing-core/latest/tracing_core/struct.Metadata.html
98 #[cfg(feature = "env-filter")]
99 #[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))]
100 #[derive(Debug)]
101 pub struct EnvFilter {
102     statics: directive::Statics,
103     dynamics: directive::Dynamics,
104     has_dynamics: bool,
105     by_id: RwLock<HashMap<span::Id, directive::SpanMatcher>>,
106     by_cs: RwLock<HashMap<callsite::Identifier, directive::CallsiteMatcher>>,
107 }
108 
109 thread_local! {
110     static SCOPE: RefCell<Vec<LevelFilter>> = RefCell::new(Vec::new());
111 }
112 
113 type FieldMap<T> = HashMap<Field, T>;
114 
115 #[cfg(feature = "smallvec")]
116 type FilterVec<T> = smallvec::SmallVec<[T; 8]>;
117 #[cfg(not(feature = "smallvec"))]
118 type FilterVec<T> = Vec<T>;
119 
120 /// Indicates that an error occurred while parsing a `EnvFilter` from an
121 /// environment variable.
122 #[derive(Debug)]
123 pub struct FromEnvError {
124     kind: ErrorKind,
125 }
126 
127 #[derive(Debug)]
128 enum ErrorKind {
129     Parse(ParseError),
130     Env(env::VarError),
131 }
132 
133 impl EnvFilter {
134     /// `RUST_LOG` is the default environment variable used by
135     /// [`EnvFilter::from_default_env`] and [`EnvFilter::try_from_default_env`].
136     ///
137     /// [`EnvFilter::from_default_env`]: #method.from_default_env
138     /// [`EnvFilter::try_from_default_env`]: #method.try_from_default_env
139     pub const DEFAULT_ENV: &'static str = "RUST_LOG";
140 
141     /// Returns a new `EnvFilter` from the value of the `RUST_LOG` environment
142     /// variable, ignoring any invalid filter directives.
from_default_env() -> Self143     pub fn from_default_env() -> Self {
144         Self::from_env(Self::DEFAULT_ENV)
145     }
146 
147     /// Returns a new `EnvFilter` from the value of the given environment
148     /// variable, ignoring any invalid filter directives.
from_env<A: AsRef<str>>(env: A) -> Self149     pub fn from_env<A: AsRef<str>>(env: A) -> Self {
150         env::var(env.as_ref()).map(Self::new).unwrap_or_default()
151     }
152 
153     /// Returns a new `EnvFilter` from the directives in the given string,
154     /// ignoring any that are invalid.
new<S: AsRef<str>>(dirs: S) -> Self155     pub fn new<S: AsRef<str>>(dirs: S) -> Self {
156         let directives = dirs.as_ref().split(',').filter_map(|s| match s.parse() {
157             Ok(d) => Some(d),
158             Err(err) => {
159                 eprintln!("ignoring `{}`: {}", s, err);
160                 None
161             }
162         });
163         Self::from_directives(directives)
164     }
165 
166     /// Returns a new `EnvFilter` from the directives in the given string,
167     /// or an error if any are invalid.
try_new<S: AsRef<str>>(dirs: S) -> Result<Self, ParseError>168     pub fn try_new<S: AsRef<str>>(dirs: S) -> Result<Self, ParseError> {
169         let directives = dirs
170             .as_ref()
171             .split(',')
172             .map(|s| s.parse())
173             .collect::<Result<Vec<_>, _>>()?;
174         Ok(Self::from_directives(directives))
175     }
176 
177     /// Returns a new `EnvFilter` from the value of the `RUST_LOG` environment
178     /// variable, or an error if the environment variable contains any invalid
179     /// filter directives.
try_from_default_env() -> Result<Self, FromEnvError>180     pub fn try_from_default_env() -> Result<Self, FromEnvError> {
181         Self::try_from_env(Self::DEFAULT_ENV)
182     }
183 
184     /// Returns a new `EnvFilter` from the value of the given environment
185     /// variable, or an error if the environment variable is unset or contains
186     /// any invalid filter directives.
try_from_env<A: AsRef<str>>(env: A) -> Result<Self, FromEnvError>187     pub fn try_from_env<A: AsRef<str>>(env: A) -> Result<Self, FromEnvError> {
188         env::var(env.as_ref())?.parse().map_err(Into::into)
189     }
190 
191     /// Add a filtering directive to this `EnvFilter`.
192     ///
193     /// The added directive will be used in addition to any previously set
194     /// directives, either added using this method or provided when the filter
195     /// is constructed.
196     ///
197     /// Filters may be created from [`LevelFilter`] or [`Level`], which will
198     /// enable all traces at or below a certain verbosity level, or
199     /// parsed from a string specifying a directive.
200     ///
201     /// If a filter directive is inserted that matches exactly the same spans
202     /// and events as a previous filter, but sets a different level for those
203     /// spans and events, the previous directive is overwritten.
204     ///
205     /// [`LevelFilter`]: ../filter/struct.LevelFilter.html
206     /// [`Level`]: https://docs.rs/tracing-core/latest/tracing_core/struct.Level.html
207     ///
208     /// # Examples
209     ///
210     /// From [`LevelFilter`]:
211     ////
212     /// ```rust
213     /// use tracing_subscriber::filter::{EnvFilter, LevelFilter};
214     /// let mut filter = EnvFilter::from_default_env()
215     ///     .add_directive(LevelFilter::INFO.into());
216     /// ```
217     ///
218     /// Or from [`Level`]:
219     ///
220     /// ```rust
221     /// # use tracing_subscriber::filter::{EnvFilter, LevelFilter};
222     /// # use tracing::Level;
223     /// let mut filter = EnvFilter::from_default_env()
224     ///     .add_directive(Level::INFO.into());
225     /// ```
226     ////
227     /// Parsed from a string:
228     ////
229     /// ```rust
230     /// use tracing_subscriber::filter::{EnvFilter, Directive};
231     ///
232     /// # fn try_mk_filter() -> Result<(), Box<dyn ::std::error::Error>> {
233     /// let mut filter = EnvFilter::try_from_default_env()?
234     ///     .add_directive("my_crate::module=trace".parse()?)
235     ///     .add_directive("my_crate::my_other_module::something=info".parse()?);
236     /// # Ok(())
237     /// # }
238     /// ```
add_directive(mut self, directive: Directive) -> Self239     pub fn add_directive(mut self, directive: Directive) -> Self {
240         if let Some(stat) = directive.to_static() {
241             self.statics.add(stat)
242         } else {
243             self.has_dynamics = true;
244             self.dynamics.add(directive);
245         }
246         self
247     }
248 
from_directives(directives: impl IntoIterator<Item = Directive>) -> Self249     fn from_directives(directives: impl IntoIterator<Item = Directive>) -> Self {
250         use tracing::level_filters::STATIC_MAX_LEVEL;
251         use tracing::Level;
252 
253         let directives: Vec<_> = directives.into_iter().collect();
254 
255         let disabled: Vec<_> = directives
256             .iter()
257             .filter(|directive| directive.level > STATIC_MAX_LEVEL)
258             .collect();
259 
260         if !disabled.is_empty() {
261             #[cfg(feature = "ansi_term")]
262             use ansi_term::{Color, Style};
263             // NOTE: We can't use a configured `MakeWriter` because the EnvFilter
264             // has no knowledge of any underlying subscriber or collector, which
265             // may or may not use a `MakeWriter`.
266             let warn = |msg: &str| {
267                 #[cfg(not(feature = "ansi_term"))]
268                 let msg = format!("warning: {}", msg);
269                 #[cfg(feature = "ansi_term")]
270                 let msg = {
271                     let bold = Style::new().bold();
272                     let mut warning = Color::Yellow.paint("warning");
273                     warning.style_ref_mut().is_bold = true;
274                     format!("{}{} {}", warning, bold.clone().paint(":"), bold.paint(msg))
275                 };
276                 eprintln!("{}", msg);
277             };
278             let ctx_prefixed = |prefix: &str, msg: &str| {
279                 #[cfg(not(feature = "ansi_term"))]
280                 let msg = format!("note: {}", msg);
281                 #[cfg(feature = "ansi_term")]
282                 let msg = {
283                     let mut equal = Color::Fixed(21).paint("="); // dark blue
284                     equal.style_ref_mut().is_bold = true;
285                     format!(" {} {} {}", equal, Style::new().bold().paint(prefix), msg)
286                 };
287                 eprintln!("{}", msg);
288             };
289             let ctx_help = |msg| ctx_prefixed("help:", msg);
290             let ctx_note = |msg| ctx_prefixed("note:", msg);
291             let ctx = |msg: &str| {
292                 #[cfg(not(feature = "ansi_term"))]
293                 let msg = format!("note: {}", msg);
294                 #[cfg(feature = "ansi_term")]
295                 let msg = {
296                     let mut pipe = Color::Fixed(21).paint("|");
297                     pipe.style_ref_mut().is_bold = true;
298                     format!(" {} {}", pipe, msg)
299                 };
300                 eprintln!("{}", msg);
301             };
302             warn("some trace filter directives would enable traces that are disabled statically");
303             for directive in disabled {
304                 let target = if let Some(target) = &directive.target {
305                     format!("the `{}` target", target)
306                 } else {
307                     "all targets".into()
308                 };
309                 let level = directive
310                     .level
311                     .clone()
312                     .into_level()
313                     .expect("=off would not have enabled any filters");
314                 ctx(&format!(
315                     "`{}` would enable the {} level for {}",
316                     directive, level, target
317                 ));
318             }
319             ctx_note(&format!("the static max level is `{}`", STATIC_MAX_LEVEL));
320             let help_msg = || {
321                 let (feature, filter) = match STATIC_MAX_LEVEL.into_level() {
322                     Some(Level::TRACE) => unreachable!(
323                         "if the max level is trace, no static filtering features are enabled"
324                     ),
325                     Some(Level::DEBUG) => ("max_level_debug", Level::TRACE),
326                     Some(Level::INFO) => ("max_level_info", Level::DEBUG),
327                     Some(Level::WARN) => ("max_level_warn", Level::INFO),
328                     Some(Level::ERROR) => ("max_level_error", Level::WARN),
329                     None => return ("max_level_off", String::new()),
330                 };
331                 (feature, format!("{} ", filter))
332             };
333             let (feature, earlier_level) = help_msg();
334             ctx_help(&format!(
335                 "to enable {}logging, remove the `{}` feature",
336                 earlier_level, feature
337             ));
338         }
339 
340         let (dynamics, mut statics) = Directive::make_tables(directives);
341         let has_dynamics = !dynamics.is_empty();
342 
343         if statics.is_empty() && !has_dynamics {
344             statics.add(directive::StaticDirective::default());
345         }
346 
347         Self {
348             statics,
349             dynamics,
350             has_dynamics,
351             by_id: RwLock::new(HashMap::new()),
352             by_cs: RwLock::new(HashMap::new()),
353         }
354     }
355 
cares_about_span(&self, span: &span::Id) -> bool356     fn cares_about_span(&self, span: &span::Id) -> bool {
357         let spans = try_lock!(self.by_id.read(), else return false);
358         spans.contains_key(span)
359     }
360 
base_interest(&self) -> Interest361     fn base_interest(&self) -> Interest {
362         if self.has_dynamics {
363             Interest::sometimes()
364         } else {
365             Interest::never()
366         }
367     }
368 }
369 
370 impl<S: Subscriber> Layer<S> for EnvFilter {
register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest371     fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
372         if self.has_dynamics && metadata.is_span() {
373             // If this metadata describes a span, first, check if there is a
374             // dynamic filter that should be constructed for it. If so, it
375             // should always be enabled, since it influences filtering.
376             if let Some(matcher) = self.dynamics.matcher(metadata) {
377                 let mut by_cs = try_lock!(self.by_cs.write(), else return self.base_interest());
378                 by_cs.insert(metadata.callsite(), matcher);
379                 return Interest::always();
380             }
381         }
382 
383         // Otherwise, check if any of our static filters enable this metadata.
384         if self.statics.enabled(metadata) {
385             Interest::always()
386         } else {
387             self.base_interest()
388         }
389     }
390 
max_level_hint(&self) -> Option<LevelFilter>391     fn max_level_hint(&self) -> Option<LevelFilter> {
392         if self.dynamics.has_value_filters() {
393             // If we perform any filtering on span field *values*, we will
394             // enable *all* spans, because their field values are not known
395             // until recording.
396             return Some(LevelFilter::TRACE);
397         }
398         std::cmp::max(
399             self.statics.max_level.clone().into(),
400             self.dynamics.max_level.clone().into(),
401         )
402     }
403 
enabled(&self, metadata: &Metadata<'_>, _: Context<'_, S>) -> bool404     fn enabled(&self, metadata: &Metadata<'_>, _: Context<'_, S>) -> bool {
405         let level = metadata.level();
406 
407         // is it possible for a dynamic filter directive to enable this event?
408         // if not, we can avoid the thread local access + iterating over the
409         // spans in the current scope.
410         if self.has_dynamics && self.dynamics.max_level >= *level {
411             if metadata.is_span() {
412                 // If the metadata is a span, see if we care about its callsite.
413                 let enabled_by_cs = self
414                     .by_cs
415                     .read()
416                     .ok()
417                     .map(|by_cs| by_cs.contains_key(&metadata.callsite()))
418                     .unwrap_or(false);
419                 if enabled_by_cs {
420                     return true;
421                 }
422             }
423 
424             let enabled_by_scope = SCOPE.with(|scope| {
425                 for filter in scope.borrow().iter() {
426                     if filter >= level {
427                         return true;
428                     }
429                 }
430                 false
431             });
432             if enabled_by_scope {
433                 return true;
434             }
435         }
436 
437         // is it possible for a static filter directive to enable this event?
438         if self.statics.max_level >= *level {
439             // Otherwise, fall back to checking if the callsite is
440             // statically enabled.
441             return self.statics.enabled(metadata);
442         }
443 
444         false
445     }
446 
new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, _: Context<'_, S>)447     fn new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, _: Context<'_, S>) {
448         let by_cs = try_lock!(self.by_cs.read());
449         if let Some(cs) = by_cs.get(&attrs.metadata().callsite()) {
450             let span = cs.to_span_match(attrs);
451             try_lock!(self.by_id.write()).insert(id.clone(), span);
452         }
453     }
454 
on_record(&self, id: &span::Id, values: &span::Record<'_>, _: Context<'_, S>)455     fn on_record(&self, id: &span::Id, values: &span::Record<'_>, _: Context<'_, S>) {
456         if let Some(span) = try_lock!(self.by_id.read()).get(id) {
457             span.record_update(values);
458         }
459     }
460 
on_enter(&self, id: &span::Id, _: Context<'_, S>)461     fn on_enter(&self, id: &span::Id, _: Context<'_, S>) {
462         // XXX: This is where _we_ could push IDs to the stack instead, and use
463         // that to allow changing the filter while a span is already entered.
464         // But that might be much less efficient...
465         if let Some(span) = try_lock!(self.by_id.read()).get(id) {
466             SCOPE.with(|scope| scope.borrow_mut().push(span.level()));
467         }
468     }
469 
on_exit(&self, id: &span::Id, _: Context<'_, S>)470     fn on_exit(&self, id: &span::Id, _: Context<'_, S>) {
471         if self.cares_about_span(id) {
472             SCOPE.with(|scope| scope.borrow_mut().pop());
473         }
474     }
475 
on_close(&self, id: span::Id, _: Context<'_, S>)476     fn on_close(&self, id: span::Id, _: Context<'_, S>) {
477         // If we don't need to acquire a write lock, avoid doing so.
478         if !self.cares_about_span(&id) {
479             return;
480         }
481 
482         let mut spans = try_lock!(self.by_id.write());
483         spans.remove(&id);
484     }
485 }
486 
487 impl FromStr for EnvFilter {
488     type Err = ParseError;
489 
from_str(spec: &str) -> Result<Self, Self::Err>490     fn from_str(spec: &str) -> Result<Self, Self::Err> {
491         Self::try_new(spec)
492     }
493 }
494 
495 impl<S> From<S> for EnvFilter
496 where
497     S: AsRef<str>,
498 {
from(s: S) -> Self499     fn from(s: S) -> Self {
500         Self::new(s)
501     }
502 }
503 
504 impl Default for EnvFilter {
default() -> Self505     fn default() -> Self {
506         Self::from_directives(std::iter::empty())
507     }
508 }
509 
510 impl fmt::Display for EnvFilter {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result511     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
512         let mut statics = self.statics.iter();
513         let wrote_statics = if let Some(next) = statics.next() {
514             fmt::Display::fmt(next, f)?;
515             for directive in statics {
516                 write!(f, ",{}", directive)?;
517             }
518             true
519         } else {
520             false
521         };
522 
523         let mut dynamics = self.dynamics.iter();
524         if let Some(next) = dynamics.next() {
525             if wrote_statics {
526                 f.write_str(",")?;
527             }
528             fmt::Display::fmt(next, f)?;
529             for directive in dynamics {
530                 write!(f, ",{}", directive)?;
531             }
532         }
533         Ok(())
534     }
535 }
536 
537 // ===== impl FromEnvError =====
538 
539 impl From<ParseError> for FromEnvError {
from(p: ParseError) -> Self540     fn from(p: ParseError) -> Self {
541         Self {
542             kind: ErrorKind::Parse(p),
543         }
544     }
545 }
546 
547 impl From<env::VarError> for FromEnvError {
from(v: env::VarError) -> Self548     fn from(v: env::VarError) -> Self {
549         Self {
550             kind: ErrorKind::Env(v),
551         }
552     }
553 }
554 
555 impl fmt::Display for FromEnvError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result556     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
557         match self.kind {
558             ErrorKind::Parse(ref p) => p.fmt(f),
559             ErrorKind::Env(ref e) => e.fmt(f),
560         }
561     }
562 }
563 
564 impl Error for FromEnvError {
source(&self) -> Option<&(dyn Error + 'static)>565     fn source(&self) -> Option<&(dyn Error + 'static)> {
566         match self.kind {
567             ErrorKind::Parse(ref p) => Some(p),
568             ErrorKind::Env(ref e) => Some(e),
569         }
570     }
571 }
572 
573 #[cfg(test)]
574 mod tests {
575     use super::*;
576     use tracing_core::field::FieldSet;
577     use tracing_core::*;
578 
579     struct NoSubscriber;
580     impl Subscriber for NoSubscriber {
581         #[inline]
register_callsite(&self, _: &'static Metadata<'static>) -> subscriber::Interest582         fn register_callsite(&self, _: &'static Metadata<'static>) -> subscriber::Interest {
583             subscriber::Interest::always()
584         }
new_span(&self, _: &span::Attributes<'_>) -> span::Id585         fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
586             span::Id::from_u64(0xDEAD)
587         }
event(&self, _event: &Event<'_>)588         fn event(&self, _event: &Event<'_>) {}
record(&self, _span: &span::Id, _values: &span::Record<'_>)589         fn record(&self, _span: &span::Id, _values: &span::Record<'_>) {}
record_follows_from(&self, _span: &span::Id, _follows: &span::Id)590         fn record_follows_from(&self, _span: &span::Id, _follows: &span::Id) {}
591 
592         #[inline]
enabled(&self, _metadata: &Metadata<'_>) -> bool593         fn enabled(&self, _metadata: &Metadata<'_>) -> bool {
594             true
595         }
enter(&self, _span: &span::Id)596         fn enter(&self, _span: &span::Id) {}
exit(&self, _span: &span::Id)597         fn exit(&self, _span: &span::Id) {}
598     }
599 
600     struct Cs;
601     impl Callsite for Cs {
set_interest(&self, _interest: Interest)602         fn set_interest(&self, _interest: Interest) {}
metadata(&self) -> &Metadata<'_>603         fn metadata(&self) -> &Metadata<'_> {
604             unimplemented!()
605         }
606     }
607 
608     #[test]
callsite_enabled_no_span_directive()609     fn callsite_enabled_no_span_directive() {
610         let filter = EnvFilter::new("app=debug").with_subscriber(NoSubscriber);
611         static META: &Metadata<'static> = &Metadata::new(
612             "mySpan",
613             "app",
614             Level::TRACE,
615             None,
616             None,
617             None,
618             FieldSet::new(&[], identify_callsite!(&Cs)),
619             Kind::SPAN,
620         );
621 
622         let interest = filter.register_callsite(META);
623         assert!(interest.is_never());
624     }
625 
626     #[test]
callsite_off()627     fn callsite_off() {
628         let filter = EnvFilter::new("app=off").with_subscriber(NoSubscriber);
629         static META: &Metadata<'static> = &Metadata::new(
630             "mySpan",
631             "app",
632             Level::ERROR,
633             None,
634             None,
635             None,
636             FieldSet::new(&[], identify_callsite!(&Cs)),
637             Kind::SPAN,
638         );
639 
640         let interest = filter.register_callsite(&META);
641         assert!(interest.is_never());
642     }
643 
644     #[test]
callsite_enabled_includes_span_directive()645     fn callsite_enabled_includes_span_directive() {
646         let filter = EnvFilter::new("app[mySpan]=debug").with_subscriber(NoSubscriber);
647         static META: &Metadata<'static> = &Metadata::new(
648             "mySpan",
649             "app",
650             Level::TRACE,
651             None,
652             None,
653             None,
654             FieldSet::new(&[], identify_callsite!(&Cs)),
655             Kind::SPAN,
656         );
657 
658         let interest = filter.register_callsite(&META);
659         assert!(interest.is_always());
660     }
661 
662     #[test]
callsite_enabled_includes_span_directive_field()663     fn callsite_enabled_includes_span_directive_field() {
664         let filter =
665             EnvFilter::new("app[mySpan{field=\"value\"}]=debug").with_subscriber(NoSubscriber);
666         static META: &Metadata<'static> = &Metadata::new(
667             "mySpan",
668             "app",
669             Level::TRACE,
670             None,
671             None,
672             None,
673             FieldSet::new(&["field"], identify_callsite!(&Cs)),
674             Kind::SPAN,
675         );
676 
677         let interest = filter.register_callsite(&META);
678         assert!(interest.is_always());
679     }
680 
681     #[test]
callsite_enabled_includes_span_directive_multiple_fields()682     fn callsite_enabled_includes_span_directive_multiple_fields() {
683         let filter = EnvFilter::new("app[mySpan{field=\"value\",field2=2}]=debug")
684             .with_subscriber(NoSubscriber);
685         static META: &Metadata<'static> = &Metadata::new(
686             "mySpan",
687             "app",
688             Level::TRACE,
689             None,
690             None,
691             None,
692             FieldSet::new(&["field"], identify_callsite!(&Cs)),
693             Kind::SPAN,
694         );
695 
696         let interest = filter.register_callsite(&META);
697         assert!(interest.is_never());
698     }
699 
700     #[test]
roundtrip()701     fn roundtrip() {
702         let f1: EnvFilter =
703             "[span1{foo=1}]=error,[span2{bar=2 baz=false}],crate2[{quux=\"quuux\"}]=debug"
704                 .parse()
705                 .unwrap();
706         let f2: EnvFilter = format!("{}", f1).parse().unwrap();
707         assert_eq!(f1.statics, f2.statics);
708         assert_eq!(f1.dynamics, f2.dynamics);
709     }
710 }
711