]> git.proxmox.com Git - rustc.git/blame - vendor/tracing-subscriber/src/filter/env/mod.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / vendor / tracing-subscriber / src / filter / env / mod.rs
CommitLineData
f035d41b
XL
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::{
8 directive::{Directive, ParseError},
9 field::BadName as BadFieldName,
10};
11mod directive;
12mod field;
13
14use crate::{
15 filter::LevelFilter,
16 layer::{Context, Layer},
17 sync::RwLock,
18};
19use std::{cell::RefCell, collections::HashMap, env, error::Error, fmt, str::FromStr};
20use tracing_core::{
21 callsite,
22 field::Field,
23 span,
24 subscriber::{Interest, Subscriber},
25 Metadata,
26};
27
28/// A [`Layer`] which filters spans and events based on a set of filter
29/// directives.
30///
31/// # 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`.
29967ef6
XL
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", ...);`
f035d41b
XL
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
29967ef6
XL
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
f035d41b
XL
98#[cfg(feature = "env-filter")]
99#[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))]
100#[derive(Debug)]
101pub 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
109thread_local! {
110 static SCOPE: RefCell<Vec<LevelFilter>> = RefCell::new(Vec::new());
111}
112
113type FieldMap<T> = HashMap<Field, T>;
114
115#[cfg(feature = "smallvec")]
116type FilterVec<T> = smallvec::SmallVec<[T; 8]>;
117#[cfg(not(feature = "smallvec"))]
118type FilterVec<T> = Vec<T>;
119
120/// Indicates that an error occurred while parsing a `EnvFilter` from an
121/// environment variable.
122#[derive(Debug)]
123pub struct FromEnvError {
124 kind: ErrorKind,
125}
126
127#[derive(Debug)]
128enum ErrorKind {
129 Parse(ParseError),
130 Env(env::VarError),
131}
132
133impl 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.
143 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.
149 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.
155 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.
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.
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.
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 ///
29967ef6 197 /// Filters may be created from [`LevelFilter`] or [`Level`], which will
f035d41b
XL
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 ///
29967ef6
XL
205 /// [`LevelFilter`]: ../filter/struct.LevelFilter.html
206 /// [`Level`]: https://docs.rs/tracing-core/latest/tracing_core/struct.Level.html
f035d41b
XL
207 ///
208 /// # Examples
29967ef6
XL
209 ///
210 /// From [`LevelFilter`]:
211 ////
f035d41b
XL
212 /// ```rust
213 /// use tracing_subscriber::filter::{EnvFilter, LevelFilter};
214 /// let mut filter = EnvFilter::from_default_env()
215 /// .add_directive(LevelFilter::INFO.into());
216 /// ```
29967ef6
XL
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 ////
f035d41b
XL
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 /// ```
239 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
249 fn from_directives(directives: impl IntoIterator<Item = Directive>) -> Self {
29967ef6
XL
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;
136023e0 274 format!("{}{} {}", warning, bold.paint(":"), bold.paint(msg))
29967ef6
XL
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
29967ef6
XL
311 .into_level()
312 .expect("=off would not have enabled any filters");
313 ctx(&format!(
314 "`{}` would enable the {} level for {}",
315 directive, level, target
316 ));
317 }
318 ctx_note(&format!("the static max level is `{}`", STATIC_MAX_LEVEL));
319 let help_msg = || {
320 let (feature, filter) = match STATIC_MAX_LEVEL.into_level() {
321 Some(Level::TRACE) => unreachable!(
322 "if the max level is trace, no static filtering features are enabled"
323 ),
324 Some(Level::DEBUG) => ("max_level_debug", Level::TRACE),
325 Some(Level::INFO) => ("max_level_info", Level::DEBUG),
326 Some(Level::WARN) => ("max_level_warn", Level::INFO),
327 Some(Level::ERROR) => ("max_level_error", Level::WARN),
328 None => return ("max_level_off", String::new()),
329 };
330 (feature, format!("{} ", filter))
331 };
332 let (feature, earlier_level) = help_msg();
333 ctx_help(&format!(
334 "to enable {}logging, remove the `{}` feature",
335 earlier_level, feature
336 ));
337 }
338
f035d41b
XL
339 let (dynamics, mut statics) = Directive::make_tables(directives);
340 let has_dynamics = !dynamics.is_empty();
341
342 if statics.is_empty() && !has_dynamics {
343 statics.add(directive::StaticDirective::default());
344 }
345
346 Self {
347 statics,
348 dynamics,
349 has_dynamics,
350 by_id: RwLock::new(HashMap::new()),
351 by_cs: RwLock::new(HashMap::new()),
352 }
353 }
354
355 fn cares_about_span(&self, span: &span::Id) -> bool {
356 let spans = try_lock!(self.by_id.read(), else return false);
357 spans.contains_key(span)
358 }
359
360 fn base_interest(&self) -> Interest {
361 if self.has_dynamics {
362 Interest::sometimes()
363 } else {
364 Interest::never()
365 }
366 }
367}
368
369impl<S: Subscriber> Layer<S> for EnvFilter {
370 fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
371 if self.has_dynamics && metadata.is_span() {
372 // If this metadata describes a span, first, check if there is a
373 // dynamic filter that should be constructed for it. If so, it
374 // should always be enabled, since it influences filtering.
375 if let Some(matcher) = self.dynamics.matcher(metadata) {
376 let mut by_cs = try_lock!(self.by_cs.write(), else return self.base_interest());
377 by_cs.insert(metadata.callsite(), matcher);
378 return Interest::always();
379 }
380 }
381
382 // Otherwise, check if any of our static filters enable this metadata.
383 if self.statics.enabled(metadata) {
384 Interest::always()
385 } else {
386 self.base_interest()
387 }
388 }
389
3dfed10e
XL
390 fn max_level_hint(&self) -> Option<LevelFilter> {
391 if self.dynamics.has_value_filters() {
392 // If we perform any filtering on span field *values*, we will
393 // enable *all* spans, because their field values are not known
394 // until recording.
395 return Some(LevelFilter::TRACE);
396 }
397 std::cmp::max(
136023e0
XL
398 self.statics.max_level.into(),
399 self.dynamics.max_level.into(),
3dfed10e
XL
400 )
401 }
402
f035d41b
XL
403 fn enabled(&self, metadata: &Metadata<'_>, _: Context<'_, S>) -> bool {
404 let level = metadata.level();
405
406 // is it possible for a dynamic filter directive to enable this event?
407 // if not, we can avoid the thread local access + iterating over the
408 // spans in the current scope.
409 if self.has_dynamics && self.dynamics.max_level >= *level {
29967ef6
XL
410 if metadata.is_span() {
411 // If the metadata is a span, see if we care about its callsite.
412 let enabled_by_cs = self
413 .by_cs
414 .read()
415 .ok()
416 .map(|by_cs| by_cs.contains_key(&metadata.callsite()))
417 .unwrap_or(false);
418 if enabled_by_cs {
419 return true;
420 }
421 }
422
f035d41b
XL
423 let enabled_by_scope = SCOPE.with(|scope| {
424 for filter in scope.borrow().iter() {
425 if filter >= level {
426 return true;
427 }
428 }
429 false
430 });
431 if enabled_by_scope {
432 return true;
433 }
434 }
435
436 // is it possible for a static filter directive to enable this event?
437 if self.statics.max_level >= *level {
438 // Otherwise, fall back to checking if the callsite is
439 // statically enabled.
f035d41b
XL
440 return self.statics.enabled(metadata);
441 }
442
443 false
444 }
445
446 fn new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, _: Context<'_, S>) {
447 let by_cs = try_lock!(self.by_cs.read());
448 if let Some(cs) = by_cs.get(&attrs.metadata().callsite()) {
449 let span = cs.to_span_match(attrs);
450 try_lock!(self.by_id.write()).insert(id.clone(), span);
451 }
452 }
453
454 fn on_record(&self, id: &span::Id, values: &span::Record<'_>, _: Context<'_, S>) {
455 if let Some(span) = try_lock!(self.by_id.read()).get(id) {
456 span.record_update(values);
457 }
458 }
459
460 fn on_enter(&self, id: &span::Id, _: Context<'_, S>) {
461 // XXX: This is where _we_ could push IDs to the stack instead, and use
462 // that to allow changing the filter while a span is already entered.
463 // But that might be much less efficient...
464 if let Some(span) = try_lock!(self.by_id.read()).get(id) {
465 SCOPE.with(|scope| scope.borrow_mut().push(span.level()));
466 }
467 }
468
469 fn on_exit(&self, id: &span::Id, _: Context<'_, S>) {
470 if self.cares_about_span(id) {
471 SCOPE.with(|scope| scope.borrow_mut().pop());
472 }
473 }
474
475 fn on_close(&self, id: span::Id, _: Context<'_, S>) {
476 // If we don't need to acquire a write lock, avoid doing so.
477 if !self.cares_about_span(&id) {
478 return;
479 }
480
481 let mut spans = try_lock!(self.by_id.write());
482 spans.remove(&id);
483 }
484}
485
486impl FromStr for EnvFilter {
487 type Err = ParseError;
488
489 fn from_str(spec: &str) -> Result<Self, Self::Err> {
490 Self::try_new(spec)
491 }
492}
493
494impl<S> From<S> for EnvFilter
495where
496 S: AsRef<str>,
497{
498 fn from(s: S) -> Self {
499 Self::new(s)
500 }
501}
502
503impl Default for EnvFilter {
504 fn default() -> Self {
505 Self::from_directives(std::iter::empty())
506 }
507}
508
509impl fmt::Display for EnvFilter {
510 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
511 let mut statics = self.statics.iter();
512 let wrote_statics = if let Some(next) = statics.next() {
513 fmt::Display::fmt(next, f)?;
514 for directive in statics {
515 write!(f, ",{}", directive)?;
516 }
517 true
518 } else {
519 false
520 };
521
522 let mut dynamics = self.dynamics.iter();
523 if let Some(next) = dynamics.next() {
524 if wrote_statics {
525 f.write_str(",")?;
526 }
527 fmt::Display::fmt(next, f)?;
528 for directive in dynamics {
529 write!(f, ",{}", directive)?;
530 }
531 }
532 Ok(())
533 }
534}
535
536// ===== impl FromEnvError =====
537
538impl From<ParseError> for FromEnvError {
539 fn from(p: ParseError) -> Self {
540 Self {
541 kind: ErrorKind::Parse(p),
542 }
543 }
544}
545
546impl From<env::VarError> for FromEnvError {
547 fn from(v: env::VarError) -> Self {
548 Self {
549 kind: ErrorKind::Env(v),
550 }
551 }
552}
553
554impl fmt::Display for FromEnvError {
555 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
556 match self.kind {
557 ErrorKind::Parse(ref p) => p.fmt(f),
558 ErrorKind::Env(ref e) => e.fmt(f),
559 }
560 }
561}
562
563impl Error for FromEnvError {
564 fn source(&self) -> Option<&(dyn Error + 'static)> {
565 match self.kind {
566 ErrorKind::Parse(ref p) => Some(p),
567 ErrorKind::Env(ref e) => Some(e),
568 }
569 }
570}
571
572#[cfg(test)]
573mod tests {
574 use super::*;
575 use tracing_core::field::FieldSet;
576 use tracing_core::*;
577
578 struct NoSubscriber;
579 impl Subscriber for NoSubscriber {
580 #[inline]
581 fn register_callsite(&self, _: &'static Metadata<'static>) -> subscriber::Interest {
582 subscriber::Interest::always()
583 }
584 fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
585 span::Id::from_u64(0xDEAD)
586 }
587 fn event(&self, _event: &Event<'_>) {}
588 fn record(&self, _span: &span::Id, _values: &span::Record<'_>) {}
589 fn record_follows_from(&self, _span: &span::Id, _follows: &span::Id) {}
590
591 #[inline]
592 fn enabled(&self, _metadata: &Metadata<'_>) -> bool {
593 true
594 }
595 fn enter(&self, _span: &span::Id) {}
596 fn exit(&self, _span: &span::Id) {}
597 }
598
599 struct Cs;
600 impl Callsite for Cs {
601 fn set_interest(&self, _interest: Interest) {}
602 fn metadata(&self) -> &Metadata<'_> {
603 unimplemented!()
604 }
605 }
606
607 #[test]
608 fn callsite_enabled_no_span_directive() {
609 let filter = EnvFilter::new("app=debug").with_subscriber(NoSubscriber);
610 static META: &Metadata<'static> = &Metadata::new(
611 "mySpan",
612 "app",
613 Level::TRACE,
614 None,
615 None,
616 None,
617 FieldSet::new(&[], identify_callsite!(&Cs)),
618 Kind::SPAN,
619 );
620
621 let interest = filter.register_callsite(META);
622 assert!(interest.is_never());
623 }
624
625 #[test]
626 fn callsite_off() {
627 let filter = EnvFilter::new("app=off").with_subscriber(NoSubscriber);
628 static META: &Metadata<'static> = &Metadata::new(
629 "mySpan",
630 "app",
631 Level::ERROR,
632 None,
633 None,
634 None,
635 FieldSet::new(&[], identify_callsite!(&Cs)),
636 Kind::SPAN,
637 );
638
639 let interest = filter.register_callsite(&META);
640 assert!(interest.is_never());
641 }
642
643 #[test]
644 fn callsite_enabled_includes_span_directive() {
645 let filter = EnvFilter::new("app[mySpan]=debug").with_subscriber(NoSubscriber);
646 static META: &Metadata<'static> = &Metadata::new(
647 "mySpan",
648 "app",
649 Level::TRACE,
650 None,
651 None,
652 None,
653 FieldSet::new(&[], identify_callsite!(&Cs)),
654 Kind::SPAN,
655 );
656
657 let interest = filter.register_callsite(&META);
658 assert!(interest.is_always());
659 }
660
661 #[test]
662 fn callsite_enabled_includes_span_directive_field() {
663 let filter =
664 EnvFilter::new("app[mySpan{field=\"value\"}]=debug").with_subscriber(NoSubscriber);
665 static META: &Metadata<'static> = &Metadata::new(
666 "mySpan",
667 "app",
668 Level::TRACE,
669 None,
670 None,
671 None,
672 FieldSet::new(&["field"], identify_callsite!(&Cs)),
673 Kind::SPAN,
674 );
675
676 let interest = filter.register_callsite(&META);
677 assert!(interest.is_always());
678 }
679
680 #[test]
681 fn callsite_enabled_includes_span_directive_multiple_fields() {
682 let filter = EnvFilter::new("app[mySpan{field=\"value\",field2=2}]=debug")
683 .with_subscriber(NoSubscriber);
684 static META: &Metadata<'static> = &Metadata::new(
685 "mySpan",
686 "app",
687 Level::TRACE,
688 None,
689 None,
690 None,
691 FieldSet::new(&["field"], identify_callsite!(&Cs)),
692 Kind::SPAN,
693 );
694
695 let interest = filter.register_callsite(&META);
696 assert!(interest.is_never());
697 }
698
699 #[test]
700 fn roundtrip() {
701 let f1: EnvFilter =
702 "[span1{foo=1}]=error,[span2{bar=2 baz=false}],crate2[{quux=\"quuux\"}]=debug"
703 .parse()
704 .unwrap();
705 let f2: EnvFilter = format!("{}", f1).parse().unwrap();
706 assert_eq!(f1.statics, f2.statics);
707 assert_eq!(f1.dynamics, f2.dynamics);
708 }
709}