/// Metadata describing a [span] or [event]. /// /// All spans and events have the following metadata: /// - A [name], represented as a static string. /// - A [target], a string that categorizes part of the system where the span /// or event occurred. The `tracing` macros default to using the module /// path where the span or event originated as the target, but it may be /// overridden. /// - A [verbosity level]. This determines how verbose a given span or event /// is, and allows enabling or disabling more verbose diagnostics /// situationally. See the documentation for the [`Level`] type for details. /// - The names of the [fields] defined by the span or event. /// - Whether the metadata corresponds to a span or event. /// /// In addition, the following optional metadata describing the source code /// location where the span or event originated _may_ be provided: /// - The [file name] /// - The [line number] /// - The [module path] /// /// Metadata is used by [`Subscriber`]s when filtering spans and events, and it /// may also be used as part of their data payload. /// /// When created by the `event!` or `span!` macro, the metadata describing a /// particular event or span is constructed statically and exists as a single /// static instance. Thus, the overhead of creating the metadata is /// _significantly_ lower than that of creating the actual span. Therefore, /// filtering is based on metadata, rather than on the constructed span. /// /// ## Equality /// /// In well-behaved applications, two `Metadata` with equal /// [callsite identifiers] will be equal in all other ways (i.e., have the same /// `name`, `target`, etc.). Consequently, in release builds, [`Metadata::eq`] /// *only* checks that its arguments have equal callsites. However, the equality /// of `Metadata`'s other fields is checked in debug builds. /// /// [span]: super::span /// [event]: super::event /// [name]: Self::name /// [target]: Self::target /// [fields]: Self::fields /// [verbosity level]: Self::level /// [file name]: Self::file /// [line number]: Self::line /// [module path]: Self::module_path /// [`Subscriber`]: super::subscriber::Subscriber /// [callsite identifiers]: Self::callsite pubstruct Metadata<'a> { /// The name of the span described by this metadata.
name: &'static str,
/// The part of the system that the span that this metadata describes /// occurred in.
target: &'a str,
/// The level of verbosity of the described span.
level: Level,
/// The name of the Rust module where the span occurred, or `None` if this /// could not be determined.
module_path: Option<&'a str>,
/// The name of the source code file where the span occurred, or `None` if /// this could not be determined.
file: Option<&'a str>,
/// The line number in the source code file where the span occurred, or /// `None` if this could not be determined.
line: Option<u32>,
/// The names of the key-value fields attached to the described span or /// event.
fields: field::FieldSet,
/// The kind of the callsite.
kind: Kind,
}
/// Indicates whether the callsite is a span or event. #[derive(Clone, Eq, PartialEq)] pubstruct Kind(u8);
/// Describes the level of verbosity of a span or event. /// /// # Comparing Levels /// /// `Level` implements the [`PartialOrd`] and [`Ord`] traits, allowing two /// `Level`s to be compared to determine which is considered more or less /// verbose. Levels which are more verbose are considered "greater than" levels /// which are less verbose, with [`Level::ERROR`] considered the lowest, and /// [`Level::TRACE`] considered the highest. /// /// For example: /// ``` /// use tracing_core::Level; /// /// assert!(Level::TRACE > Level::DEBUG); /// assert!(Level::ERROR < Level::WARN); /// assert!(Level::INFO <= Level::DEBUG); /// assert_eq!(Level::TRACE, Level::TRACE); /// ``` /// /// # Filtering /// /// `Level`s are typically used to implement filtering that determines which /// spans and events are enabled. Depending on the use case, more or less /// verbose diagnostics may be desired. For example, when running in /// development, [`DEBUG`]-level traces may be enabled by default. When running in /// production, only [`INFO`]-level and lower traces might be enabled. Libraries /// may include very verbose diagnostics at the [`DEBUG`] and/or [`TRACE`] levels. /// Applications using those libraries typically chose to ignore those traces. However, when /// debugging an issue involving said libraries, it may be useful to temporarily /// enable the more verbose traces. /// /// The [`LevelFilter`] type is provided to enable filtering traces by /// verbosity. `Level`s can be compared against [`LevelFilter`]s, and /// [`LevelFilter`] has a variant for each `Level`, which compares analogously /// to that level. In addition, [`LevelFilter`] adds a [`LevelFilter::OFF`] /// variant, which is considered "less verbose" than every other `Level`. This is /// intended to allow filters to completely disable tracing in a particular context. /// /// For example: /// ``` /// use tracing_core::{Level, LevelFilter}; /// /// assert!(LevelFilter::OFF < Level::TRACE); /// assert!(LevelFilter::TRACE > Level::DEBUG); /// assert!(LevelFilter::ERROR < Level::WARN); /// assert!(LevelFilter::INFO <= Level::DEBUG); /// assert!(LevelFilter::INFO >= Level::INFO); /// ``` /// /// ## Examples /// /// Below is a simple example of how a [`Subscriber`] could implement filtering through /// a [`LevelFilter`]. When a span or event is recorded, the [`Subscriber::enabled`] method /// compares the span or event's `Level` against the configured [`LevelFilter`]. /// The optional [`Subscriber::max_level_hint`] method can also be implemented to allow spans /// and events above a maximum verbosity level to be skipped more efficiently, /// often improving performance in short-lived programs. /// /// ``` /// use tracing_core::{span, Event, Level, LevelFilter, Subscriber, Metadata}; /// # use tracing_core::span::{Id, Record, Current}; /// /// #[derive(Debug)] /// pub struct MySubscriber { /// /// The most verbose level that this subscriber will enable. /// max_level: LevelFilter, /// /// // ... /// } /// /// impl MySubscriber { /// /// Returns a new `MySubscriber` which will record spans and events up to /// /// `max_level`. /// pub fn with_max_level(max_level: LevelFilter) -> Self { /// Self { /// max_level, /// // ... /// } /// } /// } /// impl Subscriber for MySubscriber { /// fn enabled(&self, meta: &Metadata<'_>) -> bool { /// // A span or event is enabled if it is at or below the configured /// // maximum level. /// meta.level() <= &self.max_level /// } /// /// // This optional method returns the most verbose level that this /// // subscriber will enable. Although implementing this method is not /// // *required*, it permits additional optimizations when it is provided, /// // allowing spans and events above the max level to be skipped /// // more efficiently. /// fn max_level_hint(&self) -> Option<LevelFilter> { /// Some(self.max_level) /// } /// /// // Implement the rest of the subscriber... /// fn new_span(&self, span: &span::Attributes<'_>) -> span::Id { /// // ... /// # drop(span); Id::from_u64(1) /// }
/// fn event(&self, event: &Event<'_>) { /// // ... /// # drop(event); /// } /// /// // ... /// # fn enter(&self, _: &Id) {} /// # fn exit(&self, _: &Id) {} /// # fn record(&self, _: &Id, _: &Record<'_>) {} /// # fn record_follows_from(&self, _: &Id, _: &Id) {} /// } /// ``` /// /// It is worth noting that the `tracing-subscriber` crate provides [additional /// APIs][envfilter] for performing more sophisticated filtering, such as /// enabling different levels based on which module or crate a span or event is /// recorded in. /// /// [`DEBUG`]: Level::DEBUG /// [`INFO`]: Level::INFO /// [`TRACE`]: Level::TRACE /// [`Subscriber::enabled`]: crate::subscriber::Subscriber::enabled /// [`Subscriber::max_level_hint`]: crate::subscriber::Subscriber::max_level_hint /// [`Subscriber`]: crate::subscriber::Subscriber /// [envfilter]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pubstruct Level(LevelInner);
/// A filter comparable to a verbosity [`Level`]. /// /// If a [`Level`] is considered less than a `LevelFilter`, it should be /// considered enabled; if greater than or equal to the `LevelFilter`, /// that level is disabled. See [`LevelFilter::current`] for more /// details. /// /// Note that this is essentially identical to the `Level` type, but with the /// addition of an [`OFF`] level that completely disables all trace /// instrumentation. /// /// See the documentation for the [`Level`] type to see how `Level`s /// and `LevelFilter`s interact. /// /// [`OFF`]: LevelFilter::OFF #[repr(transparent)] #[derive(Copy, Clone, Eq, PartialEq, Hash)] pubstruct LevelFilter(Option<Level>);
/// Indicates that a string could not be parsed to a valid level. #[derive(Clone, Debug)] pubstruct ParseLevelFilterError(());
impl<'a> Metadata<'a> { /// Construct new metadata for a span or event, with a name, target, level, field /// names, and optional source code location. pubconstfn new(
name: &'static str,
target: &'a str,
level: Level,
file: Option<&'a str>,
line: Option<u32>,
module_path: Option<&'a str>,
fields: field::FieldSet,
kind: Kind,
) -> Self {
Metadata {
name,
target,
level,
module_path,
file,
line,
fields,
kind,
}
}
/// Returns the names of the fields on the described span or event. pubfn fields(&self) -> &field::FieldSet {
&self.fields
}
/// Returns the level of verbosity of the described span or event. pubfn level(&self) -> &Level {
&self.level
}
/// Returns the name of the span. pubfn name(&self) -> &'static str { self.name
}
/// Returns a string describing the part of the system where the span or /// event that this metadata describes occurred. /// /// Typically, this is the module path, but alternate targets may be set /// when spans or events are constructed. pubfn target(&self) -> &'a str { self.target
}
/// Returns the path to the Rust module where the span occurred, or /// `None` if the module path is unknown. pubfn module_path(&self) -> Option<&'a str> { self.module_path
}
/// Returns the name of the source code file where the span /// occurred, or `None` if the file is unknown pubfn file(&self) -> Option<&'a str> { self.file
}
/// Returns the line number in the source code file where the span /// occurred, or `None` if the line number is unknown. pubfn line(&self) -> Option<u32> { self.line
}
/// Returns an opaque `Identifier` that uniquely identifies the callsite /// this `Metadata` originated from. #[inline] pubfn callsite(&self) -> callsite::Identifier { self.fields.callsite()
}
/// Returns true if the callsite kind is `Event`. pubfn is_event(&self) -> bool { self.kind.is_event()
}
/// Return true if the callsite kind is `Span`. pubfn is_span(&self) -> bool { self.kind.is_span()
}
}
// Note: a line num with no file is a kind of weird case that _probably_ never occurs...
(None, Some(line)) => {
meta.field("line", &line);
}
(None, None) => {}
};
/// `enabled!` callsite. [`Subscriber`][`crate::subscriber::Subscriber`]s can assume /// this `Kind` means they will never recieve a /// full event with this [`Metadata`]. pubconst HINT: Kind = Kind(Self::HINT_BIT);
/// Return true if the callsite kind is `Span` pubfn is_span(&self) -> bool { self.0 & Self::SPAN_BIT == Self::SPAN_BIT
}
/// Return true if the callsite kind is `Event` pubfn is_event(&self) -> bool { self.0 & Self::EVENT_BIT == Self::EVENT_BIT
}
/// Return true if the callsite kind is `Hint` pubfn is_hint(&self) -> bool { self.0 & Self::HINT_BIT == Self::HINT_BIT
}
/// Sets that this `Kind` is a [hint](Self::HINT). /// /// This can be called on [`SPAN`](Self::SPAN) and [`EVENT`](Self::EVENT) /// kinds to construct a hint callsite that also counts as a span or event. pubconstfn hint(self) -> Self { Self(self.0 | Self::HINT_BIT)
}
}
// if none of the expected bits were set, something is messed up, so // just print the bits for debugging purposes if !has_bits {
write!(f, "{:#b}", self.0)?;
}
f.write_str(")")
}
}
impl<'a> Eq for Metadata<'a> {}
impl<'a> PartialEq for Metadata<'a> { #[inline] fn eq(&self, other: &Self) -> bool { if core::ptr::eq(&self, &other) { true
} elseif cfg!(not(debug_assertions)) { // In a well-behaving application, two `Metadata` can be assumed to // be totally equal so long as they share the same callsite. self.callsite() == other.callsite()
} else { // However, when debug-assertions are enabled, do not assume that // the application is well-behaving; check every field of `Metadata` // for equality.
// `Metadata` is destructured here to ensure a compile-error if the // fields of `Metadata` change. let Metadata {
name: lhs_name,
target: lhs_target,
level: lhs_level,
module_path: lhs_module_path,
file: lhs_file,
line: lhs_line,
fields: lhs_fields,
kind: lhs_kind,
} = self;
impl LevelFilter { /// The "off" level. /// /// Designates that trace instrumentation should be completely disabled. pubconst OFF: LevelFilter = LevelFilter(None); /// The "error" level. /// /// Designates very serious errors. pubconst ERROR: LevelFilter = LevelFilter::from_level(Level::ERROR); /// The "warn" level. /// /// Designates hazardous situations. pubconst WARN: LevelFilter = LevelFilter::from_level(Level::WARN); /// The "info" level. /// /// Designates useful information. pubconst INFO: LevelFilter = LevelFilter::from_level(Level::INFO); /// The "debug" level. /// /// Designates lower priority information. pubconst DEBUG: LevelFilter = LevelFilter::from_level(Level::DEBUG); /// The "trace" level. /// /// Designates very low priority, often extremely verbose, information. pubconst TRACE: LevelFilter = LevelFilter(Some(Level::TRACE));
/// Returns a `LevelFilter` that enables spans and events with verbosity up /// to and including `level`. pubconstfn from_level(level: Level) -> Self { Self(Some(level))
}
/// Returns the most verbose [`Level`] that this filter accepts, or `None` /// if it is [`OFF`]. /// /// [`OFF`]: LevelFilter::OFF pubconstfn into_level(self) -> Option<Level> { self.0
}
// These consts are necessary because `as` casts are not allowed as // match patterns. const ERROR_USIZE: usize = LevelInner::Error as usize; const WARN_USIZE: usize = LevelInner::Warn as usize; const INFO_USIZE: usize = LevelInner::Info as usize; const DEBUG_USIZE: usize = LevelInner::Debug as usize; const TRACE_USIZE: usize = LevelInner::Trace as usize; // Using the value of the last variant + 1 ensures that we match the value // for `Option::None` as selected by the niche optimization for // `LevelFilter`. If this is the case, converting a `usize` value into a // `LevelFilter` (in `LevelFilter::current`) will be an identity conversion, // rather than generating a lookup table. const OFF_USIZE: usize = LevelInner::Error as usize + 1;
/// Returns a `LevelFilter` that matches the most verbose [`Level`] that any /// currently active [`Subscriber`] will enable. /// /// User code should treat this as a *hint*. If a given span or event has a /// level *higher* than the returned `LevelFilter`, it will not be enabled. /// However, if the level is less than or equal to this value, the span or /// event is *not* guaranteed to be enabled; the subscriber will still /// filter each callsite individually. /// /// Therefore, comparing a given span or event's level to the returned /// `LevelFilter` **can** be used for determining if something is /// *disabled*, but **should not** be used for determining if something is /// *enabled*. /// /// [`Level`]: super::Level /// [`Subscriber`]: super::Subscriber #[inline(always)] pubfn current() -> Self { match MAX_LEVEL.load(Ordering::Relaxed) { Self::ERROR_USIZE => Self::ERROR, Self::WARN_USIZE => Self::WARN, Self::INFO_USIZE => Self::INFO, Self::DEBUG_USIZE => Self::DEBUG, Self::TRACE_USIZE => Self::TRACE, Self::OFF_USIZE => Self::OFF, #[cfg(debug_assertions)]
unknown => unreachable!( "/!\\ `LevelFilter` representation seems to have changed! /!\\ \n\
This is a bug (and it's pretty bad). Please contact the `tracing` \
maintainers. Thank you and I'm sorry.\n \
The offending repr was: {:?}",
unknown,
), #[cfg(not(debug_assertions))]
_ => unsafe { // Using `unreachable_unchecked` here (rather than // `unreachable!()`) is necessary to ensure that rustc generates // an identity conversion from integer -> discriminant, rather // than generating a lookup table. We want to ensure this // function is a single `mov` instruction (on x86) if at all // possible, because it is called *every* time a span/event // callsite is hit; and it is (potentially) the only code in the // hottest path for skipping a majority of callsites when level // filtering is in use. // // safety: This branch is only truly unreachable if we guarantee // that no values other than the possible enum discriminants // will *ever* be present. The `AtomicUsize` is initialized to // the `OFF` value. It is only set by the `set_max` function, // which takes a `LevelFilter` as a parameter. This restricts // the inputs to `set_max` to the set of valid discriminants. // Therefore, **as long as `MAX_VALUE` is only ever set by // `set_max`**, this is safe. crate::stdlib::hint::unreachable_unchecked()
},
}
}
pub(crate) fn set_max(LevelFilter(level): LevelFilter) { let val = match level {
Some(Level(level)) => level as usize,
None => Self::OFF_USIZE,
};
// using an AcqRel swap ensures an ordered relationship of writes to the // max level.
MAX_LEVEL.swap(val, Ordering::AcqRel);
}
}
impl FromStr for LevelFilter { type Err = ParseLevelFilterError; fn from_str(from: &str) -> Result<Self, Self::Err> {
from.parse::<usize>()
.ok()
.and_then(|num| match num { 0 => Some(LevelFilter::OFF), 1 => Some(LevelFilter::ERROR), 2 => Some(LevelFilter::WARN), 3 => Some(LevelFilter::INFO), 4 => Some(LevelFilter::DEBUG), 5 => Some(LevelFilter::TRACE),
_ => None,
})
.or_else(|| match from { "" => Some(LevelFilter::ERROR),
s if s.eq_ignore_ascii_case("error") => Some(LevelFilter::ERROR),
s if s.eq_ignore_ascii_case("warn") => Some(LevelFilter::WARN),
s if s.eq_ignore_ascii_case("info") => Some(LevelFilter::INFO),
s if s.eq_ignore_ascii_case("debug") => Some(LevelFilter::DEBUG),
s if s.eq_ignore_ascii_case("trace") => Some(LevelFilter::TRACE),
s if s.eq_ignore_ascii_case("off") => Some(LevelFilter::OFF),
_ => None,
})
.ok_or(ParseLevelFilterError(()))
}
}
/// Returned if parsing a `Level` fails. #[derive(Debug)] pubstruct ParseLevelError {
_p: (),
}
impl fmt::Display for ParseLevelError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad( "error parsing level: expected one of \"error\", \"warn\", \
\"info\", \"debug\", \"trace\", or a number 1-5",
)
}
}
impl fmt::Display for ParseLevelFilterError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad( "error parsing level filter: expected one of \"off\", \"error\", \
\"warn\", \"info\", \"debug\", \"trace\", or a number 0-5",
)
}
}
#[cfg(feature = "std")] impl std::error::Error for ParseLevelFilterError {}
// ==== Level and LevelFilter comparisons ====
// /!\ BIG, IMPORTANT WARNING /!\ // Do NOT mess with these implementations! They are hand-written for a reason! // // Since comparing `Level`s and `LevelFilter`s happens in a *very* hot path // (potentially, every time a span or event macro is hit, regardless of whether // or not is enabled), we *need* to ensure that these comparisons are as fast as // possible. Therefore, we have some requirements: // // 1. We want to do our best to ensure that rustc will generate integer-integer // comparisons wherever possible. // // The derived `Ord`/`PartialOrd` impls for `LevelFilter` will not do this, // because `LevelFilter`s are represented by `Option<Level>`, rather than as // a separate `#[repr(usize)]` enum. This was (unfortunately) necessary for // backwards-compatibility reasons, as the `tracing` crate's original // version of `LevelFilter` defined `const fn` conversions between `Level`s // and `LevelFilter`, so we're stuck with the `Option<Level>` repr. // Therefore, we need hand-written `PartialOrd` impls that cast both sides of // the comparison to `usize`s, to force the compiler to generate integer // compares. // // 2. The hottest `Level`/`LevelFilter` comparison, the one that happens every // time a callsite is hit, occurs *within the `tracing` crate's macros*. // This means that the comparison is happening *inside* a crate that // *depends* on `tracing-core`, not in `tracing-core` itself. The compiler // will only inline function calls across crate boundaries if the called // function is annotated with an `#[inline]` attribute, and we *definitely* // want the comparison functions to be inlined: as previously mentioned, they // should compile down to a single integer comparison on release builds, and // it seems really sad to push an entire stack frame to call a function // consisting of one `cmp` instruction! // // Therefore, we need to ensure that all the comparison methods have // `#[inline]` or `#[inline(always)]` attributes. It's not sufficient to just // add the attribute to `partial_cmp` in a manual implementation of the // trait, since it's the comparison operators (`lt`, `le`, `gt`, and `ge`) // that will actually be *used*, and the default implementation of *those* // methods, which calls `partial_cmp`, does not have an inline annotation. // // 3. We need the comparisons to be inverted. The discriminants for the // `LevelInner` enum are assigned in "backwards" order, with `TRACE` having // the *lowest* value. However, we want `TRACE` to compare greater-than all // other levels. // // Why are the numeric values inverted? In order to ensure that `LevelFilter` // (which, as previously mentioned, *has* to be internally represented by an // `Option<Level>`) compiles down to a single integer value. This is // necessary for storing the global max in an `AtomicUsize`, and for ensuring // that we use fast integer-integer comparisons, as mentioned previously. In // order to ensure this, we exploit the niche optimization. The niche // optimization for `Option<{enum with a numeric repr}>` will choose // `(HIGHEST_DISCRIMINANT_VALUE + 1)` as the representation for `None`. // Therefore, the integer representation of `LevelFilter::OFF` (which is // `None`) will be the number 5. `OFF` must compare higher than every other // level in order for it to filter as expected. Since we want to use a single // `cmp` instruction, we can't special-case the integer value of `OFF` to // compare higher, as that will generate more code. Instead, we need it to be // on one end of the enum, with `ERROR` on the opposite end, so we assign the // value 0 to `ERROR`. // // This *does* mean that when parsing `LevelFilter`s or `Level`s from // `String`s, the integer values are inverted, but that doesn't happen in a // hot path. // // Note that we manually invert the comparisons by swapping the left-hand and // right-hand side. Using `Ordering::reverse` generates significantly worse // code (per Matt Godbolt's Compiler Explorer). // // Anyway, that's a brief history of why this code is the way it is. Don't // change it unless you know what you're doing.
#[test] fn filter_level_conversion() { let mapping = [
(LevelFilter::OFF, None),
(LevelFilter::ERROR, Some(Level::ERROR)),
(LevelFilter::WARN, Some(Level::WARN)),
(LevelFilter::INFO, Some(Level::INFO)),
(LevelFilter::DEBUG, Some(Level::DEBUG)),
(LevelFilter::TRACE, Some(Level::TRACE)),
]; for (filter, level) in mapping.iter() {
assert_eq!(filter.into_level(), *level); match level {
Some(level) => { let actual: LevelFilter = (*level).into();
assert_eq!(actual, *filter);
}
None => { let actual: LevelFilter = None.into();
assert_eq!(actual, *filter);
}
}
}
}
#[test] fn level_filter_is_usize_sized() {
assert_eq!(
mem::size_of::<LevelFilter>(),
mem::size_of::<usize>(), "`LevelFilter` is no longer `usize`-sized! global MAX_LEVEL may now be invalid!"
)
}
#[test] fn level_filter_reprs() { let mapping = [
(LevelFilter::OFF, LevelInner::Error as usize + 1),
(LevelFilter::ERROR, LevelInner::Error as usize),
(LevelFilter::WARN, LevelInner::Warn as usize),
(LevelFilter::INFO, LevelInner::Info as usize),
(LevelFilter::DEBUG, LevelInner::Debug as usize),
(LevelFilter::TRACE, LevelInner::Trace as usize),
]; for &(filter, expected) in &mapping { let repr = unsafe { // safety: The entire purpose of this test is to assert that the // actual repr matches what we expect it to be --- we're testing // that *other* unsafe code is sound using the transmuted value. // We're not going to do anything with it that might be unsound.
mem::transmute::<LevelFilter, usize>(filter)
};
assert_eq!(expected, repr, "repr changed for {:?}", filter)
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.