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