summaryrefslogtreecommitdiffstats
path: root/vendor/tracing-subscriber/src/filter
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tracing-subscriber/src/filter')
-rw-r--r--vendor/tracing-subscriber/src/filter/directive.rs456
-rw-r--r--vendor/tracing-subscriber/src/filter/env/builder.rs325
-rw-r--r--vendor/tracing-subscriber/src/filter/env/directive.rs860
-rw-r--r--vendor/tracing-subscriber/src/filter/env/field.rs626
-rw-r--r--vendor/tracing-subscriber/src/filter/env/mod.rs991
-rw-r--r--vendor/tracing-subscriber/src/filter/filter_fn.rs749
-rw-r--r--vendor/tracing-subscriber/src/filter/layer_filters/combinator.rs542
-rw-r--r--vendor/tracing-subscriber/src/filter/layer_filters/mod.rs1220
-rw-r--r--vendor/tracing-subscriber/src/filter/level.rs27
-rw-r--r--vendor/tracing-subscriber/src/filter/mod.rs66
-rw-r--r--vendor/tracing-subscriber/src/filter/targets.rs781
11 files changed, 6643 insertions, 0 deletions
diff --git a/vendor/tracing-subscriber/src/filter/directive.rs b/vendor/tracing-subscriber/src/filter/directive.rs
new file mode 100644
index 000000000..2ae3f0f24
--- /dev/null
+++ b/vendor/tracing-subscriber/src/filter/directive.rs
@@ -0,0 +1,456 @@
+use crate::filter::level::{self, LevelFilter};
+#[cfg(not(feature = "smallvec"))]
+use alloc::vec;
+#[cfg(not(feature = "std"))]
+use alloc::{string::String, vec::Vec};
+
+use core::{cmp::Ordering, fmt, iter::FromIterator, slice, str::FromStr};
+use tracing_core::{Level, Metadata};
+/// Indicates that a string could not be parsed as a filtering directive.
+#[derive(Debug)]
+pub struct ParseError {
+ kind: ParseErrorKind,
+}
+
+/// A directive which will statically enable or disable a given callsite.
+///
+/// Unlike a dynamic directive, this can be cached by the callsite.
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub(crate) struct StaticDirective {
+ pub(in crate::filter) target: Option<String>,
+ pub(in crate::filter) field_names: Vec<String>,
+ pub(in crate::filter) level: LevelFilter,
+}
+
+#[cfg(feature = "smallvec")]
+pub(crate) type FilterVec<T> = smallvec::SmallVec<[T; 8]>;
+#[cfg(not(feature = "smallvec"))]
+pub(crate) type FilterVec<T> = Vec<T>;
+
+#[derive(Debug, PartialEq, Clone)]
+pub(in crate::filter) struct DirectiveSet<T> {
+ directives: FilterVec<T>,
+ pub(in crate::filter) max_level: LevelFilter,
+}
+
+pub(in crate::filter) trait Match {
+ fn cares_about(&self, meta: &Metadata<'_>) -> bool;
+ fn level(&self) -> &LevelFilter;
+}
+
+#[derive(Debug)]
+enum ParseErrorKind {
+ #[cfg(feature = "std")]
+ Field(Box<dyn std::error::Error + Send + Sync>),
+ Level(level::ParseError),
+ Other(Option<&'static str>),
+}
+
+// === impl DirectiveSet ===
+
+impl<T> DirectiveSet<T> {
+ #[cfg(feature = "env-filter")]
+ pub(crate) fn is_empty(&self) -> bool {
+ self.directives.is_empty()
+ }
+
+ pub(crate) fn iter(&self) -> slice::Iter<'_, T> {
+ self.directives.iter()
+ }
+}
+
+impl<T: Ord> Default for DirectiveSet<T> {
+ fn default() -> Self {
+ Self {
+ directives: FilterVec::new(),
+ max_level: LevelFilter::OFF,
+ }
+ }
+}
+
+impl<T: Match + Ord> DirectiveSet<T> {
+ pub(crate) fn directives(&self) -> impl Iterator<Item = &T> {
+ self.directives.iter()
+ }
+
+ pub(crate) fn directives_for<'a>(
+ &'a self,
+ metadata: &'a Metadata<'a>,
+ ) -> impl Iterator<Item = &'a T> + 'a {
+ self.directives().filter(move |d| d.cares_about(metadata))
+ }
+
+ pub(crate) fn add(&mut self, directive: T) {
+ // does this directive enable a more verbose level than the current
+ // max? if so, update the max level.
+ let level = *directive.level();
+ if level > self.max_level {
+ self.max_level = level;
+ }
+ // insert the directive into the vec of directives, ordered by
+ // specificity (length of target + number of field filters). this
+ // ensures that, when finding a directive to match a span or event, we
+ // search the directive set in most specific first order.
+ match self.directives.binary_search(&directive) {
+ Ok(i) => self.directives[i] = directive,
+ Err(i) => self.directives.insert(i, directive),
+ }
+ }
+
+ #[cfg(test)]
+ pub(in crate::filter) fn into_vec(self) -> FilterVec<T> {
+ self.directives
+ }
+}
+
+impl<T: Match + Ord> FromIterator<T> for DirectiveSet<T> {
+ fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
+ let mut this = Self::default();
+ this.extend(iter);
+ this
+ }
+}
+
+impl<T: Match + Ord> Extend<T> for DirectiveSet<T> {
+ fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+ for directive in iter.into_iter() {
+ self.add(directive);
+ }
+ }
+}
+
+impl<T> IntoIterator for DirectiveSet<T> {
+ type Item = T;
+
+ #[cfg(feature = "smallvec")]
+ type IntoIter = smallvec::IntoIter<[T; 8]>;
+ #[cfg(not(feature = "smallvec"))]
+ type IntoIter = vec::IntoIter<T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.directives.into_iter()
+ }
+}
+
+// === impl Statics ===
+
+impl DirectiveSet<StaticDirective> {
+ pub(crate) fn enabled(&self, meta: &Metadata<'_>) -> bool {
+ let level = meta.level();
+ match self.directives_for(meta).next() {
+ Some(d) => d.level >= *level,
+ None => false,
+ }
+ }
+
+ /// Same as `enabled` above, but skips `Directive`'s with fields.
+ pub(crate) fn target_enabled(&self, target: &str, level: &Level) -> bool {
+ match self.directives_for_target(target).next() {
+ Some(d) => d.level >= *level,
+ None => false,
+ }
+ }
+
+ pub(crate) fn directives_for_target<'a>(
+ &'a self,
+ target: &'a str,
+ ) -> impl Iterator<Item = &'a StaticDirective> + 'a {
+ self.directives()
+ .filter(move |d| d.cares_about_target(target))
+ }
+}
+
+// === impl StaticDirective ===
+
+impl StaticDirective {
+ pub(in crate::filter) fn new(
+ target: Option<String>,
+ field_names: Vec<String>,
+ level: LevelFilter,
+ ) -> Self {
+ Self {
+ target,
+ field_names,
+ level,
+ }
+ }
+
+ pub(in crate::filter) fn cares_about_target(&self, to_check: &str) -> bool {
+ // Does this directive have a target filter, and does it match the
+ // metadata's target?
+ if let Some(ref target) = self.target {
+ if !to_check.starts_with(&target[..]) {
+ return false;
+ }
+ }
+
+ if !self.field_names.is_empty() {
+ return false;
+ }
+
+ true
+ }
+}
+
+impl Ord for StaticDirective {
+ fn cmp(&self, other: &StaticDirective) -> 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))
+ // Then we compare how many field names are matched by each directive.
+ .then_with(|| self.field_names.len().cmp(&other.field_names.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.field_names[..].cmp(&other.field_names[..]))
+ })
+ .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.field_names, other.field_names,
+ "invariant violated: Ordering::Equal must imply a.field_names == b.field_names"
+ );
+ }
+ }
+
+ ordering
+ }
+}
+
+impl PartialOrd for StaticDirective {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Match for StaticDirective {
+ 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;
+ }
+ }
+
+ if meta.is_event() && !self.field_names.is_empty() {
+ let fields = meta.fields();
+ for name in &self.field_names {
+ if fields.field(name).is_none() {
+ return false;
+ }
+ }
+ }
+
+ true
+ }
+
+ fn level(&self) -> &LevelFilter {
+ &self.level
+ }
+}
+
+impl Default for StaticDirective {
+ fn default() -> Self {
+ StaticDirective {
+ target: None,
+ field_names: Vec::new(),
+ level: LevelFilter::ERROR,
+ }
+ }
+}
+
+impl fmt::Display for StaticDirective {
+ 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.field_names.is_empty() {
+ f.write_str("[")?;
+
+ let mut fields = self.field_names.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 FromStr for StaticDirective {
+ type Err = ParseError;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ // This method parses a filtering directive in one of the following
+ // forms:
+ //
+ // * `foo=trace` (TARGET=LEVEL)
+ // * `foo[{bar,baz}]=info` (TARGET[{FIELD,+}]=LEVEL)
+ // * `trace` (bare LEVEL)
+ // * `foo` (bare TARGET)
+ let mut split = s.split('=');
+ let part0 = split
+ .next()
+ .ok_or_else(|| ParseError::msg("string must not be empty"))?;
+
+ // Directive includes an `=`:
+ // * `foo=trace`
+ // * `foo[{bar}]=trace`
+ // * `foo[{bar,baz}]=trace`
+ if let Some(part1) = split.next() {
+ if split.next().is_some() {
+ return Err(ParseError::msg(
+ "too many '=' in filter directive, expected 0 or 1",
+ ));
+ }
+
+ let mut split = part0.split("[{");
+ let target = split.next().map(String::from);
+ let mut field_names = Vec::new();
+ // Directive includes fields:
+ // * `foo[{bar}]=trace`
+ // * `foo[{bar,baz}]=trace`
+ if let Some(maybe_fields) = split.next() {
+ if split.next().is_some() {
+ return Err(ParseError::msg(
+ "too many '[{' in filter directive, expected 0 or 1",
+ ));
+ }
+
+ if !maybe_fields.ends_with("}]") {
+ return Err(ParseError::msg("expected fields list to end with '}]'"));
+ }
+
+ let fields = maybe_fields
+ .trim_end_matches("}]")
+ .split(',')
+ .filter_map(|s| {
+ if s.is_empty() {
+ None
+ } else {
+ Some(String::from(s))
+ }
+ });
+ field_names.extend(fields);
+ };
+ let level = part1.parse()?;
+ return Ok(Self {
+ level,
+ field_names,
+ target,
+ });
+ }
+
+ // Okay, the part after the `=` was empty, the directive is either a
+ // bare level or a bare target.
+ // * `foo`
+ // * `info`
+ Ok(match part0.parse::<LevelFilter>() {
+ Ok(level) => Self {
+ level,
+ target: None,
+ field_names: Vec::new(),
+ },
+ Err(_) => Self {
+ target: Some(String::from(part0)),
+ level: LevelFilter::TRACE,
+ field_names: Vec::new(),
+ },
+ })
+ }
+}
+
+// === impl ParseError ===
+
+impl ParseError {
+ #[cfg(feature = "env-filter")]
+ pub(crate) fn new() -> Self {
+ ParseError {
+ kind: ParseErrorKind::Other(None),
+ }
+ }
+
+ pub(crate) fn msg(s: &'static str) -> Self {
+ ParseError {
+ kind: ParseErrorKind::Other(Some(s)),
+ }
+ }
+}
+
+impl fmt::Display for ParseError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.kind {
+ ParseErrorKind::Other(None) => f.pad("invalid filter directive"),
+ ParseErrorKind::Other(Some(msg)) => write!(f, "invalid filter directive: {}", msg),
+ ParseErrorKind::Level(ref l) => l.fmt(f),
+ #[cfg(feature = "std")]
+ ParseErrorKind::Field(ref e) => write!(f, "invalid field filter: {}", e),
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for ParseError {
+ fn description(&self) -> &str {
+ "invalid filter directive"
+ }
+
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self.kind {
+ ParseErrorKind::Other(_) => None,
+ ParseErrorKind::Level(ref l) => Some(l),
+ ParseErrorKind::Field(ref n) => Some(n.as_ref()),
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl From<Box<dyn std::error::Error + Send + Sync>> for ParseError {
+ fn from(e: Box<dyn std::error::Error + Send + Sync>) -> Self {
+ Self {
+ kind: ParseErrorKind::Field(e),
+ }
+ }
+}
+
+impl From<level::ParseError> for ParseError {
+ fn from(l: level::ParseError) -> Self {
+ Self {
+ kind: ParseErrorKind::Level(l),
+ }
+ }
+}
diff --git a/vendor/tracing-subscriber/src/filter/env/builder.rs b/vendor/tracing-subscriber/src/filter/env/builder.rs
new file mode 100644
index 000000000..c814707e6
--- /dev/null
+++ b/vendor/tracing-subscriber/src/filter/env/builder.rs
@@ -0,0 +1,325 @@
+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)]
+#[must_use]
+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 = "nu_ansi_term")]
+ use nu_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 = "nu_ansi_term"))]
+ let msg = format!("warning: {}", msg);
+ #[cfg(feature = "nu_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 = "nu_ansi_term"))]
+ let msg = format!("{} {}", prefix, msg);
+ #[cfg(feature = "nu_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 = "nu_ansi_term"))]
+ let msg = format!("note: {}", msg);
+ #[cfg(feature = "nu_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 from the `tracing` crate",
+ 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,
+ }
+ }
+}
diff --git a/vendor/tracing-subscriber/src/filter/env/directive.rs b/vendor/tracing-subscriber/src/filter/env/directive.rs
new file mode 100644
index 000000000..f062e6ef9
--- /dev/null
+++ b/vendor/tracing-subscriber/src/filter/env/directive.rs
@@ -0,0 +1,860 @@
+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);
+ }
+}
diff --git a/vendor/tracing-subscriber/src/filter/env/field.rs b/vendor/tracing-subscriber/src/filter/env/field.rs
new file mode 100644
index 000000000..1394fd04a
--- /dev/null
+++ b/vendor/tracing-subscriber/src/filter/env/field.rs
@@ -0,0 +1,626 @@
+use matchers::Pattern;
+use std::{
+ cmp::Ordering,
+ error::Error,
+ fmt::{self, Write},
+ str::FromStr,
+ sync::{
+ atomic::{AtomicBool, Ordering::*},
+ Arc,
+ },
+};
+
+use super::{FieldMap, LevelFilter};
+use tracing_core::field::{Field, Visit};
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub(crate) struct Match {
+ pub(crate) name: String, // TODO: allow match patterns for names?
+ pub(crate) value: Option<ValueMatch>,
+}
+
+#[derive(Debug, Eq, PartialEq)]
+pub(crate) struct CallsiteMatch {
+ pub(crate) fields: FieldMap<ValueMatch>,
+ pub(crate) level: LevelFilter,
+}
+
+#[derive(Debug)]
+pub(crate) struct SpanMatch {
+ fields: FieldMap<(ValueMatch, AtomicBool)>,
+ level: LevelFilter,
+ has_matched: AtomicBool,
+}
+
+pub(crate) struct MatchVisitor<'a> {
+ inner: &'a SpanMatch,
+}
+
+#[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>),
+}
+
+impl Eq for ValueMatch {}
+
+impl PartialEq for ValueMatch {
+ fn eq(&self, other: &Self) -> bool {
+ use ValueMatch::*;
+ match (self, other) {
+ (Bool(a), Bool(b)) => a.eq(b),
+ (F64(a), F64(b)) => {
+ debug_assert!(!a.is_nan());
+ debug_assert!(!b.is_nan());
+
+ a.eq(b)
+ }
+ (U64(a), U64(b)) => a.eq(b),
+ (I64(a), I64(b)) => a.eq(b),
+ (NaN, NaN) => true,
+ (Pat(a), Pat(b)) => a.eq(b),
+ _ => false,
+ }
+ }
+}
+
+impl Ord for ValueMatch {
+ fn cmp(&self, other: &Self) -> Ordering {
+ use ValueMatch::*;
+ match (self, other) {
+ (Bool(this), Bool(that)) => this.cmp(that),
+ (Bool(_), _) => Ordering::Less,
+
+ (F64(this), F64(that)) => this
+ .partial_cmp(that)
+ .expect("`ValueMatch::F64` may not contain `NaN` values"),
+ (F64(_), Bool(_)) => Ordering::Greater,
+ (F64(_), _) => Ordering::Less,
+
+ (NaN, NaN) => Ordering::Equal,
+ (NaN, Bool(_)) | (NaN, F64(_)) => Ordering::Greater,
+ (NaN, _) => Ordering::Less,
+
+ (U64(this), U64(that)) => this.cmp(that),
+ (U64(_), Bool(_)) | (U64(_), F64(_)) | (U64(_), NaN) => Ordering::Greater,
+ (U64(_), _) => Ordering::Less,
+
+ (I64(this), I64(that)) => this.cmp(that),
+ (I64(_), Bool(_)) | (I64(_), F64(_)) | (I64(_), NaN) | (I64(_), U64(_)) => {
+ Ordering::Greater
+ }
+ (I64(_), _) => Ordering::Less,
+
+ (Pat(this), Pat(that)) => this.cmp(that),
+ (Pat(_), _) => Ordering::Greater,
+
+ (Debug(this), Debug(that)) => this.cmp(that),
+ (Debug(_), _) => Ordering::Greater,
+ }
+ }
+}
+
+impl PartialOrd for ValueMatch {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+/// 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")))]
+pub struct BadName {
+ name: String,
+}
+
+// === 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>> {
+ let mut parts = s.split('=');
+ let name = parts
+ .next()
+ .ok_or_else(|| BadName {
+ name: "".to_string(),
+ })?
+ // 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()?;
+ Ok(Match { name, value })
+ }
+}
+
+impl fmt::Display for Match {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(&self.name, f)?;
+ if let Some(ref value) = self.value {
+ write!(f, "={}", value)?;
+ }
+ Ok(())
+ }
+}
+
+impl Ord for Match {
+ fn cmp(&self, other: &Self) -> Ordering {
+ // Ordering for `Match` directives is based first on _whether_ a value
+ // is matched or not. This is semantically meaningful --- we would
+ // prefer to check directives that match values first as they are more
+ // specific.
+ let has_value = match (self.value.as_ref(), other.value.as_ref()) {
+ (Some(_), None) => Ordering::Greater,
+ (None, Some(_)) => Ordering::Less,
+ _ => Ordering::Equal,
+ };
+ // If both directives match a value, we fall back to the field names in
+ // length + lexicographic ordering, and if these are equal as well, we
+ // compare the match directives.
+ //
+ // This ordering is no longer semantically meaningful but is necessary
+ // so that the directives can be stored in the `BTreeMap` in a defined
+ // order.
+ has_value
+ .then_with(|| self.name.cmp(&other.name))
+ .then_with(|| self.value.cmp(&other.value))
+ }
+}
+
+impl PartialOrd for Match {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+// === impl ValueMatch ===
+
+fn value_match_f64(v: f64) -> ValueMatch {
+ if v.is_nan() {
+ ValueMatch::NaN
+ } else {
+ ValueMatch::F64(v)
+ }
+}
+
+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> {
+ 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))
+ .or_else(|_| {
+ s.parse::<MatchPattern>()
+ .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 {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ ValueMatch::Bool(ref inner) => fmt::Display::fmt(inner, f),
+ ValueMatch::F64(ref inner) => fmt::Display::fmt(inner, f),
+ 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),
+ }
+ }
+}
+
+// === impl MatchPattern ===
+
+impl FromStr for MatchPattern {
+ type Err = matchers::Error;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let matcher = s.parse::<Pattern>()?;
+ Ok(Self {
+ matcher,
+ pattern: s.to_owned().into(),
+ })
+ }
+}
+
+impl fmt::Display for MatchPattern {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(&*self.pattern, f)
+ }
+}
+
+impl AsRef<str> for MatchPattern {
+ #[inline]
+ fn as_ref(&self) -> &str {
+ self.pattern.as_ref()
+ }
+}
+
+impl MatchPattern {
+ #[inline]
+ fn str_matches(&self, s: &impl AsRef<str>) -> bool {
+ self.matcher.matches(s)
+ }
+
+ #[inline]
+ 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 {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.pattern == other.pattern
+ }
+}
+
+impl Eq for MatchPattern {}
+
+impl PartialOrd for MatchPattern {
+ #[inline]
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.pattern.cmp(&other.pattern))
+ }
+}
+
+impl Ord for MatchPattern {
+ #[inline]
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.pattern.cmp(&other.pattern)
+ }
+}
+
+// === 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 {}
+
+impl fmt::Display for BadName {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "invalid field name `{}`", self.name)
+ }
+}
+
+impl CallsiteMatch {
+ pub(crate) fn to_span_match(&self) -> SpanMatch {
+ let fields = self
+ .fields
+ .iter()
+ .map(|(k, v)| (k.clone(), (v.clone(), AtomicBool::new(false))))
+ .collect();
+ SpanMatch {
+ fields,
+ level: self.level,
+ has_matched: AtomicBool::new(false),
+ }
+ }
+}
+
+impl SpanMatch {
+ pub(crate) fn visitor(&self) -> MatchVisitor<'_> {
+ MatchVisitor { inner: self }
+ }
+
+ #[inline]
+ pub(crate) fn is_matched(&self) -> bool {
+ if self.has_matched.load(Acquire) {
+ return true;
+ }
+ self.is_matched_slow()
+ }
+
+ #[inline(never)]
+ fn is_matched_slow(&self) -> bool {
+ let matched = self
+ .fields
+ .values()
+ .all(|(_, matched)| matched.load(Acquire));
+ if matched {
+ self.has_matched.store(true, Release);
+ }
+ matched
+ }
+
+ #[inline]
+ pub(crate) fn filter(&self) -> Option<LevelFilter> {
+ if self.is_matched() {
+ Some(self.level)
+ } else {
+ None
+ }
+ }
+}
+
+impl<'a> Visit for MatchVisitor<'a> {
+ fn record_f64(&mut self, field: &Field, value: f64) {
+ match self.inner.fields.get(field) {
+ Some((ValueMatch::NaN, ref matched)) if value.is_nan() => {
+ matched.store(true, Release);
+ }
+ Some((ValueMatch::F64(ref e), ref matched))
+ if (value - *e).abs() < std::f64::EPSILON =>
+ {
+ matched.store(true, Release);
+ }
+ _ => {}
+ }
+ }
+
+ fn record_i64(&mut self, field: &Field, value: i64) {
+ use std::convert::TryInto;
+
+ match self.inner.fields.get(field) {
+ Some((ValueMatch::I64(ref e), ref matched)) if value == *e => {
+ matched.store(true, Release);
+ }
+ Some((ValueMatch::U64(ref e), ref matched)) if Ok(value) == (*e).try_into() => {
+ matched.store(true, Release);
+ }
+ _ => {}
+ }
+ }
+
+ fn record_u64(&mut self, field: &Field, value: u64) {
+ match self.inner.fields.get(field) {
+ Some((ValueMatch::U64(ref e), ref matched)) if value == *e => {
+ matched.store(true, Release);
+ }
+ _ => {}
+ }
+ }
+
+ fn record_bool(&mut self, field: &Field, value: bool) {
+ match self.inner.fields.get(field) {
+ Some((ValueMatch::Bool(ref e), ref matched)) if value == *e => {
+ matched.store(true, Release);
+ }
+ _ => {}
+ }
+ }
+
+ fn record_str(&mut self, field: &Field, value: &str) {
+ match self.inner.fields.get(field) {
+ 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)
+ }
+ _ => {}
+ }
+ }
+
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+ match self.inner.fields.get(field) {
+ 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/src/filter/env/mod.rs
new file mode 100644
index 000000000..81a9ae2bd
--- /dev/null
+++ b/vendor/tracing-subscriber/src/filter/env/mod.rs
@@ -0,0 +1,991 @@
+//! A `Layer` that enables or disables spans and events based on a set of
+//! filtering directives.
+
+// 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;
+mod directive;
+mod field;
+
+use crate::{
+ filter::LevelFilter,
+ layer::{Context, Layer},
+ sync::RwLock,
+};
+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,
+ span,
+ subscriber::{Interest, Subscriber},
+ Metadata,
+};
+
+/// 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.
+/// Each directive may have a corresponding maximum verbosity [`level`] which
+/// enables (e.g., _selects for_) spans and events that match. Like `log`,
+/// `tracing` considers less exclusive levels (like `trace` or `info`) to be more
+/// verbose than more exclusive levels (like `error` or `warn`).
+///
+/// The directive syntax is similar to that of [`env_logger`]'s. At a high level, the syntax for directives
+/// consists of several parts:
+///
+/// ```text
+/// target[span{field=value}]=level
+/// ```
+///
+/// Each component (`target`, `span`, `field`, `value`, and `level`) will be covered in turn.
+///
+/// - `target` matches the event or span's target. In general, this is the module path and/or crate name.
+/// Examples of targets `h2`, `tokio::net`, or `tide::server`. For more information on targets,
+/// please refer to [`Metadata`]'s documentation.
+/// - `span` matches on the span's name. If a `span` directive is provided alongside a `target`,
+/// the `span` directive will match on spans _within_ the `target`.
+/// - `field` matches on [fields] within spans. Field names can also be supplied without a `value`
+/// 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.
+/// - `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.
+/// - Any portion of the directive can be omitted.
+/// - The sole exception are the `field` and `value` directives. If a `value` is provided,
+/// a `field` must _also_ be provided. However, the converse does not hold, as fields can
+/// be matched without a value.
+/// - If only a level is provided, it will set the maximum level for all `Span`s and `Event`s
+/// that are not enabled by other filters.
+/// - A directive without a level will enable anything that it matches. This is equivalent to `=trace`.
+/// - When a crate has a dash in its name, the default target for events will be the
+/// crate's module path as it appears in Rust. This means every dash will be replaced
+/// with an underscore.
+/// - A dash in a target will only appear when being specified explicitly:
+/// `tracing::info!(target: "target-name", ...);`
+///
+/// ## Example Syntax
+///
+/// - `tokio::net=info` will enable all spans or events that:
+/// - have the `tokio::net` target,
+/// - at the level `info` or above.
+/// - `warn,tokio::net=info` will enable all spans and events that:
+/// - are at the level `warn` or above, *or*
+/// - have the `tokio::net` target at the level `info` or above.
+/// - `my_crate[span_a]=trace` will enable all spans and events that:
+/// - are within the `span_a` span or named `span_a` _if_ `span_a` has the target `my_crate`,
+/// - at the level `trace` or above.
+/// - `[span_b{name=\"bob\"}]` will enable all spans or event that:
+/// - have _any_ target,
+/// - are inside a span named `span_b`,
+/// - 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.
+///
+/// [`Span`]: tracing_core::span
+/// [fields]: tracing_core::Field
+/// [`Event`]: tracing_core::Event
+/// [`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 {
+ statics: directive::Statics,
+ dynamics: directive::Dynamics,
+ 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,
+}
+
+type FieldMap<T> = HashMap<Field, T>;
+
+/// Indicates that an error occurred while parsing a `EnvFilter` from an
+/// environment variable.
+#[cfg_attr(docsrs, doc(cfg(all(feature = "env-filter", feature = "std"))))]
+#[derive(Debug)]
+pub struct FromEnvError {
+ kind: ErrorKind,
+}
+
+#[derive(Debug)]
+enum ErrorKind {
+ Parse(ParseError),
+ Env(env::VarError),
+}
+
+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()
+ 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()
+ }
+
+ /// 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()
+ }
+
+ /// 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)
+ }
+
+ /// 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)
+ }
+
+ /// 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()
+ /// # }
+ /// ```
+ pub fn try_from_default_env() -> Result<Self, FromEnvError> {
+ Self::builder().try_from_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()
+ }
+
+ /// Add a filtering directive to this `EnvFilter`.
+ ///
+ /// The added directive will be used in addition to any previously set
+ /// directives, either added using this method or provided when the filter
+ /// is constructed.
+ ///
+ /// Filters may be created from [`LevelFilter`] or [`Level`], which will
+ /// enable all traces at or below a certain verbosity level, or
+ /// parsed from a string specifying a directive.
+ ///
+ /// If a filter directive is inserted that matches exactly the same spans
+ /// 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
+ ///
+ /// # Examples
+ ///
+ /// From [`LevelFilter`]:
+ ///
+ /// ```rust
+ /// use tracing_subscriber::filter::{EnvFilter, LevelFilter};
+ /// let mut filter = EnvFilter::from_default_env()
+ /// .add_directive(LevelFilter::INFO.into());
+ /// ```
+ ///
+ /// Or from [`Level`]:
+ ///
+ /// ```rust
+ /// # use tracing_subscriber::filter::{EnvFilter, LevelFilter};
+ /// # use tracing::Level;
+ /// let mut filter = EnvFilter::from_default_env()
+ /// .add_directive(Level::INFO.into());
+ /// ```
+ ///
+ /// Parsed from a string:
+ ///
+ /// ```rust
+ /// use tracing_subscriber::filter::{EnvFilter, Directive};
+ ///
+ /// # fn try_mk_filter() -> Result<(), Box<dyn ::std::error::Error>> {
+ /// let mut filter = EnvFilter::try_from_default_env()?
+ /// .add_directive("my_crate::module=trace".parse()?)
+ /// .add_directive("my_crate::my_other_module::something=info".parse()?);
+ /// # 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();
+ }
+ if let Some(stat) = directive.to_static() {
+ self.statics.add(stat)
+ } else {
+ self.has_dynamics = true;
+ self.dynamics.add(directive);
+ }
+ self
+ }
+
+ // === filtering methods ===
+
+ /// 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 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
+ // spans in the current scope.
+ if self.has_dynamics && self.dynamics.max_level >= *level {
+ if metadata.is_span() {
+ // If the metadata is a span, see if we care about its callsite.
+ let enabled_by_cs = self
+ .by_cs
+ .read()
+ .ok()
+ .map(|by_cs| by_cs.contains_key(&metadata.callsite()))
+ .unwrap_or(false);
+ if enabled_by_cs {
+ return true;
+ }
+ }
+
+ let enabled_by_scope = {
+ let scope = self.scope.get_or_default().borrow();
+ for filter in &*scope {
+ if filter >= level {
+ return true;
+ }
+ }
+ false
+ };
+ if enabled_by_scope {
+ return true;
+ }
+ }
+
+ // is it possible for a static filter directive to enable this event?
+ if self.statics.max_level >= *level {
+ // Otherwise, fall back to checking if the callsite is
+ // statically enabled.
+ return self.statics.enabled(metadata);
+ }
+
+ 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>) {
+ 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);
+ try_lock!(self.by_id.write()).insert(id.clone(), span);
+ }
+ }
+
+ /// 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>) {
+ // 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());
+ }
+ }
+
+ /// 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>) {
+ if self.cares_about_span(id) {
+ self.scope.get_or_default().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>) {
+ // If we don't need to acquire a write lock, avoid doing so.
+ if !self.cares_about_span(&id) {
+ return;
+ }
+
+ 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 {
+ type Err = directive::ParseError;
+
+ fn from_str(spec: &str) -> Result<Self, Self::Err> {
+ Self::try_new(spec)
+ }
+}
+
+impl<S> From<S> for EnvFilter
+where
+ S: AsRef<str>,
+{
+ fn from(s: S) -> Self {
+ Self::new(s)
+ }
+}
+
+impl Default for EnvFilter {
+ fn default() -> Self {
+ Builder::default().from_directives(std::iter::empty())
+ }
+}
+
+impl fmt::Display for EnvFilter {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut statics = self.statics.iter();
+ let wrote_statics = if let Some(next) = statics.next() {
+ fmt::Display::fmt(next, f)?;
+ for directive in statics {
+ write!(f, ",{}", directive)?;
+ }
+ true
+ } else {
+ false
+ };
+
+ let mut dynamics = self.dynamics.iter();
+ if let Some(next) = dynamics.next() {
+ if wrote_statics {
+ f.write_str(",")?;
+ }
+ fmt::Display::fmt(next, f)?;
+ for directive in dynamics {
+ write!(f, ",{}", directive)?;
+ }
+ }
+ Ok(())
+ }
+}
+
+// ===== impl FromEnvError =====
+
+impl From<directive::ParseError> for FromEnvError {
+ fn from(p: directive::ParseError) -> Self {
+ Self {
+ kind: ErrorKind::Parse(p),
+ }
+ }
+}
+
+impl From<env::VarError> for FromEnvError {
+ fn from(v: env::VarError) -> Self {
+ Self {
+ kind: ErrorKind::Env(v),
+ }
+ }
+}
+
+impl fmt::Display for FromEnvError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.kind {
+ ErrorKind::Parse(ref p) => p.fmt(f),
+ ErrorKind::Env(ref e) => e.fmt(f),
+ }
+ }
+}
+
+impl Error for FromEnvError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self.kind {
+ ErrorKind::Parse(ref p) => Some(p),
+ ErrorKind::Env(ref e) => Some(e),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use tracing_core::field::FieldSet;
+ use tracing_core::*;
+
+ struct NoSubscriber;
+ impl Subscriber for NoSubscriber {
+ #[inline]
+ fn register_callsite(&self, _: &'static Metadata<'static>) -> subscriber::Interest {
+ subscriber::Interest::always()
+ }
+ fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
+ span::Id::from_u64(0xDEAD)
+ }
+ fn event(&self, _event: &Event<'_>) {}
+ fn record(&self, _span: &span::Id, _values: &span::Record<'_>) {}
+ fn record_follows_from(&self, _span: &span::Id, _follows: &span::Id) {}
+
+ #[inline]
+ fn enabled(&self, _metadata: &Metadata<'_>) -> bool {
+ true
+ }
+ fn enter(&self, _span: &span::Id) {}
+ fn exit(&self, _span: &span::Id) {}
+ }
+
+ struct Cs;
+ impl Callsite for Cs {
+ fn set_interest(&self, _interest: Interest) {}
+ fn metadata(&self) -> &Metadata<'_> {
+ unimplemented!()
+ }
+ }
+
+ #[test]
+ fn callsite_enabled_no_span_directive() {
+ let filter = EnvFilter::new("app=debug").with_subscriber(NoSubscriber);
+ static META: &Metadata<'static> = &Metadata::new(
+ "mySpan",
+ "app",
+ Level::TRACE,
+ None,
+ None,
+ None,
+ FieldSet::new(&[], identify_callsite!(&Cs)),
+ Kind::SPAN,
+ );
+
+ let interest = filter.register_callsite(META);
+ assert!(interest.is_never());
+ }
+
+ #[test]
+ fn callsite_off() {
+ let filter = EnvFilter::new("app=off").with_subscriber(NoSubscriber);
+ static META: &Metadata<'static> = &Metadata::new(
+ "mySpan",
+ "app",
+ Level::ERROR,
+ None,
+ None,
+ None,
+ FieldSet::new(&[], identify_callsite!(&Cs)),
+ Kind::SPAN,
+ );
+
+ let interest = filter.register_callsite(META);
+ assert!(interest.is_never());
+ }
+
+ #[test]
+ fn callsite_enabled_includes_span_directive() {
+ let filter = EnvFilter::new("app[mySpan]=debug").with_subscriber(NoSubscriber);
+ static META: &Metadata<'static> = &Metadata::new(
+ "mySpan",
+ "app",
+ Level::TRACE,
+ None,
+ None,
+ None,
+ FieldSet::new(&[], identify_callsite!(&Cs)),
+ Kind::SPAN,
+ );
+
+ let interest = filter.register_callsite(META);
+ assert!(interest.is_always());
+ }
+
+ #[test]
+ fn callsite_enabled_includes_span_directive_field() {
+ let filter =
+ EnvFilter::new("app[mySpan{field=\"value\"}]=debug").with_subscriber(NoSubscriber);
+ static META: &Metadata<'static> = &Metadata::new(
+ "mySpan",
+ "app",
+ Level::TRACE,
+ None,
+ None,
+ None,
+ FieldSet::new(&["field"], identify_callsite!(&Cs)),
+ Kind::SPAN,
+ );
+
+ let interest = filter.register_callsite(META);
+ assert!(interest.is_always());
+ }
+
+ #[test]
+ fn callsite_enabled_includes_span_directive_multiple_fields() {
+ let filter = EnvFilter::new("app[mySpan{field=\"value\",field2=2}]=debug")
+ .with_subscriber(NoSubscriber);
+ static META: &Metadata<'static> = &Metadata::new(
+ "mySpan",
+ "app",
+ Level::TRACE,
+ None,
+ None,
+ None,
+ FieldSet::new(&["field"], identify_callsite!(&Cs)),
+ Kind::SPAN,
+ );
+
+ let interest = filter.register_callsite(META);
+ assert!(interest.is_never());
+ }
+
+ #[test]
+ fn roundtrip() {
+ let f1: EnvFilter =
+ "[span1{foo=1}]=error,[span2{bar=2 baz=false}],crate2[{quux=\"quuux\"}]=debug"
+ .parse()
+ .unwrap();
+ let f2: EnvFilter = format!("{}", f1).parse().unwrap();
+ assert_eq!(f1.statics, f2.statics);
+ assert_eq!(f1.dynamics, f2.dynamics);
+ }
+
+ #[test]
+ fn size_of_filters() {
+ fn print_sz(s: &str) {
+ let filter = s.parse::<EnvFilter>().expect("filter should parse");
+ println!(
+ "size_of_val({:?})\n -> {}B",
+ s,
+ std::mem::size_of_val(&filter)
+ );
+ }
+
+ print_sz("info");
+
+ print_sz("foo=debug");
+
+ print_sz(
+ "crate1::mod1=error,crate1::mod2=warn,crate1::mod2::mod3=info,\
+ crate2=debug,crate3=trace,crate3::mod2::mod1=off",
+ );
+
+ print_sz("[span1{foo=1}]=error,[span2{bar=2 baz=false}],crate2[{quux=\"quuux\"}]=debug");
+
+ print_sz(
+ "crate1::mod1=error,crate1::mod2=warn,crate1::mod2::mod3=info,\
+ crate2=debug,crate3=trace,crate3::mod2::mod1=off,[span1{foo=1}]=error,\
+ [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/filter_fn.rs b/vendor/tracing-subscriber/src/filter/filter_fn.rs
new file mode 100644
index 000000000..332bf860a
--- /dev/null
+++ b/vendor/tracing-subscriber/src/filter/filter_fn.rs
@@ -0,0 +1,749 @@
+use crate::{
+ filter::LevelFilter,
+ layer::{Context, Layer},
+};
+use core::{any::type_name, fmt, marker::PhantomData};
+use tracing_core::{Interest, Metadata, Subscriber};
+
+/// A filter implemented by a closure or function pointer that
+/// determines whether a given span or event is enabled, based on its
+/// [`Metadata`].
+///
+/// This type can be used for both [per-layer filtering][plf] (using its
+/// [`Filter`] implementation) and [global filtering][global] (using its
+/// [`Layer`] implementation).
+///
+/// See the [documentation on filtering with layers][filtering] for details.
+///
+/// [`Metadata`]: tracing_core::Metadata
+/// [`Filter`]: crate::layer::Filter
+/// [`Layer`]: crate::layer::Layer
+/// [plf]: crate::layer#per-layer-filtering
+/// [global]: crate::layer#global-filtering
+/// [filtering]: crate::layer#filtering-with-layers
+#[derive(Clone)]
+pub struct FilterFn<F = fn(&Metadata<'_>) -> bool> {
+ enabled: F,
+ max_level_hint: Option<LevelFilter>,
+}
+
+/// A filter implemented by a closure or function pointer that
+/// determines whether a given span or event is enabled _dynamically_,
+/// potentially based on the current [span context].
+///
+/// This type can be used for both [per-layer filtering][plf] (using its
+/// [`Filter`] implementation) and [global filtering][global] (using its
+/// [`Layer`] implementation).
+///
+/// See the [documentation on filtering with layers][filtering] for details.
+///
+/// [span context]: crate::layer::Context
+/// [`Filter`]: crate::layer::Filter
+/// [`Layer`]: crate::layer::Layer
+/// [plf]: crate::layer#per-layer-filtering
+/// [global]: crate::layer#global-filtering
+/// [filtering]: crate::layer#filtering-with-layers
+pub struct DynFilterFn<
+ S,
+ // TODO(eliza): should these just be boxed functions?
+ F = fn(&Metadata<'_>, &Context<'_, S>) -> bool,
+ R = fn(&'static Metadata<'static>) -> Interest,
+> {
+ enabled: F,
+ register_callsite: Option<R>,
+ max_level_hint: Option<LevelFilter>,
+ _s: PhantomData<fn(S)>,
+}
+
+// === impl FilterFn ===
+
+/// Constructs a [`FilterFn`], from a function or closure that returns `true` if
+/// a span or event should be enabled, based on its [`Metadata`].
+///
+/// The returned [`FilterFn`] can be used for both [per-layer filtering][plf]
+/// (using its [`Filter`] implementation) and [global filtering][global] (using
+/// its [`Layer`] implementation).
+///
+/// See the [documentation on filtering with layers][filtering] for details.
+///
+/// This is equivalent to calling [`FilterFn::new`].
+///
+/// [`Metadata`]: tracing_core::Metadata
+/// [`Filter`]: crate::layer::Filter
+/// [`Layer`]: crate::layer::Layer
+/// [plf]: crate::layer#per-layer-filtering
+/// [global]: crate::layer#global-filtering
+/// [filtering]: crate::layer#filtering-with-layers
+///
+/// # Examples
+///
+/// ```
+/// use tracing_subscriber::{
+/// layer::{Layer, SubscriberExt},
+/// filter,
+/// util::SubscriberInitExt,
+/// };
+///
+/// let my_filter = filter::filter_fn(|metadata| {
+/// // Only enable spans or events with the target "interesting_things"
+/// metadata.target() == "interesting_things"
+/// });
+///
+/// let my_layer = tracing_subscriber::fmt::layer();
+///
+/// tracing_subscriber::registry()
+/// .with(my_layer.with_filter(my_filter))
+/// .init();
+///
+/// // This event will not be enabled.
+/// tracing::warn!("something important but uninteresting happened!");
+///
+/// // This event will be enabled.
+/// tracing::debug!(target: "interesting_things", "an interesting minor detail...");
+/// ```
+pub fn filter_fn<F>(f: F) -> FilterFn<F>
+where
+ F: Fn(&Metadata<'_>) -> bool,
+{
+ FilterFn::new(f)
+}
+
+/// Constructs a [`DynFilterFn`] from a function or closure that returns `true`
+/// if a span or event should be enabled within a particular [span context][`Context`].
+///
+/// This is equivalent to calling [`DynFilterFn::new`].
+///
+/// Unlike [`filter_fn`], this function takes a closure or function pointer
+/// taking the [`Metadata`] for a span or event *and* the current [`Context`].
+/// This means that a [`DynFilterFn`] can choose whether to enable spans or
+/// events based on information about the _current_ span (or its parents).
+///
+/// If this is *not* necessary, use [`filter_fn`] instead.
+///
+/// The returned [`DynFilterFn`] can be used for both [per-layer filtering][plf]
+/// (using its [`Filter`] implementation) and [global filtering][global] (using
+/// its [`Layer`] implementation).
+///
+/// See the [documentation on filtering with layers][filtering] for details.
+///
+/// # Examples
+///
+/// ```
+/// use tracing_subscriber::{
+/// layer::{Layer, SubscriberExt},
+/// filter,
+/// util::SubscriberInitExt,
+/// };
+///
+/// // Only enable spans or events within a span named "interesting_span".
+/// let my_filter = filter::dynamic_filter_fn(|metadata, cx| {
+/// // If this *is* "interesting_span", make sure to enable it.
+/// if metadata.is_span() && metadata.name() == "interesting_span" {
+/// return true;
+/// }
+///
+/// // Otherwise, are we in an interesting span?
+/// if let Some(current_span) = cx.lookup_current() {
+/// return current_span.name() == "interesting_span";
+/// }
+///
+/// false
+/// });
+///
+/// let my_layer = tracing_subscriber::fmt::layer();
+///
+/// tracing_subscriber::registry()
+/// .with(my_layer.with_filter(my_filter))
+/// .init();
+///
+/// // This event will not be enabled.
+/// tracing::info!("something happened");
+///
+/// tracing::info_span!("interesting_span").in_scope(|| {
+/// // This event will be enabled.
+/// tracing::debug!("something else happened");
+/// });
+/// ```
+///
+/// [`Filter`]: crate::layer::Filter
+/// [`Layer`]: crate::layer::Layer
+/// [plf]: crate::layer#per-layer-filtering
+/// [global]: crate::layer#global-filtering
+/// [filtering]: crate::layer#filtering-with-layers
+/// [`Context`]: crate::layer::Context
+/// [`Metadata`]: tracing_core::Metadata
+pub fn dynamic_filter_fn<S, F>(f: F) -> DynFilterFn<S, F>
+where
+ F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool,
+{
+ DynFilterFn::new(f)
+}
+
+impl<F> FilterFn<F>
+where
+ F: Fn(&Metadata<'_>) -> bool,
+{
+ /// Constructs a [`FilterFn`] from a function or closure that returns `true`
+ /// if a span or event should be enabled, based on its [`Metadata`].
+ ///
+ /// If determining whether a span or event should be enabled also requires
+ /// information about the current span context, use [`DynFilterFn`] instead.
+ ///
+ /// See the [documentation on per-layer filtering][plf] for details on using
+ /// [`Filter`]s.
+ ///
+ /// [`Filter`]: crate::layer::Filter
+ /// [plf]: crate::layer#per-layer-filtering
+ /// [`Metadata`]: tracing_core::Metadata
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tracing_subscriber::{
+ /// layer::{Layer, SubscriberExt},
+ /// filter::FilterFn,
+ /// util::SubscriberInitExt,
+ /// };
+ ///
+ /// let my_filter = FilterFn::new(|metadata| {
+ /// // Only enable spans or events with the target "interesting_things"
+ /// metadata.target() == "interesting_things"
+ /// });
+ ///
+ /// let my_layer = tracing_subscriber::fmt::layer();
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(my_layer.with_filter(my_filter))
+ /// .init();
+ ///
+ /// // This event will not be enabled.
+ /// tracing::warn!("something important but uninteresting happened!");
+ ///
+ /// // This event will be enabled.
+ /// tracing::debug!(target: "interesting_things", "an interesting minor detail...");
+ /// ```
+ pub fn new(enabled: F) -> Self {
+ Self {
+ enabled,
+ max_level_hint: None,
+ }
+ }
+
+ /// Sets the highest verbosity [`Level`] the filter function will enable.
+ ///
+ /// The value passed to this method will be returned by this `FilterFn`'s
+ /// [`Filter::max_level_hint`] method.
+ ///
+ /// If the provided function will not enable all levels, it is recommended
+ /// to call this method to configure it with the most verbose level it will
+ /// enable.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tracing_subscriber::{
+ /// layer::{Layer, SubscriberExt},
+ /// filter::{filter_fn, LevelFilter},
+ /// util::SubscriberInitExt,
+ /// };
+ /// use tracing_core::Level;
+ ///
+ /// let my_filter = filter_fn(|metadata| {
+ /// // Only enable spans or events with targets starting with `my_crate`
+ /// // and levels at or below `INFO`.
+ /// metadata.level() <= &Level::INFO && metadata.target().starts_with("my_crate")
+ /// })
+ /// // Since the filter closure will only enable the `INFO` level and
+ /// // below, set the max level hint
+ /// .with_max_level_hint(LevelFilter::INFO);
+ ///
+ /// let my_layer = tracing_subscriber::fmt::layer();
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(my_layer.with_filter(my_filter))
+ /// .init();
+ /// ```
+ ///
+ /// [`Level`]: tracing_core::Level
+ /// [`Filter::max_level_hint`]: crate::layer::Filter::max_level_hint
+ pub fn with_max_level_hint(self, max_level_hint: impl Into<LevelFilter>) -> Self {
+ Self {
+ max_level_hint: Some(max_level_hint.into()),
+ ..self
+ }
+ }
+
+ #[inline]
+ pub(in crate::filter) fn is_enabled(&self, metadata: &Metadata<'_>) -> bool {
+ let enabled = (self.enabled)(metadata);
+ debug_assert!(
+ !enabled || self.is_below_max_level(metadata),
+ "FilterFn<{}> claimed it would only enable {:?} and below, \
+ but it enabled metadata with the {:?} level\nmetadata={:#?}",
+ type_name::<F>(),
+ self.max_level_hint.unwrap(),
+ metadata.level(),
+ metadata,
+ );
+
+ enabled
+ }
+
+ #[inline]
+ pub(in crate::filter) fn is_callsite_enabled(
+ &self,
+ metadata: &'static Metadata<'static>,
+ ) -> Interest {
+ // Because `self.enabled` takes a `Metadata` only (and no `Context`
+ // parameter), we can reasonably assume its results are cachable, and
+ // just return `Interest::always`/`Interest::never`.
+ if (self.enabled)(metadata) {
+ debug_assert!(
+ self.is_below_max_level(metadata),
+ "FilterFn<{}> claimed it was only interested in {:?} and below, \
+ but it enabled metadata with the {:?} level\nmetadata={:#?}",
+ type_name::<F>(),
+ self.max_level_hint.unwrap(),
+ metadata.level(),
+ metadata,
+ );
+ return Interest::always();
+ }
+
+ Interest::never()
+ }
+
+ fn is_below_max_level(&self, metadata: &Metadata<'_>) -> bool {
+ self.max_level_hint
+ .as_ref()
+ .map(|hint| metadata.level() <= hint)
+ .unwrap_or(true)
+ }
+}
+
+impl<S, F> Layer<S> for FilterFn<F>
+where
+ F: Fn(&Metadata<'_>) -> bool + 'static,
+ S: Subscriber,
+{
+ fn enabled(&self, metadata: &Metadata<'_>, _: Context<'_, S>) -> bool {
+ self.is_enabled(metadata)
+ }
+
+ fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
+ self.is_callsite_enabled(metadata)
+ }
+
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ self.max_level_hint
+ }
+}
+
+impl<F> From<F> for FilterFn<F>
+where
+ F: Fn(&Metadata<'_>) -> bool,
+{
+ fn from(enabled: F) -> Self {
+ Self::new(enabled)
+ }
+}
+
+impl<F> fmt::Debug for FilterFn<F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("FilterFn")
+ .field("enabled", &format_args!("{}", type_name::<F>()))
+ .field("max_level_hint", &self.max_level_hint)
+ .finish()
+ }
+}
+
+// === impl DynFilterFn ==
+
+impl<S, F> DynFilterFn<S, F>
+where
+ F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool,
+{
+ /// Constructs a [`Filter`] from a function or closure that returns `true`
+ /// if a span or event should be enabled in the current [span
+ /// context][`Context`].
+ ///
+ /// Unlike [`FilterFn`], a `DynFilterFn` is constructed from a closure or
+ /// function pointer that takes both the [`Metadata`] for a span or event
+ /// *and* the current [`Context`]. This means that a [`DynFilterFn`] can
+ /// choose whether to enable spans or events based on information about the
+ /// _current_ span (or its parents).
+ ///
+ /// If this is *not* necessary, use [`FilterFn`] instead.
+ ///
+ /// See the [documentation on per-layer filtering][plf] for details on using
+ /// [`Filter`]s.
+ ///
+ /// [`Filter`]: crate::layer::Filter
+ /// [plf]: crate::layer#per-layer-filtering
+ /// [`Context`]: crate::layer::Context
+ /// [`Metadata`]: tracing_core::Metadata
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tracing_subscriber::{
+ /// layer::{Layer, SubscriberExt},
+ /// filter::DynFilterFn,
+ /// util::SubscriberInitExt,
+ /// };
+ ///
+ /// // Only enable spans or events within a span named "interesting_span".
+ /// let my_filter = DynFilterFn::new(|metadata, cx| {
+ /// // If this *is* "interesting_span", make sure to enable it.
+ /// if metadata.is_span() && metadata.name() == "interesting_span" {
+ /// return true;
+ /// }
+ ///
+ /// // Otherwise, are we in an interesting span?
+ /// if let Some(current_span) = cx.lookup_current() {
+ /// return current_span.name() == "interesting_span";
+ /// }
+ ///
+ /// false
+ /// });
+ ///
+ /// let my_layer = tracing_subscriber::fmt::layer();
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(my_layer.with_filter(my_filter))
+ /// .init();
+ ///
+ /// // This event will not be enabled.
+ /// tracing::info!("something happened");
+ ///
+ /// tracing::info_span!("interesting_span").in_scope(|| {
+ /// // This event will be enabled.
+ /// tracing::debug!("something else happened");
+ /// });
+ /// ```
+ pub fn new(enabled: F) -> Self {
+ Self {
+ enabled,
+ register_callsite: None,
+ max_level_hint: None,
+ _s: PhantomData,
+ }
+ }
+}
+
+impl<S, F, R> DynFilterFn<S, F, R>
+where
+ F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool,
+{
+ /// Sets the highest verbosity [`Level`] the filter function will enable.
+ ///
+ /// The value passed to this method will be returned by this `DynFilterFn`'s
+ /// [`Filter::max_level_hint`] method.
+ ///
+ /// If the provided function will not enable all levels, it is recommended
+ /// to call this method to configure it with the most verbose level it will
+ /// enable.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tracing_subscriber::{
+ /// layer::{Layer, SubscriberExt},
+ /// filter::{DynFilterFn, LevelFilter},
+ /// util::SubscriberInitExt,
+ /// };
+ /// use tracing_core::Level;
+ ///
+ /// // Only enable spans or events with levels at or below `INFO`, if
+ /// // we are inside a span called "interesting_span".
+ /// let my_filter = DynFilterFn::new(|metadata, cx| {
+ /// // If the level is greater than INFO, disable it.
+ /// if metadata.level() > &Level::INFO {
+ /// return false;
+ /// }
+ ///
+ /// // If any span in the current scope is named "interesting_span",
+ /// // enable this span or event.
+ /// for span in cx.lookup_current().iter().flat_map(|span| span.scope()) {
+ /// if span.name() == "interesting_span" {
+ /// return true;
+ /// }
+ /// }
+ ///
+ /// // Otherwise, disable it.
+ /// false
+ /// })
+ /// // Since the filter closure will only enable the `INFO` level and
+ /// // below, set the max level hint
+ /// .with_max_level_hint(LevelFilter::INFO);
+ ///
+ /// let my_layer = tracing_subscriber::fmt::layer();
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(my_layer.with_filter(my_filter))
+ /// .init();
+ /// ```
+ ///
+ /// [`Level`]: tracing_core::Level
+ /// [`Filter::max_level_hint`]: crate::layer::Filter::max_level_hint
+ pub fn with_max_level_hint(self, max_level_hint: impl Into<LevelFilter>) -> Self {
+ Self {
+ max_level_hint: Some(max_level_hint.into()),
+ ..self
+ }
+ }
+
+ /// Adds a function for filtering callsites to this filter.
+ ///
+ /// When this filter's [`Filter::callsite_enabled`][cse] method is called,
+ /// the provided function will be used rather than the default.
+ ///
+ /// By default, `DynFilterFn` assumes that, because the filter _may_ depend
+ /// dynamically on the current [span context], its result should never be
+ /// cached. However, some filtering strategies may require dynamic information
+ /// from the current span context in *some* cases, but are able to make
+ /// static filtering decisions from [`Metadata`] alone in others.
+ ///
+ /// For example, consider the filter given in the example for
+ /// [`DynFilterFn::new`]. That filter enables all spans named
+ /// "interesting_span", and any events and spans that occur inside of an
+ /// interesting span. Since the span's name is part of its static
+ /// [`Metadata`], the "interesting_span" can be enabled in
+ /// [`callsite_enabled`][cse]:
+ ///
+ /// ```
+ /// use tracing_subscriber::{
+ /// layer::{Layer, SubscriberExt},
+ /// filter::DynFilterFn,
+ /// util::SubscriberInitExt,
+ /// };
+ /// use tracing_core::subscriber::Interest;
+ ///
+ /// // Only enable spans or events within a span named "interesting_span".
+ /// let my_filter = DynFilterFn::new(|metadata, cx| {
+ /// // If this *is* "interesting_span", make sure to enable it.
+ /// if metadata.is_span() && metadata.name() == "interesting_span" {
+ /// return true;
+ /// }
+ ///
+ /// // Otherwise, are we in an interesting span?
+ /// if let Some(current_span) = cx.lookup_current() {
+ /// return current_span.name() == "interesting_span";
+ /// }
+ ///
+ /// false
+ /// }).with_callsite_filter(|metadata| {
+ /// // If this is an "interesting_span", we know we will always
+ /// // enable it.
+ /// if metadata.is_span() && metadata.name() == "interesting_span" {
+ /// return Interest::always();
+ /// }
+ ///
+ /// // Otherwise, it depends on whether or not we're in an interesting
+ /// // span. You'll have to ask us again for each span/event!
+ /// Interest::sometimes()
+ /// });
+ ///
+ /// let my_layer = tracing_subscriber::fmt::layer();
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(my_layer.with_filter(my_filter))
+ /// .init();
+ /// ```
+ ///
+ /// [cse]: crate::layer::Filter::callsite_enabled
+ /// [`enabled`]: crate::layer::Filter::enabled
+ /// [`Metadata`]: tracing_core::Metadata
+ /// [span context]: crate::layer::Context
+ pub fn with_callsite_filter<R2>(self, callsite_enabled: R2) -> DynFilterFn<S, F, R2>
+ where
+ R2: Fn(&'static Metadata<'static>) -> Interest,
+ {
+ let register_callsite = Some(callsite_enabled);
+ let DynFilterFn {
+ enabled,
+ max_level_hint,
+ _s,
+ ..
+ } = self;
+ DynFilterFn {
+ enabled,
+ register_callsite,
+ max_level_hint,
+ _s,
+ }
+ }
+
+ fn default_callsite_enabled(&self, metadata: &Metadata<'_>) -> Interest {
+ // If it's below the configured max level, assume that `enabled` will
+ // never enable it...
+ if !is_below_max_level(&self.max_level_hint, metadata) {
+ debug_assert!(
+ !(self.enabled)(metadata, &Context::none()),
+ "DynFilterFn<{}> claimed it would only enable {:?} and below, \
+ but it enabled metadata with the {:?} level\nmetadata={:#?}",
+ type_name::<F>(),
+ self.max_level_hint.unwrap(),
+ metadata.level(),
+ metadata,
+ );
+ return Interest::never();
+ }
+
+ // Otherwise, since this `enabled` function is dynamic and depends on
+ // the current context, we don't know whether this span or event will be
+ // enabled or not. Ask again every time it's recorded!
+ Interest::sometimes()
+ }
+}
+
+impl<S, F, R> DynFilterFn<S, F, R>
+where
+ F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool,
+ R: Fn(&'static Metadata<'static>) -> Interest,
+{
+ #[inline]
+ fn is_enabled(&self, metadata: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
+ let enabled = (self.enabled)(metadata, cx);
+ debug_assert!(
+ !enabled || is_below_max_level(&self.max_level_hint, metadata),
+ "DynFilterFn<{}> claimed it would only enable {:?} and below, \
+ but it enabled metadata with the {:?} level\nmetadata={:#?}",
+ type_name::<F>(),
+ self.max_level_hint.unwrap(),
+ metadata.level(),
+ metadata,
+ );
+
+ enabled
+ }
+
+ #[inline]
+ fn is_callsite_enabled(&self, metadata: &'static Metadata<'static>) -> Interest {
+ let interest = self
+ .register_callsite
+ .as_ref()
+ .map(|callsite_enabled| callsite_enabled(metadata))
+ .unwrap_or_else(|| self.default_callsite_enabled(metadata));
+ debug_assert!(
+ interest.is_never() || is_below_max_level(&self.max_level_hint, metadata),
+ "DynFilterFn<{}, {}> claimed it was only interested in {:?} and below, \
+ but it enabled metadata with the {:?} level\nmetadata={:#?}",
+ type_name::<F>(),
+ type_name::<R>(),
+ self.max_level_hint.unwrap(),
+ metadata.level(),
+ metadata,
+ );
+
+ interest
+ }
+}
+
+impl<S, F, R> Layer<S> for DynFilterFn<S, F, R>
+where
+ F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool + 'static,
+ R: Fn(&'static Metadata<'static>) -> Interest + 'static,
+ S: Subscriber,
+{
+ fn enabled(&self, metadata: &Metadata<'_>, cx: Context<'_, S>) -> bool {
+ self.is_enabled(metadata, &cx)
+ }
+
+ fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
+ self.is_callsite_enabled(metadata)
+ }
+
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ self.max_level_hint
+ }
+}
+
+impl<S, F, R> fmt::Debug for DynFilterFn<S, F, R> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut s = f.debug_struct("DynFilterFn");
+ s.field("enabled", &format_args!("{}", type_name::<F>()));
+ if self.register_callsite.is_some() {
+ s.field(
+ "register_callsite",
+ &format_args!("Some({})", type_name::<R>()),
+ );
+ } else {
+ s.field("register_callsite", &format_args!("None"));
+ }
+
+ s.field("max_level_hint", &self.max_level_hint).finish()
+ }
+}
+
+impl<S, F, R> Clone for DynFilterFn<S, F, R>
+where
+ F: Clone,
+ R: Clone,
+{
+ fn clone(&self) -> Self {
+ Self {
+ enabled: self.enabled.clone(),
+ register_callsite: self.register_callsite.clone(),
+ max_level_hint: self.max_level_hint,
+ _s: PhantomData,
+ }
+ }
+}
+
+impl<F, S> From<F> for DynFilterFn<S, F>
+where
+ F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool,
+{
+ fn from(f: F) -> Self {
+ Self::new(f)
+ }
+}
+
+// === PLF impls ===
+
+feature! {
+ #![all(feature = "registry", feature = "std")]
+ use crate::layer::Filter;
+
+ impl<S, F> Filter<S> for FilterFn<F>
+ where
+ F: Fn(&Metadata<'_>) -> bool,
+ {
+ fn enabled(&self, metadata: &Metadata<'_>, _: &Context<'_, S>) -> bool {
+ self.is_enabled(metadata)
+ }
+
+ fn callsite_enabled(&self, metadata: &'static Metadata<'static>) -> Interest {
+ self.is_callsite_enabled(metadata)
+ }
+
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ self.max_level_hint
+ }
+ }
+
+ impl<S, F, R> Filter<S> for DynFilterFn<S, F, R>
+ where
+ F: Fn(&Metadata<'_>, &Context<'_, S>) -> bool,
+ R: Fn(&'static Metadata<'static>) -> Interest,
+ {
+ fn enabled(&self, metadata: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
+ self.is_enabled(metadata, cx)
+ }
+
+ fn callsite_enabled(&self, metadata: &'static Metadata<'static>) -> Interest {
+ self.is_callsite_enabled(metadata)
+ }
+
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ self.max_level_hint
+ }
+ }
+}
+
+fn is_below_max_level(hint: &Option<LevelFilter>, metadata: &Metadata<'_>) -> bool {
+ hint.as_ref()
+ .map(|hint| metadata.level() <= hint)
+ .unwrap_or(true)
+}
diff --git a/vendor/tracing-subscriber/src/filter/layer_filters/combinator.rs b/vendor/tracing-subscriber/src/filter/layer_filters/combinator.rs
new file mode 100644
index 000000000..3934a1326
--- /dev/null
+++ b/vendor/tracing-subscriber/src/filter/layer_filters/combinator.rs
@@ -0,0 +1,542 @@
+//! Filter combinators
+use crate::layer::{Context, Filter};
+use std::{cmp, fmt, marker::PhantomData};
+use tracing_core::{
+ span::{Attributes, Id, Record},
+ subscriber::Interest,
+ LevelFilter, Metadata,
+};
+
+/// Combines two [`Filter`]s so that spans and events are enabled if and only if
+/// *both* filters return `true`.
+///
+/// This type is typically returned by the [`FilterExt::and`] method. See that
+/// method's documentation for details.
+///
+/// [`Filter`]: crate::layer::Filter
+/// [`FilterExt::and`]: crate::filter::FilterExt::and
+pub struct And<A, B, S> {
+ a: A,
+ b: B,
+ _s: PhantomData<fn(S)>,
+}
+
+/// Combines two [`Filter`]s so that spans and events are enabled if *either* filter
+/// returns `true`.
+///
+/// This type is typically returned by the [`FilterExt::or`] method. See that
+/// method's documentation for details.
+///
+/// [`Filter`]: crate::layer::Filter
+/// [`FilterExt::or`]: crate::filter::FilterExt::or
+pub struct Or<A, B, S> {
+ a: A,
+ b: B,
+ _s: PhantomData<fn(S)>,
+}
+
+/// Inverts the result of a [`Filter`].
+///
+/// If the wrapped filter would enable a span or event, it will be disabled. If
+/// it would disable a span or event, that span or event will be enabled.
+///
+/// This type is typically returned by the [`FilterExt::not`] method. See that
+/// method's documentation for details.
+///
+/// [`Filter`]: crate::layer::Filter
+/// [`FilterExt::not`]: crate::filter::FilterExt::not
+pub struct Not<A, S> {
+ a: A,
+ _s: PhantomData<fn(S)>,
+}
+
+// === impl And ===
+
+impl<A, B, S> And<A, B, S>
+where
+ A: Filter<S>,
+ B: Filter<S>,
+{
+ /// Combines two [`Filter`]s so that spans and events are enabled if and only if
+ /// *both* filters return `true`.
+ ///
+ /// # Examples
+ ///
+ /// Enabling spans or events if they have both a particular target *and* are
+ /// above a certain level:
+ ///
+ /// ```ignore
+ /// use tracing_subscriber::{
+ /// filter::{filter_fn, LevelFilter, combinator::And},
+ /// prelude::*,
+ /// };
+ ///
+ /// // Enables spans and events with targets starting with `interesting_target`:
+ /// let target_filter = filter_fn(|meta| {
+ /// meta.target().starts_with("interesting_target")
+ /// });
+ ///
+ /// // Enables spans and events with levels `INFO` and below:
+ /// let level_filter = LevelFilter::INFO;
+ ///
+ /// // Combine the two filters together so that a span or event is only enabled
+ /// // if *both* filters would enable it:
+ /// let filter = And::new(level_filter, target_filter);
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(tracing_subscriber::fmt::layer().with_filter(filter))
+ /// .init();
+ ///
+ /// // This event will *not* be enabled:
+ /// tracing::info!("an event with an uninteresting target");
+ ///
+ /// // This event *will* be enabled:
+ /// tracing::info!(target: "interesting_target", "a very interesting event");
+ ///
+ /// // This event will *not* be enabled:
+ /// tracing::debug!(target: "interesting_target", "interesting debug event...");
+ /// ```
+ ///
+ /// [`Filter`]: crate::layer::Filter
+ pub(crate) fn new(a: A, b: B) -> Self {
+ Self {
+ a,
+ b,
+ _s: PhantomData,
+ }
+ }
+}
+
+impl<A, B, S> Filter<S> for And<A, B, S>
+where
+ A: Filter<S>,
+ B: Filter<S>,
+{
+ #[inline]
+ fn enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
+ self.a.enabled(meta, cx) && self.b.enabled(meta, cx)
+ }
+
+ fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest {
+ let a = self.a.callsite_enabled(meta);
+ if a.is_never() {
+ return a;
+ }
+
+ let b = self.b.callsite_enabled(meta);
+
+ if !b.is_always() {
+ return b;
+ }
+
+ a
+ }
+
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ // If either hint is `None`, return `None`. Otherwise, return the most restrictive.
+ cmp::min(self.a.max_level_hint(), self.b.max_level_hint())
+ }
+
+ #[inline]
+ fn event_enabled(&self, event: &tracing_core::Event<'_>, cx: &Context<'_, S>) -> bool {
+ self.a.event_enabled(event, cx) && self.b.event_enabled(event, cx)
+ }
+
+ #[inline]
+ fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
+ self.a.on_new_span(attrs, id, ctx.clone());
+ self.b.on_new_span(attrs, id, ctx)
+ }
+
+ #[inline]
+ fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {
+ self.a.on_record(id, values, ctx.clone());
+ self.b.on_record(id, values, ctx);
+ }
+
+ #[inline]
+ fn on_enter(&self, id: &Id, ctx: Context<'_, S>) {
+ self.a.on_enter(id, ctx.clone());
+ self.b.on_enter(id, ctx);
+ }
+
+ #[inline]
+ fn on_exit(&self, id: &Id, ctx: Context<'_, S>) {
+ self.a.on_exit(id, ctx.clone());
+ self.b.on_exit(id, ctx);
+ }
+
+ #[inline]
+ fn on_close(&self, id: Id, ctx: Context<'_, S>) {
+ self.a.on_close(id.clone(), ctx.clone());
+ self.b.on_close(id, ctx);
+ }
+}
+
+impl<A, B, S> Clone for And<A, B, S>
+where
+ A: Clone,
+ B: Clone,
+{
+ fn clone(&self) -> Self {
+ Self {
+ a: self.a.clone(),
+ b: self.b.clone(),
+ _s: PhantomData,
+ }
+ }
+}
+
+impl<A, B, S> fmt::Debug for And<A, B, S>
+where
+ A: fmt::Debug,
+ B: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("And")
+ .field("a", &self.a)
+ .field("b", &self.b)
+ .finish()
+ }
+}
+
+// === impl Or ===
+
+impl<A, B, S> Or<A, B, S>
+where
+ A: Filter<S>,
+ B: Filter<S>,
+{
+ /// Combines two [`Filter`]s so that spans and events are enabled if *either* filter
+ /// returns `true`.
+ ///
+ /// # Examples
+ ///
+ /// Enabling spans and events at the `INFO` level and above, and all spans
+ /// and events with a particular target:
+ ///
+ /// ```ignore
+ /// use tracing_subscriber::{
+ /// filter::{filter_fn, LevelFilter, combinator::Or},
+ /// prelude::*,
+ /// };
+ ///
+ /// // Enables spans and events with targets starting with `interesting_target`:
+ /// let target_filter = filter_fn(|meta| {
+ /// meta.target().starts_with("interesting_target")
+ /// });
+ ///
+ /// // Enables spans and events with levels `INFO` and below:
+ /// let level_filter = LevelFilter::INFO;
+ ///
+ /// // Combine the two filters together so that a span or event is enabled
+ /// // if it is at INFO or lower, or if it has a target starting with
+ /// // `interesting_target`.
+ /// let filter = Or::new(level_filter, target_filter);
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(tracing_subscriber::fmt::layer().with_filter(filter))
+ /// .init();
+ ///
+ /// // This event will *not* be enabled:
+ /// tracing::debug!("an uninteresting event");
+ ///
+ /// // This event *will* be enabled:
+ /// tracing::info!("an uninteresting INFO event");
+ ///
+ /// // This event *will* be enabled:
+ /// tracing::info!(target: "interesting_target", "a very interesting event");
+ ///
+ /// // This event *will* be enabled:
+ /// tracing::debug!(target: "interesting_target", "interesting debug event...");
+ /// ```
+ ///
+ /// Enabling a higher level for a particular target by using `Or` in
+ /// conjunction with the [`And`] combinator:
+ ///
+ /// ```ignore
+ /// use tracing_subscriber::{
+ /// filter::{filter_fn, LevelFilter, combinator},
+ /// prelude::*,
+ /// };
+ ///
+ /// // This filter will enable spans and events with targets beginning with
+ /// // `my_crate`:
+ /// let my_crate = filter_fn(|meta| {
+ /// meta.target().starts_with("my_crate")
+ /// });
+ ///
+ /// // Combine the `my_crate` filter with a `LevelFilter` to produce a filter
+ /// // that will enable the `INFO` level and lower for spans and events with
+ /// // `my_crate` targets:
+ /// let filter = combinator::And::new(my_crate, LevelFilter::INFO);
+ ///
+ /// // If a span or event *doesn't* have a target beginning with
+ /// // `my_crate`, enable it if it has the `WARN` level or lower:
+ /// // let filter = combinator::Or::new(filter, LevelFilter::WARN);
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(tracing_subscriber::fmt::layer().with_filter(filter))
+ /// .init();
+ /// ```
+ ///
+ /// [`Filter`]: crate::layer::Filter
+ pub(crate) fn new(a: A, b: B) -> Self {
+ Self {
+ a,
+ b,
+ _s: PhantomData,
+ }
+ }
+}
+
+impl<A, B, S> Filter<S> for Or<A, B, S>
+where
+ A: Filter<S>,
+ B: Filter<S>,
+{
+ #[inline]
+ fn enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
+ self.a.enabled(meta, cx) || self.b.enabled(meta, cx)
+ }
+
+ fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest {
+ let a = self.a.callsite_enabled(meta);
+ let b = self.b.callsite_enabled(meta);
+
+ // If either filter will always enable the span or event, return `always`.
+ if a.is_always() || b.is_always() {
+ return Interest::always();
+ }
+
+ // Okay, if either filter will sometimes enable the span or event,
+ // return `sometimes`.
+ if a.is_sometimes() || b.is_sometimes() {
+ return Interest::sometimes();
+ }
+
+ debug_assert!(
+ a.is_never() && b.is_never(),
+ "if neither filter was `always` or `sometimes`, both must be `never` (a={:?}; b={:?})",
+ a,
+ b,
+ );
+ Interest::never()
+ }
+
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ // If either hint is `None`, return `None`. Otherwise, return the less restrictive.
+ Some(cmp::max(self.a.max_level_hint()?, self.b.max_level_hint()?))
+ }
+
+ #[inline]
+ fn event_enabled(&self, event: &tracing_core::Event<'_>, cx: &Context<'_, S>) -> bool {
+ self.a.event_enabled(event, cx) || self.b.event_enabled(event, cx)
+ }
+
+ #[inline]
+ fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
+ self.a.on_new_span(attrs, id, ctx.clone());
+ self.b.on_new_span(attrs, id, ctx)
+ }
+
+ #[inline]
+ fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {
+ self.a.on_record(id, values, ctx.clone());
+ self.b.on_record(id, values, ctx);
+ }
+
+ #[inline]
+ fn on_enter(&self, id: &Id, ctx: Context<'_, S>) {
+ self.a.on_enter(id, ctx.clone());
+ self.b.on_enter(id, ctx);
+ }
+
+ #[inline]
+ fn on_exit(&self, id: &Id, ctx: Context<'_, S>) {
+ self.a.on_exit(id, ctx.clone());
+ self.b.on_exit(id, ctx);
+ }
+
+ #[inline]
+ fn on_close(&self, id: Id, ctx: Context<'_, S>) {
+ self.a.on_close(id.clone(), ctx.clone());
+ self.b.on_close(id, ctx);
+ }
+}
+
+impl<A, B, S> Clone for Or<A, B, S>
+where
+ A: Clone,
+ B: Clone,
+{
+ fn clone(&self) -> Self {
+ Self {
+ a: self.a.clone(),
+ b: self.b.clone(),
+ _s: PhantomData,
+ }
+ }
+}
+
+impl<A, B, S> fmt::Debug for Or<A, B, S>
+where
+ A: fmt::Debug,
+ B: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Or")
+ .field("a", &self.a)
+ .field("b", &self.b)
+ .finish()
+ }
+}
+
+// === impl Not ===
+
+impl<A, S> Not<A, S>
+where
+ A: Filter<S>,
+{
+ /// Inverts the result of a [`Filter`].
+ ///
+ /// If the wrapped filter would enable a span or event, it will be disabled. If
+ /// it would disable a span or event, that span or event will be enabled.
+ ///
+ /// This inverts the values returned by the [`enabled`] and [`callsite_enabled`]
+ /// methods on the wrapped filter; it does *not* invert [`event_enabled`], as
+ /// filters which do not implement filtering on event field values will return
+ /// the default `true` even for events that their [`enabled`] method disables.
+ ///
+ /// Consider a normal filter defined as:
+ ///
+ /// ```ignore (pseudo-code)
+ /// // for spans
+ /// match callsite_enabled() {
+ /// ALWAYS => on_span(),
+ /// SOMETIMES => if enabled() { on_span() },
+ /// NEVER => (),
+ /// }
+ /// // for events
+ /// match callsite_enabled() {
+ /// ALWAYS => on_event(),
+ /// SOMETIMES => if enabled() && event_enabled() { on_event() },
+ /// NEVER => (),
+ /// }
+ /// ```
+ ///
+ /// and an inverted filter defined as:
+ ///
+ /// ```ignore (pseudo-code)
+ /// // for spans
+ /// match callsite_enabled() {
+ /// ALWAYS => (),
+ /// SOMETIMES => if !enabled() { on_span() },
+ /// NEVER => on_span(),
+ /// }
+ /// // for events
+ /// match callsite_enabled() {
+ /// ALWAYS => (),
+ /// SOMETIMES => if !enabled() { on_event() },
+ /// NEVER => on_event(),
+ /// }
+ /// ```
+ ///
+ /// A proper inversion would do `!(enabled() && event_enabled())` (or
+ /// `!enabled() || !event_enabled()`), but because of the implicit `&&`
+ /// relation between `enabled` and `event_enabled`, it is difficult to
+ /// short circuit and not call the wrapped `event_enabled`.
+ ///
+ /// A combinator which remembers the result of `enabled` in order to call
+ /// `event_enabled` only when `enabled() == true` is possible, but requires
+ /// additional thread-local mutable state to support a very niche use case.
+ //
+ // Also, it'd mean the wrapped layer's `enabled()` always gets called and
+ // globally applied to events where it doesn't today, since we can't know
+ // what `event_enabled` will say until we have the event to call it with.
+ ///
+ /// [`Filter`]: crate::layer::Filter
+ /// [`enabled`]: crate::layer::Filter::enabled
+ /// [`event_enabled`]: crate::layer::Filter::event_enabled
+ /// [`callsite_enabled`]: crate::layer::Filter::callsite_enabled
+ pub(crate) fn new(a: A) -> Self {
+ Self { a, _s: PhantomData }
+ }
+}
+
+impl<A, S> Filter<S> for Not<A, S>
+where
+ A: Filter<S>,
+{
+ #[inline]
+ fn enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
+ !self.a.enabled(meta, cx)
+ }
+
+ fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest {
+ match self.a.callsite_enabled(meta) {
+ i if i.is_always() => Interest::never(),
+ i if i.is_never() => Interest::always(),
+ _ => Interest::sometimes(),
+ }
+ }
+
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ // TODO(eliza): figure this out???
+ None
+ }
+
+ #[inline]
+ fn event_enabled(&self, event: &tracing_core::Event<'_>, cx: &Context<'_, S>) -> bool {
+ // Never disable based on event_enabled; we "disabled" it in `enabled`,
+ // so the `not` has already been applied and filtered this not out.
+ let _ = (event, cx);
+ true
+ }
+
+ #[inline]
+ fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
+ self.a.on_new_span(attrs, id, ctx);
+ }
+
+ #[inline]
+ fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {
+ self.a.on_record(id, values, ctx.clone());
+ }
+
+ #[inline]
+ fn on_enter(&self, id: &Id, ctx: Context<'_, S>) {
+ self.a.on_enter(id, ctx);
+ }
+
+ #[inline]
+ fn on_exit(&self, id: &Id, ctx: Context<'_, S>) {
+ self.a.on_exit(id, ctx);
+ }
+
+ #[inline]
+ fn on_close(&self, id: Id, ctx: Context<'_, S>) {
+ self.a.on_close(id, ctx);
+ }
+}
+
+impl<A, S> Clone for Not<A, S>
+where
+ A: Clone,
+{
+ fn clone(&self) -> Self {
+ Self {
+ a: self.a.clone(),
+ _s: PhantomData,
+ }
+ }
+}
+
+impl<A, S> fmt::Debug for Not<A, S>
+where
+ A: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("Not").field(&self.a).finish()
+ }
+}
diff --git a/vendor/tracing-subscriber/src/filter/layer_filters/mod.rs b/vendor/tracing-subscriber/src/filter/layer_filters/mod.rs
new file mode 100644
index 000000000..e50ee6f00
--- /dev/null
+++ b/vendor/tracing-subscriber/src/filter/layer_filters/mod.rs
@@ -0,0 +1,1220 @@
+//! ## Per-Layer Filtering
+//!
+//! Per-layer filters permit individual `Layer`s to have their own filter
+//! configurations without interfering with other `Layer`s.
+//!
+//! This module is not public; the public APIs defined in this module are
+//! re-exported in the top-level `filter` module. Therefore, this documentation
+//! primarily concerns the internal implementation details. For the user-facing
+//! public API documentation, see the individual public types in this module, as
+//! well as the, see the `Layer` trait documentation's [per-layer filtering
+//! section]][1].
+//!
+//! ## How does per-layer filtering work?
+//!
+//! As described in the API documentation, the [`Filter`] trait defines a
+//! filtering strategy for a per-layer filter. We expect there will be a variety
+//! of implementations of [`Filter`], both in `tracing-subscriber` and in user
+//! code.
+//!
+//! To actually *use* a [`Filter`] implementation, it is combined with a
+//! [`Layer`] by the [`Filtered`] struct defined in this module. [`Filtered`]
+//! implements [`Layer`] by calling into the wrapped [`Layer`], or not, based on
+//! the filtering strategy. While there will be a variety of types that implement
+//! [`Filter`], all actual *uses* of per-layer filtering will occur through the
+//! [`Filtered`] struct. Therefore, most of the implementation details live
+//! there.
+//!
+//! [1]: crate::layer#per-layer-filtering
+//! [`Filter`]: crate::layer::Filter
+use crate::{
+ filter::LevelFilter,
+ layer::{self, Context, Layer},
+ registry,
+};
+use std::{
+ any::TypeId,
+ cell::{Cell, RefCell},
+ fmt,
+ marker::PhantomData,
+ ops::Deref,
+ sync::Arc,
+ thread_local,
+};
+use tracing_core::{
+ span,
+ subscriber::{Interest, Subscriber},
+ Dispatch, Event, Metadata,
+};
+pub mod combinator;
+
+/// A [`Layer`] that wraps an inner [`Layer`] and adds a [`Filter`] which
+/// controls what spans and events are enabled for that layer.
+///
+/// This is returned by the [`Layer::with_filter`] method. See the
+/// [documentation on per-layer filtering][plf] for details.
+///
+/// [`Filter`]: crate::layer::Filter
+/// [plf]: crate::layer#per-layer-filtering
+#[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
+#[derive(Clone)]
+pub struct Filtered<L, F, S> {
+ filter: F,
+ layer: L,
+ id: MagicPlfDowncastMarker,
+ _s: PhantomData<fn(S)>,
+}
+
+/// Uniquely identifies an individual [`Filter`] instance in the context of
+/// a [`Subscriber`].
+///
+/// When adding a [`Filtered`] [`Layer`] to a [`Subscriber`], the [`Subscriber`]
+/// generates a `FilterId` for that [`Filtered`] layer. The [`Filtered`] layer
+/// will then use the generated ID to query whether a particular span was
+/// previously enabled by that layer's [`Filter`].
+///
+/// **Note**: Currently, the [`Registry`] type provided by this crate is the
+/// **only** [`Subscriber`] implementation capable of participating in per-layer
+/// filtering. Therefore, the `FilterId` type cannot currently be constructed by
+/// code outside of `tracing-subscriber`. In the future, new APIs will be added to `tracing-subscriber` to
+/// allow non-Registry [`Subscriber`]s to also participate in per-layer
+/// filtering. When those APIs are added, subscribers will be responsible
+/// for generating and assigning `FilterId`s.
+///
+/// [`Filter`]: crate::layer::Filter
+/// [`Subscriber`]: tracing_core::Subscriber
+/// [`Layer`]: crate::layer::Layer
+/// [`Registry`]: crate::registry::Registry
+#[cfg(feature = "registry")]
+#[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
+#[derive(Copy, Clone)]
+pub struct FilterId(u64);
+
+/// A bitmap tracking which [`FilterId`]s have enabled a given span or
+/// event.
+///
+/// This is currently a private type that's used exclusively by the
+/// [`Registry`]. However, in the future, this may become a public API, in order
+/// to allow user subscribers to host [`Filter`]s.
+///
+/// [`Registry`]: crate::Registry
+/// [`Filter`]: crate::layer::Filter
+#[derive(Default, Copy, Clone, Eq, PartialEq)]
+pub(crate) struct FilterMap {
+ bits: u64,
+}
+
+/// The current state of `enabled` calls to per-layer filters on this
+/// thread.
+///
+/// When `Filtered::enabled` is called, the filter will set the bit
+/// corresponding to its ID if the filter will disable the event/span being
+/// filtered. When the event or span is recorded, the per-layer filter will
+/// check its bit to determine if it disabled that event or span, and skip
+/// forwarding the event or span to the inner layer if the bit is set. Once
+/// a span or event has been skipped by a per-layer filter, it unsets its
+/// bit, so that the `FilterMap` has been cleared for the next set of
+/// `enabled` calls.
+///
+/// FilterState is also read by the `Registry`, for two reasons:
+///
+/// 1. When filtering a span, the Registry must store the `FilterMap`
+/// generated by `Filtered::enabled` calls for that span as part of the
+/// span's per-span data. This allows `Filtered` layers to determine
+/// whether they had previously disabled a given span, and avoid showing it
+/// to the wrapped layer if it was disabled.
+///
+/// This allows `Filtered` layers to also filter out the spans they
+/// disable from span traversals (such as iterating over parents, etc).
+/// 2. If all the bits are set, then every per-layer filter has decided it
+/// doesn't want to enable that span or event. In that case, the
+/// `Registry`'s `enabled` method will return `false`, so that
+/// recording a span or event can be skipped entirely.
+#[derive(Debug)]
+pub(crate) struct FilterState {
+ enabled: Cell<FilterMap>,
+ // TODO(eliza): `Interest`s should _probably_ be `Copy`. The only reason
+ // they're not is our Obsessive Commitment to Forwards-Compatibility. If
+ // this changes in tracing-core`, we can make this a `Cell` rather than
+ // `RefCell`...
+ interest: RefCell<Option<Interest>>,
+
+ #[cfg(debug_assertions)]
+ counters: DebugCounters,
+}
+
+/// Extra counters added to `FilterState` used only to make debug assertions.
+#[cfg(debug_assertions)]
+#[derive(Debug, Default)]
+struct DebugCounters {
+ /// How many per-layer filters have participated in the current `enabled`
+ /// call?
+ in_filter_pass: Cell<usize>,
+
+ /// How many per-layer filters have participated in the current `register_callsite`
+ /// call?
+ in_interest_pass: Cell<usize>,
+}
+
+thread_local! {
+ pub(crate) static FILTERING: FilterState = FilterState::new();
+}
+
+/// Extension trait adding [combinators] for combining [`Filter`].
+///
+/// [combinators]: crate::filter::combinator
+/// [`Filter`]: crate::layer::Filter
+pub trait FilterExt<S>: layer::Filter<S> {
+ /// Combines this [`Filter`] with another [`Filter`] s so that spans and
+ /// events are enabled if and only if *both* filters return `true`.
+ ///
+ /// # Examples
+ ///
+ /// Enabling spans or events if they have both a particular target *and* are
+ /// above a certain level:
+ ///
+ /// ```
+ /// use tracing_subscriber::{
+ /// filter::{filter_fn, LevelFilter, FilterExt},
+ /// prelude::*,
+ /// };
+ ///
+ /// // Enables spans and events with targets starting with `interesting_target`:
+ /// let target_filter = filter_fn(|meta| {
+ /// meta.target().starts_with("interesting_target")
+ /// });
+ ///
+ /// // Enables spans and events with levels `INFO` and below:
+ /// let level_filter = LevelFilter::INFO;
+ ///
+ /// // Combine the two filters together, returning a filter that only enables
+ /// // spans and events that *both* filters will enable:
+ /// let filter = target_filter.and(level_filter);
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(tracing_subscriber::fmt::layer().with_filter(filter))
+ /// .init();
+ ///
+ /// // This event will *not* be enabled:
+ /// tracing::info!("an event with an uninteresting target");
+ ///
+ /// // This event *will* be enabled:
+ /// tracing::info!(target: "interesting_target", "a very interesting event");
+ ///
+ /// // This event will *not* be enabled:
+ /// tracing::debug!(target: "interesting_target", "interesting debug event...");
+ /// ```
+ ///
+ /// [`Filter`]: crate::layer::Filter
+ fn and<B>(self, other: B) -> combinator::And<Self, B, S>
+ where
+ Self: Sized,
+ B: layer::Filter<S>,
+ {
+ combinator::And::new(self, other)
+ }
+
+ /// Combines two [`Filter`]s so that spans and events are enabled if *either* filter
+ /// returns `true`.
+ ///
+ /// # Examples
+ ///
+ /// Enabling spans and events at the `INFO` level and above, and all spans
+ /// and events with a particular target:
+ /// ```
+ /// use tracing_subscriber::{
+ /// filter::{filter_fn, LevelFilter, FilterExt},
+ /// prelude::*,
+ /// };
+ ///
+ /// // Enables spans and events with targets starting with `interesting_target`:
+ /// let target_filter = filter_fn(|meta| {
+ /// meta.target().starts_with("interesting_target")
+ /// });
+ ///
+ /// // Enables spans and events with levels `INFO` and below:
+ /// let level_filter = LevelFilter::INFO;
+ ///
+ /// // Combine the two filters together so that a span or event is enabled
+ /// // if it is at INFO or lower, or if it has a target starting with
+ /// // `interesting_target`.
+ /// let filter = level_filter.or(target_filter);
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(tracing_subscriber::fmt::layer().with_filter(filter))
+ /// .init();
+ ///
+ /// // This event will *not* be enabled:
+ /// tracing::debug!("an uninteresting event");
+ ///
+ /// // This event *will* be enabled:
+ /// tracing::info!("an uninteresting INFO event");
+ ///
+ /// // This event *will* be enabled:
+ /// tracing::info!(target: "interesting_target", "a very interesting event");
+ ///
+ /// // This event *will* be enabled:
+ /// tracing::debug!(target: "interesting_target", "interesting debug event...");
+ /// ```
+ ///
+ /// Enabling a higher level for a particular target by using `or` in
+ /// conjunction with the [`and`] combinator:
+ ///
+ /// ```
+ /// use tracing_subscriber::{
+ /// filter::{filter_fn, LevelFilter, FilterExt},
+ /// prelude::*,
+ /// };
+ ///
+ /// // This filter will enable spans and events with targets beginning with
+ /// // `my_crate`:
+ /// let my_crate = filter_fn(|meta| {
+ /// meta.target().starts_with("my_crate")
+ /// });
+ ///
+ /// let filter = my_crate
+ /// // Combine the `my_crate` filter with a `LevelFilter` to produce a
+ /// // filter that will enable the `INFO` level and lower for spans and
+ /// // events with `my_crate` targets:
+ /// .and(LevelFilter::INFO)
+ /// // If a span or event *doesn't* have a target beginning with
+ /// // `my_crate`, enable it if it has the `WARN` level or lower:
+ /// .or(LevelFilter::WARN);
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(tracing_subscriber::fmt::layer().with_filter(filter))
+ /// .init();
+ /// ```
+ ///
+ /// [`Filter`]: crate::layer::Filter
+ /// [`and`]: FilterExt::and
+ fn or<B>(self, other: B) -> combinator::Or<Self, B, S>
+ where
+ Self: Sized,
+ B: layer::Filter<S>,
+ {
+ combinator::Or::new(self, other)
+ }
+
+ /// Inverts `self`, returning a filter that enables spans and events only if
+ /// `self` would *not* enable them.
+ ///
+ /// This inverts the values returned by the [`enabled`] and [`callsite_enabled`]
+ /// methods on the wrapped filter; it does *not* invert [`event_enabled`], as
+ /// filters which do not implement filtering on event field values will return
+ /// the default `true` even for events that their [`enabled`] method disables.
+ ///
+ /// Consider a normal filter defined as:
+ ///
+ /// ```ignore (pseudo-code)
+ /// // for spans
+ /// match callsite_enabled() {
+ /// ALWAYS => on_span(),
+ /// SOMETIMES => if enabled() { on_span() },
+ /// NEVER => (),
+ /// }
+ /// // for events
+ /// match callsite_enabled() {
+ /// ALWAYS => on_event(),
+ /// SOMETIMES => if enabled() && event_enabled() { on_event() },
+ /// NEVER => (),
+ /// }
+ /// ```
+ ///
+ /// and an inverted filter defined as:
+ ///
+ /// ```ignore (pseudo-code)
+ /// // for spans
+ /// match callsite_enabled() {
+ /// ALWAYS => (),
+ /// SOMETIMES => if !enabled() { on_span() },
+ /// NEVER => on_span(),
+ /// }
+ /// // for events
+ /// match callsite_enabled() {
+ /// ALWAYS => (),
+ /// SOMETIMES => if !enabled() { on_event() },
+ /// NEVER => on_event(),
+ /// }
+ /// ```
+ ///
+ /// A proper inversion would do `!(enabled() && event_enabled())` (or
+ /// `!enabled() || !event_enabled()`), but because of the implicit `&&`
+ /// relation between `enabled` and `event_enabled`, it is difficult to
+ /// short circuit and not call the wrapped `event_enabled`.
+ ///
+ /// A combinator which remembers the result of `enabled` in order to call
+ /// `event_enabled` only when `enabled() == true` is possible, but requires
+ /// additional thread-local mutable state to support a very niche use case.
+ //
+ // Also, it'd mean the wrapped layer's `enabled()` always gets called and
+ // globally applied to events where it doesn't today, since we can't know
+ // what `event_enabled` will say until we have the event to call it with.
+ ///
+ /// [`Filter`]: crate::subscribe::Filter
+ /// [`enabled`]: crate::subscribe::Filter::enabled
+ /// [`event_enabled`]: crate::subscribe::Filter::event_enabled
+ /// [`callsite_enabled`]: crate::subscribe::Filter::callsite_enabled
+ fn not(self) -> combinator::Not<Self, S>
+ where
+ Self: Sized,
+ {
+ combinator::Not::new(self)
+ }
+
+ /// [Boxes] `self`, erasing its concrete type.
+ ///
+ /// This is equivalent to calling [`Box::new`], but in method form, so that
+ /// it can be used when chaining combinator methods.
+ ///
+ /// # Examples
+ ///
+ /// When different combinations of filters are used conditionally, they may
+ /// have different types. For example, the following code won't compile,
+ /// since the `if` and `else` clause produce filters of different types:
+ ///
+ /// ```compile_fail
+ /// use tracing_subscriber::{
+ /// filter::{filter_fn, LevelFilter, FilterExt},
+ /// prelude::*,
+ /// };
+ ///
+ /// let enable_bar_target: bool = // ...
+ /// # false;
+ ///
+ /// let filter = if enable_bar_target {
+ /// filter_fn(|meta| meta.target().starts_with("foo"))
+ /// // If `enable_bar_target` is true, add a `filter_fn` enabling
+ /// // spans and events with the target `bar`:
+ /// .or(filter_fn(|meta| meta.target().starts_with("bar")))
+ /// .and(LevelFilter::INFO)
+ /// } else {
+ /// filter_fn(|meta| meta.target().starts_with("foo"))
+ /// .and(LevelFilter::INFO)
+ /// };
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(tracing_subscriber::fmt::layer().with_filter(filter))
+ /// .init();
+ /// ```
+ ///
+ /// By using `boxed`, the types of the two different branches can be erased,
+ /// so the assignment to the `filter` variable is valid (as both branches
+ /// have the type `Box<dyn Filter<S> + Send + Sync + 'static>`). The
+ /// following code *does* compile:
+ ///
+ /// ```
+ /// use tracing_subscriber::{
+ /// filter::{filter_fn, LevelFilter, FilterExt},
+ /// prelude::*,
+ /// };
+ ///
+ /// let enable_bar_target: bool = // ...
+ /// # false;
+ ///
+ /// let filter = if enable_bar_target {
+ /// filter_fn(|meta| meta.target().starts_with("foo"))
+ /// .or(filter_fn(|meta| meta.target().starts_with("bar")))
+ /// .and(LevelFilter::INFO)
+ /// // Boxing the filter erases its type, so both branches now
+ /// // have the same type.
+ /// .boxed()
+ /// } else {
+ /// filter_fn(|meta| meta.target().starts_with("foo"))
+ /// .and(LevelFilter::INFO)
+ /// .boxed()
+ /// };
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(tracing_subscriber::fmt::layer().with_filter(filter))
+ /// .init();
+ /// ```
+ ///
+ /// [Boxes]: std::boxed
+ /// [`Box::new`]: std::boxed::Box::new
+ fn boxed(self) -> Box<dyn layer::Filter<S> + Send + Sync + 'static>
+ where
+ Self: Sized + Send + Sync + 'static,
+ {
+ Box::new(self)
+ }
+}
+
+// === impl Filter ===
+
+#[cfg(feature = "registry")]
+#[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
+impl<S> layer::Filter<S> for LevelFilter {
+ fn enabled(&self, meta: &Metadata<'_>, _: &Context<'_, S>) -> bool {
+ meta.level() <= self
+ }
+
+ fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest {
+ if meta.level() <= self {
+ Interest::always()
+ } else {
+ Interest::never()
+ }
+ }
+
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ Some(*self)
+ }
+}
+
+macro_rules! filter_impl_body {
+ () => {
+ #[inline]
+ fn enabled(&self, meta: &Metadata<'_>, cx: &Context<'_, S>) -> bool {
+ self.deref().enabled(meta, cx)
+ }
+
+ #[inline]
+ fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest {
+ self.deref().callsite_enabled(meta)
+ }
+
+ #[inline]
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ self.deref().max_level_hint()
+ }
+ };
+}
+
+#[cfg(feature = "registry")]
+#[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
+impl<S> layer::Filter<S> for Arc<dyn layer::Filter<S> + Send + Sync + 'static> {
+ filter_impl_body!();
+}
+
+#[cfg(feature = "registry")]
+#[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
+impl<S> layer::Filter<S> for Box<dyn layer::Filter<S> + Send + Sync + 'static> {
+ filter_impl_body!();
+}
+
+// === impl Filtered ===
+
+impl<L, F, S> Filtered<L, F, S> {
+ /// Wraps the provided [`Layer`] so that it is filtered by the given
+ /// [`Filter`].
+ ///
+ /// This is equivalent to calling the [`Layer::with_filter`] method.
+ ///
+ /// See the [documentation on per-layer filtering][plf] for details.
+ ///
+ /// [`Filter`]: crate::layer::Filter
+ /// [plf]: crate::layer#per-layer-filtering
+ pub fn new(layer: L, filter: F) -> Self {
+ Self {
+ layer,
+ filter,
+ id: MagicPlfDowncastMarker(FilterId::disabled()),
+ _s: PhantomData,
+ }
+ }
+
+ #[inline(always)]
+ fn id(&self) -> FilterId {
+ debug_assert!(
+ !self.id.0.is_disabled(),
+ "a `Filtered` layer was used, but it had no `FilterId`; \
+ was it registered with the subscriber?"
+ );
+ self.id.0
+ }
+
+ fn did_enable(&self, f: impl FnOnce()) {
+ FILTERING.with(|filtering| filtering.did_enable(self.id(), f))
+ }
+
+ /// Borrows the [`Filter`](crate::layer::Filter) used by this layer.
+ pub fn filter(&self) -> &F {
+ &self.filter
+ }
+
+ /// Mutably borrows the [`Filter`](crate::layer::Filter) used by this layer.
+ ///
+ /// When this layer can be mutably borrowed, this may be used to mutate the filter.
+ /// Generally, this will primarily be used with the
+ /// [`reload::Handle::modify`](crate::reload::Handle::modify) method.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use tracing::info;
+ /// # use tracing_subscriber::{filter,fmt,reload,Registry,prelude::*};
+ /// # fn main() {
+ /// let filtered_layer = fmt::Layer::default().with_filter(filter::LevelFilter::WARN);
+ /// let (filtered_layer, reload_handle) = reload::Layer::new(filtered_layer);
+ /// #
+ /// # // specifying the Registry type is required
+ /// # let _: &reload::Handle<filter::Filtered<fmt::Layer<Registry>,
+ /// # filter::LevelFilter, Registry>,Registry>
+ /// # = &reload_handle;
+ /// #
+ /// info!("This will be ignored");
+ /// reload_handle.modify(|layer| *layer.filter_mut() = filter::LevelFilter::INFO);
+ /// info!("This will be logged");
+ /// # }
+ /// ```
+ pub fn filter_mut(&mut self) -> &mut F {
+ &mut self.filter
+ }
+
+ /// Borrows the inner [`Layer`] wrapped by this `Filtered` layer.
+ pub fn inner(&self) -> &L {
+ &self.layer
+ }
+
+ /// Mutably borrows the inner [`Layer`] wrapped by this `Filtered` layer.
+ ///
+ /// This method is primarily expected to be used with the
+ /// [`reload::Handle::modify`](crate::reload::Handle::modify) method.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use tracing::info;
+ /// # use tracing_subscriber::{filter,fmt,reload,Registry,prelude::*};
+ /// # fn non_blocking<T: std::io::Write>(writer: T) -> (fn() -> std::io::Stdout) {
+ /// # std::io::stdout
+ /// # }
+ /// # fn main() {
+ /// let filtered_layer = fmt::layer().with_writer(non_blocking(std::io::stderr())).with_filter(filter::LevelFilter::INFO);
+ /// let (filtered_layer, reload_handle) = reload::Layer::new(filtered_layer);
+ /// #
+ /// # // specifying the Registry type is required
+ /// # let _: &reload::Handle<filter::Filtered<fmt::Layer<Registry, _, _, fn() -> std::io::Stdout>,
+ /// # filter::LevelFilter, Registry>, Registry>
+ /// # = &reload_handle;
+ /// #
+ /// info!("This will be logged to stderr");
+ /// reload_handle.modify(|layer| *layer.inner_mut().writer_mut() = non_blocking(std::io::stdout()));
+ /// info!("This will be logged to stdout");
+ /// # }
+ /// ```
+ ///
+ /// [subscriber]: Subscribe
+ pub fn inner_mut(&mut self) -> &mut L {
+ &mut self.layer
+ }
+}
+
+impl<S, L, F> Layer<S> for Filtered<L, F, S>
+where
+ S: Subscriber + for<'span> registry::LookupSpan<'span> + 'static,
+ F: layer::Filter<S> + 'static,
+ L: Layer<S>,
+{
+ fn on_register_dispatch(&self, collector: &Dispatch) {
+ self.layer.on_register_dispatch(collector);
+ }
+
+ fn on_layer(&mut self, subscriber: &mut S) {
+ self.id = MagicPlfDowncastMarker(subscriber.register_filter());
+ self.layer.on_layer(subscriber);
+ }
+
+ // TODO(eliza): can we figure out a nice way to make the `Filtered` layer
+ // not call `is_enabled_for` in hooks that the inner layer doesn't actually
+ // have real implementations of? probably not...
+ //
+ // it would be cool if there was some wild rust reflection way of checking
+ // if a trait impl has the default impl of a trait method or not, but that's
+ // almsot certainly impossible...right?
+
+ fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
+ let interest = self.filter.callsite_enabled(metadata);
+
+ // If the filter didn't disable the callsite, allow the inner layer to
+ // register it — since `register_callsite` is also used for purposes
+ // such as reserving/caching per-callsite data, we want the inner layer
+ // to be able to perform any other registration steps. However, we'll
+ // ignore its `Interest`.
+ if !interest.is_never() {
+ self.layer.register_callsite(metadata);
+ }
+
+ // Add our `Interest` to the current sum of per-layer filter `Interest`s
+ // for this callsite.
+ FILTERING.with(|filtering| filtering.add_interest(interest));
+
+ // don't short circuit! if the stack consists entirely of `Layer`s with
+ // per-layer filters, the `Registry` will return the actual `Interest`
+ // value that's the sum of all the `register_callsite` calls to those
+ // per-layer filters. if we returned an actual `never` interest here, a
+ // `Layered` layer would short-circuit and not allow any `Filtered`
+ // layers below us if _they_ are interested in the callsite.
+ Interest::always()
+ }
+
+ fn enabled(&self, metadata: &Metadata<'_>, cx: Context<'_, S>) -> bool {
+ let cx = cx.with_filter(self.id());
+ let enabled = self.filter.enabled(metadata, &cx);
+ FILTERING.with(|filtering| filtering.set(self.id(), enabled));
+
+ if enabled {
+ // If the filter enabled this metadata, ask the wrapped layer if
+ // _it_ wants it --- it might have a global filter.
+ self.layer.enabled(metadata, cx)
+ } else {
+ // Otherwise, return `true`. The _per-layer_ filter disabled this
+ // metadata, but returning `false` in `Layer::enabled` will
+ // short-circuit and globally disable the span or event. This is
+ // *not* what we want for per-layer filters, as other layers may
+ // still want this event. Returning `true` here means we'll continue
+ // asking the next layer in the stack.
+ //
+ // Once all per-layer filters have been evaluated, the `Registry`
+ // at the root of the stack will return `false` from its `enabled`
+ // method if *every* per-layer filter disabled this metadata.
+ // Otherwise, the individual per-layer filters will skip the next
+ // `new_span` or `on_event` call for their layer if *they* disabled
+ // the span or event, but it was not globally disabled.
+ true
+ }
+ }
+
+ fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, cx: Context<'_, S>) {
+ self.did_enable(|| {
+ let cx = cx.with_filter(self.id());
+ self.filter.on_new_span(attrs, id, cx.clone());
+ self.layer.on_new_span(attrs, id, cx);
+ })
+ }
+
+ #[doc(hidden)]
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ self.filter.max_level_hint()
+ }
+
+ fn on_record(&self, span: &span::Id, values: &span::Record<'_>, cx: Context<'_, S>) {
+ if let Some(cx) = cx.if_enabled_for(span, self.id()) {
+ self.filter.on_record(span, values, cx.clone());
+ self.layer.on_record(span, values, cx)
+ }
+ }
+
+ fn on_follows_from(&self, span: &span::Id, follows: &span::Id, cx: Context<'_, S>) {
+ // only call `on_follows_from` if both spans are enabled by us
+ if cx.is_enabled_for(span, self.id()) && cx.is_enabled_for(follows, self.id()) {
+ self.layer
+ .on_follows_from(span, follows, cx.with_filter(self.id()))
+ }
+ }
+
+ fn event_enabled(&self, event: &Event<'_>, cx: Context<'_, S>) -> bool {
+ let cx = cx.with_filter(self.id());
+ let enabled = FILTERING
+ .with(|filtering| filtering.and(self.id(), || self.filter.event_enabled(event, &cx)));
+
+ if enabled {
+ // If the filter enabled this event, ask the wrapped subscriber if
+ // _it_ wants it --- it might have a global filter.
+ self.layer.event_enabled(event, cx)
+ } else {
+ // Otherwise, return `true`. See the comment in `enabled` for why this
+ // is necessary.
+ true
+ }
+ }
+
+ fn on_event(&self, event: &Event<'_>, cx: Context<'_, S>) {
+ self.did_enable(|| {
+ self.layer.on_event(event, cx.with_filter(self.id()));
+ })
+ }
+
+ fn on_enter(&self, id: &span::Id, cx: Context<'_, S>) {
+ if let Some(cx) = cx.if_enabled_for(id, self.id()) {
+ self.filter.on_enter(id, cx.clone());
+ self.layer.on_enter(id, cx);
+ }
+ }
+
+ fn on_exit(&self, id: &span::Id, cx: Context<'_, S>) {
+ if let Some(cx) = cx.if_enabled_for(id, self.id()) {
+ self.filter.on_exit(id, cx.clone());
+ self.layer.on_exit(id, cx);
+ }
+ }
+
+ fn on_close(&self, id: span::Id, cx: Context<'_, S>) {
+ if let Some(cx) = cx.if_enabled_for(&id, self.id()) {
+ self.filter.on_close(id.clone(), cx.clone());
+ self.layer.on_close(id, cx);
+ }
+ }
+
+ // XXX(eliza): the existence of this method still makes me sad...
+ fn on_id_change(&self, old: &span::Id, new: &span::Id, cx: Context<'_, S>) {
+ if let Some(cx) = cx.if_enabled_for(old, self.id()) {
+ self.layer.on_id_change(old, new, cx)
+ }
+ }
+
+ #[doc(hidden)]
+ #[inline]
+ unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
+ match id {
+ id if id == TypeId::of::<Self>() => Some(self as *const _ as *const ()),
+ id if id == TypeId::of::<L>() => Some(&self.layer as *const _ as *const ()),
+ id if id == TypeId::of::<F>() => Some(&self.filter as *const _ as *const ()),
+ id if id == TypeId::of::<MagicPlfDowncastMarker>() => {
+ Some(&self.id as *const _ as *const ())
+ }
+ _ => self.layer.downcast_raw(id),
+ }
+ }
+}
+
+impl<F, L, S> fmt::Debug for Filtered<F, L, S>
+where
+ F: fmt::Debug,
+ L: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Filtered")
+ .field("filter", &self.filter)
+ .field("layer", &self.layer)
+ .field("id", &self.id)
+ .finish()
+ }
+}
+
+// === impl FilterId ===
+
+impl FilterId {
+ const fn disabled() -> Self {
+ Self(std::u64::MAX)
+ }
+
+ /// Returns a `FilterId` that will consider _all_ spans enabled.
+ pub(crate) const fn none() -> Self {
+ Self(0)
+ }
+
+ pub(crate) fn new(id: u8) -> Self {
+ assert!(id < 64, "filter IDs may not be greater than 64");
+ Self(1 << id as usize)
+ }
+
+ /// Combines two `FilterId`s, returning a new `FilterId` that will match a
+ /// [`FilterMap`] where the span was disabled by _either_ this `FilterId`
+ /// *or* the combined `FilterId`.
+ ///
+ /// This method is called by [`Context`]s when adding the `FilterId` of a
+ /// [`Filtered`] layer to the context.
+ ///
+ /// This is necessary for cases where we have a tree of nested [`Filtered`]
+ /// layers, like this:
+ ///
+ /// ```text
+ /// Filtered {
+ /// filter1,
+ /// Layered {
+ /// layer1,
+ /// Filtered {
+ /// filter2,
+ /// layer2,
+ /// },
+ /// }
+ /// ```
+ ///
+ /// We want `layer2` to be affected by both `filter1` _and_ `filter2`.
+ /// Without combining `FilterId`s, this works fine when filtering
+ /// `on_event`/`new_span`, because the outer `Filtered` layer (`filter1`)
+ /// won't call the inner layer's `on_event` or `new_span` callbacks if it
+ /// disabled the event/span.
+ ///
+ /// However, it _doesn't_ work when filtering span lookups and traversals
+ /// (e.g. `scope`). This is because the [`Context`] passed to `layer2`
+ /// would set its filter ID to the filter ID of `filter2`, and would skip
+ /// spans that were disabled by `filter2`. However, what if a span was
+ /// disabled by `filter1`? We wouldn't see it in `new_span`, but we _would_
+ /// see it in lookups and traversals...which we don't want.
+ ///
+ /// When a [`Filtered`] layer adds its ID to a [`Context`], it _combines_ it
+ /// with any previous filter ID that the context had, rather than replacing
+ /// it. That way, `layer2`'s context will check if a span was disabled by
+ /// `filter1` _or_ `filter2`. The way we do this, instead of representing
+ /// `FilterId`s as a number number that we shift a 1 over by to get a mask,
+ /// we just store the actual mask,so we can combine them with a bitwise-OR.
+ ///
+ /// For example, if we consider the following case (pretending that the
+ /// masks are 8 bits instead of 64 just so i don't have to write out a bunch
+ /// of extra zeroes):
+ ///
+ /// - `filter1` has the filter id 1 (`0b0000_0001`)
+ /// - `filter2` has the filter id 2 (`0b0000_0010`)
+ ///
+ /// A span that gets disabled by filter 1 would have the [`FilterMap`] with
+ /// bits `0b0000_0001`.
+ ///
+ /// If the `FilterId` was internally represented as `(bits to shift + 1),
+ /// when `layer2`'s [`Context`] checked if it enabled the span, it would
+ /// make the mask `0b0000_0010` (`1 << 1`). That bit would not be set in the
+ /// [`FilterMap`], so it would see that it _didn't_ disable the span. Which
+ /// is *true*, it just doesn't reflect the tree-like shape of the actual
+ /// subscriber.
+ ///
+ /// By having the IDs be masks instead of shifts, though, when the
+ /// [`Filtered`] with `filter2` gets the [`Context`] with `filter1`'s filter ID,
+ /// instead of replacing it, it ors them together:
+ ///
+ /// ```ignore
+ /// 0b0000_0001 | 0b0000_0010 == 0b0000_0011;
+ /// ```
+ ///
+ /// We then test if the span was disabled by seeing if _any_ bits in the
+ /// mask are `1`:
+ ///
+ /// ```ignore
+ /// filtermap & mask != 0;
+ /// 0b0000_0001 & 0b0000_0011 != 0;
+ /// 0b0000_0001 != 0;
+ /// true;
+ /// ```
+ ///
+ /// [`Context`]: crate::layer::Context
+ pub(crate) fn and(self, FilterId(other): Self) -> Self {
+ // If this mask is disabled, just return the other --- otherwise, we
+ // would always see that every span is disabled.
+ if self.0 == Self::disabled().0 {
+ return Self(other);
+ }
+
+ Self(self.0 | other)
+ }
+
+ fn is_disabled(self) -> bool {
+ self.0 == Self::disabled().0
+ }
+}
+
+impl fmt::Debug for FilterId {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // don't print a giant set of the numbers 0..63 if the filter ID is disabled.
+ if self.0 == Self::disabled().0 {
+ return f
+ .debug_tuple("FilterId")
+ .field(&format_args!("DISABLED"))
+ .finish();
+ }
+
+ if f.alternate() {
+ f.debug_struct("FilterId")
+ .field("ids", &format_args!("{:?}", FmtBitset(self.0)))
+ .field("bits", &format_args!("{:b}", self.0))
+ .finish()
+ } else {
+ f.debug_tuple("FilterId").field(&FmtBitset(self.0)).finish()
+ }
+ }
+}
+
+impl fmt::Binary for FilterId {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("FilterId")
+ .field(&format_args!("{:b}", self.0))
+ .finish()
+ }
+}
+
+// === impl FilterExt ===
+
+impl<F, S> FilterExt<S> for F where F: layer::Filter<S> {}
+
+// === impl FilterMap ===
+
+impl FilterMap {
+ pub(crate) fn set(self, FilterId(mask): FilterId, enabled: bool) -> Self {
+ if mask == std::u64::MAX {
+ return self;
+ }
+
+ if enabled {
+ Self {
+ bits: self.bits & (!mask),
+ }
+ } else {
+ Self {
+ bits: self.bits | mask,
+ }
+ }
+ }
+
+ #[inline]
+ pub(crate) fn is_enabled(self, FilterId(mask): FilterId) -> bool {
+ self.bits & mask == 0
+ }
+
+ #[inline]
+ pub(crate) fn any_enabled(self) -> bool {
+ self.bits != std::u64::MAX
+ }
+}
+
+impl fmt::Debug for FilterMap {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let alt = f.alternate();
+ let mut s = f.debug_struct("FilterMap");
+ s.field("disabled_by", &format_args!("{:?}", &FmtBitset(self.bits)));
+
+ if alt {
+ s.field("bits", &format_args!("{:b}", self.bits));
+ }
+
+ s.finish()
+ }
+}
+
+impl fmt::Binary for FilterMap {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("FilterMap")
+ .field("bits", &format_args!("{:b}", self.bits))
+ .finish()
+ }
+}
+
+// === impl FilterState ===
+
+impl FilterState {
+ fn new() -> Self {
+ Self {
+ enabled: Cell::new(FilterMap::default()),
+ interest: RefCell::new(None),
+
+ #[cfg(debug_assertions)]
+ counters: DebugCounters::default(),
+ }
+ }
+
+ fn set(&self, filter: FilterId, enabled: bool) {
+ #[cfg(debug_assertions)]
+ {
+ let in_current_pass = self.counters.in_filter_pass.get();
+ if in_current_pass == 0 {
+ debug_assert_eq!(self.enabled.get(), FilterMap::default());
+ }
+ self.counters.in_filter_pass.set(in_current_pass + 1);
+ debug_assert_eq!(
+ self.counters.in_interest_pass.get(),
+ 0,
+ "if we are in or starting a filter pass, we must not be in an interest pass."
+ )
+ }
+
+ self.enabled.set(self.enabled.get().set(filter, enabled))
+ }
+
+ fn add_interest(&self, interest: Interest) {
+ let mut curr_interest = self.interest.borrow_mut();
+
+ #[cfg(debug_assertions)]
+ {
+ let in_current_pass = self.counters.in_interest_pass.get();
+ if in_current_pass == 0 {
+ debug_assert!(curr_interest.is_none());
+ }
+ self.counters.in_interest_pass.set(in_current_pass + 1);
+ }
+
+ if let Some(curr_interest) = curr_interest.as_mut() {
+ if (curr_interest.is_always() && !interest.is_always())
+ || (curr_interest.is_never() && !interest.is_never())
+ {
+ *curr_interest = Interest::sometimes();
+ }
+ // If the two interests are the same, do nothing. If the current
+ // interest is `sometimes`, stay sometimes.
+ } else {
+ *curr_interest = Some(interest);
+ }
+ }
+
+ pub(crate) fn event_enabled() -> bool {
+ FILTERING
+ .try_with(|this| {
+ let enabled = this.enabled.get().any_enabled();
+ #[cfg(debug_assertions)]
+ {
+ if this.counters.in_filter_pass.get() == 0 {
+ debug_assert_eq!(this.enabled.get(), FilterMap::default());
+ }
+
+ // Nothing enabled this event, we won't tick back down the
+ // counter in `did_enable`. Reset it.
+ if !enabled {
+ this.counters.in_filter_pass.set(0);
+ }
+ }
+ enabled
+ })
+ .unwrap_or(true)
+ }
+
+ /// Executes a closure if the filter with the provided ID did not disable
+ /// the current span/event.
+ ///
+ /// This is used to implement the `on_event` and `new_span` methods for
+ /// `Filtered`.
+ fn did_enable(&self, filter: FilterId, f: impl FnOnce()) {
+ let map = self.enabled.get();
+ if map.is_enabled(filter) {
+ // If the filter didn't disable the current span/event, run the
+ // callback.
+ f();
+ } else {
+ // Otherwise, if this filter _did_ disable the span or event
+ // currently being processed, clear its bit from this thread's
+ // `FilterState`. The bit has already been "consumed" by skipping
+ // this callback, and we need to ensure that the `FilterMap` for
+ // this thread is reset when the *next* `enabled` call occurs.
+ self.enabled.set(map.set(filter, true));
+ }
+ #[cfg(debug_assertions)]
+ {
+ let in_current_pass = self.counters.in_filter_pass.get();
+ if in_current_pass <= 1 {
+ debug_assert_eq!(self.enabled.get(), FilterMap::default());
+ }
+ self.counters
+ .in_filter_pass
+ .set(in_current_pass.saturating_sub(1));
+ debug_assert_eq!(
+ self.counters.in_interest_pass.get(),
+ 0,
+ "if we are in a filter pass, we must not be in an interest pass."
+ )
+ }
+ }
+
+ /// Run a second filtering pass, e.g. for Subscribe::event_enabled.
+ fn and(&self, filter: FilterId, f: impl FnOnce() -> bool) -> bool {
+ let map = self.enabled.get();
+ let enabled = map.is_enabled(filter) && f();
+ self.enabled.set(map.set(filter, enabled));
+ enabled
+ }
+
+ /// Clears the current in-progress filter state.
+ ///
+ /// This resets the [`FilterMap`] and current [`Interest`] as well as
+ /// clearing the debug counters.
+ pub(crate) fn clear_enabled() {
+ // Drop the `Result` returned by `try_with` --- if we are in the middle
+ // a panic and the thread-local has been torn down, that's fine, just
+ // ignore it ratehr than panicking.
+ let _ = FILTERING.try_with(|filtering| {
+ filtering.enabled.set(FilterMap::default());
+
+ #[cfg(debug_assertions)]
+ filtering.counters.in_filter_pass.set(0);
+ });
+ }
+
+ pub(crate) fn take_interest() -> Option<Interest> {
+ FILTERING
+ .try_with(|filtering| {
+ #[cfg(debug_assertions)]
+ {
+ if filtering.counters.in_interest_pass.get() == 0 {
+ debug_assert!(filtering.interest.try_borrow().ok()?.is_none());
+ }
+ filtering.counters.in_interest_pass.set(0);
+ }
+ filtering.interest.try_borrow_mut().ok()?.take()
+ })
+ .ok()?
+ }
+
+ pub(crate) fn filter_map(&self) -> FilterMap {
+ let map = self.enabled.get();
+ #[cfg(debug_assertions)]
+ {
+ if self.counters.in_filter_pass.get() == 0 {
+ debug_assert_eq!(map, FilterMap::default());
+ }
+ }
+
+ map
+ }
+}
+/// This is a horrible and bad abuse of the downcasting system to expose
+/// *internally* whether a layer has per-layer filtering, within
+/// `tracing-subscriber`, without exposing a public API for it.
+///
+/// If a `Layer` has per-layer filtering, it will downcast to a
+/// `MagicPlfDowncastMarker`. Since layers which contain other layers permit
+/// downcasting to recurse to their children, this will do the Right Thing with
+/// layers like Reload, Option, etc.
+///
+/// Why is this a wrapper around the `FilterId`, you may ask? Because
+/// downcasting works by returning a pointer, and we don't want to risk
+/// introducing UB by constructing pointers that _don't_ point to a valid
+/// instance of the type they claim to be. In this case, we don't _intend_ for
+/// this pointer to be dereferenced, so it would actually be fine to return one
+/// that isn't a valid pointer...but we can't guarantee that the caller won't
+/// (accidentally) dereference it, so it's better to be safe than sorry. We
+/// could, alternatively, add an additional field to the type that's used only
+/// for returning pointers to as as part of the evil downcasting hack, but I
+/// thought it was nicer to just add a `repr(transparent)` wrapper to the
+/// existing `FilterId` field, since it won't make the struct any bigger.
+///
+/// Don't worry, this isn't on the test. :)
+#[derive(Clone, Copy)]
+#[repr(transparent)]
+struct MagicPlfDowncastMarker(FilterId);
+impl fmt::Debug for MagicPlfDowncastMarker {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Just pretend that `MagicPlfDowncastMarker` doesn't exist for
+ // `fmt::Debug` purposes...if no one *sees* it in their `Debug` output,
+ // they don't have to know I thought this code would be a good idea.
+ fmt::Debug::fmt(&self.0, f)
+ }
+}
+
+pub(crate) fn is_plf_downcast_marker(type_id: TypeId) -> bool {
+ type_id == TypeId::of::<MagicPlfDowncastMarker>()
+}
+
+/// Does a type implementing `Subscriber` contain any per-layer filters?
+pub(crate) fn subscriber_has_plf<S>(subscriber: &S) -> bool
+where
+ S: Subscriber,
+{
+ (subscriber as &dyn Subscriber).is::<MagicPlfDowncastMarker>()
+}
+
+/// Does a type implementing `Layer` contain any per-layer filters?
+pub(crate) fn layer_has_plf<L, S>(layer: &L) -> bool
+where
+ L: Layer<S>,
+ S: Subscriber,
+{
+ unsafe {
+ // Safety: we're not actually *doing* anything with this pointer --- we
+ // only care about the `Option`, which we're turning into a `bool`. So
+ // even if the layer decides to be evil and give us some kind of invalid
+ // pointer, we don't ever dereference it, so this is always safe.
+ layer.downcast_raw(TypeId::of::<MagicPlfDowncastMarker>())
+ }
+ .is_some()
+}
+
+struct FmtBitset(u64);
+
+impl fmt::Debug for FmtBitset {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut set = f.debug_set();
+ for bit in 0..64 {
+ // if the `bit`-th bit is set, add it to the debug set
+ if self.0 & (1 << bit) != 0 {
+ set.entry(&bit);
+ }
+ }
+ set.finish()
+ }
+}
diff --git a/vendor/tracing-subscriber/src/filter/level.rs b/vendor/tracing-subscriber/src/filter/level.rs
new file mode 100644
index 000000000..0fa601260
--- /dev/null
+++ b/vendor/tracing-subscriber/src/filter/level.rs
@@ -0,0 +1,27 @@
+use tracing_core::{
+ subscriber::{Interest, Subscriber},
+ Metadata,
+};
+
+#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
+pub use tracing_core::metadata::{LevelFilter, ParseLevelFilterError as ParseError};
+
+// === impl LevelFilter ===
+
+impl<S: Subscriber> crate::Layer<S> for LevelFilter {
+ fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
+ if self >= metadata.level() {
+ Interest::always()
+ } else {
+ Interest::never()
+ }
+ }
+
+ fn enabled(&self, metadata: &Metadata<'_>, _: crate::layer::Context<'_, S>) -> bool {
+ self >= metadata.level()
+ }
+
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ Some(*self)
+ }
+}
diff --git a/vendor/tracing-subscriber/src/filter/mod.rs b/vendor/tracing-subscriber/src/filter/mod.rs
new file mode 100644
index 000000000..000a27195
--- /dev/null
+++ b/vendor/tracing-subscriber/src/filter/mod.rs
@@ -0,0 +1,66 @@
+//! [`Layer`]s that control which spans and events are enabled by the wrapped
+//! subscriber.
+//!
+//! This module contains a number of types that provide implementations of
+//! various strategies for filtering which spans and events are enabled. For
+//! details on filtering spans and events using [`Layer`]s, see the
+//! [`layer` module's documentation].
+//!
+//! [`layer` module's documentation]: crate::layer#filtering-with-layers
+//! [`Layer`]: crate::layer
+mod filter_fn;
+
+feature! {
+ #![all(feature = "env-filter", feature = "std")]
+ mod env;
+ pub use self::env::*;
+}
+
+feature! {
+ #![all(feature = "registry", feature = "std")]
+ mod layer_filters;
+ pub use self::layer_filters::*;
+}
+
+mod level;
+
+pub use self::filter_fn::*;
+pub use self::level::{LevelFilter, ParseError as LevelParseError};
+
+#[cfg(not(all(feature = "registry", feature = "std")))]
+pub(crate) use self::has_plf_stubs::*;
+
+feature! {
+ #![any(feature = "std", feature = "alloc")]
+ pub mod targets;
+ pub use self::targets::Targets;
+
+ mod directive;
+ pub use self::directive::ParseError;
+}
+
+/// Stub implementations of the per-layer-fitler detection functions for when the
+/// `registry` feature is disabled.
+#[cfg(not(all(feature = "registry", feature = "std")))]
+mod has_plf_stubs {
+ pub(crate) fn is_plf_downcast_marker(_: core::any::TypeId) -> bool {
+ false
+ }
+
+ /// Does a type implementing `Subscriber` contain any per-layer filters?
+ pub(crate) fn subscriber_has_plf<S>(_: &S) -> bool
+ where
+ S: tracing_core::Subscriber,
+ {
+ false
+ }
+
+ /// Does a type implementing `Layer` contain any per-layer filters?
+ pub(crate) fn layer_has_plf<L, S>(_: &L) -> bool
+ where
+ L: crate::Layer<S>,
+ S: tracing_core::Subscriber,
+ {
+ false
+ }
+}
diff --git a/vendor/tracing-subscriber/src/filter/targets.rs b/vendor/tracing-subscriber/src/filter/targets.rs
new file mode 100644
index 000000000..e1407114b
--- /dev/null
+++ b/vendor/tracing-subscriber/src/filter/targets.rs
@@ -0,0 +1,781 @@
+//! A [filter] that enables or disables spans and events based on their [target] and [level].
+//!
+//! See [`Targets`] for details.
+//!
+//! [target]: tracing_core::Metadata::target
+//! [level]: tracing_core::Level
+//! [filter]: crate::layer#filtering-with-layers
+
+use crate::{
+ filter::{
+ directive::{DirectiveSet, ParseError, StaticDirective},
+ LevelFilter,
+ },
+ layer,
+};
+#[cfg(not(feature = "std"))]
+use alloc::string::String;
+use core::{
+ iter::{Extend, FilterMap, FromIterator},
+ slice,
+ str::FromStr,
+};
+use tracing_core::{Interest, Level, Metadata, Subscriber};
+
+/// A filter that enables or disables spans and events based on their [target]
+/// and [level].
+///
+/// Targets are typically equal to the Rust module path of the code where the
+/// span or event was recorded, although they may be overridden.
+///
+/// This type can be used for both [per-layer filtering][plf] (using its
+/// [`Filter`] implementation) and [global filtering][global] (using its
+/// [`Layer`] implementation).
+///
+/// See the [documentation on filtering with layers][filtering] for details.
+///
+/// # Filtering With `Targets`
+///
+/// A `Targets` filter consists of one or more [target] prefixes, paired with
+/// [`LevelFilter`]s. If a span or event's [target] begins with one of those
+/// prefixes, and its [level] is at or below the [`LevelFilter`] enabled for
+/// that prefix, then the span or event will be enabled.
+///
+/// This is similar to the behavior implemented by the [`env_logger` crate] in
+/// the `log` ecosystem.
+///
+/// The [`EnvFilter`] type also provided by this crate is very similar to `Targets`,
+/// but is capable of a more sophisticated form of filtering where events may
+/// also be enabled or disabled based on the span they are recorded in.
+/// `Targets` can be thought of as a lighter-weight form of [`EnvFilter`] that
+/// can be used instead when this dynamic filtering is not required.
+///
+/// # Examples
+///
+/// A `Targets` filter can be constructed by programmatically adding targets and
+/// levels to enable:
+///
+/// ```
+/// use tracing_subscriber::{filter, prelude::*};
+/// use tracing_core::Level;
+///
+/// let filter = filter::Targets::new()
+/// // Enable the `INFO` level for anything in `my_crate`
+/// .with_target("my_crate", Level::INFO)
+/// // Enable the `DEBUG` level for a specific module.
+/// .with_target("my_crate::interesting_module", Level::DEBUG);
+///
+/// // Build a new subscriber with the `fmt` layer using the `Targets`
+/// // filter we constructed above.
+/// tracing_subscriber::registry()
+/// .with(tracing_subscriber::fmt::layer())
+/// .with(filter)
+/// .init();
+/// ```
+///
+/// [`LevelFilter::OFF`] can be used to disable a particular target:
+/// ```
+/// use tracing_subscriber::filter::{Targets, LevelFilter};
+/// use tracing_core::Level;
+///
+/// let filter = Targets::new()
+/// .with_target("my_crate", Level::INFO)
+/// // Disable all traces from `annoying_module`.
+/// .with_target("my_crate::annoying_module", LevelFilter::OFF);
+/// # drop(filter);
+/// ```
+///
+/// Alternatively, `Targets` implements [`std::str::FromStr`], allowing it to be
+/// parsed from a comma-delimited list of `target=level` pairs. For example:
+///
+/// ```rust
+/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+/// use tracing_subscriber::filter;
+/// use tracing_core::Level;
+///
+/// let filter = "my_crate=info,my_crate::interesting_module=trace,other_crate=debug"
+/// .parse::<filter::Targets>()?;
+///
+/// // The parsed filter is identical to a filter constructed using `with_target`:
+/// assert_eq!(
+/// filter,
+/// filter::Targets::new()
+/// .with_target("my_crate", Level::INFO)
+/// .with_target("my_crate::interesting_module", Level::TRACE)
+/// .with_target("other_crate", Level::DEBUG)
+/// );
+/// # Ok(()) }
+/// ```
+///
+/// This is particularly useful when the list of enabled targets is configurable
+/// by the user at runtime.
+///
+/// The `Targets` filter can be used as a [per-layer filter][plf] *and* as a
+/// [global filter][global]:
+///
+/// ```rust
+/// use tracing_subscriber::{
+/// fmt,
+/// filter::{Targets, LevelFilter},
+/// prelude::*,
+/// };
+/// use tracing_core::Level;
+/// use std::{sync::Arc, fs::File};
+/// # fn docs() -> Result<(), Box<dyn std::error::Error>> {
+///
+/// // A layer that logs events to stdout using the human-readable "pretty"
+/// // format.
+/// let stdout_log = fmt::layer().pretty();
+///
+/// // A layer that logs events to a file, using the JSON format.
+/// let file = File::create("debug_log.json")?;
+/// let debug_log = fmt::layer()
+/// .with_writer(Arc::new(file))
+/// .json();
+///
+/// tracing_subscriber::registry()
+/// // Only log INFO and above to stdout, unless the span or event
+/// // has the `my_crate::cool_module` target prefix.
+/// .with(stdout_log
+/// .with_filter(
+/// Targets::default()
+/// .with_target("my_crate::cool_module", Level::DEBUG)
+/// .with_default(Level::INFO)
+/// )
+/// )
+/// // Log everything enabled by the global filter to `debug_log.json`.
+/// .with(debug_log)
+/// // Configure a global filter for the whole subscriber stack. This will
+/// // control what spans and events are recorded by both the `debug_log`
+/// // and the `stdout_log` layers, and `stdout_log` will *additionally* be
+/// // filtered by its per-layer filter.
+/// .with(
+/// Targets::default()
+/// .with_target("my_crate", Level::TRACE)
+/// .with_target("other_crate", Level::INFO)
+/// .with_target("other_crate::annoying_module", LevelFilter::OFF)
+/// .with_target("third_crate", Level::DEBUG)
+/// ).init();
+/// # Ok(()) }
+///```
+///
+/// [target]: tracing_core::Metadata::target
+/// [level]: tracing_core::Level
+/// [`Filter`]: crate::layer::Filter
+/// [`Layer`]: crate::layer::Layer
+/// [plf]: crate::layer#per-layer-filtering
+/// [global]: crate::layer#global-filtering
+/// [filtering]: crate::layer#filtering-with-layers
+/// [`env_logger` crate]: https://docs.rs/env_logger/0.9.0/env_logger/index.html#enabling-logging
+/// [`EnvFilter`]: crate::filter::EnvFilter
+#[derive(Debug, Default, Clone, PartialEq)]
+pub struct Targets(DirectiveSet<StaticDirective>);
+
+impl Targets {
+ /// Returns a new `Targets` filter.
+ ///
+ /// This filter will enable no targets. Call [`with_target`] or [`with_targets`]
+ /// to add enabled targets, and [`with_default`] to change the default level
+ /// enabled for spans and events that didn't match any of the provided targets.
+ ///
+ /// [`with_target`]: Targets::with_target
+ /// [`with_targets`]: Targets::with_targets
+ /// [`with_default`]: Targets::with_default
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Enables spans and events with [target]s starting with the provided target
+ /// prefix if they are at or below the provided [`LevelFilter`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tracing_subscriber::filter;
+ /// use tracing_core::Level;
+ ///
+ /// let filter = filter::Targets::new()
+ /// // Enable the `INFO` level for anything in `my_crate`
+ /// .with_target("my_crate", Level::INFO)
+ /// // Enable the `DEBUG` level for a specific module.
+ /// .with_target("my_crate::interesting_module", Level::DEBUG);
+ /// # drop(filter);
+ /// ```
+ ///
+ /// [`LevelFilter::OFF`] can be used to disable a particular target:
+ /// ```
+ /// use tracing_subscriber::filter::{Targets, LevelFilter};
+ /// use tracing_core::Level;
+ ///
+ /// let filter = Targets::new()
+ /// .with_target("my_crate", Level::INFO)
+ /// // Disable all traces from `annoying_module`.
+ /// .with_target("my_crate::interesting_module", LevelFilter::OFF);
+ /// # drop(filter);
+ /// ```
+ ///
+ /// [target]: tracing_core::Metadata::target
+ pub fn with_target(mut self, target: impl Into<String>, level: impl Into<LevelFilter>) -> Self {
+ self.0.add(StaticDirective::new(
+ Some(target.into()),
+ Default::default(),
+ level.into(),
+ ));
+ self
+ }
+ /// Adds [target]s from an iterator of [target]-[`LevelFilter`] pairs to this filter.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tracing_subscriber::filter;
+ /// use tracing_core::Level;
+ ///
+ /// let filter = filter::Targets::new()
+ /// .with_targets(vec![
+ /// ("my_crate", Level::INFO),
+ /// ("my_crate::some_module", Level::DEBUG),
+ /// ("my_crate::other_module::cool_stuff", Level::TRACE),
+ /// ("other_crate", Level::WARN)
+ /// ]);
+ /// # drop(filter);
+ /// ```
+ ///
+ /// [`LevelFilter::OFF`] can be used to disable a particular target:
+ /// ```
+ /// use tracing_subscriber::filter::{Targets, LevelFilter};
+ /// use tracing_core::Level;
+ ///
+ /// let filter = Targets::new()
+ /// .with_target("my_crate", Level::INFO)
+ /// // Disable all traces from `annoying_module`.
+ /// .with_target("my_crate::interesting_module", LevelFilter::OFF);
+ /// # drop(filter);
+ /// ```
+ ///
+ /// [target]: tracing_core::Metadata::target
+ pub fn with_targets<T, L>(mut self, targets: impl IntoIterator<Item = (T, L)>) -> Self
+ where
+ String: From<T>,
+ LevelFilter: From<L>,
+ {
+ self.extend(targets);
+ self
+ }
+
+ /// Sets the default level to enable for spans and events whose targets did
+ /// not match any of the configured prefixes.
+ ///
+ /// By default, this is [`LevelFilter::OFF`]. This means that spans and
+ /// events will only be enabled if they match one of the configured target
+ /// prefixes. If this is changed to a different [`LevelFilter`], spans and
+ /// events with targets that did not match any of the configured prefixes
+ /// will be enabled if their level is at or below the provided level.
+ pub fn with_default(mut self, level: impl Into<LevelFilter>) -> Self {
+ self.0
+ .add(StaticDirective::new(None, Default::default(), level.into()));
+ self
+ }
+
+ /// Returns the default level for this filter, if one is set.
+ ///
+ /// The default level is used to filter any spans or events with targets
+ /// that do not match any of the configured set of prefixes.
+ ///
+ /// The default level can be set for a filter either by using
+ /// [`with_default`](Self::with_default) or when parsing from a filter string that includes a
+ /// level without a target (e.g. `"trace"`).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tracing_subscriber::filter::{LevelFilter, Targets};
+ ///
+ /// let filter = Targets::new().with_default(LevelFilter::INFO);
+ /// assert_eq!(filter.default_level(), Some(LevelFilter::INFO));
+ ///
+ /// let filter: Targets = "info".parse().unwrap();
+ /// assert_eq!(filter.default_level(), Some(LevelFilter::INFO));
+ /// ```
+ ///
+ /// The default level is `None` if no default is set:
+ ///
+ /// ```
+ /// use tracing_subscriber::filter::Targets;
+ ///
+ /// let filter = Targets::new();
+ /// assert_eq!(filter.default_level(), None);
+ ///
+ /// let filter: Targets = "my_crate=info".parse().unwrap();
+ /// assert_eq!(filter.default_level(), None);
+ /// ```
+ ///
+ /// Note that an unset default level (`None`) behaves like [`LevelFilter::OFF`] when the filter is
+ /// used, but it could also be set explicitly which may be useful to distinguish (such as when
+ /// merging multiple `Targets`).
+ ///
+ /// ```
+ /// use tracing_subscriber::filter::{LevelFilter, Targets};
+ ///
+ /// let filter = Targets::new().with_default(LevelFilter::OFF);
+ /// assert_eq!(filter.default_level(), Some(LevelFilter::OFF));
+ ///
+ /// let filter: Targets = "off".parse().unwrap();
+ /// assert_eq!(filter.default_level(), Some(LevelFilter::OFF));
+ /// ```
+ pub fn default_level(&self) -> Option<LevelFilter> {
+ self.0.directives().into_iter().find_map(|d| {
+ if d.target.is_none() {
+ Some(d.level)
+ } else {
+ None
+ }
+ })
+ }
+
+ /// Returns an iterator over the [target]-[`LevelFilter`] pairs in this filter.
+ ///
+ /// The order of iteration is undefined.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tracing_subscriber::filter::{Targets, LevelFilter};
+ /// use tracing_core::Level;
+ ///
+ /// let filter = Targets::new()
+ /// .with_target("my_crate", Level::INFO)
+ /// .with_target("my_crate::interesting_module", Level::DEBUG);
+ ///
+ /// let mut targets: Vec<_> = filter.iter().collect();
+ /// targets.sort();
+ ///
+ /// assert_eq!(targets, vec![
+ /// ("my_crate", LevelFilter::INFO),
+ /// ("my_crate::interesting_module", LevelFilter::DEBUG),
+ /// ]);
+ /// ```
+ ///
+ /// [target]: tracing_core::Metadata::target
+ pub fn iter(&self) -> Iter<'_> {
+ self.into_iter()
+ }
+
+ #[inline]
+ fn interested(&self, metadata: &'static Metadata<'static>) -> Interest {
+ if self.0.enabled(metadata) {
+ Interest::always()
+ } else {
+ Interest::never()
+ }
+ }
+
+ /// Returns whether a [target]-[`Level`] pair would be enabled
+ /// by this `Targets`.
+ ///
+ /// This method can be used with [`module_path!`] from `std` as the target
+ /// in order to emulate the behavior of the [`tracing::event!`] and [`tracing::span!`]
+ /// macros.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tracing_subscriber::filter::{Targets, LevelFilter};
+ /// use tracing_core::Level;
+ ///
+ /// let filter = Targets::new()
+ /// .with_target("my_crate", Level::INFO)
+ /// .with_target("my_crate::interesting_module", Level::DEBUG);
+ ///
+ /// assert!(filter.would_enable("my_crate", &Level::INFO));
+ /// assert!(!filter.would_enable("my_crate::interesting_module", &Level::TRACE));
+ /// ```
+ ///
+ /// [target]: tracing_core::Metadata::target
+ /// [`module_path!`]: std::module_path!
+ pub fn would_enable(&self, target: &str, level: &Level) -> bool {
+ // "Correct" to call because `Targets` only produces `StaticDirective`'s with NO
+ // fields
+ self.0.target_enabled(target, level)
+ }
+}
+
+impl<T, L> Extend<(T, L)> for Targets
+where
+ T: Into<String>,
+ L: Into<LevelFilter>,
+{
+ fn extend<I: IntoIterator<Item = (T, L)>>(&mut self, iter: I) {
+ let iter = iter.into_iter().map(|(target, level)| {
+ StaticDirective::new(Some(target.into()), Default::default(), level.into())
+ });
+ self.0.extend(iter);
+ }
+}
+
+impl<T, L> FromIterator<(T, L)> for Targets
+where
+ T: Into<String>,
+ L: Into<LevelFilter>,
+{
+ fn from_iter<I: IntoIterator<Item = (T, L)>>(iter: I) -> Self {
+ let mut this = Self::default();
+ this.extend(iter);
+ this
+ }
+}
+
+impl FromStr for Targets {
+ type Err = ParseError;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ s.split(',')
+ .map(StaticDirective::from_str)
+ .collect::<Result<_, _>>()
+ .map(Self)
+ }
+}
+
+impl<S> layer::Layer<S> for Targets
+where
+ S: Subscriber,
+{
+ fn enabled(&self, metadata: &Metadata<'_>, _: layer::Context<'_, S>) -> bool {
+ self.0.enabled(metadata)
+ }
+
+ fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
+ self.interested(metadata)
+ }
+
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ Some(self.0.max_level)
+ }
+}
+
+#[cfg(feature = "registry")]
+#[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
+impl<S> layer::Filter<S> for Targets {
+ fn enabled(&self, metadata: &Metadata<'_>, _: &layer::Context<'_, S>) -> bool {
+ self.0.enabled(metadata)
+ }
+
+ fn callsite_enabled(&self, metadata: &'static Metadata<'static>) -> Interest {
+ self.interested(metadata)
+ }
+
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ Some(self.0.max_level)
+ }
+}
+
+impl IntoIterator for Targets {
+ type Item = (String, LevelFilter);
+
+ type IntoIter = IntoIter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ IntoIter::new(self)
+ }
+}
+
+impl<'a> IntoIterator for &'a Targets {
+ type Item = (&'a str, LevelFilter);
+
+ type IntoIter = Iter<'a>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ Iter::new(self)
+ }
+}
+
+/// An owning iterator over the [target]-[level] pairs of a `Targets` filter.
+///
+/// This struct is created by the `IntoIterator` trait implementation of [`Targets`].
+///
+/// # Examples
+///
+/// Merge the targets from one `Targets` with another:
+///
+/// ```
+/// use tracing_subscriber::filter::Targets;
+/// use tracing_core::Level;
+///
+/// let mut filter = Targets::new().with_target("my_crate", Level::INFO);
+/// let overrides = Targets::new().with_target("my_crate::interesting_module", Level::DEBUG);
+///
+/// filter.extend(overrides);
+/// # drop(filter);
+/// ```
+///
+/// [target]: tracing_core::Metadata::target
+/// [level]: tracing_core::Level
+#[derive(Debug)]
+pub struct IntoIter(
+ #[allow(clippy::type_complexity)] // alias indirection would probably make this more confusing
+ FilterMap<
+ <DirectiveSet<StaticDirective> as IntoIterator>::IntoIter,
+ fn(StaticDirective) -> Option<(String, LevelFilter)>,
+ >,
+);
+
+impl IntoIter {
+ fn new(targets: Targets) -> Self {
+ Self(targets.0.into_iter().filter_map(|directive| {
+ let level = directive.level;
+ directive.target.map(|target| (target, level))
+ }))
+ }
+}
+
+impl Iterator for IntoIter {
+ type Item = (String, LevelFilter);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.0.size_hint()
+ }
+}
+
+/// A borrowing iterator over the [target]-[level] pairs of a `Targets` filter.
+///
+/// This struct is created by [`iter`] method of [`Targets`], or from the `IntoIterator`
+/// implementation for `&Targets`.
+///
+/// [target]: tracing_core::Metadata::target
+/// [level]: tracing_core::Level
+/// [`iter`]: Targets::iter
+#[derive(Debug)]
+pub struct Iter<'a>(
+ FilterMap<
+ slice::Iter<'a, StaticDirective>,
+ fn(&'a StaticDirective) -> Option<(&'a str, LevelFilter)>,
+ >,
+);
+
+impl<'a> Iter<'a> {
+ fn new(targets: &'a Targets) -> Self {
+ Self(targets.0.iter().filter_map(|directive| {
+ directive
+ .target
+ .as_deref()
+ .map(|target| (target, directive.level))
+ }))
+ }
+}
+
+impl<'a> Iterator for Iter<'a> {
+ type Item = (&'a str, LevelFilter);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.0.size_hint()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ feature! {
+ #![not(feature = "std")]
+ use alloc::{vec, vec::Vec, string::ToString};
+
+ // `dbg!` is only available with `libstd`; just nop it out when testing
+ // with alloc only.
+ macro_rules! dbg {
+ ($x:expr) => { $x }
+ }
+ }
+
+ fn expect_parse(s: &str) -> Targets {
+ match dbg!(s).parse::<Targets>() {
+ Err(e) => panic!("string {:?} did not parse successfully: {}", s, e),
+ Ok(e) => e,
+ }
+ }
+
+ fn expect_parse_ralith(s: &str) {
+ let dirs = expect_parse(s).0.into_vec();
+ assert_eq!(dirs.len(), 2, "\nparsed: {:#?}", dirs);
+ assert_eq!(dirs[0].target, Some("server".to_string()));
+ assert_eq!(dirs[0].level, LevelFilter::DEBUG);
+ assert_eq!(dirs[0].field_names, Vec::<String>::new());
+
+ assert_eq!(dirs[1].target, Some("common".to_string()));
+ assert_eq!(dirs[1].level, LevelFilter::INFO);
+ assert_eq!(dirs[1].field_names, Vec::<String>::new());
+ }
+
+ fn expect_parse_level_directives(s: &str) {
+ let dirs = expect_parse(s).0.into_vec();
+ assert_eq!(dirs.len(), 6, "\nparsed: {:#?}", dirs);
+
+ assert_eq!(dirs[0].target, Some("crate3::mod2::mod1".to_string()));
+ assert_eq!(dirs[0].level, LevelFilter::OFF);
+ assert_eq!(dirs[0].field_names, Vec::<String>::new());
+
+ assert_eq!(dirs[1].target, Some("crate1::mod2::mod3".to_string()));
+ assert_eq!(dirs[1].level, LevelFilter::INFO);
+ assert_eq!(dirs[1].field_names, Vec::<String>::new());
+
+ assert_eq!(dirs[2].target, Some("crate1::mod2".to_string()));
+ assert_eq!(dirs[2].level, LevelFilter::WARN);
+ assert_eq!(dirs[2].field_names, Vec::<String>::new());
+
+ assert_eq!(dirs[3].target, Some("crate1::mod1".to_string()));
+ assert_eq!(dirs[3].level, LevelFilter::ERROR);
+ assert_eq!(dirs[3].field_names, Vec::<String>::new());
+
+ assert_eq!(dirs[4].target, Some("crate3".to_string()));
+ assert_eq!(dirs[4].level, LevelFilter::TRACE);
+ assert_eq!(dirs[4].field_names, Vec::<String>::new());
+
+ assert_eq!(dirs[5].target, Some("crate2".to_string()));
+ assert_eq!(dirs[5].level, LevelFilter::DEBUG);
+ assert_eq!(dirs[5].field_names, Vec::<String>::new());
+ }
+
+ #[test]
+ fn parse_ralith() {
+ expect_parse_ralith("common=info,server=debug");
+ }
+
+ #[test]
+ fn parse_ralith_uc() {
+ expect_parse_ralith("common=INFO,server=DEBUG");
+ }
+
+ #[test]
+ fn parse_ralith_mixed() {
+ expect_parse("common=iNfo,server=dEbUg");
+ }
+
+ #[test]
+ fn expect_parse_valid() {
+ let dirs = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
+ .0
+ .into_vec();
+ assert_eq!(dirs.len(), 4, "\nparsed: {:#?}", dirs);
+ assert_eq!(dirs[0].target, Some("crate1::mod2".to_string()));
+ assert_eq!(dirs[0].level, LevelFilter::TRACE);
+ assert_eq!(dirs[0].field_names, Vec::<String>::new());
+
+ assert_eq!(dirs[1].target, Some("crate1::mod1".to_string()));
+ assert_eq!(dirs[1].level, LevelFilter::ERROR);
+ assert_eq!(dirs[1].field_names, Vec::<String>::new());
+
+ assert_eq!(dirs[2].target, Some("crate3".to_string()));
+ assert_eq!(dirs[2].level, LevelFilter::OFF);
+ assert_eq!(dirs[2].field_names, Vec::<String>::new());
+
+ assert_eq!(dirs[3].target, Some("crate2".to_string()));
+ assert_eq!(dirs[3].level, LevelFilter::DEBUG);
+ assert_eq!(dirs[3].field_names, Vec::<String>::new());
+ }
+
+ #[test]
+ fn parse_level_directives() {
+ expect_parse_level_directives(
+ "crate1::mod1=error,crate1::mod2=warn,crate1::mod2::mod3=info,\
+ crate2=debug,crate3=trace,crate3::mod2::mod1=off",
+ )
+ }
+
+ #[test]
+ fn parse_uppercase_level_directives() {
+ expect_parse_level_directives(
+ "crate1::mod1=ERROR,crate1::mod2=WARN,crate1::mod2::mod3=INFO,\
+ crate2=DEBUG,crate3=TRACE,crate3::mod2::mod1=OFF",
+ )
+ }
+
+ #[test]
+ fn parse_numeric_level_directives() {
+ expect_parse_level_directives(
+ "crate1::mod1=1,crate1::mod2=2,crate1::mod2::mod3=3,crate2=4,\
+ crate3=5,crate3::mod2::mod1=0",
+ )
+ }
+
+ #[test]
+ fn targets_iter() {
+ let filter = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
+ .with_default(LevelFilter::WARN);
+
+ let mut targets: Vec<_> = filter.iter().collect();
+ targets.sort();
+
+ assert_eq!(
+ targets,
+ vec![
+ ("crate1::mod1", LevelFilter::ERROR),
+ ("crate1::mod2", LevelFilter::TRACE),
+ ("crate2", LevelFilter::DEBUG),
+ ("crate3", LevelFilter::OFF),
+ ]
+ );
+ }
+
+ #[test]
+ fn targets_into_iter() {
+ let filter = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
+ .with_default(LevelFilter::WARN);
+
+ let mut targets: Vec<_> = filter.into_iter().collect();
+ targets.sort();
+
+ assert_eq!(
+ targets,
+ vec![
+ ("crate1::mod1".to_string(), LevelFilter::ERROR),
+ ("crate1::mod2".to_string(), LevelFilter::TRACE),
+ ("crate2".to_string(), LevelFilter::DEBUG),
+ ("crate3".to_string(), LevelFilter::OFF),
+ ]
+ );
+ }
+
+ #[test]
+ fn targets_default_level() {
+ let filter = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off");
+ assert_eq!(filter.default_level(), None);
+
+ let filter = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
+ .with_default(LevelFilter::OFF);
+ assert_eq!(filter.default_level(), Some(LevelFilter::OFF));
+
+ let filter = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
+ .with_default(LevelFilter::OFF)
+ .with_default(LevelFilter::INFO);
+ assert_eq!(filter.default_level(), Some(LevelFilter::INFO));
+ }
+
+ #[test]
+ // `println!` is only available with `libstd`.
+ #[cfg(feature = "std")]
+ fn size_of_filters() {
+ fn print_sz(s: &str) {
+ let filter = s.parse::<Targets>().expect("filter should parse");
+ println!(
+ "size_of_val({:?})\n -> {}B",
+ s,
+ std::mem::size_of_val(&filter)
+ );
+ }
+
+ print_sz("info");
+
+ print_sz("foo=debug");
+
+ print_sz(
+ "crate1::mod1=error,crate1::mod2=warn,crate1::mod2::mod3=info,\
+ crate2=debug,crate3=trace,crate3::mod2::mod1=off",
+ );
+ }
+}