From cf94bdc0742c13e2a0cac864c478b8626b266e1b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:11:38 +0200 Subject: Merging upstream version 1.66.0+dfsg1. Signed-off-by: Daniel Baumann --- .../tracing-subscriber/src/filter/env/directive.rs | 860 --------------------- 1 file changed, 860 deletions(-) delete mode 100644 vendor/tracing-subscriber/src/filter/env/directive.rs (limited to 'vendor/tracing-subscriber/src/filter/env/directive.rs') diff --git a/vendor/tracing-subscriber/src/filter/env/directive.rs b/vendor/tracing-subscriber/src/filter/env/directive.rs deleted file mode 100644 index f062e6ef9..000000000 --- a/vendor/tracing-subscriber/src/filter/env/directive.rs +++ /dev/null @@ -1,860 +0,0 @@ -pub(crate) use crate::filter::directive::{FilterVec, ParseError, StaticDirective}; -use crate::filter::{ - directive::{DirectiveSet, Match}, - env::{field, FieldMap}, - level::LevelFilter, -}; -use once_cell::sync::Lazy; -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)] -#[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))] -pub struct Directive { - in_span: Option, - fields: Vec, - pub(crate) target: Option, - pub(crate) level: LevelFilter, -} - -/// A set of dynamic filtering directives. -pub(super) type Dynamics = DirectiveSet; - -/// A set of static filtering directives. -pub(super) type Statics = DirectiveSet; - -pub(crate) type CallsiteMatcher = MatchSet; -pub(crate) type SpanMatcher = MatchSet; - -#[derive(Debug, PartialEq, Eq)] -pub(crate) struct MatchSet { - field_matches: FilterVec, - base_level: LevelFilter, -} - -impl Directive { - pub(super) fn has_name(&self) -> bool { - self.in_span.is_some() - } - - pub(super) fn has_fields(&self) -> bool { - !self.fields.is_empty() - } - - pub(super) fn to_static(&self) -> Option { - if !self.is_static() { - return None; - } - - // TODO(eliza): these strings are all immutable; we should consider - // `Arc`ing them to make this more efficient... - let field_names = self.fields.iter().map(field::Match::name).collect(); - - Some(StaticDirective::new( - self.target.clone(), - field_names, - self.level, - )) - } - - fn is_static(&self) -> bool { - !self.has_name() && !self.fields.iter().any(field::Match::has_value) - } - - pub(super) fn is_dynamic(&self) -> bool { - self.has_name() || self.has_fields() - } - - pub(crate) fn field_matcher(&self, meta: &Metadata<'_>) -> Option { - let fieldset = meta.fields(); - let fields = self - .fields - .iter() - .filter_map( - |field::Match { - ref name, - ref value, - }| { - if let Some(field) = fieldset.field(name) { - let value = value.as_ref().cloned()?; - Some(Ok((field, value))) - } else { - Some(Err(())) - } - }, - ) - .collect::, ()>>() - .ok()?; - Some(field::CallsiteMatch { - fields, - level: self.level, - }) - } - - pub(super) fn make_tables( - directives: impl IntoIterator, - ) -> (Dynamics, Statics) { - // TODO(eliza): this could be made more efficient... - let (dyns, stats): (Vec, Vec) = - directives.into_iter().partition(Directive::is_dynamic); - let statics = stats - .into_iter() - .filter_map(|d| d.to_static()) - .chain(dyns.iter().filter_map(Directive::to_static)) - .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, - } - } - } - - pub(super) fn parse(from: &str, regex: bool) -> Result { - static DIRECTIVE_RE: Lazy = Lazy::new(|| Regex::new( - r"(?x) - ^(?P(?i:trace|debug|info|warn|error|off|[0-5]))$ | - # ^^^. - # `note: we match log level names case-insensitively - ^ - (?: # target name or span name - (?P[\w:-]+)|(?P\[[^\]]*\]) - ){1,2} - (?: # level or nothing - =(?P(?i:trace|debug|info|warn|error|off|[0-5]))? - # ^^^. - # `note: we match log level names case-insensitively - )? - $ - " - ) - .unwrap()); - static SPAN_PART_RE: Lazy = - Lazy::new(|| Regex::new(r#"(?P[^\]\{]+)?(?:\{(?P[^\}]*)\})?"#).unwrap()); - static FIELD_FILTER_RE: Lazy = - // 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()); - - let caps = DIRECTIVE_RE.captures(from).ok_or_else(ParseError::new)?; - - if let Some(level) = caps - .name("global_level") - .and_then(|s| s.as_str().parse().ok()) - { - return Ok(Directive { - level, - ..Default::default() - }); - } - - let target = caps.name("target").and_then(|c| { - let s = c.as_str(); - if s.parse::().is_ok() { - None - } else { - Some(s.to_owned()) - } - }); - - let (in_span, fields) = caps - .name("span") - .and_then(|cap| { - let cap = cap.as_str().trim_matches(|c| c == '[' || c == ']'); - let caps = SPAN_PART_RE.captures(cap)?; - let span = caps.name("name").map(|c| c.as_str().to_owned()); - let fields = caps - .name("fields") - .map(|c| { - FIELD_FILTER_RE - .find_iter(c.as_str()) - .map(|c| field::Match::parse(c.as_str(), regex)) - .collect::, _>>() - }) - .unwrap_or_else(|| Ok(Vec::new())); - Some((span, fields)) - }) - .unwrap_or_else(|| (None, Ok(Vec::new()))); - - let level = caps - .name("level") - .and_then(|l| l.as_str().parse().ok()) - // Setting the target without the level enables every level for that target - .unwrap_or(LevelFilter::TRACE); - - Ok(Self { - level, - target, - in_span, - fields: fields?, - }) - } -} - -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 { - Directive::parse(from, true) - } -} - -impl Default for Directive { - fn default() -> Self { - Directive { - level: LevelFilter::OFF, - target: None, - in_span: None, - fields: Vec::new(), - } - } -} - -impl PartialOrd for Directive { - fn partial_cmp(&self, other: &Directive) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Directive { - fn cmp(&self, other: &Directive) -> Ordering { - // We attempt to order directives by how "specific" they are. This - // ensures that we try the most specific directives first when - // attempting to match a piece of metadata. - - // First, we compare based on whether a target is specified, and the - // lengths of those targets if both have targets. - let ordering = self - .target - .as_ref() - .map(String::len) - .cmp(&other.target.as_ref().map(String::len)) - // Next compare based on the presence of span names. - .then_with(|| self.in_span.is_some().cmp(&other.in_span.is_some())) - // Then we compare how many fields are defined by each - // directive. - .then_with(|| self.fields.len().cmp(&other.fields.len())) - // Finally, we fall back to lexicographical ordering if the directives are - // equally specific. Although this is no longer semantically important, - // we need to define a total ordering to determine the directive's place - // in the BTreeMap. - .then_with(|| { - self.target - .cmp(&other.target) - .then_with(|| self.in_span.cmp(&other.in_span)) - .then_with(|| self.fields[..].cmp(&other.fields[..])) - }) - .reverse(); - - #[cfg(debug_assertions)] - { - if ordering == Ordering::Equal { - debug_assert_eq!( - self.target, other.target, - "invariant violated: Ordering::Equal must imply a.target == b.target" - ); - debug_assert_eq!( - self.in_span, other.in_span, - "invariant violated: Ordering::Equal must imply a.in_span == b.in_span" - ); - debug_assert_eq!( - self.fields, other.fields, - "invariant violated: Ordering::Equal must imply a.fields == b.fields" - ); - } - } - - ordering - } -} - -impl fmt::Display for Directive { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut wrote_any = false; - if let Some(ref target) = self.target { - fmt::Display::fmt(target, f)?; - wrote_any = true; - } - - if self.in_span.is_some() || !self.fields.is_empty() { - f.write_str("[")?; - - if let Some(ref span) = self.in_span { - fmt::Display::fmt(span, f)?; - } - - let mut fields = self.fields.iter(); - if let Some(field) = fields.next() { - write!(f, "{{{}", field)?; - for field in fields { - write!(f, ",{}", field)?; - } - f.write_str("}")?; - } - - f.write_str("]")?; - wrote_any = true; - } - - if wrote_any { - f.write_str("=")?; - } - - fmt::Display::fmt(&self.level, f) - } -} - -impl From for Directive { - fn from(level: LevelFilter) -> Self { - Self { - level, - ..Self::default() - } - } -} - -impl From for Directive { - fn from(level: Level) -> Self { - LevelFilter::from_level(level).into() - } -} - -// === impl Dynamics === - -impl Dynamics { - pub(crate) fn matcher(&self, metadata: &Metadata<'_>) -> Option { - let mut base_level = None; - let field_matches = self - .directives_for(metadata) - .filter_map(|d| { - if let Some(f) = d.field_matcher(metadata) { - return Some(f); - } - match base_level { - Some(ref b) if d.level > *b => base_level = Some(d.level), - None => base_level = Some(d.level), - _ => {} - } - None - }) - .collect(); - - if let Some(base_level) = base_level { - Some(CallsiteMatcher { - field_matches, - base_level, - }) - } else if !field_matches.is_empty() { - Some(CallsiteMatcher { - field_matches, - base_level: base_level.unwrap_or(LevelFilter::OFF), - }) - } else { - None - } - } - - pub(crate) fn has_value_filters(&self) -> bool { - self.directives() - .any(|d| d.fields.iter().any(|f| f.value.is_some())) - } -} - -// ===== impl DynamicMatch ===== - -impl CallsiteMatcher { - /// Create a new `SpanMatch` for a given instance of the matched callsite. - pub(crate) fn to_span_match(&self, attrs: &span::Attributes<'_>) -> SpanMatcher { - let field_matches = self - .field_matches - .iter() - .map(|m| { - let m = m.to_span_match(); - attrs.record(&mut m.visitor()); - m - }) - .collect(); - SpanMatcher { - field_matches, - base_level: self.base_level, - } - } -} - -impl SpanMatcher { - /// Returns the level currently enabled for this callsite. - pub(crate) fn level(&self) -> LevelFilter { - self.field_matches - .iter() - .filter_map(field::SpanMatch::filter) - .max() - .unwrap_or(self.base_level) - } - - pub(crate) fn record_update(&self, record: &span::Record<'_>) { - for m in &self.field_matches { - record.record(&mut m.visitor()) - } - } -} - -#[cfg(test)] -mod test { - use super::*; - - fn parse_directives(dirs: impl AsRef) -> Vec { - dirs.as_ref() - .split(',') - .filter_map(|s| s.parse().ok()) - .collect() - } - - fn expect_parse(dirs: impl AsRef) -> Vec { - dirs.as_ref() - .split(',') - .map(|s| { - s.parse() - .unwrap_or_else(|err| panic!("directive '{:?}' should parse: {}", s, err)) - }) - .collect() - } - - #[test] - fn directive_ordering_by_target_len() { - // TODO(eliza): it would be nice to have a property-based test for this - // instead. - let mut dirs = expect_parse( - "foo::bar=debug,foo::bar::baz=trace,foo=info,a_really_long_name_with_no_colons=warn", - ); - dirs.sort_unstable(); - - let expected = vec![ - "a_really_long_name_with_no_colons", - "foo::bar::baz", - "foo::bar", - "foo", - ]; - let sorted = dirs - .iter() - .map(|d| d.target.as_ref().unwrap()) - .collect::>(); - - assert_eq!(expected, sorted); - } - #[test] - fn directive_ordering_by_span() { - // TODO(eliza): it would be nice to have a property-based test for this - // instead. - let mut dirs = expect_parse("bar[span]=trace,foo=debug,baz::quux=info,a[span]=warn"); - dirs.sort_unstable(); - - let expected = vec!["baz::quux", "bar", "foo", "a"]; - let sorted = dirs - .iter() - .map(|d| d.target.as_ref().unwrap()) - .collect::>(); - - assert_eq!(expected, sorted); - } - - #[test] - fn directive_ordering_uses_lexicographic_when_equal() { - // TODO(eliza): it would be nice to have a property-based test for this - // instead. - let mut dirs = expect_parse("span[b]=debug,b=debug,a=trace,c=info,span[a]=info"); - dirs.sort_unstable(); - - let expected = vec![ - ("span", Some("b")), - ("span", Some("a")), - ("c", None), - ("b", None), - ("a", None), - ]; - let sorted = dirs - .iter() - .map(|d| { - ( - d.target.as_ref().unwrap().as_ref(), - d.in_span.as_ref().map(String::as_ref), - ) - }) - .collect::>(); - - assert_eq!(expected, sorted); - } - - // TODO: this test requires the parser to support directives with multiple - // fields, which it currently can't handle. We should enable this test when - // that's implemented. - #[test] - #[ignore] - fn directive_ordering_by_field_num() { - // TODO(eliza): it would be nice to have a property-based test for this - // instead. - let mut dirs = expect_parse( - "b[{foo,bar}]=info,c[{baz,quuux,quuux}]=debug,a[{foo}]=warn,bar[{field}]=trace,foo=debug,baz::quux=info" - ); - dirs.sort_unstable(); - - let expected = vec!["baz::quux", "bar", "foo", "c", "b", "a"]; - let sorted = dirs - .iter() - .map(|d| d.target.as_ref().unwrap()) - .collect::>(); - - assert_eq!(expected, sorted); - } - - #[test] - fn parse_directives_ralith() { - let dirs = parse_directives("common=trace,server=trace"); - assert_eq!(dirs.len(), 2, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("common".to_string())); - assert_eq!(dirs[0].level, LevelFilter::TRACE); - assert_eq!(dirs[0].in_span, None); - - assert_eq!(dirs[1].target, Some("server".to_string())); - assert_eq!(dirs[1].level, LevelFilter::TRACE); - assert_eq!(dirs[1].in_span, None); - } - - #[test] - fn parse_directives_ralith_uc() { - let dirs = parse_directives("common=INFO,server=DEBUG"); - assert_eq!(dirs.len(), 2, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("common".to_string())); - assert_eq!(dirs[0].level, LevelFilter::INFO); - assert_eq!(dirs[0].in_span, None); - - assert_eq!(dirs[1].target, Some("server".to_string())); - assert_eq!(dirs[1].level, LevelFilter::DEBUG); - assert_eq!(dirs[1].in_span, None); - } - - #[test] - fn parse_directives_ralith_mixed() { - let dirs = parse_directives("common=iNfo,server=dEbUg"); - assert_eq!(dirs.len(), 2, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("common".to_string())); - assert_eq!(dirs[0].level, LevelFilter::INFO); - assert_eq!(dirs[0].in_span, None); - - assert_eq!(dirs[1].target, Some("server".to_string())); - assert_eq!(dirs[1].level, LevelFilter::DEBUG); - assert_eq!(dirs[1].in_span, None); - } - - #[test] - fn parse_directives_valid() { - let dirs = parse_directives("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off"); - assert_eq!(dirs.len(), 4, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("crate1::mod1".to_string())); - assert_eq!(dirs[0].level, LevelFilter::ERROR); - assert_eq!(dirs[0].in_span, None); - - assert_eq!(dirs[1].target, Some("crate1::mod2".to_string())); - assert_eq!(dirs[1].level, LevelFilter::TRACE); - assert_eq!(dirs[1].in_span, None); - - assert_eq!(dirs[2].target, Some("crate2".to_string())); - assert_eq!(dirs[2].level, LevelFilter::DEBUG); - assert_eq!(dirs[2].in_span, None); - - assert_eq!(dirs[3].target, Some("crate3".to_string())); - assert_eq!(dirs[3].level, LevelFilter::OFF); - assert_eq!(dirs[3].in_span, None); - } - - #[test] - - fn parse_level_directives() { - let dirs = parse_directives( - "crate1::mod1=error,crate1::mod2=warn,crate1::mod2::mod3=info,\ - crate2=debug,crate3=trace,crate3::mod2::mod1=off", - ); - assert_eq!(dirs.len(), 6, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("crate1::mod1".to_string())); - assert_eq!(dirs[0].level, LevelFilter::ERROR); - assert_eq!(dirs[0].in_span, None); - - assert_eq!(dirs[1].target, Some("crate1::mod2".to_string())); - assert_eq!(dirs[1].level, LevelFilter::WARN); - assert_eq!(dirs[1].in_span, None); - - assert_eq!(dirs[2].target, Some("crate1::mod2::mod3".to_string())); - assert_eq!(dirs[2].level, LevelFilter::INFO); - assert_eq!(dirs[2].in_span, None); - - assert_eq!(dirs[3].target, Some("crate2".to_string())); - assert_eq!(dirs[3].level, LevelFilter::DEBUG); - assert_eq!(dirs[3].in_span, None); - - assert_eq!(dirs[4].target, Some("crate3".to_string())); - assert_eq!(dirs[4].level, LevelFilter::TRACE); - assert_eq!(dirs[4].in_span, None); - - assert_eq!(dirs[5].target, Some("crate3::mod2::mod1".to_string())); - assert_eq!(dirs[5].level, LevelFilter::OFF); - assert_eq!(dirs[5].in_span, None); - } - - #[test] - fn parse_uppercase_level_directives() { - let dirs = parse_directives( - "crate1::mod1=ERROR,crate1::mod2=WARN,crate1::mod2::mod3=INFO,\ - crate2=DEBUG,crate3=TRACE,crate3::mod2::mod1=OFF", - ); - assert_eq!(dirs.len(), 6, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("crate1::mod1".to_string())); - assert_eq!(dirs[0].level, LevelFilter::ERROR); - assert_eq!(dirs[0].in_span, None); - - assert_eq!(dirs[1].target, Some("crate1::mod2".to_string())); - assert_eq!(dirs[1].level, LevelFilter::WARN); - assert_eq!(dirs[1].in_span, None); - - assert_eq!(dirs[2].target, Some("crate1::mod2::mod3".to_string())); - assert_eq!(dirs[2].level, LevelFilter::INFO); - assert_eq!(dirs[2].in_span, None); - - assert_eq!(dirs[3].target, Some("crate2".to_string())); - assert_eq!(dirs[3].level, LevelFilter::DEBUG); - assert_eq!(dirs[3].in_span, None); - - assert_eq!(dirs[4].target, Some("crate3".to_string())); - assert_eq!(dirs[4].level, LevelFilter::TRACE); - assert_eq!(dirs[4].in_span, None); - - assert_eq!(dirs[5].target, Some("crate3::mod2::mod1".to_string())); - assert_eq!(dirs[5].level, LevelFilter::OFF); - assert_eq!(dirs[5].in_span, None); - } - - #[test] - fn parse_numeric_level_directives() { - let dirs = parse_directives( - "crate1::mod1=1,crate1::mod2=2,crate1::mod2::mod3=3,crate2=4,\ - crate3=5,crate3::mod2::mod1=0", - ); - assert_eq!(dirs.len(), 6, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("crate1::mod1".to_string())); - assert_eq!(dirs[0].level, LevelFilter::ERROR); - assert_eq!(dirs[0].in_span, None); - - assert_eq!(dirs[1].target, Some("crate1::mod2".to_string())); - assert_eq!(dirs[1].level, LevelFilter::WARN); - assert_eq!(dirs[1].in_span, None); - - assert_eq!(dirs[2].target, Some("crate1::mod2::mod3".to_string())); - assert_eq!(dirs[2].level, LevelFilter::INFO); - assert_eq!(dirs[2].in_span, None); - - assert_eq!(dirs[3].target, Some("crate2".to_string())); - assert_eq!(dirs[3].level, LevelFilter::DEBUG); - assert_eq!(dirs[3].in_span, None); - - assert_eq!(dirs[4].target, Some("crate3".to_string())); - assert_eq!(dirs[4].level, LevelFilter::TRACE); - assert_eq!(dirs[4].in_span, None); - - assert_eq!(dirs[5].target, Some("crate3::mod2::mod1".to_string())); - assert_eq!(dirs[5].level, LevelFilter::OFF); - assert_eq!(dirs[5].in_span, None); - } - - #[test] - fn parse_directives_invalid_crate() { - // test parse_directives with multiple = in specification - let dirs = parse_directives("crate1::mod1=warn=info,crate2=debug"); - assert_eq!(dirs.len(), 1, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("crate2".to_string())); - assert_eq!(dirs[0].level, LevelFilter::DEBUG); - assert_eq!(dirs[0].in_span, None); - } - - #[test] - fn parse_directives_invalid_level() { - // test parse_directives with 'noNumber' as log level - let dirs = parse_directives("crate1::mod1=noNumber,crate2=debug"); - assert_eq!(dirs.len(), 1, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("crate2".to_string())); - assert_eq!(dirs[0].level, LevelFilter::DEBUG); - assert_eq!(dirs[0].in_span, None); - } - - #[test] - fn parse_directives_string_level() { - // test parse_directives with 'warn' as log level - let dirs = parse_directives("crate1::mod1=wrong,crate2=warn"); - assert_eq!(dirs.len(), 1, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("crate2".to_string())); - assert_eq!(dirs[0].level, LevelFilter::WARN); - assert_eq!(dirs[0].in_span, None); - } - - #[test] - fn parse_directives_empty_level() { - // test parse_directives with '' as log level - let dirs = parse_directives("crate1::mod1=wrong,crate2="); - assert_eq!(dirs.len(), 1, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("crate2".to_string())); - assert_eq!(dirs[0].level, LevelFilter::TRACE); - assert_eq!(dirs[0].in_span, None); - } - - #[test] - fn parse_directives_global() { - // test parse_directives with no crate - let dirs = parse_directives("warn,crate2=debug"); - assert_eq!(dirs.len(), 2, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, None); - assert_eq!(dirs[0].level, LevelFilter::WARN); - assert_eq!(dirs[1].in_span, None); - - assert_eq!(dirs[1].target, Some("crate2".to_string())); - assert_eq!(dirs[1].level, LevelFilter::DEBUG); - assert_eq!(dirs[1].in_span, None); - } - - // helper function for tests below - fn test_parse_bare_level(directive_to_test: &str, level_expected: LevelFilter) { - let dirs = parse_directives(directive_to_test); - assert_eq!( - dirs.len(), - 1, - "\ninput: \"{}\"; parsed: {:#?}", - directive_to_test, - dirs - ); - assert_eq!(dirs[0].target, None); - assert_eq!(dirs[0].level, level_expected); - assert_eq!(dirs[0].in_span, None); - } - - #[test] - fn parse_directives_global_bare_warn_lc() { - // test parse_directives with no crate, in isolation, all lowercase - test_parse_bare_level("warn", LevelFilter::WARN); - } - - #[test] - fn parse_directives_global_bare_warn_uc() { - // test parse_directives with no crate, in isolation, all uppercase - test_parse_bare_level("WARN", LevelFilter::WARN); - } - - #[test] - fn parse_directives_global_bare_warn_mixed() { - // test parse_directives with no crate, in isolation, mixed case - test_parse_bare_level("wArN", LevelFilter::WARN); - } - - #[test] - fn parse_directives_valid_with_spans() { - let dirs = parse_directives("crate1::mod1[foo]=error,crate1::mod2[bar],crate2[baz]=debug"); - assert_eq!(dirs.len(), 3, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("crate1::mod1".to_string())); - assert_eq!(dirs[0].level, LevelFilter::ERROR); - assert_eq!(dirs[0].in_span, Some("foo".to_string())); - - assert_eq!(dirs[1].target, Some("crate1::mod2".to_string())); - assert_eq!(dirs[1].level, LevelFilter::TRACE); - assert_eq!(dirs[1].in_span, Some("bar".to_string())); - - assert_eq!(dirs[2].target, Some("crate2".to_string())); - assert_eq!(dirs[2].level, LevelFilter::DEBUG); - assert_eq!(dirs[2].in_span, Some("baz".to_string())); - } - - #[test] - fn parse_directives_with_dash_in_target_name() { - let dirs = parse_directives("target-name=info"); - assert_eq!(dirs.len(), 1, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("target-name".to_string())); - assert_eq!(dirs[0].level, LevelFilter::INFO); - assert_eq!(dirs[0].in_span, None); - } - - #[test] - fn parse_directives_with_dash_in_span_name() { - // Reproduces https://github.com/tokio-rs/tracing/issues/1367 - - let dirs = parse_directives("target[span-name]=info"); - assert_eq!(dirs.len(), 1, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("target".to_string())); - assert_eq!(dirs[0].level, LevelFilter::INFO); - assert_eq!(dirs[0].in_span, Some("span-name".to_string())); - } - - #[test] - fn parse_directives_with_special_characters_in_span_name() { - let span_name = "!\"#$%&'()*+-./:;<=>?@^_`|~[}"; - - let dirs = parse_directives(format!("target[{}]=info", span_name)); - assert_eq!(dirs.len(), 1, "\nparsed: {:#?}", dirs); - assert_eq!(dirs[0].target, Some("target".to_string())); - assert_eq!(dirs[0].level, LevelFilter::INFO); - assert_eq!(dirs[0].in_span, Some(span_name.to_string())); - } - - #[test] - fn parse_directives_with_invalid_span_chars() { - let invalid_span_name = "]{"; - - let dirs = parse_directives(format!("target[{}]=info", invalid_span_name)); - assert_eq!(dirs.len(), 0, "\nparsed: {:#?}", dirs); - } -} -- cgit v1.2.3