tracing_core/
metadata.rs

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