@@ -10,11 +10,12 @@ mod field;
1010
1111use crate :: {
1212 filter:: LevelFilter ,
13- layer:: { Context , Layer } ,
13+ layer:: { self , Context , Layer } ,
1414 sync:: RwLock ,
1515} ;
1616use directive:: ParseError ;
1717use std:: { cell:: RefCell , collections:: HashMap , env, error:: Error , fmt, str:: FromStr } ;
18+ use thread_local:: ThreadLocal ;
1819use tracing_core:: {
1920 callsite,
2021 field:: Field ,
@@ -26,6 +27,16 @@ use tracing_core::{
2627/// A [`Layer`] which filters spans and events based on a set of filter
2728/// directives.
2829///
30+ /// `EnvFilter` implements both the [`Layer`](#impl-Layer<S>) and [`Filter`] traits, so it may
31+ /// be used for both [global filtering][global] and [per-layer filtering][plf],
32+ /// respectively. See [the documentation on filtering with `Layer`s][filtering]
33+ /// for details.
34+ ///
35+ /// The [`Targets`] type implements a similar form of filtering, but without the
36+ /// ability to dynamically enable events based on the current span context, and
37+ /// without filtering on field values. When these features are not required,
38+ /// [`Targets`] provides a lighter-weight alternative to [`EnvFilter`].
39+ ///
2940/// # Directives
3041///
3142/// A filter consists of one or more comma-separated directives which match on [`Span`]s and [`Event`]s.
@@ -72,7 +83,7 @@ use tracing_core::{
7283/// - A dash in a target will only appear when being specified explicitly:
7384/// `tracing::info!(target: "target-name", ...);`
7485///
75- /// ## Examples
86+ /// ## Example Syntax
7687///
7788/// - `tokio::net=info` will enable all spans or events that:
7889/// - have the `tokio::net` target,
@@ -89,10 +100,54 @@ use tracing_core::{
89100/// - which has a field named `name` with value `bob`,
90101/// - at _any_ level.
91102///
92- /// The [`Targets`] type implements a similar form of filtering, but without the
93- /// ability to dynamically enable events based on the current span context, and
94- /// without filtering on field values. When these features are not required,
95- /// [`Targets`] provides a lighter-weight alternative to [`EnvFilter`].
103+ /// # Examples
104+ ///
105+ /// Parsing an `EnvFilter` from the [default environment
106+ /// variable](EnvFilter::from_default_env) (`RUST_LOG`):
107+ ///
108+ /// ```
109+ /// use tracing_subscriber::{EnvFilter, fmt, prelude::*};
110+ ///
111+ /// tracing_subscriber::registry()
112+ /// .with(fmt::layer())
113+ /// .with(EnvFilter::from_default_env())
114+ /// .init();
115+ /// ```
116+ ///
117+ /// Parsing an `EnvFilter` [from a user-provided environment
118+ /// variable](EnvFilter::from_env):
119+ ///
120+ /// ```
121+ /// use tracing_subscriber::{EnvFilter, fmt, prelude::*};
122+ ///
123+ /// tracing_subscriber::registry()
124+ /// .with(fmt::layer())
125+ /// .with(EnvFilter::from_env("MYAPP_LOG"))
126+ /// .init();
127+ /// ```
128+ ///
129+ /// Using `EnvFilter` as a [per-layer filter][plf] to filter only a single
130+ /// [`Layer`]:
131+ ///
132+ /// ```
133+ /// use tracing_subscriber::{EnvFilter, fmt, prelude::*};
134+ ///
135+ /// // Parse an `EnvFilter` configuration from the `RUST_LOG`
136+ /// // environment variable.
137+ /// let filter = EnvFilter::from_default_env();
138+ ///
139+ /// // Apply the filter to this layer *only*.
140+ /// let filtered_layer = fmt::layer().with_filter(filter);
141+ ///
142+ /// // Some other layer, whose output we don't want to filter.
143+ /// let unfiltered_layer = // ...
144+ /// # fmt::layer();
145+ ///
146+ /// tracing_subscriber::registry()
147+ /// .with(filtered_layer)
148+ /// .with(unfiltered_layer)
149+ /// .init();
150+ /// ```
96151///
97152/// [`Span`]: tracing_core::span
98153/// [fields]: tracing_core::Field
@@ -101,6 +156,10 @@ use tracing_core::{
101156/// [`Metadata`]: tracing_core::Metadata
102157/// [`Targets`]: crate::filter::Targets
103158/// [`env_logger`]: https://crates.io/crates/env_logger
159+ /// [`Filter`]: #impl-Filter<S>
160+ /// [global]: crate::layer#global-filtering
161+ /// [plf]: crate::layer#per-layer-filtering
162+ /// [filtering]: crate::layer#filtering-with-layers
104163#[ cfg_attr( docsrs, doc( cfg( all( feature = "env-filter" , feature = "std" ) ) ) ) ]
105164#[ derive( Debug ) ]
106165pub struct EnvFilter {
@@ -109,10 +168,7 @@ pub struct EnvFilter {
109168 has_dynamics : bool ,
110169 by_id : RwLock < HashMap < span:: Id , directive:: SpanMatcher > > ,
111170 by_cs : RwLock < HashMap < callsite:: Identifier , directive:: CallsiteMatcher > > ,
112- }
113-
114- thread_local ! {
115- static SCOPE : RefCell <Vec <LevelFilter >> = RefCell :: new( Vec :: new( ) ) ;
171+ scope : ThreadLocal < RefCell < Vec < LevelFilter > > > ,
116172}
117173
118174type FieldMap < T > = HashMap < Field , T > ;
@@ -350,6 +406,10 @@ impl EnvFilter {
350406 has_dynamics,
351407 by_id : RwLock :: new ( HashMap :: new ( ) ) ,
352408 by_cs : RwLock :: new ( HashMap :: new ( ) ) ,
409+ // TODO(eliza): maybe worth allocating capacity for `num_cpus`
410+ // threads or something (assuming we're running in Tokio)? or
411+ // `num_cpus * 2` or something?
412+ scope : ThreadLocal :: new ( ) ,
353413 }
354414 }
355415
@@ -365,9 +425,7 @@ impl EnvFilter {
365425 Interest :: never ( )
366426 }
367427 }
368- }
369428
370- impl < S : Subscriber > Layer < S > for EnvFilter {
371429 fn register_callsite ( & self , metadata : & ' static Metadata < ' static > ) -> Interest {
372430 if self . has_dynamics && metadata. is_span ( ) {
373431 // If this metadata describes a span, first, check if there is a
@@ -388,20 +446,7 @@ impl<S: Subscriber> Layer<S> for EnvFilter {
388446 }
389447 }
390448
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 . into ( ) ,
400- self . dynamics . max_level . into ( ) ,
401- )
402- }
403-
404- fn enabled ( & self , metadata : & Metadata < ' _ > , _: Context < ' _ , S > ) -> bool {
449+ fn enabled ( & self , metadata : & Metadata < ' _ > ) -> bool {
405450 let level = metadata. level ( ) ;
406451
407452 // is it possible for a dynamic filter directive to enable this event?
@@ -421,14 +466,15 @@ impl<S: Subscriber> Layer<S> for EnvFilter {
421466 }
422467 }
423468
424- let enabled_by_scope = SCOPE . with ( |scope| {
425- for filter in scope. borrow ( ) . iter ( ) {
469+ let enabled_by_scope = {
470+ let scope = self . scope . get_or_default ( ) . borrow ( ) ;
471+ for filter in & * scope {
426472 if filter >= level {
427473 return true ;
428474 }
429475 }
430476 false
431- } ) ;
477+ } ;
432478 if enabled_by_scope {
433479 return true ;
434480 }
@@ -444,36 +490,43 @@ impl<S: Subscriber> Layer<S> for EnvFilter {
444490 false
445491 }
446492
447- fn on_new_span ( & self , attrs : & span:: Attributes < ' _ > , id : & span:: Id , _: Context < ' _ , S > ) {
493+ fn max_level_hint ( & self ) -> Option < LevelFilter > {
494+ if self . dynamics . has_value_filters ( ) {
495+ // If we perform any filtering on span field *values*, we will
496+ // enable *all* spans, because their field values are not known
497+ // until recording.
498+ return Some ( LevelFilter :: TRACE ) ;
499+ }
500+ std:: cmp:: max (
501+ self . statics . max_level . into ( ) ,
502+ self . dynamics . max_level . into ( ) ,
503+ )
504+ }
505+
506+ fn on_new_span ( & self , attrs : & span:: Attributes < ' _ > , id : & span:: Id ) {
448507 let by_cs = try_lock ! ( self . by_cs. read( ) ) ;
449508 if let Some ( cs) = by_cs. get ( & attrs. metadata ( ) . callsite ( ) ) {
450509 let span = cs. to_span_match ( attrs) ;
451510 try_lock ! ( self . by_id. write( ) ) . insert ( id. clone ( ) , span) ;
452511 }
453512 }
454513
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-
461- fn on_enter ( & self , id : & span:: Id , _: Context < ' _ , S > ) {
514+ fn on_enter ( & self , id : & span:: Id ) {
462515 // XXX: This is where _we_ could push IDs to the stack instead, and use
463516 // that to allow changing the filter while a span is already entered.
464517 // But that might be much less efficient...
465518 if let Some ( span) = try_lock ! ( self . by_id. read( ) ) . get ( id) {
466- SCOPE . with ( | scope| scope . borrow_mut ( ) . push ( span. level ( ) ) ) ;
519+ self . scope . get_or_default ( ) . borrow_mut ( ) . push ( span. level ( ) ) ;
467520 }
468521 }
469522
470- fn on_exit ( & self , id : & span:: Id , _ : Context < ' _ , S > ) {
523+ fn on_exit ( & self , id : & span:: Id ) {
471524 if self . cares_about_span ( id) {
472- SCOPE . with ( | scope| scope . borrow_mut ( ) . pop ( ) ) ;
525+ self . scope . get_or_default ( ) . borrow_mut ( ) . pop ( ) ;
473526 }
474527 }
475528
476- fn on_close ( & self , id : span:: Id , _ : Context < ' _ , S > ) {
529+ fn on_close ( & self , id : span:: Id ) {
477530 // If we don't need to acquire a write lock, avoid doing so.
478531 if !self . cares_about_span ( & id) {
479532 return ;
@@ -484,6 +537,90 @@ impl<S: Subscriber> Layer<S> for EnvFilter {
484537 }
485538}
486539
540+ impl < S : Subscriber > Layer < S > for EnvFilter {
541+ #[ inline]
542+ fn register_callsite ( & self , metadata : & ' static Metadata < ' static > ) -> Interest {
543+ EnvFilter :: register_callsite ( self , metadata)
544+ }
545+
546+ #[ inline]
547+ fn max_level_hint ( & self ) -> Option < LevelFilter > {
548+ EnvFilter :: max_level_hint ( self )
549+ }
550+
551+ #[ inline]
552+ fn enabled ( & self , metadata : & Metadata < ' _ > , _: Context < ' _ , S > ) -> bool {
553+ self . enabled ( metadata)
554+ }
555+
556+ #[ inline]
557+ fn on_new_span ( & self , attrs : & span:: Attributes < ' _ > , id : & span:: Id , _: Context < ' _ , S > ) {
558+ self . on_new_span ( attrs, id)
559+ }
560+
561+ fn on_record ( & self , id : & span:: Id , values : & span:: Record < ' _ > , _: Context < ' _ , S > ) {
562+ if let Some ( span) = try_lock ! ( self . by_id. read( ) ) . get ( id) {
563+ span. record_update ( values) ;
564+ }
565+ }
566+
567+ #[ inline]
568+ fn on_enter ( & self , id : & span:: Id , _: Context < ' _ , S > ) {
569+ self . on_enter ( id) ;
570+ }
571+
572+ #[ inline]
573+ fn on_exit ( & self , id : & span:: Id , _: Context < ' _ , S > ) {
574+ self . on_exit ( id) ;
575+ }
576+
577+ #[ inline]
578+ fn on_close ( & self , id : span:: Id , _: Context < ' _ , S > ) {
579+ self . on_close ( id) ;
580+ }
581+ }
582+
583+ feature ! {
584+ #![ all( feature = "registry" , feature = "std" ) ]
585+
586+ impl <S > layer:: Filter <S > for EnvFilter {
587+ #[ inline]
588+ fn enabled( & self , meta: & Metadata <' _>, _: & Context <' _, S >) -> bool {
589+ self . enabled( meta)
590+ }
591+
592+ #[ inline]
593+ fn callsite_enabled( & self , meta: & ' static Metadata <' static >) -> Interest {
594+ self . register_callsite( meta)
595+ }
596+
597+ #[ inline]
598+ fn max_level_hint( & self ) -> Option <LevelFilter > {
599+ EnvFilter :: max_level_hint( self )
600+ }
601+
602+ #[ inline]
603+ fn on_new_span( & self , attrs: & span:: Attributes <' _>, id: & span:: Id , _: Context <' _, S >) {
604+ self . on_new_span( attrs, id)
605+ }
606+
607+ #[ inline]
608+ fn on_enter( & self , id: & span:: Id , _: Context <' _, S >) {
609+ self . on_enter( id) ;
610+ }
611+
612+ #[ inline]
613+ fn on_exit( & self , id: & span:: Id , _: Context <' _, S >) {
614+ self . on_exit( id) ;
615+ }
616+
617+ #[ inline]
618+ fn on_close( & self , id: span:: Id , _: Context <' _, S >) {
619+ self . on_close( id) ;
620+ }
621+ }
622+ }
623+
487624impl FromStr for EnvFilter {
488625 type Err = directive:: ParseError ;
489626
0 commit comments