summaryrefslogtreecommitdiffstats
path: root/vendor/tracing-subscriber/src/filter/env/directive.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vendor/tracing-subscriber/src/filter/env/directive.rs860
1 files changed, 0 insertions, 860 deletions
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<String>,
- fields: Vec<field::Match>,
- pub(crate) target: Option<String>,
- pub(crate) level: LevelFilter,
-}
-
-/// A set of dynamic filtering directives.
-pub(super) type Dynamics = DirectiveSet<Directive>;
-
-/// A set of static filtering directives.
-pub(super) type Statics = DirectiveSet<StaticDirective>;
-
-pub(crate) type CallsiteMatcher = MatchSet<field::CallsiteMatch>;
-pub(crate) type SpanMatcher = MatchSet<field::SpanMatch>;
-
-#[derive(Debug, PartialEq, Eq)]
-pub(crate) struct MatchSet<T> {
- field_matches: FilterVec<T>,
- 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<StaticDirective> {
- 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<field::CallsiteMatch> {
- 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::<Result<FieldMap<_>, ()>>()
- .ok()?;
- Some(field::CallsiteMatch {
- fields,
- level: self.level,
- })
- }
-
- pub(super) fn make_tables(
- directives: impl IntoIterator<Item = Directive>,
- ) -> (Dynamics, Statics) {
- // TODO(eliza): this could be made more efficient...
- let (dyns, stats): (Vec<Directive>, Vec<Directive>) =
- 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<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());
-
- 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::<LevelFilter>().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::<Result<Vec<_>, _>>()
- })
- .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<Self, Self::Err> {
- 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<Ordering> {
- 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<LevelFilter> for Directive {
- fn from(level: LevelFilter) -> Self {
- Self {
- level,
- ..Self::default()
- }
- }
-}
-
-impl From<Level> for Directive {
- fn from(level: Level) -> Self {
- LevelFilter::from_level(level).into()
- }
-}
-
-// === impl Dynamics ===
-
-impl Dynamics {
- pub(crate) fn matcher(&self, metadata: &Metadata<'_>) -> Option<CallsiteMatcher> {
- 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<str>) -> Vec<Directive> {
- dirs.as_ref()
- .split(',')
- .filter_map(|s| s.parse().ok())
- .collect()
- }
-
- fn expect_parse(dirs: impl AsRef<str>) -> Vec<Directive> {
- 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::<Vec<_>>();
-
- 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::<Vec<_>>();
-
- 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::<Vec<_>>();
-
- 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::<Vec<_>>();
-
- 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);
- }
-}