🛈 Note: This is pre-release documentation for the upcoming tracing 0.2.0 ecosystem.

For the release documentation, please see docs.rs, instead.

tracing_core/
metadata.rs

1//! Metadata describing trace data.
2use super::{callsite, field};
3use core::{cmp, fmt, str::FromStr, sync::atomic::Ordering};
4
5#[cfg(feature = "portable-atomic")]
6use portable_atomic::AtomicUsize;
7
8#[cfg(not(feature = "portable-atomic"))]
9use core::sync::atomic::AtomicUsize;
10
11/// Metadata describing a [span] or [event].
12///
13/// All spans and events have the following metadata:
14/// - A [name], represented as a static string.
15/// - A [target], a string that categorizes part of the system where the span
16///   or event occurred. The `tracing` macros default to using the module
17///   path where the span or event originated as the target, but it may be
18///   overridden.
19/// - A [verbosity level]. This determines how verbose a given span or event
20///   is, and allows enabling or disabling more verbose diagnostics
21///   situationally. See the documentation for the [`Level`] type for details.
22/// - The names of the [fields] defined by the span or event.
23/// - Whether the metadata corresponds to a span or event.
24///
25/// In addition, the following optional metadata describing the source code
26/// location where the span or event originated _may_ be provided:
27/// - The [file name]
28/// - The [line number]
29/// - The [module path]
30///
31/// Metadata is used by [collector]s when filtering spans and events, and it
32/// may also be used as part of their data payload.
33///
34/// When created by the `event!` or `span!` macro, the metadata describing a
35/// particular event or span is constructed statically and exists as a single
36/// static instance. Thus, the overhead of creating the metadata is
37/// _significantly_ lower than that of creating the actual span. Therefore,
38/// filtering is based on metadata, rather than on the constructed span.
39///
40/// ## Equality
41///
42/// In well-behaved applications, two `Metadata` with equal
43/// [callsite identifiers] will be equal in all other ways (i.e., have the same
44/// `name`, `target`, etc.). Consequently, in release builds, [`Metadata::eq`]
45/// *only* checks that its arguments have equal callsites. However, the equality
46/// of `Metadata`'s other fields is checked in debug builds.
47///
48/// [span]: super::span
49/// [event]: super::event
50/// [name]: Self::name
51/// [target]: Self::target
52/// [fields]: Self::fields
53/// [verbosity level]: Self::level
54/// [file name]: Self::file
55/// [line number]: Self::line
56/// [module path]: Self::module_path
57/// [collector]: super::collect::Collect
58/// [callsite identifiers]: Self::callsite
59pub struct Metadata<'a> {
60    /// The name of the span described by this metadata.
61    name: &'static str,
62
63    /// The part of the system that the span that this metadata describes
64    /// occurred in.
65    target: &'a str,
66
67    /// The level of verbosity of the described span.
68    level: Level,
69
70    /// The name of the Rust module where the span occurred, or `None` if this
71    /// could not be determined.
72    module_path: Option<&'a str>,
73
74    /// The name of the source code file where the span occurred, or `None` if
75    /// this could not be determined.
76    file: Option<&'a str>,
77
78    /// The line number in the source code file where the span occurred, or
79    /// `None` if this could not be determined.
80    line: Option<u32>,
81
82    /// The names of the key-value fields attached to the described span or
83    /// event.
84    fields: field::FieldSet,
85
86    /// The kind of the callsite.
87    kind: Kind,
88}
89
90/// Indicates whether the callsite is a span or event.
91#[derive(Clone, Eq, PartialEq)]
92pub struct Kind(u8);
93
94/// Describes the level of verbosity of a span or event.
95///
96/// # Comparing Levels
97///
98/// `Level` implements the [`PartialOrd`] and [`Ord`] traits, allowing two
99/// `Level`s to be compared to determine which is considered more or less
100/// verbose. Levels which are more verbose are considered "greater than" levels
101/// which are less verbose, with [`Level::ERROR`] considered the lowest, and
102/// [`Level::TRACE`] considered the highest.
103///
104/// For example:
105/// ```
106/// use tracing_core::Level;
107///
108/// assert!(Level::TRACE > Level::DEBUG);
109/// assert!(Level::ERROR < Level::WARN);
110/// assert!(Level::INFO <= Level::DEBUG);
111/// assert_eq!(Level::TRACE, Level::TRACE);
112/// ```
113///
114/// # Filtering
115///
116/// `Level`s are typically used to implement filtering that determines which
117/// spans and events are enabled. Depending on the use case, more or less
118/// verbose diagnostics may be desired. For example, when running in
119/// development, [`DEBUG`]-level traces may be enabled by default. When running in
120/// production, only [`INFO`]-level and lower traces might be enabled. Libraries
121/// may include very verbose diagnostics at the [`DEBUG`] and/or [`TRACE`] levels.
122/// Applications using those libraries typically chose to ignore those traces. However, when
123/// debugging an issue involving said libraries, it may be useful to temporarily
124/// enable the more verbose traces.
125///
126/// The [`LevelFilter`] type is provided to enable filtering traces by
127/// verbosity. `Level`s can be compared against [`LevelFilter`]s, and
128/// [`LevelFilter`] has a variant for each `Level`, which compares analogously
129/// to that level. In addition, [`LevelFilter`] adds a [`LevelFilter::OFF`]
130/// variant, which is considered "less verbose" than every other `Level`. This is
131/// intended to allow filters to completely disable tracing in a particular context.
132///
133/// For example:
134/// ```
135/// use tracing_core::{Level, LevelFilter};
136///
137/// assert!(LevelFilter::OFF < Level::TRACE);
138/// assert!(LevelFilter::TRACE > Level::DEBUG);
139/// assert!(LevelFilter::ERROR < Level::WARN);
140/// assert!(LevelFilter::INFO <= Level::DEBUG);
141/// assert!(LevelFilter::INFO >= Level::INFO);
142/// ```
143///
144/// ## Examples
145///
146/// Below is a simple example of how a [collector] could implement filtering through
147/// a [`LevelFilter`]. When a span or event is recorded, the [`Collect::enabled`] method
148/// compares the span or event's `Level` against the configured [`LevelFilter`].
149/// The optional [`Collect::max_level_hint`] method can also be implemented to  allow spans
150/// and events above a maximum verbosity level to be skipped more efficiently,
151/// often improving performance in short-lived programs.
152///
153/// ```
154/// use tracing_core::{span, Event, Level, LevelFilter, Collect, Metadata};
155/// # use tracing_core::span::{Id, Record, Current};
156///
157/// #[derive(Debug)]
158/// pub struct MyCollector {
159///     /// The most verbose level that this collector will enable.
160///     max_level: LevelFilter,
161///
162///     // ...
163/// }
164///
165/// impl MyCollector {
166///     /// Returns a new `MyCollector` which will record spans and events up to
167///     /// `max_level`.
168///     pub fn with_max_level(max_level: LevelFilter) -> Self {
169///         Self {
170///             max_level,
171///             // ...
172///         }
173///     }
174/// }
175/// impl Collect for MyCollector {
176///     fn enabled(&self, meta: &Metadata<'_>) -> bool {
177///         // A span or event is enabled if it is at or below the configured
178///         // maximum level.
179///         meta.level() <= &self.max_level
180///     }
181///
182///     // This optional method returns the most verbose level that this
183///     // collector will enable. Although implementing this method is not
184///     // *required*, it permits additional optimizations when it is provided,
185///     // allowing spans and events above the max level to be skipped
186///     // more efficiently.
187///     fn max_level_hint(&self) -> Option<LevelFilter> {
188///         Some(self.max_level)
189///     }
190///
191///     // Implement the rest of the collector...
192///     fn new_span(&self, span: &span::Attributes<'_>) -> span::Id {
193///         // ...
194///         # drop(span); Id::from_u64(1)
195///     }
196///
197///     fn event(&self, event: &Event<'_>) {
198///         // ...
199///         # drop(event);
200///     }
201///
202///     // ...
203///     # fn enter(&self, _: &Id) {}
204///     # fn exit(&self, _: &Id) {}
205///     # fn record(&self, _: &Id, _: &Record<'_>) {}
206///     # fn record_follows_from(&self, _: &Id, _: &Id) {}
207///     # fn current_span(&self) -> Current { Current::unknown() }
208/// }
209/// ```
210///
211/// It is worth noting that the `tracing-subscriber` crate provides [additional
212/// APIs][envfilter] for performing more sophisticated filtering, such as
213/// enabling different levels based on which module or crate a span or event is
214/// recorded in.
215///
216/// [`DEBUG`]: Level::DEBUG
217/// [`INFO`]: Level::INFO
218/// [`TRACE`]: Level::TRACE
219/// [`Collect::enabled`]: crate::collect::Collect::enabled
220/// [`Collect::max_level_hint`]: crate::collect::Collect::max_level_hint
221/// [collector]: crate::collect::Collect
222/// [envfilter]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html
223#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
224pub struct Level(LevelInner);
225
226/// A filter comparable to a verbosity [`Level`].
227///
228/// If a [`Level`] is considered less than or equal to a `LevelFilter`, it
229/// should be considered enabled; if greater than the `LevelFilter`, that level
230/// is disabled. See [`LevelFilter::current`] for more details.
231///
232/// Note that this is essentially identical to the `Level` type, but with the
233/// addition of an [`OFF`] level that completely disables all trace
234/// instrumentation.
235///
236/// See the documentation for the [`Level`] type to see how `Level`s
237/// and `LevelFilter`s interact.
238///
239/// [`OFF`]: LevelFilter::OFF
240#[repr(transparent)]
241#[derive(Copy, Clone, Eq, PartialEq, Hash)]
242pub struct LevelFilter(Option<Level>);
243
244/// Indicates that a string could not be parsed to a valid level.
245#[derive(Clone, Debug)]
246pub struct ParseLevelFilterError(());
247
248static MAX_LEVEL: AtomicUsize = AtomicUsize::new(LevelFilter::OFF_USIZE);
249
250// ===== impl Metadata =====
251
252impl<'a> Metadata<'a> {
253    /// Construct new metadata for a span or event, with a name, target, level, field
254    /// names, and optional source code location.
255    pub const fn new(
256        name: &'static str,
257        target: &'a str,
258        level: Level,
259        file: Option<&'a str>,
260        line: Option<u32>,
261        module_path: Option<&'a str>,
262        fields: field::FieldSet,
263        kind: Kind,
264    ) -> Self {
265        Metadata {
266            name,
267            target,
268            level,
269            module_path,
270            file,
271            line,
272            fields,
273            kind,
274        }
275    }
276
277    /// Returns the names of the fields on the described span or event.
278    #[inline]
279    pub fn fields(&self) -> &field::FieldSet {
280        &self.fields
281    }
282
283    /// Returns the level of verbosity of the described span or event.
284    pub fn level(&self) -> &Level {
285        &self.level
286    }
287
288    /// Returns the name of the span.
289    pub fn name(&self) -> &'static str {
290        self.name
291    }
292
293    /// Returns a string describing the part of the system where the span or
294    /// event that this metadata describes occurred.
295    ///
296    /// Typically, this is the module path, but alternate targets may be set
297    /// when spans or events are constructed.
298    pub fn target(&self) -> &'a str {
299        self.target
300    }
301
302    /// Returns the path to the Rust module where the span occurred, or
303    /// `None` if the module path is unknown.
304    pub fn module_path(&self) -> Option<&'a str> {
305        self.module_path
306    }
307
308    /// Returns the name of the source code file where the span
309    /// occurred, or `None` if the file is unknown
310    pub fn file(&self) -> Option<&'a str> {
311        self.file
312    }
313
314    /// Returns the line number in the source code file where the span
315    /// occurred, or `None` if the line number is unknown.
316    pub fn line(&self) -> Option<u32> {
317        self.line
318    }
319
320    /// Returns an opaque `Identifier` that uniquely identifies the callsite
321    /// this `Metadata` originated from.
322    #[inline]
323    pub fn callsite(&self) -> callsite::Identifier {
324        self.fields.callsite()
325    }
326
327    /// Returns true if the callsite kind is `Event`.
328    pub fn is_event(&self) -> bool {
329        self.kind.is_event()
330    }
331
332    /// Return true if the callsite kind is `Span`.
333    pub fn is_span(&self) -> bool {
334        self.kind.is_span()
335    }
336}
337
338impl fmt::Debug for Metadata<'_> {
339    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
340        let mut meta = f.debug_struct("Metadata");
341        meta.field("name", &self.name)
342            .field("target", &self.target)
343            .field("level", &self.level);
344
345        if let Some(path) = self.module_path() {
346            meta.field("module_path", &path);
347        }
348
349        match (self.file(), self.line()) {
350            (Some(file), Some(line)) => {
351                meta.field("location", &format_args!("{}:{}", file, line));
352            }
353            (Some(file), None) => {
354                meta.field("file", &format_args!("{}", file));
355            }
356
357            // Note: a line num with no file is a kind of weird case that _probably_ never occurs...
358            (None, Some(line)) => {
359                meta.field("line", &line);
360            }
361            (None, None) => {}
362        };
363
364        meta.field("fields", &format_args!("{}", self.fields))
365            .field("callsite", &self.callsite())
366            .field("kind", &self.kind)
367            .finish()
368    }
369}
370
371impl Kind {
372    const EVENT_BIT: u8 = 1 << 0;
373    const SPAN_BIT: u8 = 1 << 1;
374    const HINT_BIT: u8 = 1 << 2;
375
376    /// `Event` callsite
377    pub const EVENT: Kind = Kind(Self::EVENT_BIT);
378
379    /// `Span` callsite
380    pub const SPAN: Kind = Kind(Self::SPAN_BIT);
381
382    /// `enabled!` callsite. [`Collect`][`crate::collect::Collect`]s can assume
383    /// this `Kind` means they will never receive a
384    /// full event with this [`Metadata`].
385    pub const HINT: Kind = Kind(Self::HINT_BIT);
386
387    /// Return true if the callsite kind is `Span`
388    pub fn is_span(&self) -> bool {
389        self.0 & Self::SPAN_BIT == Self::SPAN_BIT
390    }
391
392    /// Return true if the callsite kind is `Event`
393    pub fn is_event(&self) -> bool {
394        self.0 & Self::EVENT_BIT == Self::EVENT_BIT
395    }
396
397    /// Return true if the callsite kind is `Hint`
398    pub fn is_hint(&self) -> bool {
399        self.0 & Self::HINT_BIT == Self::HINT_BIT
400    }
401
402    /// Sets that this `Kind` is a [hint](Self::HINT).
403    ///
404    /// This can be called on [`SPAN`](Self::SPAN) and [`EVENT`](Self::EVENT)
405    /// kinds to construct a hint callsite that also counts as a span or event.
406    pub const fn hint(self) -> Self {
407        Self(self.0 | Self::HINT_BIT)
408    }
409}
410
411impl fmt::Debug for Kind {
412    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
413        f.write_str("Kind(")?;
414        let mut has_bits = false;
415        let mut write_bit = |name: &str| {
416            if has_bits {
417                f.write_str(" | ")?;
418            }
419            f.write_str(name)?;
420            has_bits = true;
421            Ok(())
422        };
423
424        if self.is_event() {
425            write_bit("EVENT")?;
426        }
427
428        if self.is_span() {
429            write_bit("SPAN")?;
430        }
431
432        if self.is_hint() {
433            write_bit("HINT")?;
434        }
435
436        // if none of the expected bits were set, something is messed up, so
437        // just print the bits for debugging purposes
438        if !has_bits {
439            write!(f, "{:#b}", self.0)?;
440        }
441
442        f.write_str(")")
443    }
444}
445
446impl Eq for Metadata<'_> {}
447
448impl PartialEq for Metadata<'_> {
449    #[inline]
450    fn eq(&self, other: &Self) -> bool {
451        if core::ptr::eq(&self, &other) {
452            true
453        } else if cfg!(not(debug_assertions)) {
454            // In a well-behaving application, two `Metadata` can be assumed to
455            // be totally equal so long as they share the same callsite.
456            self.callsite() == other.callsite()
457        } else {
458            // However, when debug-assertions are enabled, do not assume that
459            // the application is well-behaving; check every field of `Metadata`
460            // for equality.
461
462            // `Metadata` is destructured here to ensure a compile-error if the
463            // fields of `Metadata` change.
464            let Metadata {
465                name: lhs_name,
466                target: lhs_target,
467                level: lhs_level,
468                module_path: lhs_module_path,
469                file: lhs_file,
470                line: lhs_line,
471                fields: lhs_fields,
472                kind: lhs_kind,
473            } = self;
474
475            let Metadata {
476                name: rhs_name,
477                target: rhs_target,
478                level: rhs_level,
479                module_path: rhs_module_path,
480                file: rhs_file,
481                line: rhs_line,
482                fields: rhs_fields,
483                kind: rhs_kind,
484            } = &other;
485
486            // The initial comparison of callsites is purely an optimization;
487            // it can be removed without affecting the overall semantics of the
488            // expression.
489            self.callsite() == other.callsite()
490                && lhs_name == rhs_name
491                && lhs_target == rhs_target
492                && lhs_level == rhs_level
493                && lhs_module_path == rhs_module_path
494                && lhs_file == rhs_file
495                && lhs_line == rhs_line
496                && lhs_fields == rhs_fields
497                && lhs_kind == rhs_kind
498        }
499    }
500}
501
502// ===== impl Level =====
503
504impl Level {
505    /// The "error" level.
506    ///
507    /// Designates very serious errors.
508    pub const ERROR: Level = Level(LevelInner::Error);
509    /// The "warn" level.
510    ///
511    /// Designates hazardous situations.
512    pub const WARN: Level = Level(LevelInner::Warn);
513    /// The "info" level.
514    ///
515    /// Designates useful information.
516    pub const INFO: Level = Level(LevelInner::Info);
517    /// The "debug" level.
518    ///
519    /// Designates lower priority information.
520    pub const DEBUG: Level = Level(LevelInner::Debug);
521    /// The "trace" level.
522    ///
523    /// Designates very low priority, often extremely verbose, information.
524    pub const TRACE: Level = Level(LevelInner::Trace);
525
526    /// Returns the string representation of the `Level`.
527    ///
528    /// This returns the same string as the `fmt::Display` implementation.
529    pub fn as_str(&self) -> &'static str {
530        match *self {
531            Level::TRACE => "TRACE",
532            Level::DEBUG => "DEBUG",
533            Level::INFO => "INFO",
534            Level::WARN => "WARN",
535            Level::ERROR => "ERROR",
536        }
537    }
538}
539
540impl fmt::Display for Level {
541    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
542        match *self {
543            Level::TRACE => f.pad("TRACE"),
544            Level::DEBUG => f.pad("DEBUG"),
545            Level::INFO => f.pad("INFO"),
546            Level::WARN => f.pad("WARN"),
547            Level::ERROR => f.pad("ERROR"),
548        }
549    }
550}
551
552#[cfg(feature = "std")]
553#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
554impl std::error::Error for ParseLevelError {}
555
556impl FromStr for Level {
557    type Err = ParseLevelError;
558    fn from_str(s: &str) -> Result<Self, ParseLevelError> {
559        s.parse::<usize>()
560            .map_err(|_| ParseLevelError { _p: () })
561            .and_then(|num| match num {
562                1 => Ok(Level::ERROR),
563                2 => Ok(Level::WARN),
564                3 => Ok(Level::INFO),
565                4 => Ok(Level::DEBUG),
566                5 => Ok(Level::TRACE),
567                _ => Err(ParseLevelError { _p: () }),
568            })
569            .or_else(|_| match s {
570                s if s.eq_ignore_ascii_case("error") => Ok(Level::ERROR),
571                s if s.eq_ignore_ascii_case("warn") => Ok(Level::WARN),
572                s if s.eq_ignore_ascii_case("info") => Ok(Level::INFO),
573                s if s.eq_ignore_ascii_case("debug") => Ok(Level::DEBUG),
574                s if s.eq_ignore_ascii_case("trace") => Ok(Level::TRACE),
575                _ => Err(ParseLevelError { _p: () }),
576            })
577    }
578}
579
580#[repr(usize)]
581#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
582enum LevelInner {
583    /// The "trace" level.
584    ///
585    /// Designates very low priority, often extremely verbose, information.
586    Trace = 0,
587    /// The "debug" level.
588    ///
589    /// Designates lower priority information.
590    Debug = 1,
591    /// The "info" level.
592    ///
593    /// Designates useful information.
594    Info = 2,
595    /// The "warn" level.
596    ///
597    /// Designates hazardous situations.
598    Warn = 3,
599    /// The "error" level.
600    ///
601    /// Designates very serious errors.
602    Error = 4,
603}
604
605// === impl LevelFilter ===
606
607impl From<Level> for LevelFilter {
608    #[inline]
609    fn from(level: Level) -> Self {
610        Self::from_level(level)
611    }
612}
613
614impl From<Option<Level>> for LevelFilter {
615    #[inline]
616    fn from(level: Option<Level>) -> Self {
617        Self(level)
618    }
619}
620
621impl From<LevelFilter> for Option<Level> {
622    #[inline]
623    fn from(filter: LevelFilter) -> Self {
624        filter.into_level()
625    }
626}
627
628impl LevelFilter {
629    /// The "off" level.
630    ///
631    /// Designates that trace instrumentation should be completely disabled.
632    pub const OFF: LevelFilter = LevelFilter(None);
633    /// The "error" level.
634    ///
635    /// Designates very serious errors.
636    pub const ERROR: LevelFilter = LevelFilter::from_level(Level::ERROR);
637    /// The "warn" level.
638    ///
639    /// Designates hazardous situations.
640    pub const WARN: LevelFilter = LevelFilter::from_level(Level::WARN);
641    /// The "info" level.
642    ///
643    /// Designates useful information.
644    pub const INFO: LevelFilter = LevelFilter::from_level(Level::INFO);
645    /// The "debug" level.
646    ///
647    /// Designates lower priority information.
648    pub const DEBUG: LevelFilter = LevelFilter::from_level(Level::DEBUG);
649    /// The "trace" level.
650    ///
651    /// Designates very low priority, often extremely verbose, information.
652    pub const TRACE: LevelFilter = LevelFilter(Some(Level::TRACE));
653
654    /// Returns a `LevelFilter` that enables spans and events with verbosity up
655    /// to and including `level`.
656    pub const fn from_level(level: Level) -> Self {
657        Self(Some(level))
658    }
659
660    /// Returns the most verbose [`Level`] that this filter accepts, or `None`
661    /// if it is [`OFF`].
662    ///
663    /// [`Level`]: super::Level
664    /// [`OFF`]: LevelFilter::OFF
665    pub const fn into_level(self) -> Option<Level> {
666        self.0
667    }
668
669    // These consts are necessary because `as` casts are not allowed as
670    // match patterns.
671    const ERROR_USIZE: usize = LevelInner::Error as usize;
672    const WARN_USIZE: usize = LevelInner::Warn as usize;
673    const INFO_USIZE: usize = LevelInner::Info as usize;
674    const DEBUG_USIZE: usize = LevelInner::Debug as usize;
675    const TRACE_USIZE: usize = LevelInner::Trace as usize;
676    // Using the value of the last variant + 1 ensures that we match the value
677    // for `Option::None` as selected by the niche optimization for
678    // `LevelFilter`. If this is the case, converting a `usize` value into a
679    // `LevelFilter` (in `LevelFilter::current`) will be an identity conversion,
680    // rather than generating a lookup table.
681    const OFF_USIZE: usize = LevelInner::Error as usize + 1;
682
683    /// Returns a `LevelFilter` that matches the most verbose [`Level`] that any
684    /// currently active [collector] will enable.
685    ///
686    /// User code should treat this as a *hint*. If a given span or event has a
687    /// level *higher* than the returned `LevelFilter`, it will not be enabled.
688    /// However, if the level is less than or equal to this value, the span or
689    /// event is *not* guaranteed to be enabled; the collector will still
690    /// filter each callsite individually.
691    ///
692    /// Therefore, comparing a given span or event's level to the returned
693    /// `LevelFilter` **can** be used for determining if something is
694    /// *disabled*, but **should not** be used for determining if something is
695    /// *enabled*.
696    ///
697    /// [`Level`]: super::Level
698    /// [collector]: super::Collect
699    #[inline(always)]
700    pub fn current() -> Self {
701        match MAX_LEVEL.load(Ordering::Relaxed) {
702            Self::ERROR_USIZE => Self::ERROR,
703            Self::WARN_USIZE => Self::WARN,
704            Self::INFO_USIZE => Self::INFO,
705            Self::DEBUG_USIZE => Self::DEBUG,
706            Self::TRACE_USIZE => Self::TRACE,
707            Self::OFF_USIZE => Self::OFF,
708            #[cfg(debug_assertions)]
709            unknown => unreachable!(
710                "/!\\ `LevelFilter` representation seems to have changed! /!\\ \n\
711                This is a bug (and it's pretty bad). Please contact the `tracing` \
712                maintainers. Thank you and I'm sorry.\n \
713                The offending repr was: {:?}",
714                unknown,
715            ),
716            #[cfg(not(debug_assertions))]
717            _ => unsafe {
718                // Using `unreachable_unchecked` here (rather than
719                // `unreachable!()`) is necessary to ensure that rustc generates
720                // an identity conversion from integer -> discriminant, rather
721                // than generating a lookup table. We want to ensure this
722                // function is a single `mov` instruction (on x86) if at all
723                // possible, because it is called *every* time a span/event
724                // callsite is hit; and it is (potentially) the only code in the
725                // hottest path for skipping a majority of callsites when level
726                // filtering is in use.
727                //
728                // safety: This branch is only truly unreachable if we guarantee
729                // that no values other than the possible enum discriminants
730                // will *ever* be present. The `AtomicUsize` is initialized to
731                // the `OFF` value. It is only set by the `set_max` function,
732                // which takes a `LevelFilter` as a parameter. This restricts
733                // the inputs to `set_max` to the set of valid discriminants.
734                // Therefore, **as long as `MAX_VALUE` is only ever set by
735                // `set_max`**, this is safe.
736                core::hint::unreachable_unchecked()
737            },
738        }
739    }
740
741    pub(crate) fn set_max(LevelFilter(level): LevelFilter) {
742        let val = match level {
743            Some(Level(level)) => level as usize,
744            None => Self::OFF_USIZE,
745        };
746
747        // using an AcqRel swap ensures an ordered relationship of writes to the
748        // max level.
749        MAX_LEVEL.swap(val, Ordering::AcqRel);
750    }
751}
752
753impl fmt::Display for LevelFilter {
754    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
755        match *self {
756            LevelFilter::OFF => f.pad("off"),
757            LevelFilter::ERROR => f.pad("error"),
758            LevelFilter::WARN => f.pad("warn"),
759            LevelFilter::INFO => f.pad("info"),
760            LevelFilter::DEBUG => f.pad("debug"),
761            LevelFilter::TRACE => f.pad("trace"),
762        }
763    }
764}
765
766impl fmt::Debug for LevelFilter {
767    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
768        match *self {
769            LevelFilter::OFF => f.pad("LevelFilter::OFF"),
770            LevelFilter::ERROR => f.pad("LevelFilter::ERROR"),
771            LevelFilter::WARN => f.pad("LevelFilter::WARN"),
772            LevelFilter::INFO => f.pad("LevelFilter::INFO"),
773            LevelFilter::DEBUG => f.pad("LevelFilter::DEBUG"),
774            LevelFilter::TRACE => f.pad("LevelFilter::TRACE"),
775        }
776    }
777}
778
779impl FromStr for LevelFilter {
780    type Err = ParseLevelFilterError;
781    fn from_str(from: &str) -> Result<Self, Self::Err> {
782        from.parse::<usize>()
783            .ok()
784            .and_then(|num| match num {
785                0 => Some(LevelFilter::OFF),
786                1 => Some(LevelFilter::ERROR),
787                2 => Some(LevelFilter::WARN),
788                3 => Some(LevelFilter::INFO),
789                4 => Some(LevelFilter::DEBUG),
790                5 => Some(LevelFilter::TRACE),
791                _ => None,
792            })
793            .or_else(|| match from {
794                "" => Some(LevelFilter::ERROR),
795                s if s.eq_ignore_ascii_case("error") => Some(LevelFilter::ERROR),
796                s if s.eq_ignore_ascii_case("warn") => Some(LevelFilter::WARN),
797                s if s.eq_ignore_ascii_case("info") => Some(LevelFilter::INFO),
798                s if s.eq_ignore_ascii_case("debug") => Some(LevelFilter::DEBUG),
799                s if s.eq_ignore_ascii_case("trace") => Some(LevelFilter::TRACE),
800                s if s.eq_ignore_ascii_case("off") => Some(LevelFilter::OFF),
801                _ => None,
802            })
803            .ok_or(ParseLevelFilterError(()))
804    }
805}
806
807/// Returned if parsing a `Level` fails.
808#[derive(Debug)]
809pub struct ParseLevelError {
810    _p: (),
811}
812
813impl fmt::Display for ParseLevelError {
814    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
815        f.pad(
816            "error parsing level: expected one of \"error\", \"warn\", \
817             \"info\", \"debug\", \"trace\", or a number 1-5",
818        )
819    }
820}
821
822impl fmt::Display for ParseLevelFilterError {
823    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
824        f.pad(
825            "error parsing level filter: expected one of \"off\", \"error\", \
826            \"warn\", \"info\", \"debug\", \"trace\", or a number 0-5",
827        )
828    }
829}
830
831#[cfg(feature = "std")]
832impl std::error::Error for ParseLevelFilterError {}
833
834// ==== Level and LevelFilter comparisons ====
835
836// /!\ BIG, IMPORTANT WARNING /!\
837// Do NOT mess with these implementations! They are hand-written for a reason!
838//
839// Since comparing `Level`s and `LevelFilter`s happens in a *very* hot path
840// (potentially, every time a span or event macro is hit, regardless of whether
841// or not is enabled), we *need* to ensure that these comparisons are as fast as
842// possible. Therefore, we have some requirements:
843//
844// 1. We want to do our best to ensure that rustc will generate integer-integer
845//    comparisons wherever possible.
846//
847//    The derived `Ord`/`PartialOrd` impls for `LevelFilter` will not do this,
848//    because `LevelFilter`s are represented by `Option<Level>`, rather than as
849//    a separate `#[repr(usize)]` enum. This was (unfortunately) necessary for
850//    backwards-compatibility reasons, as the  `tracing` crate's original
851//    version of `LevelFilter` defined `const fn` conversions between `Level`s
852//    and `LevelFilter`, so we're stuck with the `Option<Level>` repr.
853//    Therefore, we need hand-written `PartialOrd` impls that cast both sides of
854//    the comparison to `usize`s, to force the compiler to generate integer
855//    compares.
856//
857// 2. The hottest `Level`/`LevelFilter` comparison, the one that happens every
858//    time a callsite is hit, occurs *within the `tracing` crate's macros*.
859//    This means that the comparison is happening *inside* a crate that
860//    *depends* on `tracing-core`, not in `tracing-core` itself. The compiler
861//    will only inline function calls across crate boundaries if the called
862//    function is annotated with an `#[inline]` attribute, and we *definitely*
863//    want the comparison functions to be inlined: as previously mentioned, they
864//    should compile down to a single integer comparison on release builds, and
865//    it seems really sad to push an entire stack frame to call a function
866//    consisting of one `cmp` instruction!
867//
868//    Therefore, we need to ensure that all the comparison methods have
869//    `#[inline]` or `#[inline(always)]` attributes. It's not sufficient to just
870//    add the attribute to `partial_cmp` in a manual implementation of the
871//    trait, since it's the comparison operators (`lt`, `le`, `gt`, and `ge`)
872//    that will actually be *used*, and the default implementation of *those*
873//    methods, which calls `partial_cmp`, does not have an inline annotation.
874//
875// 3. We need the comparisons to be inverted. The discriminants for the
876//    `LevelInner` enum are assigned in "backwards" order, with `TRACE` having
877//    the *lowest* value. However, we want `TRACE` to compare greater-than all
878//    other levels.
879//
880//    Why are the numeric values inverted? In order to ensure that `LevelFilter`
881//    (which, as previously mentioned, *has* to be internally represented by an
882//    `Option<Level>`) compiles down to a single integer value. This is
883//    necessary for storing the global max in an `AtomicUsize`, and for ensuring
884//    that we use fast integer-integer comparisons, as mentioned previously. In
885//    order to ensure this, we exploit the niche optimization. The niche
886//    optimization for `Option<{enum with a numeric repr}>` will choose
887//    `(HIGHEST_DISCRIMINANT_VALUE + 1)` as the representation for `None`.
888//    Therefore, the integer representation of `LevelFilter::OFF` (which is
889//    `None`) will be the number 5. `OFF` must compare higher than every other
890//    level in order for it to filter as expected. Since we want to use a single
891//    `cmp` instruction, we can't special-case the integer value of `OFF` to
892//    compare higher, as that will generate more code. Instead, we need it to be
893//    on one end of the enum, with `ERROR` on the opposite end, so we assign the
894//    value 0 to `ERROR`.
895//
896//    This *does* mean that when parsing `LevelFilter`s or `Level`s from
897//    `String`s, the integer values are inverted, but that doesn't happen in a
898//    hot path.
899//
900//    Note that we manually invert the comparisons by swapping the left-hand and
901//    right-hand side. Using `Ordering::reverse` generates significantly worse
902//    code (per Matt Godbolt's Compiler Explorer).
903//
904// Anyway, that's a brief history of why this code is the way it is. Don't
905// change it unless you know what you're doing.
906
907impl PartialEq<LevelFilter> for Level {
908    #[inline(always)]
909    fn eq(&self, other: &LevelFilter) -> bool {
910        self.0 as usize == filter_as_usize(&other.0)
911    }
912}
913
914impl PartialOrd for Level {
915    #[inline(always)]
916    fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> {
917        Some(self.cmp(other))
918    }
919
920    #[inline(always)]
921    fn lt(&self, other: &Level) -> bool {
922        (other.0 as usize) < (self.0 as usize)
923    }
924
925    #[inline(always)]
926    fn le(&self, other: &Level) -> bool {
927        (other.0 as usize) <= (self.0 as usize)
928    }
929
930    #[inline(always)]
931    fn gt(&self, other: &Level) -> bool {
932        (other.0 as usize) > (self.0 as usize)
933    }
934
935    #[inline(always)]
936    fn ge(&self, other: &Level) -> bool {
937        (other.0 as usize) >= (self.0 as usize)
938    }
939}
940
941impl Ord for Level {
942    #[inline(always)]
943    fn cmp(&self, other: &Self) -> cmp::Ordering {
944        (other.0 as usize).cmp(&(self.0 as usize))
945    }
946}
947
948impl PartialOrd<LevelFilter> for Level {
949    #[inline(always)]
950    fn partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering> {
951        Some(filter_as_usize(&other.0).cmp(&(self.0 as usize)))
952    }
953
954    #[inline(always)]
955    fn lt(&self, other: &LevelFilter) -> bool {
956        filter_as_usize(&other.0) < (self.0 as usize)
957    }
958
959    #[inline(always)]
960    fn le(&self, other: &LevelFilter) -> bool {
961        filter_as_usize(&other.0) <= (self.0 as usize)
962    }
963
964    #[inline(always)]
965    fn gt(&self, other: &LevelFilter) -> bool {
966        filter_as_usize(&other.0) > (self.0 as usize)
967    }
968
969    #[inline(always)]
970    fn ge(&self, other: &LevelFilter) -> bool {
971        filter_as_usize(&other.0) >= (self.0 as usize)
972    }
973}
974
975#[inline(always)]
976fn filter_as_usize(x: &Option<Level>) -> usize {
977    match x {
978        Some(Level(f)) => *f as usize,
979        None => LevelFilter::OFF_USIZE,
980    }
981}
982
983impl PartialEq<Level> for LevelFilter {
984    #[inline(always)]
985    fn eq(&self, other: &Level) -> bool {
986        filter_as_usize(&self.0) == other.0 as usize
987    }
988}
989
990impl PartialOrd for LevelFilter {
991    #[inline(always)]
992    fn partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering> {
993        Some(self.cmp(other))
994    }
995
996    #[inline(always)]
997    fn lt(&self, other: &LevelFilter) -> bool {
998        filter_as_usize(&other.0) < filter_as_usize(&self.0)
999    }
1000
1001    #[inline(always)]
1002    fn le(&self, other: &LevelFilter) -> bool {
1003        filter_as_usize(&other.0) <= filter_as_usize(&self.0)
1004    }
1005
1006    #[inline(always)]
1007    fn gt(&self, other: &LevelFilter) -> bool {
1008        filter_as_usize(&other.0) > filter_as_usize(&self.0)
1009    }
1010
1011    #[inline(always)]
1012    fn ge(&self, other: &LevelFilter) -> bool {
1013        filter_as_usize(&other.0) >= filter_as_usize(&self.0)
1014    }
1015}
1016
1017impl Ord for LevelFilter {
1018    #[inline(always)]
1019    fn cmp(&self, other: &Self) -> cmp::Ordering {
1020        filter_as_usize(&other.0).cmp(&filter_as_usize(&self.0))
1021    }
1022}
1023
1024impl PartialOrd<Level> for LevelFilter {
1025    #[inline(always)]
1026    fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> {
1027        Some((other.0 as usize).cmp(&filter_as_usize(&self.0)))
1028    }
1029
1030    #[inline(always)]
1031    fn lt(&self, other: &Level) -> bool {
1032        (other.0 as usize) < filter_as_usize(&self.0)
1033    }
1034
1035    #[inline(always)]
1036    fn le(&self, other: &Level) -> bool {
1037        (other.0 as usize) <= filter_as_usize(&self.0)
1038    }
1039
1040    #[inline(always)]
1041    fn gt(&self, other: &Level) -> bool {
1042        (other.0 as usize) > filter_as_usize(&self.0)
1043    }
1044
1045    #[inline(always)]
1046    fn ge(&self, other: &Level) -> bool {
1047        (other.0 as usize) >= filter_as_usize(&self.0)
1048    }
1049}
1050
1051#[cfg(test)]
1052mod tests {
1053    use super::*;
1054    use core::mem;
1055
1056    #[test]
1057    fn level_from_str() {
1058        assert_eq!("error".parse::<Level>().unwrap(), Level::ERROR);
1059        assert_eq!("4".parse::<Level>().unwrap(), Level::DEBUG);
1060        assert!("0".parse::<Level>().is_err())
1061    }
1062
1063    #[test]
1064    fn filter_level_conversion() {
1065        let mapping = [
1066            (LevelFilter::OFF, None),
1067            (LevelFilter::ERROR, Some(Level::ERROR)),
1068            (LevelFilter::WARN, Some(Level::WARN)),
1069            (LevelFilter::INFO, Some(Level::INFO)),
1070            (LevelFilter::DEBUG, Some(Level::DEBUG)),
1071            (LevelFilter::TRACE, Some(Level::TRACE)),
1072        ];
1073        for (filter, level) in mapping.iter() {
1074            assert_eq!(filter.into_level(), *level);
1075            match level {
1076                Some(level) => {
1077                    let actual: LevelFilter = (*level).into();
1078                    assert_eq!(actual, *filter);
1079                }
1080                None => {
1081                    let actual: LevelFilter = None.into();
1082                    assert_eq!(actual, *filter);
1083                }
1084            }
1085        }
1086    }
1087
1088    #[test]
1089    fn level_filter_is_usize_sized() {
1090        assert_eq!(
1091            mem::size_of::<LevelFilter>(),
1092            mem::size_of::<usize>(),
1093            "`LevelFilter` is no longer `usize`-sized! global MAX_LEVEL may now be invalid!"
1094        )
1095    }
1096
1097    #[test]
1098    fn level_filter_reprs() {
1099        let mapping = [
1100            (LevelFilter::OFF, LevelInner::Error as usize + 1),
1101            (LevelFilter::ERROR, LevelInner::Error as usize),
1102            (LevelFilter::WARN, LevelInner::Warn as usize),
1103            (LevelFilter::INFO, LevelInner::Info as usize),
1104            (LevelFilter::DEBUG, LevelInner::Debug as usize),
1105            (LevelFilter::TRACE, LevelInner::Trace as usize),
1106        ];
1107        for &(filter, expected) in &mapping {
1108            let repr = unsafe {
1109                // safety: The entire purpose of this test is to assert that the
1110                // actual repr matches what we expect it to be --- we're testing
1111                // that *other* unsafe code is sound using the transmuted value.
1112                // We're not going to do anything with it that might be unsound.
1113                mem::transmute::<LevelFilter, usize>(filter)
1114            };
1115            assert_eq!(expected, repr, "repr changed for {:?}", filter)
1116        }
1117    }
1118}