diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:11:38 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:13:23 +0000 |
commit | 20431706a863f92cb37dc512fef6e48d192aaf2c (patch) | |
tree | 2867f13f5fd5437ba628c67d7f87309ccadcd286 /vendor/tracing-subscriber/src/filter/env | |
parent | Releasing progress-linux version 1.65.0+dfsg1-2~progress7.99u1. (diff) | |
download | rustc-20431706a863f92cb37dc512fef6e48d192aaf2c.tar.xz rustc-20431706a863f92cb37dc512fef6e48d192aaf2c.zip |
Merging upstream version 1.66.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | vendor/tracing-subscriber-0.3.3/src/filter/env/directive.rs (renamed from vendor/tracing-subscriber/src/filter/env/directive.rs) | 160 | ||||
-rw-r--r-- | vendor/tracing-subscriber-0.3.3/src/filter/env/field.rs (renamed from vendor/tracing-subscriber/src/filter/env/field.rs) | 250 | ||||
-rw-r--r-- | vendor/tracing-subscriber-0.3.3/src/filter/env/mod.rs (renamed from vendor/tracing-subscriber/src/filter/env/mod.rs) | 677 | ||||
-rw-r--r-- | vendor/tracing-subscriber/src/filter/env/builder.rs | 324 |
4 files changed, 305 insertions, 1106 deletions
diff --git a/vendor/tracing-subscriber/src/filter/env/directive.rs b/vendor/tracing-subscriber-0.3.3/src/filter/env/directive.rs index f062e6ef9..66ca23dc4 100644 --- a/vendor/tracing-subscriber/src/filter/env/directive.rs +++ b/vendor/tracing-subscriber-0.3.3/src/filter/env/directive.rs @@ -4,14 +4,14 @@ use crate::filter::{ env::{field, FieldMap}, level::LevelFilter, }; -use once_cell::sync::Lazy; +use lazy_static::lazy_static; use regex::Regex; use std::{cmp::Ordering, fmt, iter::FromIterator, str::FromStr}; use tracing_core::{span, Level, Metadata}; /// A single filtering directive. // TODO(eliza): add a builder for programmatically constructing directives? -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq)] #[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))] pub struct Directive { in_span: Option<String>, @@ -107,52 +107,80 @@ impl Directive { .collect(); (Dynamics::from_iter(dyns), statics) } +} - pub(super) fn deregexify(&mut self) { - for field in &mut self.fields { - field.value = match field.value.take() { - Some(field::ValueMatch::Pat(pat)) => { - Some(field::ValueMatch::Debug(pat.into_debug_match())) - } - x => x, +impl Match for Directive { + fn cares_about(&self, meta: &Metadata<'_>) -> bool { + // Does this directive have a target filter, and does it match the + // metadata's target? + if let Some(ref target) = self.target { + if !meta.target().starts_with(&target[..]) { + return false; } } + + // Do we have a name filter, and does it match the metadata's name? + // TODO(eliza): put name globbing here? + if let Some(ref name) = self.in_span { + if name != meta.name() { + return false; + } + } + + // Does the metadata define all the fields that this directive cares about? + let fields = meta.fields(); + for field in &self.fields { + if fields.field(&field.name).is_none() { + return false; + } + } + + true } - pub(super) fn parse(from: &str, regex: bool) -> Result<Self, ParseError> { - static DIRECTIVE_RE: Lazy<Regex> = Lazy::new(|| Regex::new( - r"(?x) - ^(?P<global_level>(?i:trace|debug|info|warn|error|off|[0-5]))$ | - # ^^^. - # `note: we match log level names case-insensitively - ^ - (?: # target name or span name - (?P<target>[\w:-]+)|(?P<span>\[[^\]]*\]) - ){1,2} - (?: # level or nothing - =(?P<level>(?i:trace|debug|info|warn|error|off|[0-5]))? - # ^^^. - # `note: we match log level names case-insensitively - )? - $ - " - ) - .unwrap()); - static SPAN_PART_RE: Lazy<Regex> = - Lazy::new(|| Regex::new(r#"(?P<name>[^\]\{]+)?(?:\{(?P<fields>[^\}]*)\})?"#).unwrap()); - static FIELD_FILTER_RE: Lazy<Regex> = - // TODO(eliza): this doesn't _currently_ handle value matchers that include comma - // characters. We should fix that. - Lazy::new(|| Regex::new(r#"(?x) - ( - # field name - [[:word:]][[[:word:]]\.]* - # value part (optional) - (?:=[^,]+)? - ) - # trailing comma or EOS - (?:,\s?|$) - "#).unwrap()); + fn level(&self) -> &LevelFilter { + &self.level + } +} + +impl FromStr for Directive { + type Err = ParseError; + fn from_str(from: &str) -> Result<Self, Self::Err> { + lazy_static! { + static ref DIRECTIVE_RE: Regex = Regex::new( + r"(?x) + ^(?P<global_level>(?i:trace|debug|info|warn|error|off|[0-5]))$ | + # ^^^. + # `note: we match log level names case-insensitively + ^ + (?: # target name or span name + (?P<target>[\w:-]+)|(?P<span>\[[^\]]*\]) + ){1,2} + (?: # level or nothing + =(?P<level>(?i:trace|debug|info|warn|error|off|[0-5]))? + # ^^^. + # `note: we match log level names case-insensitively + )? + $ + " + ) + .unwrap(); + static ref SPAN_PART_RE: Regex = + Regex::new(r#"(?P<name>[^\]\{]+)?(?:\{(?P<fields>[^\}]*)\})?"#).unwrap(); + static ref FIELD_FILTER_RE: Regex = + // TODO(eliza): this doesn't _currently_ handle value matchers that include comma + // characters. We should fix that. + Regex::new(r#"(?x) + ( + # field name + [[:word:]][[[:word:]]\.]* + # value part (optional) + (?:=[^,]+)? + ) + # trailing comma or EOS + (?:,\s?|$) + "#).unwrap(); + } let caps = DIRECTIVE_RE.captures(from).ok_or_else(ParseError::new)?; @@ -186,7 +214,7 @@ impl Directive { .map(|c| { FIELD_FILTER_RE .find_iter(c.as_str()) - .map(|c| field::Match::parse(c.as_str(), regex)) + .map(|c| c.as_str().parse()) .collect::<Result<Vec<_>, _>>() }) .unwrap_or_else(|| Ok(Vec::new())); @@ -200,7 +228,7 @@ impl Directive { // Setting the target without the level enables every level for that target .unwrap_or(LevelFilter::TRACE); - Ok(Self { + Ok(Directive { level, target, in_span, @@ -209,48 +237,6 @@ impl Directive { } } -impl Match for Directive { - fn cares_about(&self, meta: &Metadata<'_>) -> bool { - // Does this directive have a target filter, and does it match the - // metadata's target? - if let Some(ref target) = self.target { - if !meta.target().starts_with(&target[..]) { - return false; - } - } - - // Do we have a name filter, and does it match the metadata's name? - // TODO(eliza): put name globbing here? - if let Some(ref name) = self.in_span { - if name != meta.name() { - return false; - } - } - - // Does the metadata define all the fields that this directive cares about? - let actual_fields = meta.fields(); - for expected_field in &self.fields { - // Does the actual field set (from the metadata) contain this field? - if actual_fields.field(&expected_field.name).is_none() { - return false; - } - } - - true - } - - fn level(&self) -> &LevelFilter { - &self.level - } -} - -impl FromStr for Directive { - type Err = ParseError; - fn from_str(from: &str) -> Result<Self, Self::Err> { - Directive::parse(from, true) - } -} - impl Default for Directive { fn default() -> Self { Directive { diff --git a/vendor/tracing-subscriber/src/filter/env/field.rs b/vendor/tracing-subscriber-0.3.3/src/filter/env/field.rs index 1394fd04a..970850f92 100644 --- a/vendor/tracing-subscriber/src/filter/env/field.rs +++ b/vendor/tracing-subscriber-0.3.3/src/filter/env/field.rs @@ -2,7 +2,7 @@ use matchers::Pattern; use std::{ cmp::Ordering, error::Error, - fmt::{self, Write}, + fmt, str::FromStr, sync::{ atomic::{AtomicBool, Ordering::*}, @@ -13,7 +13,7 @@ use std::{ use super::{FieldMap, LevelFilter}; use tracing_core::field::{Field, Visit}; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub(crate) struct Match { pub(crate) name: String, // TODO: allow match patterns for names? pub(crate) value: Option<ValueMatch>, @@ -38,20 +38,11 @@ pub(crate) struct MatchVisitor<'a> { #[derive(Debug, Clone)] pub(crate) enum ValueMatch { - /// Matches a specific `bool` value. Bool(bool), - /// Matches a specific `f64` value. F64(f64), - /// Matches a specific `u64` value. U64(u64), - /// Matches a specific `i64` value. I64(i64), - /// Matches any `NaN` `f64` value. NaN, - /// Matches any field whose `fmt::Debug` output is equal to a fixed string. - Debug(MatchDebug), - /// Matches any field whose `fmt::Debug` output matches a regular expression - /// pattern. Pat(Box<MatchPattern>), } @@ -106,9 +97,6 @@ impl Ord for ValueMatch { (Pat(this), Pat(that)) => this.cmp(that), (Pat(_), _) => Ordering::Greater, - - (Debug(this), Debug(that)) => this.cmp(that), - (Debug(_), _) => Ordering::Greater, } } } @@ -119,25 +107,12 @@ impl PartialOrd for ValueMatch { } } -/// Matches a field's `fmt::Debug` output against a regular expression pattern. -/// -/// This is used for matching all non-literal field value filters when regular -/// expressions are enabled. #[derive(Debug, Clone)] pub(crate) struct MatchPattern { pub(crate) matcher: Pattern, pattern: Arc<str>, } -/// Matches a field's `fmt::Debug` output against a fixed string pattern. -/// -/// This is used for matching all non-literal field value filters when regular -/// expressions are disabled. -#[derive(Debug, Clone)] -pub(crate) struct MatchDebug { - pattern: Arc<str>, -} - /// Indicates that a field name specified in a filter directive was invalid. #[derive(Clone, Debug)] #[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))] @@ -147,17 +122,9 @@ pub struct BadName { // === impl Match === -impl Match { - pub(crate) fn has_value(&self) -> bool { - self.value.is_some() - } - - // TODO: reference count these strings? - pub(crate) fn name(&self) -> String { - self.name.clone() - } - - pub(crate) fn parse(s: &str, regex: bool) -> Result<Self, Box<dyn Error + Send + Sync>> { +impl FromStr for Match { + type Err = Box<dyn Error + Send + Sync>; + fn from_str(s: &str) -> Result<Self, Self::Err> { let mut parts = s.split('='); let name = parts .next() @@ -166,17 +133,22 @@ impl Match { })? // TODO: validate field name .to_string(); - let value = parts - .next() - .map(|part| match regex { - true => ValueMatch::parse_regex(part), - false => Ok(ValueMatch::parse_non_regex(part)), - }) - .transpose()?; + let value = parts.next().map(ValueMatch::from_str).transpose()?; Ok(Match { name, value }) } } +impl Match { + pub(crate) fn has_value(&self) -> bool { + self.value.is_some() + } + + // TODO: reference count these strings? + pub(crate) fn name(&self) -> String { + self.name.clone() + } +} + impl fmt::Display for Match { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.name, f)?; @@ -227,14 +199,9 @@ fn value_match_f64(v: f64) -> ValueMatch { } } -impl ValueMatch { - /// Parse a `ValueMatch` that will match `fmt::Debug` fields using regular - /// expressions. - /// - /// This returns an error if the string didn't contain a valid `bool`, - /// `u64`, `i64`, or `f64` literal, and couldn't be parsed as a regular - /// expression. - fn parse_regex(s: &str) -> Result<Self, matchers::Error> { +impl FromStr for ValueMatch { + type Err = matchers::Error; + fn from_str(s: &str) -> Result<Self, Self::Err> { s.parse::<bool>() .map(ValueMatch::Bool) .or_else(|_| s.parse::<u64>().map(ValueMatch::U64)) @@ -245,21 +212,6 @@ impl ValueMatch { .map(|p| ValueMatch::Pat(Box::new(p))) }) } - - /// Parse a `ValueMatch` that will match `fmt::Debug` against a fixed - /// string. - /// - /// This does *not* return an error, because any string that isn't a valid - /// `bool`, `u64`, `i64`, or `f64` literal is treated as expected - /// `fmt::Debug` output. - fn parse_non_regex(s: &str) -> Self { - s.parse::<bool>() - .map(ValueMatch::Bool) - .or_else(|_| s.parse::<u64>().map(ValueMatch::U64)) - .or_else(|_| s.parse::<i64>().map(ValueMatch::I64)) - .or_else(|_| s.parse::<f64>().map(value_match_f64)) - .unwrap_or_else(|_| ValueMatch::Debug(MatchDebug::new(s))) - } } impl fmt::Display for ValueMatch { @@ -270,7 +222,6 @@ impl fmt::Display for ValueMatch { ValueMatch::NaN => fmt::Display::fmt(&std::f64::NAN, f), ValueMatch::I64(ref inner) => fmt::Display::fmt(inner, f), ValueMatch::U64(ref inner) => fmt::Display::fmt(inner, f), - ValueMatch::Debug(ref inner) => fmt::Display::fmt(inner, f), ValueMatch::Pat(ref inner) => fmt::Display::fmt(inner, f), } } @@ -313,12 +264,6 @@ impl MatchPattern { fn debug_matches(&self, d: &impl fmt::Debug) -> bool { self.matcher.debug_matches(d) } - - pub(super) fn into_debug_match(self) -> MatchDebug { - MatchDebug { - pattern: self.pattern, - } - } } impl PartialEq for MatchPattern { @@ -344,102 +289,6 @@ impl Ord for MatchPattern { } } -// === impl MatchDebug === - -impl MatchDebug { - fn new(s: &str) -> Self { - Self { - pattern: s.to_owned().into(), - } - } - - #[inline] - fn debug_matches(&self, d: &impl fmt::Debug) -> bool { - // Naively, we would probably match a value's `fmt::Debug` output by - // formatting it to a string, and then checking if the string is equal - // to the expected pattern. However, this would require allocating every - // time we want to match a field value against a `Debug` matcher, which - // can be avoided. - // - // Instead, we implement `fmt::Write` for a type that, rather than - // actually _writing_ the strings to something, matches them against the - // expected pattern, and returns an error if the pattern does not match. - struct Matcher<'a> { - pattern: &'a str, - } - - impl fmt::Write for Matcher<'_> { - fn write_str(&mut self, s: &str) -> fmt::Result { - // If the string is longer than the remaining expected string, - // we know it won't match, so bail. - if s.len() > self.pattern.len() { - return Err(fmt::Error); - } - - // If the expected string begins with the string that was - // written, we are still potentially a match. Advance the - // position in the expected pattern to chop off the matched - // output, and continue. - if self.pattern.starts_with(s) { - self.pattern = &self.pattern[s.len()..]; - return Ok(()); - } - - // Otherwise, the expected string doesn't include the string - // that was written at the current position, so the `fmt::Debug` - // output doesn't match! Return an error signalling that this - // doesn't match. - Err(fmt::Error) - } - } - let mut matcher = Matcher { - pattern: &self.pattern, - }; - - // Try to "write" the value's `fmt::Debug` output to a `Matcher`. This - // returns an error if the `fmt::Debug` implementation wrote any - // characters that did not match the expected pattern. - write!(matcher, "{:?}", d).is_ok() - } -} - -impl fmt::Display for MatchDebug { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&*self.pattern, f) - } -} - -impl AsRef<str> for MatchDebug { - #[inline] - fn as_ref(&self) -> &str { - self.pattern.as_ref() - } -} - -impl PartialEq for MatchDebug { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.pattern == other.pattern - } -} - -impl Eq for MatchDebug {} - -impl PartialOrd for MatchDebug { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - Some(self.pattern.cmp(&other.pattern)) - } -} - -impl Ord for MatchDebug { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - self.pattern.cmp(&other.pattern) - } -} - // === impl BadName === impl Error for BadName {} @@ -552,9 +401,6 @@ impl<'a> Visit for MatchVisitor<'a> { Some((ValueMatch::Pat(ref e), ref matched)) if e.str_matches(&value) => { matched.store(true, Release); } - Some((ValueMatch::Debug(ref e), ref matched)) if e.debug_matches(&value) => { - matched.store(true, Release) - } _ => {} } } @@ -564,63 +410,7 @@ impl<'a> Visit for MatchVisitor<'a> { Some((ValueMatch::Pat(ref e), ref matched)) if e.debug_matches(&value) => { matched.store(true, Release); } - Some((ValueMatch::Debug(ref e), ref matched)) if e.debug_matches(&value) => { - matched.store(true, Release) - } _ => {} } } } - -#[cfg(test)] -mod tests { - use super::*; - #[derive(Debug)] - #[allow(dead_code)] - struct MyStruct { - answer: usize, - question: &'static str, - } - - #[test] - fn debug_struct_match() { - let my_struct = MyStruct { - answer: 42, - question: "life, the universe, and everything", - }; - - let pattern = "MyStruct { answer: 42, question: \"life, the universe, and everything\" }"; - - assert_eq!( - format!("{:?}", my_struct), - pattern, - "`MyStruct`'s `Debug` impl doesn't output the expected string" - ); - - let matcher = MatchDebug { - pattern: pattern.into(), - }; - assert!(matcher.debug_matches(&my_struct)) - } - - #[test] - fn debug_struct_not_match() { - let my_struct = MyStruct { - answer: 42, - question: "what shall we have for lunch?", - }; - - let pattern = "MyStruct { answer: 42, question: \"life, the universe, and everything\" }"; - - assert_eq!( - format!("{:?}", my_struct), - "MyStruct { answer: 42, question: \"what shall we have for lunch?\" }", - "`MyStruct`'s `Debug` impl doesn't output the expected string" - ); - - let matcher = MatchDebug { - pattern: pattern.into(), - }; - assert!(!matcher.debug_matches(&my_struct)) - } -} diff --git a/vendor/tracing-subscriber/src/filter/env/mod.rs b/vendor/tracing-subscriber-0.3.3/src/filter/env/mod.rs index 81a9ae2bd..81fe0e62d 100644 --- a/vendor/tracing-subscriber/src/filter/env/mod.rs +++ b/vendor/tracing-subscriber-0.3.3/src/filter/env/mod.rs @@ -4,8 +4,7 @@ // these are publicly re-exported, but the compiler doesn't realize // that for some reason. #[allow(unreachable_pub)] -pub use self::{builder::Builder, directive::Directive, field::BadName as BadFieldName}; -mod builder; +pub use self::{directive::Directive, field::BadName as BadFieldName}; mod directive; mod field; @@ -16,7 +15,6 @@ use crate::{ }; use directive::ParseError; use std::{cell::RefCell, collections::HashMap, env, error::Error, fmt, str::FromStr}; -use thread_local::ThreadLocal; use tracing_core::{ callsite, field::Field, @@ -28,16 +26,6 @@ use tracing_core::{ /// A [`Layer`] which filters spans and events based on a set of filter /// directives. /// -/// `EnvFilter` implements both the [`Layer`](#impl-Layer<S>) and [`Filter`] traits, so it may -/// be used for both [global filtering][global] and [per-layer filtering][plf], -/// respectively. See [the documentation on filtering with `Layer`s][filtering] -/// for details. -/// -/// The [`Targets`] type implements a similar form of filtering, but without the -/// ability to dynamically enable events based on the current span context, and -/// without filtering on field values. When these features are not required, -/// [`Targets`] provides a lighter-weight alternative to [`EnvFilter`]. -/// /// # Directives /// /// A filter consists of one or more comma-separated directives which match on [`Span`]s and [`Event`]s. @@ -64,27 +52,10 @@ use tracing_core::{ /// and will match on any [`Span`] or [`Event`] that has a field with that name. /// For example: `[span{field=\"value\"}]=debug`, `[{field}]=trace`. /// - `value` matches on the value of a span's field. If a value is a numeric literal or a bool, -/// it will match _only_ on that value. Otherwise, this filter matches the -/// [`std::fmt::Debug`] output from the value. +/// it will match _only_ on that value. Otherwise, this filter acts as a regex on +/// the `std::fmt::Debug` output from the value. /// - `level` sets a maximum verbosity level accepted by this directive. /// -/// When a field value directive (`[{<FIELD NAME>=<FIELD_VALUE>}]=...`) matches a -/// value's [`std::fmt::Debug`] output (i.e., the field value in the directive -/// is not a `bool`, `i64`, `u64`, or `f64` literal), the matched pattern may be -/// interpreted as either a regular expression or as the precise expected -/// output of the field's [`std::fmt::Debug`] implementation. By default, these -/// filters are interpreted as regular expressions, but this can be disabled -/// using the [`Builder::with_regex`] builder method to use precise matching -/// instead. -/// -/// When field value filters are interpreted as regular expressions, the -/// [`regex-automata` crate's regular expression syntax][re-syntax] is -/// supported. -/// -/// **Note**: When filters are constructed from potentially untrusted inputs, -/// [disabling regular expression matching](Builder::with_regex) is strongly -/// recommended. -/// /// ## Usage Notes /// /// - The portion of the directive which is included within the square brackets is `tracing`-specific. @@ -101,7 +72,7 @@ use tracing_core::{ /// - A dash in a target will only appear when being specified explicitly: /// `tracing::info!(target: "target-name", ...);` /// -/// ## Example Syntax +/// ## Examples /// /// - `tokio::net=info` will enable all spans or events that: /// - have the `tokio::net` target, @@ -118,68 +89,10 @@ use tracing_core::{ /// - which has a field named `name` with value `bob`, /// - at _any_ level. /// -/// # Examples -/// -/// Parsing an `EnvFilter` from the [default environment -/// variable](EnvFilter::from_default_env) (`RUST_LOG`): -/// -/// ``` -/// use tracing_subscriber::{EnvFilter, fmt, prelude::*}; -/// -/// tracing_subscriber::registry() -/// .with(fmt::layer()) -/// .with(EnvFilter::from_default_env()) -/// .init(); -/// ``` -/// -/// Parsing an `EnvFilter` [from a user-provided environment -/// variable](EnvFilter::from_env): -/// -/// ``` -/// use tracing_subscriber::{EnvFilter, fmt, prelude::*}; -/// -/// tracing_subscriber::registry() -/// .with(fmt::layer()) -/// .with(EnvFilter::from_env("MYAPP_LOG")) -/// .init(); -/// ``` -/// -/// Using `EnvFilter` as a [per-layer filter][plf] to filter only a single -/// [`Layer`]: -/// -/// ``` -/// use tracing_subscriber::{EnvFilter, fmt, prelude::*}; -/// -/// // Parse an `EnvFilter` configuration from the `RUST_LOG` -/// // environment variable. -/// let filter = EnvFilter::from_default_env(); -/// -/// // Apply the filter to this layer *only*. -/// let filtered_layer = fmt::layer().with_filter(filter); -/// -/// // Some other layer, whose output we don't want to filter. -/// let unfiltered_layer = // ... -/// # fmt::layer(); -/// -/// tracing_subscriber::registry() -/// .with(filtered_layer) -/// .with(unfiltered_layer) -/// .init(); -/// ``` -/// # Constructing `EnvFilter`s -/// -/// An `EnvFilter` is be constructed by parsing a string containing one or more -/// directives. The [`EnvFilter::new`] constructor parses an `EnvFilter` from a -/// string, ignoring any invalid directives, while [`EnvFilter::try_new`] -/// returns an error if invalid directives are encountered. Similarly, the -/// [`EnvFilter::from_env`] and [`EnvFilter::try_from_env`] constructors parse -/// an `EnvFilter` from the value of the provided environment variable, with -/// lossy and strict validation, respectively. -/// -/// A [builder](EnvFilter::builder) interface is available to set additional -/// configuration options prior to parsing an `EnvFilter`. See the [`Builder` -/// type's documentation](Builder) for details on the options that can be -/// configured using the builder. +/// The [`Targets`] type implements a similar form of filtering, but without the +/// ability to dynamically enable events based on the current span context, and +/// without filtering on field values. When these features are not required, +/// [`Targets`] provides a lighter-weight alternative to [`EnvFilter`]. /// /// [`Span`]: tracing_core::span /// [fields]: tracing_core::Field @@ -187,11 +100,6 @@ use tracing_core::{ /// [`level`]: tracing_core::Level /// [`Metadata`]: tracing_core::Metadata /// [`Targets`]: crate::filter::Targets -/// [`env_logger`]: https://crates.io/crates/env_logger -/// [`Filter`]: #impl-Filter<S> -/// [global]: crate::layer#global-filtering -/// [plf]: crate::layer#per-layer-filtering -/// [filtering]: crate::layer#filtering-with-layers #[cfg_attr(docsrs, doc(cfg(all(feature = "env-filter", feature = "std"))))] #[derive(Debug)] pub struct EnvFilter { @@ -200,8 +108,10 @@ pub struct EnvFilter { has_dynamics: bool, by_id: RwLock<HashMap<span::Id, directive::SpanMatcher>>, by_cs: RwLock<HashMap<callsite::Identifier, directive::CallsiteMatcher>>, - scope: ThreadLocal<RefCell<Vec<LevelFilter>>>, - regex: bool, +} + +thread_local! { + static SCOPE: RefCell<Vec<LevelFilter>> = RefCell::new(Vec::new()); } type FieldMap<T> = HashMap<Field, T>; @@ -224,181 +134,58 @@ impl EnvFilter { /// `RUST_LOG` is the default environment variable used by /// [`EnvFilter::from_default_env`] and [`EnvFilter::try_from_default_env`]. /// - /// [`EnvFilter::from_default_env`]: EnvFilter::from_default_env() - /// [`EnvFilter::try_from_default_env`]: EnvFilter::try_from_default_env() + /// [`EnvFilter::from_default_env`]: #method.from_default_env + /// [`EnvFilter::try_from_default_env`]: #method.try_from_default_env pub const DEFAULT_ENV: &'static str = "RUST_LOG"; - // === constructors, etc === - - /// Returns a [builder] that can be used to configure a new [`EnvFilter`] - /// instance. - /// - /// The [`Builder`] type is used to set additional configurations, such as - /// [whether regular expressions are enabled](Builder::with_regex) or [the - /// default directive](Builder::with_default_directive) before parsing an - /// [`EnvFilter`] from a string or environment variable. - /// - /// [builder]: https://rust-unofficial.github.io/patterns/patterns/creational/builder.html - pub fn builder() -> Builder { - Builder::default() - } - /// Returns a new `EnvFilter` from the value of the `RUST_LOG` environment /// variable, ignoring any invalid filter directives. - /// - /// If the environment variable is empty or not set, or if it contains only - /// invalid directives, a default directive enabling the [`ERROR`] level is - /// added. - /// - /// To set additional configuration options prior to parsing the filter, use - /// the [`Builder`] type instead. - /// - /// This function is equivalent to the following: - /// - /// ```rust - /// use tracing_subscriber::filter::{EnvFilter, LevelFilter}; - /// - /// # fn docs() -> EnvFilter { - /// EnvFilter::builder() - /// .with_default_directive(LevelFilter::ERROR.into()) - /// .from_env_lossy() - /// # } - /// ``` - /// - /// [`ERROR`]: tracing::Level::ERROR pub fn from_default_env() -> Self { - Self::builder() - .with_default_directive(LevelFilter::ERROR.into()) - .from_env_lossy() + Self::from_env(Self::DEFAULT_ENV) } /// Returns a new `EnvFilter` from the value of the given environment /// variable, ignoring any invalid filter directives. - /// - /// If the environment variable is empty or not set, or if it contains only - /// invalid directives, a default directive enabling the [`ERROR`] level is - /// added. - /// - /// To set additional configuration options prior to parsing the filter, use - /// the [`Builder`] type instead. - /// - /// This function is equivalent to the following: - /// - /// ```rust - /// use tracing_subscriber::filter::{EnvFilter, LevelFilter}; - /// - /// # fn docs() -> EnvFilter { - /// # let env = ""; - /// EnvFilter::builder() - /// .with_default_directive(LevelFilter::ERROR.into()) - /// .with_env_var(env) - /// .from_env_lossy() - /// # } - /// ``` - /// - /// [`ERROR`]: tracing::Level::ERROR pub fn from_env<A: AsRef<str>>(env: A) -> Self { - Self::builder() - .with_default_directive(LevelFilter::ERROR.into()) - .with_env_var(env.as_ref()) - .from_env_lossy() + env::var(env.as_ref()).map(Self::new).unwrap_or_default() } /// Returns a new `EnvFilter` from the directives in the given string, /// ignoring any that are invalid. - /// - /// If the string is empty or contains only invalid directives, a default - /// directive enabling the [`ERROR`] level is added. - /// - /// To set additional configuration options prior to parsing the filter, use - /// the [`Builder`] type instead. - /// - /// This function is equivalent to the following: - /// - /// ```rust - /// use tracing_subscriber::filter::{EnvFilter, LevelFilter}; - /// - /// # fn docs() -> EnvFilter { - /// # let directives = ""; - /// EnvFilter::builder() - /// .with_default_directive(LevelFilter::ERROR.into()) - /// .parse_lossy(directives) - /// # } - /// ``` - /// - /// [`ERROR`]: tracing::Level::ERROR - pub fn new<S: AsRef<str>>(directives: S) -> Self { - Self::builder() - .with_default_directive(LevelFilter::ERROR.into()) - .parse_lossy(directives) + pub fn new<S: AsRef<str>>(dirs: S) -> Self { + let directives = dirs.as_ref().split(',').filter_map(|s| match s.parse() { + Ok(d) => Some(d), + Err(err) => { + eprintln!("ignoring `{}`: {}", s, err); + None + } + }); + Self::from_directives(directives) } /// Returns a new `EnvFilter` from the directives in the given string, /// or an error if any are invalid. - /// - /// If the string is empty, a default directive enabling the [`ERROR`] level - /// is added. - /// - /// To set additional configuration options prior to parsing the filter, use - /// the [`Builder`] type instead. - /// - /// This function is equivalent to the following: - /// - /// ```rust - /// use tracing_subscriber::filter::{EnvFilter, LevelFilter}; - /// - /// # fn docs() -> Result<EnvFilter, tracing_subscriber::filter::ParseError> { - /// # let directives = ""; - /// EnvFilter::builder() - /// .with_default_directive(LevelFilter::ERROR.into()) - /// .parse(directives) - /// # } - /// ``` - /// - /// [`ERROR`]: tracing::Level::ERROR pub fn try_new<S: AsRef<str>>(dirs: S) -> Result<Self, directive::ParseError> { - Self::builder().parse(dirs) + let directives = dirs + .as_ref() + .split(',') + .map(|s| s.parse()) + .collect::<Result<Vec<_>, _>>()?; + Ok(Self::from_directives(directives)) } /// Returns a new `EnvFilter` from the value of the `RUST_LOG` environment - /// variable, or an error if the environment variable is unset or contains - /// any invalid filter directives. - /// - /// To set additional configuration options prior to parsing the filter, use - /// the [`Builder`] type instead. - /// - /// This function is equivalent to the following: - /// - /// ```rust - /// use tracing_subscriber::EnvFilter; - /// - /// # fn docs() -> Result<EnvFilter, tracing_subscriber::filter::FromEnvError> { - /// EnvFilter::builder().try_from_env() - /// # } - /// ``` + /// variable, or an error if the environment variable contains any invalid + /// filter directives. pub fn try_from_default_env() -> Result<Self, FromEnvError> { - Self::builder().try_from_env() + Self::try_from_env(Self::DEFAULT_ENV) } /// Returns a new `EnvFilter` from the value of the given environment /// variable, or an error if the environment variable is unset or contains /// any invalid filter directives. - /// - /// To set additional configuration options prior to parsing the filter, use - /// the [`Builder`] type instead. - /// - /// This function is equivalent to the following: - /// - /// ```rust - /// use tracing_subscriber::EnvFilter; - /// - /// # fn docs() -> Result<EnvFilter, tracing_subscriber::filter::FromEnvError> { - /// # let env = ""; - /// EnvFilter::builder().with_env_var(env).try_from_env() - /// # } - /// ``` pub fn try_from_env<A: AsRef<str>>(env: A) -> Result<Self, FromEnvError> { - Self::builder().with_env_var(env.as_ref()).try_from_env() + env::var(env.as_ref())?.parse().map_err(Into::into) } /// Add a filtering directive to this `EnvFilter`. @@ -415,13 +202,13 @@ impl EnvFilter { /// and events as a previous filter, but sets a different level for those /// spans and events, the previous directive is overwritten. /// - /// [`LevelFilter`]: super::LevelFilter - /// [`Level`]: tracing_core::Level + /// [`LevelFilter`]: ../filter/struct.LevelFilter.html + /// [`Level`]: https://docs.rs/tracing-core/latest/tracing_core/struct.Level.html /// /// # Examples /// /// From [`LevelFilter`]: - /// + //// /// ```rust /// use tracing_subscriber::filter::{EnvFilter, LevelFilter}; /// let mut filter = EnvFilter::from_default_env() @@ -436,9 +223,9 @@ impl EnvFilter { /// let mut filter = EnvFilter::from_default_env() /// .add_directive(Level::INFO.into()); /// ``` - /// + //// /// Parsed from a string: - /// + //// /// ```rust /// use tracing_subscriber::filter::{EnvFilter, Directive}; /// @@ -449,15 +236,7 @@ impl EnvFilter { /// # Ok(()) /// # } /// ``` - /// In the above example, substitute `my_crate`, `module`, etc. with the - /// name your target crate/module is imported with. This might be - /// different from the package name in Cargo.toml (`-` is replaced by `_`). - /// Example, if the package name in your Cargo.toml is `MY-FANCY-LIB`, then - /// the corresponding Rust identifier would be `MY_FANCY_LIB`: - pub fn add_directive(mut self, mut directive: Directive) -> Self { - if !self.regex { - directive.deregexify(); - } + pub fn add_directive(mut self, directive: Directive) -> Self { if let Some(stat) = directive.to_static() { self.statics.add(stat) } else { @@ -467,19 +246,165 @@ impl EnvFilter { self } - // === filtering methods === + fn from_directives(directives: impl IntoIterator<Item = Directive>) -> Self { + use tracing::level_filters::STATIC_MAX_LEVEL; + use tracing::Level; + + let directives: Vec<_> = directives.into_iter().collect(); + + let disabled: Vec<_> = directives + .iter() + .filter(|directive| directive.level > STATIC_MAX_LEVEL) + .collect(); + + if !disabled.is_empty() { + #[cfg(feature = "ansi_term")] + use ansi_term::{Color, Style}; + // NOTE: We can't use a configured `MakeWriter` because the EnvFilter + // has no knowledge of any underlying subscriber or subscriber, which + // may or may not use a `MakeWriter`. + let warn = |msg: &str| { + #[cfg(not(feature = "ansi_term"))] + let msg = format!("warning: {}", msg); + #[cfg(feature = "ansi_term")] + let msg = { + let bold = Style::new().bold(); + let mut warning = Color::Yellow.paint("warning"); + warning.style_ref_mut().is_bold = true; + format!("{}{} {}", warning, bold.paint(":"), bold.paint(msg)) + }; + eprintln!("{}", msg); + }; + let ctx_prefixed = |prefix: &str, msg: &str| { + #[cfg(not(feature = "ansi_term"))] + let msg = format!("note: {}", msg); + #[cfg(feature = "ansi_term")] + let msg = { + let mut equal = Color::Fixed(21).paint("="); // dark blue + equal.style_ref_mut().is_bold = true; + format!(" {} {} {}", equal, Style::new().bold().paint(prefix), msg) + }; + eprintln!("{}", msg); + }; + let ctx_help = |msg| ctx_prefixed("help:", msg); + let ctx_note = |msg| ctx_prefixed("note:", msg); + let ctx = |msg: &str| { + #[cfg(not(feature = "ansi_term"))] + let msg = format!("note: {}", msg); + #[cfg(feature = "ansi_term")] + let msg = { + let mut pipe = Color::Fixed(21).paint("|"); + pipe.style_ref_mut().is_bold = true; + format!(" {} {}", pipe, msg) + }; + eprintln!("{}", msg); + }; + warn("some trace filter directives would enable traces that are disabled statically"); + for directive in disabled { + let target = if let Some(target) = &directive.target { + format!("the `{}` target", target) + } else { + "all targets".into() + }; + let level = directive + .level + .into_level() + .expect("=off would not have enabled any filters"); + ctx(&format!( + "`{}` would enable the {} level for {}", + directive, level, target + )); + } + ctx_note(&format!("the static max level is `{}`", STATIC_MAX_LEVEL)); + let help_msg = || { + let (feature, filter) = match STATIC_MAX_LEVEL.into_level() { + Some(Level::TRACE) => unreachable!( + "if the max level is trace, no static filtering features are enabled" + ), + Some(Level::DEBUG) => ("max_level_debug", Level::TRACE), + Some(Level::INFO) => ("max_level_info", Level::DEBUG), + Some(Level::WARN) => ("max_level_warn", Level::INFO), + Some(Level::ERROR) => ("max_level_error", Level::WARN), + None => return ("max_level_off", String::new()), + }; + (feature, format!("{} ", filter)) + }; + let (feature, earlier_level) = help_msg(); + ctx_help(&format!( + "to enable {}logging, remove the `{}` feature", + earlier_level, feature + )); + } - /// Returns `true` if this `EnvFilter` would enable the provided `metadata` - /// in the current context. - /// - /// This is equivalent to calling the [`Layer::enabled`] or - /// [`Filter::enabled`] methods on `EnvFilter`'s implementations of those - /// traits, but it does not require the trait to be in scope. - pub fn enabled<S>(&self, metadata: &Metadata<'_>, _: Context<'_, S>) -> bool { + let (dynamics, mut statics) = Directive::make_tables(directives); + let has_dynamics = !dynamics.is_empty(); + + if statics.is_empty() && !has_dynamics { + statics.add(directive::StaticDirective::default()); + } + + Self { + statics, + dynamics, + has_dynamics, + by_id: RwLock::new(HashMap::new()), + by_cs: RwLock::new(HashMap::new()), + } + } + + fn cares_about_span(&self, span: &span::Id) -> bool { + let spans = try_lock!(self.by_id.read(), else return false); + spans.contains_key(span) + } + + fn base_interest(&self) -> Interest { + if self.has_dynamics { + Interest::sometimes() + } else { + Interest::never() + } + } +} + +impl<S: Subscriber> Layer<S> for EnvFilter { + fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest { + if self.has_dynamics && metadata.is_span() { + // If this metadata describes a span, first, check if there is a + // dynamic filter that should be constructed for it. If so, it + // should always be enabled, since it influences filtering. + if let Some(matcher) = self.dynamics.matcher(metadata) { + let mut by_cs = try_lock!(self.by_cs.write(), else return self.base_interest()); + by_cs.insert(metadata.callsite(), matcher); + return Interest::always(); + } + } + + // Otherwise, check if any of our static filters enable this metadata. + if self.statics.enabled(metadata) { + Interest::always() + } else { + self.base_interest() + } + } + + fn max_level_hint(&self) -> Option<LevelFilter> { + if self.dynamics.has_value_filters() { + // If we perform any filtering on span field *values*, we will + // enable *all* spans, because their field values are not known + // until recording. + return Some(LevelFilter::TRACE); + } + std::cmp::max( + self.statics.max_level.into(), + self.dynamics.max_level.into(), + ) + } + + fn enabled(&self, metadata: &Metadata<'_>, _: Context<'_, S>) -> bool { let level = metadata.level(); // is it possible for a dynamic filter directive to enable this event? - // if not, we can avoid the thread loca'l access + iterating over the + // if not, we can avoid the thread local access + iterating over the // spans in the current scope. if self.has_dynamics && self.dynamics.max_level >= *level { if metadata.is_span() { @@ -495,15 +420,14 @@ impl EnvFilter { } } - let enabled_by_scope = { - let scope = self.scope.get_or_default().borrow(); - for filter in &*scope { + let enabled_by_scope = SCOPE.with(|scope| { + for filter in scope.borrow().iter() { if filter >= level { return true; } } false - }; + }); if enabled_by_scope { return true; } @@ -519,33 +443,7 @@ impl EnvFilter { false } - /// Returns an optional hint of the highest [verbosity level][level] that - /// this `EnvFilter` will enable. - /// - /// This is equivalent to calling the [`Layer::max_level_hint`] or - /// [`Filter::max_level_hint`] methods on `EnvFilter`'s implementations of those - /// traits, but it does not require the trait to be in scope. - /// - /// [level]: tracing_core::metadata::Level - pub fn max_level_hint(&self) -> Option<LevelFilter> { - if self.dynamics.has_value_filters() { - // If we perform any filtering on span field *values*, we will - // enable *all* spans, because their field values are not known - // until recording. - return Some(LevelFilter::TRACE); - } - std::cmp::max( - self.statics.max_level.into(), - self.dynamics.max_level.into(), - ) - } - - /// Informs the filter that a new span was created. - /// - /// This is equivalent to calling the [`Layer::on_new_span`] or - /// [`Filter::on_new_span`] methods on `EnvFilter`'s implementations of those - /// traits, but it does not require the trait to be in scope. - pub fn on_new_span<S>(&self, attrs: &span::Attributes<'_>, id: &span::Id, _: Context<'_, S>) { + fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, _: Context<'_, S>) { let by_cs = try_lock!(self.by_cs.read()); if let Some(cs) = by_cs.get(&attrs.metadata().callsite()) { let span = cs.to_span_match(attrs); @@ -553,37 +451,28 @@ impl EnvFilter { } } - /// Informs the filter that the span with the provided `id` was entered. - /// - /// This is equivalent to calling the [`Layer::on_enter`] or - /// [`Filter::on_enter`] methods on `EnvFilter`'s implementations of those - /// traits, but it does not require the trait to be in scope. - pub fn on_enter<S>(&self, id: &span::Id, _: Context<'_, S>) { + fn on_record(&self, id: &span::Id, values: &span::Record<'_>, _: Context<'_, S>) { + if let Some(span) = try_lock!(self.by_id.read()).get(id) { + span.record_update(values); + } + } + + fn on_enter(&self, id: &span::Id, _: Context<'_, S>) { // XXX: This is where _we_ could push IDs to the stack instead, and use // that to allow changing the filter while a span is already entered. // But that might be much less efficient... if let Some(span) = try_lock!(self.by_id.read()).get(id) { - self.scope.get_or_default().borrow_mut().push(span.level()); + SCOPE.with(|scope| scope.borrow_mut().push(span.level())); } } - /// Informs the filter that the span with the provided `id` was exited. - /// - /// This is equivalent to calling the [`Layer::on_exit`] or - /// [`Filter::on_exit`] methods on `EnvFilter`'s implementations of those - /// traits, but it does not require the trait to be in scope. - pub fn on_exit<S>(&self, id: &span::Id, _: Context<'_, S>) { + fn on_exit(&self, id: &span::Id, _: Context<'_, S>) { if self.cares_about_span(id) { - self.scope.get_or_default().borrow_mut().pop(); + SCOPE.with(|scope| scope.borrow_mut().pop()); } } - /// Informs the filter that the span with the provided `id` was closed. - /// - /// This is equivalent to calling the [`Layer::on_close`] or - /// [`Filter::on_close`] methods on `EnvFilter`'s implementations of those - /// traits, but it does not require the trait to be in scope. - pub fn on_close<S>(&self, id: span::Id, _: Context<'_, S>) { + fn on_close(&self, id: span::Id, _: Context<'_, S>) { // If we don't need to acquire a write lock, avoid doing so. if !self.cares_about_span(&id) { return; @@ -592,140 +481,6 @@ impl EnvFilter { let mut spans = try_lock!(self.by_id.write()); spans.remove(&id); } - - /// Informs the filter that the span with the provided `id` recorded the - /// provided field `values`. - /// - /// This is equivalent to calling the [`Layer::on_record`] or - /// [`Filter::on_record`] methods on `EnvFilter`'s implementations of those - /// traits, but it does not require the trait to be in scope - pub fn on_record<S>(&self, id: &span::Id, values: &span::Record<'_>, _: Context<'_, S>) { - if let Some(span) = try_lock!(self.by_id.read()).get(id) { - span.record_update(values); - } - } - - fn cares_about_span(&self, span: &span::Id) -> bool { - let spans = try_lock!(self.by_id.read(), else return false); - spans.contains_key(span) - } - - fn base_interest(&self) -> Interest { - if self.has_dynamics { - Interest::sometimes() - } else { - Interest::never() - } - } - - fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest { - if self.has_dynamics && metadata.is_span() { - // If this metadata describes a span, first, check if there is a - // dynamic filter that should be constructed for it. If so, it - // should always be enabled, since it influences filtering. - if let Some(matcher) = self.dynamics.matcher(metadata) { - let mut by_cs = try_lock!(self.by_cs.write(), else return self.base_interest()); - by_cs.insert(metadata.callsite(), matcher); - return Interest::always(); - } - } - - // Otherwise, check if any of our static filters enable this metadata. - if self.statics.enabled(metadata) { - Interest::always() - } else { - self.base_interest() - } - } -} - -impl<S: Subscriber> Layer<S> for EnvFilter { - #[inline] - fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest { - EnvFilter::register_callsite(self, metadata) - } - - #[inline] - fn max_level_hint(&self) -> Option<LevelFilter> { - EnvFilter::max_level_hint(self) - } - - #[inline] - fn enabled(&self, metadata: &Metadata<'_>, ctx: Context<'_, S>) -> bool { - self.enabled(metadata, ctx) - } - - #[inline] - fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) { - self.on_new_span(attrs, id, ctx) - } - - #[inline] - fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) { - self.on_record(id, values, ctx); - } - - #[inline] - fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) { - self.on_enter(id, ctx); - } - - #[inline] - fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) { - self.on_exit(id, ctx); - } - - #[inline] - fn on_close(&self, id: span::Id, ctx: Context<'_, S>) { - self.on_close(id, ctx); - } -} - -feature! { - #![all(feature = "registry", feature = "std")] - use crate::layer::Filter; - - impl<S> Filter<S> for EnvFilter { - #[inline] - fn enabled(&self, meta: &Metadata<'_>, ctx: &Context<'_, S>) -> bool { - self.enabled(meta, ctx.clone()) - } - - #[inline] - fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest { - self.register_callsite(meta) - } - - #[inline] - fn max_level_hint(&self) -> Option<LevelFilter> { - EnvFilter::max_level_hint(self) - } - - #[inline] - fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) { - self.on_new_span(attrs, id, ctx) - } - - #[inline] - fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) { - self.on_record(id, values, ctx); - } - - #[inline] - fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) { - self.on_enter(id, ctx); - } - - #[inline] - fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) { - self.on_exit(id, ctx); - } - - #[inline] - fn on_close(&self, id: span::Id, ctx: Context<'_, S>) { - self.on_close(id, ctx); - } - } } impl FromStr for EnvFilter { @@ -747,7 +502,7 @@ where impl Default for EnvFilter { fn default() -> Self { - Builder::default().from_directives(std::iter::empty()) + Self::from_directives(std::iter::empty()) } } @@ -980,12 +735,4 @@ mod tests { [span2{bar=2 baz=false}],crate2[{quux=\"quuux\"}]=debug", ); } - - #[test] - fn parse_empty_string() { - // There is no corresponding test for [`Builder::parse_lossy`] as failed - // parsing does not produce any observable side effects. If this test fails - // check that [`Builder::parse_lossy`] is behaving correctly as well. - assert!(EnvFilter::builder().parse("").is_ok()); - } } diff --git a/vendor/tracing-subscriber/src/filter/env/builder.rs b/vendor/tracing-subscriber/src/filter/env/builder.rs deleted file mode 100644 index 36b520543..000000000 --- a/vendor/tracing-subscriber/src/filter/env/builder.rs +++ /dev/null @@ -1,324 +0,0 @@ -use super::{ - directive::{self, Directive}, - EnvFilter, FromEnvError, -}; -use crate::sync::RwLock; -use std::env; -use thread_local::ThreadLocal; -use tracing::level_filters::STATIC_MAX_LEVEL; - -/// A [builder] for constructing new [`EnvFilter`]s. -/// -/// [builder]: https://rust-unofficial.github.io/patterns/patterns/creational/builder.html -#[derive(Debug, Clone)] -pub struct Builder { - regex: bool, - env: Option<String>, - default_directive: Option<Directive>, -} - -impl Builder { - /// Sets whether span field values can be matched with regular expressions. - /// - /// If this is `true`, field filter directives will be interpreted as - /// regular expressions if they are not able to be interpreted as a `bool`, - /// `i64`, `u64`, or `f64` literal. If this is `false,` those field values - /// will be interpreted as literal [`std::fmt::Debug`] output instead. - /// - /// By default, regular expressions are enabled. - /// - /// **Note**: when [`EnvFilter`]s are constructed from untrusted inputs, - /// disabling regular expressions is strongly encouraged. - pub fn with_regex(self, regex: bool) -> Self { - Self { regex, ..self } - } - - /// Sets a default [filtering directive] that will be added to the filter if - /// the parsed string or environment variable contains no filter directives. - /// - /// By default, there is no default directive. - /// - /// # Examples - /// - /// If [`parse`], [`parse_lossy`], [`from_env`], or [`from_env_lossy`] are - /// called with an empty string or environment variable, the default - /// directive is used instead: - /// - /// ```rust - /// # fn main() -> Result<(), Box<dyn std::error::Error>> { - /// use tracing_subscriber::filter::{EnvFilter, LevelFilter}; - /// - /// let filter = EnvFilter::builder() - /// .with_default_directive(LevelFilter::INFO.into()) - /// .parse("")?; - /// - /// assert_eq!(format!("{}", filter), "info"); - /// # Ok(()) } - /// ``` - /// - /// Note that the `lossy` variants ([`parse_lossy`] and [`from_env_lossy`]) - /// will ignore any invalid directives. If all directives in a filter - /// string or environment variable are invalid, those methods will also use - /// the default directive: - /// - /// ```rust - /// use tracing_subscriber::filter::{EnvFilter, LevelFilter}; - /// - /// let filter = EnvFilter::builder() - /// .with_default_directive(LevelFilter::INFO.into()) - /// .parse_lossy("some_target=fake level,foo::bar=lolwut"); - /// - /// assert_eq!(format!("{}", filter), "info"); - /// ``` - /// - /// - /// If the string or environment variable contains valid filtering - /// directives, the default directive is not used: - /// - /// ```rust - /// use tracing_subscriber::filter::{EnvFilter, LevelFilter}; - /// - /// let filter = EnvFilter::builder() - /// .with_default_directive(LevelFilter::INFO.into()) - /// .parse_lossy("foo=trace"); - /// - /// // The default directive is *not* used: - /// assert_eq!(format!("{}", filter), "foo=trace"); - /// ``` - /// - /// Parsing a more complex default directive from a string: - /// - /// ```rust - /// # fn main() -> Result<(), Box<dyn std::error::Error>> { - /// use tracing_subscriber::filter::{EnvFilter, LevelFilter}; - /// - /// let default = "myapp=debug".parse() - /// .expect("hard-coded default directive should be valid"); - /// - /// let filter = EnvFilter::builder() - /// .with_default_directive(default) - /// .parse("")?; - /// - /// assert_eq!(format!("{}", filter), "myapp=debug"); - /// # Ok(()) } - /// ``` - /// - /// [`parse_lossy`]: Self::parse_lossy - /// [`from_env_lossy`]: Self::from_env_lossy - /// [`parse`]: Self::parse - /// [`from_env`]: Self::from_env - pub fn with_default_directive(self, default_directive: Directive) -> Self { - Self { - default_directive: Some(default_directive), - ..self - } - } - - /// Sets the name of the environment variable used by the [`from_env`], - /// [`from_env_lossy`], and [`try_from_env`] methods. - /// - /// By default, this is the value of [`EnvFilter::DEFAULT_ENV`] - /// (`RUST_LOG`). - /// - /// [`from_env`]: Self::from_env - /// [`from_env_lossy`]: Self::from_env_lossy - /// [`try_from_env`]: Self::try_from_env - pub fn with_env_var(self, var: impl ToString) -> Self { - Self { - env: Some(var.to_string()), - ..self - } - } - - /// Returns a new [`EnvFilter`] from the directives in the given string, - /// *ignoring* any that are invalid. - pub fn parse_lossy<S: AsRef<str>>(&self, dirs: S) -> EnvFilter { - let directives = dirs - .as_ref() - .split(',') - .filter(|s| !s.is_empty()) - .filter_map(|s| match Directive::parse(s, self.regex) { - Ok(d) => Some(d), - Err(err) => { - eprintln!("ignoring `{}`: {}", s, err); - None - } - }); - self.from_directives(directives) - } - - /// Returns a new [`EnvFilter`] from the directives in the given string, - /// or an error if any are invalid. - pub fn parse<S: AsRef<str>>(&self, dirs: S) -> Result<EnvFilter, directive::ParseError> { - let dirs = dirs.as_ref(); - if dirs.is_empty() { - return Ok(self.from_directives(std::iter::empty())); - } - let directives = dirs - .split(',') - .filter(|s| !s.is_empty()) - .map(|s| Directive::parse(s, self.regex)) - .collect::<Result<Vec<_>, _>>()?; - Ok(self.from_directives(directives)) - } - - /// Returns a new [`EnvFilter`] from the directives in the configured - /// environment variable, ignoring any directives that are invalid. - pub fn from_env_lossy(&self) -> EnvFilter { - let var = env::var(self.env_var_name()).unwrap_or_default(); - self.parse_lossy(var) - } - - /// Returns a new [`EnvFilter`] from the directives in the in the configured - /// environment variable, or an error if the environment variable is not set - /// or contains invalid directives. - pub fn from_env(&self) -> Result<EnvFilter, FromEnvError> { - let var = env::var(self.env_var_name()).unwrap_or_default(); - self.parse(var).map_err(Into::into) - } - - /// Returns a new [`EnvFilter`] from the directives in the in the configured - /// environment variable, or an error if the environment variable is not set - /// or contains invalid directives. - pub fn try_from_env(&self) -> Result<EnvFilter, FromEnvError> { - let var = env::var(self.env_var_name())?; - self.parse(var).map_err(Into::into) - } - - // TODO(eliza): consider making this a public API? - // Clippy doesn't love this naming, because it suggests that `from_` methods - // should not take a `Self`...but in this case, it's the `EnvFilter` that is - // being constructed "from" the directives, rather than the builder itself. - #[allow(clippy::wrong_self_convention)] - pub(super) fn from_directives( - &self, - directives: impl IntoIterator<Item = Directive>, - ) -> EnvFilter { - use tracing::Level; - - let mut directives: Vec<_> = directives.into_iter().collect(); - let mut disabled = Vec::new(); - for directive in &mut directives { - if directive.level > STATIC_MAX_LEVEL { - disabled.push(directive.clone()); - } - if !self.regex { - directive.deregexify(); - } - } - - if !disabled.is_empty() { - #[cfg(feature = "ansi_term")] - use ansi_term::{Color, Style}; - // NOTE: We can't use a configured `MakeWriter` because the EnvFilter - // has no knowledge of any underlying subscriber or collector, which - // may or may not use a `MakeWriter`. - let warn = |msg: &str| { - #[cfg(not(feature = "ansi_term"))] - let msg = format!("warning: {}", msg); - #[cfg(feature = "ansi_term")] - let msg = { - let bold = Style::new().bold(); - let mut warning = Color::Yellow.paint("warning"); - warning.style_ref_mut().is_bold = true; - format!("{}{} {}", warning, bold.paint(":"), bold.paint(msg)) - }; - eprintln!("{}", msg); - }; - let ctx_prefixed = |prefix: &str, msg: &str| { - #[cfg(not(feature = "ansi_term"))] - let msg = format!("{} {}", prefix, msg); - #[cfg(feature = "ansi_term")] - let msg = { - let mut equal = Color::Fixed(21).paint("="); // dark blue - equal.style_ref_mut().is_bold = true; - format!(" {} {} {}", equal, Style::new().bold().paint(prefix), msg) - }; - eprintln!("{}", msg); - }; - let ctx_help = |msg| ctx_prefixed("help:", msg); - let ctx_note = |msg| ctx_prefixed("note:", msg); - let ctx = |msg: &str| { - #[cfg(not(feature = "ansi_term"))] - let msg = format!("note: {}", msg); - #[cfg(feature = "ansi_term")] - let msg = { - let mut pipe = Color::Fixed(21).paint("|"); - pipe.style_ref_mut().is_bold = true; - format!(" {} {}", pipe, msg) - }; - eprintln!("{}", msg); - }; - warn("some trace filter directives would enable traces that are disabled statically"); - for directive in disabled { - let target = if let Some(target) = &directive.target { - format!("the `{}` target", target) - } else { - "all targets".into() - }; - let level = directive - .level - .into_level() - .expect("=off would not have enabled any filters"); - ctx(&format!( - "`{}` would enable the {} level for {}", - directive, level, target - )); - } - ctx_note(&format!("the static max level is `{}`", STATIC_MAX_LEVEL)); - let help_msg = || { - let (feature, filter) = match STATIC_MAX_LEVEL.into_level() { - Some(Level::TRACE) => unreachable!( - "if the max level is trace, no static filtering features are enabled" - ), - Some(Level::DEBUG) => ("max_level_debug", Level::TRACE), - Some(Level::INFO) => ("max_level_info", Level::DEBUG), - Some(Level::WARN) => ("max_level_warn", Level::INFO), - Some(Level::ERROR) => ("max_level_error", Level::WARN), - None => return ("max_level_off", String::new()), - }; - (feature, format!("{} ", filter)) - }; - let (feature, earlier_level) = help_msg(); - ctx_help(&format!( - "to enable {}logging, remove the `{}` feature", - earlier_level, feature - )); - } - - let (dynamics, statics) = Directive::make_tables(directives); - let has_dynamics = !dynamics.is_empty(); - - let mut filter = EnvFilter { - statics, - dynamics, - has_dynamics, - by_id: RwLock::new(Default::default()), - by_cs: RwLock::new(Default::default()), - scope: ThreadLocal::new(), - regex: self.regex, - }; - - if !has_dynamics && filter.statics.is_empty() { - if let Some(ref default) = self.default_directive { - filter = filter.add_directive(default.clone()); - } - } - - filter - } - - fn env_var_name(&self) -> &str { - self.env.as_deref().unwrap_or(EnvFilter::DEFAULT_ENV) - } -} - -impl Default for Builder { - fn default() -> Self { - Self { - regex: true, - env: None, - default_directive: None, - } - } -} |