1//! Metadata describing trace data.
2use super::{callsite, field};
3use crate::stdlib::{
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 a `LevelFilter`, it should be
226/// considered enabled; if greater than or equal to the `LevelFilter`,
227/// that level is disabled. See [`LevelFilter::current`] for more
228/// details.
229///
230/// Note that this is essentially identical to the `Level` type, but with the
231/// addition of an [`OFF`] level that completely disables all trace
232/// instrumentation.
233///
234/// See the documentation for the [`Level`] type to see how `Level`s
235/// and `LevelFilter`s interact.
236///
237/// [`OFF`]: LevelFilter::OFF
238#[repr(transparent)]
239#[derive(Copy, Clone, Eq, PartialEq, Hash)]
240pub struct LevelFilter(Option<Level>);
241
242/// Indicates that a string could not be parsed to a valid level.
243#[derive(Clone, Debug)]
244pub struct ParseLevelFilterError(());
245
246static MAX_LEVEL: AtomicUsize = AtomicUsize::new(LevelFilter::OFF_USIZE);
247
248// ===== impl Metadata =====
249
250impl<'a> Metadata<'a> {
251 /// Construct new metadata for a span or event, with a name, target, level, field
252 /// names, and optional source code location.
253 pub const fn new(
254 name: &'static str,
255 target: &'a str,
256 level: Level,
257 file: Option<&'a str>,
258 line: Option<u32>,
259 module_path: Option<&'a str>,
260 fields: field::FieldSet,
261 kind: Kind,
262 ) -> Self {
263 Metadata {
264 name,
265 target,
266 level,
267 module_path,
268 file,
269 line,
270 fields,
271 kind,
272 }
273 }
274
275 /// Returns the names of the fields on the described span or event.
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
335impl<'a> fmt::Debug for Metadata<'a> {
336 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
337 let mut meta = f.debug_struct("Metadata");
338 meta.field("name", &self.name)
339 .field("target", &self.target)
340 .field("level", &self.level);
341
342 if let Some(path) = self.module_path() {
343 meta.field("module_path", &path);
344 }
345
346 match (self.file(), self.line()) {
347 (Some(file), Some(line)) => {
348 meta.field("location", &format_args!("{}:{}", file, line));
349 }
350 (Some(file), None) => {
351 meta.field("file", &format_args!("{}", file));
352 }
353
354 // Note: a line num with no file is a kind of weird case that _probably_ never occurs...
355 (None, Some(line)) => {
356 meta.field("line", &line);
357 }
358 (None, None) => {}
359 };
360
361 meta.field("fields", &format_args!("{}", self.fields))
362 .field("callsite", &self.callsite())
363 .field("kind", &self.kind)
364 .finish()
365 }
366}
367
368impl Kind {
369 const EVENT_BIT: u8 = 1 << 0;
370 const SPAN_BIT: u8 = 1 << 1;
371 const HINT_BIT: u8 = 1 << 2;
372
373 /// `Event` callsite
374 pub const EVENT: Kind = Kind(Self::EVENT_BIT);
375
376 /// `Span` callsite
377 pub const SPAN: Kind = Kind(Self::SPAN_BIT);
378
379 /// `enabled!` callsite. [`Subscriber`][`crate::subscriber::Subscriber`]s can assume
380 /// this `Kind` means they will never recieve a
381 /// full event with this [`Metadata`].
382 pub const HINT: Kind = Kind(Self::HINT_BIT);
383
384 /// Return true if the callsite kind is `Span`
385 pub fn is_span(&self) -> bool {
386 self.0 & Self::SPAN_BIT == Self::SPAN_BIT
387 }
388
389 /// Return true if the callsite kind is `Event`
390 pub fn is_event(&self) -> bool {
391 self.0 & Self::EVENT_BIT == Self::EVENT_BIT
392 }
393
394 /// Return true if the callsite kind is `Hint`
395 pub fn is_hint(&self) -> bool {
396 self.0 & Self::HINT_BIT == Self::HINT_BIT
397 }
398
399 /// Sets that this `Kind` is a [hint](Self::HINT).
400 ///
401 /// This can be called on [`SPAN`](Self::SPAN) and [`EVENT`](Self::EVENT)
402 /// kinds to construct a hint callsite that also counts as a span or event.
403 pub const fn hint(self) -> Self {
404 Self(self.0 | Self::HINT_BIT)
405 }
406}
407
408impl fmt::Debug for Kind {
409 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
410 f.write_str("Kind(")?;
411 let mut has_bits = false;
412 let mut write_bit = |name: &str| {
413 if has_bits {
414 f.write_str(" | ")?;
415 }
416 f.write_str(name)?;
417 has_bits = true;
418 Ok(())
419 };
420
421 if self.is_event() {
422 write_bit("EVENT")?;
423 }
424
425 if self.is_span() {
426 write_bit("SPAN")?;
427 }
428
429 if self.is_hint() {
430 write_bit("HINT")?;
431 }
432
433 // if none of the expected bits were set, something is messed up, so
434 // just print the bits for debugging purposes
435 if !has_bits {
436 write!(f, "{:#b}", self.0)?;
437 }
438
439 f.write_str(")")
440 }
441}
442
443impl<'a> Eq for Metadata<'a> {}
444
445impl<'a> PartialEq for Metadata<'a> {
446 #[inline]
447 fn eq(&self, other: &Self) -> bool {
448 if core::ptr::eq(&self, &other) {
449 true
450 } else if cfg!(not(debug_assertions)) {
451 // In a well-behaving application, two `Metadata` can be assumed to
452 // be totally equal so long as they share the same callsite.
453 self.callsite() == other.callsite()
454 } else {
455 // However, when debug-assertions are enabled, do not assume that
456 // the application is well-behaving; check every field of `Metadata`
457 // for equality.
458
459 // `Metadata` is destructured here to ensure a compile-error if the
460 // fields of `Metadata` change.
461 let Metadata {
462 name: lhs_name,
463 target: lhs_target,
464 level: lhs_level,
465 module_path: lhs_module_path,
466 file: lhs_file,
467 line: lhs_line,
468 fields: lhs_fields,
469 kind: lhs_kind,
470 } = self;
471
472 let Metadata {
473 name: rhs_name,
474 target: rhs_target,
475 level: rhs_level,
476 module_path: rhs_module_path,
477 file: rhs_file,
478 line: rhs_line,
479 fields: rhs_fields,
480 kind: rhs_kind,
481 } = &other;
482
483 // The initial comparison of callsites is purely an optimization;
484 // it can be removed without affecting the overall semantics of the
485 // expression.
486 self.callsite() == other.callsite()
487 && lhs_name == rhs_name
488 && lhs_target == rhs_target
489 && lhs_level == rhs_level
490 && lhs_module_path == rhs_module_path
491 && lhs_file == rhs_file
492 && lhs_line == rhs_line
493 && lhs_fields == rhs_fields
494 && lhs_kind == rhs_kind
495 }
496 }
497}
498
499// ===== impl Level =====
500
501impl Level {
502 /// The "error" level.
503 ///
504 /// Designates very serious errors.
505 pub const ERROR: Level = Level(LevelInner::Error);
506 /// The "warn" level.
507 ///
508 /// Designates hazardous situations.
509 pub const WARN: Level = Level(LevelInner::Warn);
510 /// The "info" level.
511 ///
512 /// Designates useful information.
513 pub const INFO: Level = Level(LevelInner::Info);
514 /// The "debug" level.
515 ///
516 /// Designates lower priority information.
517 pub const DEBUG: Level = Level(LevelInner::Debug);
518 /// The "trace" level.
519 ///
520 /// Designates very low priority, often extremely verbose, information.
521 pub const TRACE: Level = Level(LevelInner::Trace);
522
523 /// Returns the string representation of the `Level`.
524 ///
525 /// This returns the same string as the `fmt::Display` implementation.
526 pub fn as_str(&self) -> &'static str {
527 match *self {
528 Level::TRACE => "TRACE",
529 Level::DEBUG => "DEBUG",
530 Level::INFO => "INFO",
531 Level::WARN => "WARN",
532 Level::ERROR => "ERROR",
533 }
534 }
535}
536
537impl fmt::Display for Level {
538 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
539 match *self {
540 Level::TRACE => f.pad("TRACE"),
541 Level::DEBUG => f.pad("DEBUG"),
542 Level::INFO => f.pad("INFO"),
543 Level::WARN => f.pad("WARN"),
544 Level::ERROR => f.pad("ERROR"),
545 }
546 }
547}
548
549#[cfg(feature = "std")]
550#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
551impl crate::stdlib::error::Error for ParseLevelError {}
552
553impl FromStr for Level {
554 type Err = ParseLevelError;
555 fn from_str(s: &str) -> Result<Self, ParseLevelError> {
556 s.parse::<usize>()
557 .map_err(|_| ParseLevelError { _p: () })
558 .and_then(|num| match num {
559 1 => Ok(Level::ERROR),
560 2 => Ok(Level::WARN),
561 3 => Ok(Level::INFO),
562 4 => Ok(Level::DEBUG),
563 5 => Ok(Level::TRACE),
564 _ => Err(ParseLevelError { _p: () }),
565 })
566 .or_else(|_| match s {
567 s: &str if s.eq_ignore_ascii_case("error") => Ok(Level::ERROR),
568 s: &str if s.eq_ignore_ascii_case("warn") => Ok(Level::WARN),
569 s: &str if s.eq_ignore_ascii_case("info") => Ok(Level::INFO),
570 s: &str if s.eq_ignore_ascii_case("debug") => Ok(Level::DEBUG),
571 s: &str if s.eq_ignore_ascii_case("trace") => Ok(Level::TRACE),
572 _ => Err(ParseLevelError { _p: () }),
573 })
574 }
575}
576
577#[repr(usize)]
578#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
579enum LevelInner {
580 /// The "trace" level.
581 ///
582 /// Designates very low priority, often extremely verbose, information.
583 Trace = 0,
584 /// The "debug" level.
585 ///
586 /// Designates lower priority information.
587 Debug = 1,
588 /// The "info" level.
589 ///
590 /// Designates useful information.
591 Info = 2,
592 /// The "warn" level.
593 ///
594 /// Designates hazardous situations.
595 Warn = 3,
596 /// The "error" level.
597 ///
598 /// Designates very serious errors.
599 Error = 4,
600}
601
602// === impl LevelFilter ===
603
604impl From<Level> for LevelFilter {
605 #[inline]
606 fn from(level: Level) -> Self {
607 Self::from_level(level)
608 }
609}
610
611impl From<Option<Level>> for LevelFilter {
612 #[inline]
613 fn from(level: Option<Level>) -> Self {
614 Self(level)
615 }
616}
617
618impl From<LevelFilter> for Option<Level> {
619 #[inline]
620 fn from(filter: LevelFilter) -> Self {
621 filter.into_level()
622 }
623}
624
625impl LevelFilter {
626 /// The "off" level.
627 ///
628 /// Designates that trace instrumentation should be completely disabled.
629 pub const OFF: LevelFilter = LevelFilter(None);
630 /// The "error" level.
631 ///
632 /// Designates very serious errors.
633 pub const ERROR: LevelFilter = LevelFilter::from_level(Level::ERROR);
634 /// The "warn" level.
635 ///
636 /// Designates hazardous situations.
637 pub const WARN: LevelFilter = LevelFilter::from_level(Level::WARN);
638 /// The "info" level.
639 ///
640 /// Designates useful information.
641 pub const INFO: LevelFilter = LevelFilter::from_level(Level::INFO);
642 /// The "debug" level.
643 ///
644 /// Designates lower priority information.
645 pub const DEBUG: LevelFilter = LevelFilter::from_level(Level::DEBUG);
646 /// The "trace" level.
647 ///
648 /// Designates very low priority, often extremely verbose, information.
649 pub const TRACE: LevelFilter = LevelFilter(Some(Level::TRACE));
650
651 /// Returns a `LevelFilter` that enables spans and events with verbosity up
652 /// to and including `level`.
653 pub const fn from_level(level: Level) -> Self {
654 Self(Some(level))
655 }
656
657 /// Returns the most verbose [`Level`] that this filter accepts, or `None`
658 /// if it is [`OFF`].
659 ///
660 /// [`OFF`]: LevelFilter::OFF
661 pub const fn into_level(self) -> Option<Level> {
662 self.0
663 }
664
665 // These consts are necessary because `as` casts are not allowed as
666 // match patterns.
667 const ERROR_USIZE: usize = LevelInner::Error as usize;
668 const WARN_USIZE: usize = LevelInner::Warn as usize;
669 const INFO_USIZE: usize = LevelInner::Info as usize;
670 const DEBUG_USIZE: usize = LevelInner::Debug as usize;
671 const TRACE_USIZE: usize = LevelInner::Trace as usize;
672 // Using the value of the last variant + 1 ensures that we match the value
673 // for `Option::None` as selected by the niche optimization for
674 // `LevelFilter`. If this is the case, converting a `usize` value into a
675 // `LevelFilter` (in `LevelFilter::current`) will be an identity conversion,
676 // rather than generating a lookup table.
677 const OFF_USIZE: usize = LevelInner::Error as usize + 1;
678
679 /// Returns a `LevelFilter` that matches the most verbose [`Level`] that any
680 /// currently active [`Subscriber`] will enable.
681 ///
682 /// User code should treat this as a *hint*. If a given span or event has a
683 /// level *higher* than the returned `LevelFilter`, it will not be enabled.
684 /// However, if the level is less than or equal to this value, the span or
685 /// event is *not* guaranteed to be enabled; the subscriber will still
686 /// filter each callsite individually.
687 ///
688 /// Therefore, comparing a given span or event's level to the returned
689 /// `LevelFilter` **can** be used for determining if something is
690 /// *disabled*, but **should not** be used for determining if something is
691 /// *enabled*.
692 ///
693 /// [`Level`]: super::Level
694 /// [`Subscriber`]: super::Subscriber
695 #[inline(always)]
696 pub fn current() -> Self {
697 match MAX_LEVEL.load(Ordering::Relaxed) {
698 Self::ERROR_USIZE => Self::ERROR,
699 Self::WARN_USIZE => Self::WARN,
700 Self::INFO_USIZE => Self::INFO,
701 Self::DEBUG_USIZE => Self::DEBUG,
702 Self::TRACE_USIZE => Self::TRACE,
703 Self::OFF_USIZE => Self::OFF,
704 #[cfg(debug_assertions)]
705 unknown => unreachable!(
706 "/!\\ `LevelFilter` representation seems to have changed! /!\\ \n\
707 This is a bug (and it's pretty bad). Please contact the `tracing` \
708 maintainers. Thank you and I'm sorry.\n \
709 The offending repr was: {:?}",
710 unknown,
711 ),
712 #[cfg(not(debug_assertions))]
713 _ => unsafe {
714 // Using `unreachable_unchecked` here (rather than
715 // `unreachable!()`) is necessary to ensure that rustc generates
716 // an identity conversion from integer -> discriminant, rather
717 // than generating a lookup table. We want to ensure this
718 // function is a single `mov` instruction (on x86) if at all
719 // possible, because it is called *every* time a span/event
720 // callsite is hit; and it is (potentially) the only code in the
721 // hottest path for skipping a majority of callsites when level
722 // filtering is in use.
723 //
724 // safety: This branch is only truly unreachable if we guarantee
725 // that no values other than the possible enum discriminants
726 // will *ever* be present. The `AtomicUsize` is initialized to
727 // the `OFF` value. It is only set by the `set_max` function,
728 // which takes a `LevelFilter` as a parameter. This restricts
729 // the inputs to `set_max` to the set of valid discriminants.
730 // Therefore, **as long as `MAX_VALUE` is only ever set by
731 // `set_max`**, this is safe.
732 crate::stdlib::hint::unreachable_unchecked()
733 },
734 }
735 }
736
737 pub(crate) fn set_max(LevelFilter(level): LevelFilter) {
738 let val = match level {
739 Some(Level(level)) => level as usize,
740 None => Self::OFF_USIZE,
741 };
742
743 // using an AcqRel swap ensures an ordered relationship of writes to the
744 // max level.
745 MAX_LEVEL.swap(val, Ordering::AcqRel);
746 }
747}
748
749impl fmt::Display for LevelFilter {
750 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
751 match *self {
752 LevelFilter::OFF => f.pad("off"),
753 LevelFilter::ERROR => f.pad("error"),
754 LevelFilter::WARN => f.pad("warn"),
755 LevelFilter::INFO => f.pad("info"),
756 LevelFilter::DEBUG => f.pad("debug"),
757 LevelFilter::TRACE => f.pad("trace"),
758 }
759 }
760}
761
762impl fmt::Debug for LevelFilter {
763 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
764 match *self {
765 LevelFilter::OFF => f.pad("LevelFilter::OFF"),
766 LevelFilter::ERROR => f.pad("LevelFilter::ERROR"),
767 LevelFilter::WARN => f.pad("LevelFilter::WARN"),
768 LevelFilter::INFO => f.pad("LevelFilter::INFO"),
769 LevelFilter::DEBUG => f.pad("LevelFilter::DEBUG"),
770 LevelFilter::TRACE => f.pad("LevelFilter::TRACE"),
771 }
772 }
773}
774
775impl FromStr for LevelFilter {
776 type Err = ParseLevelFilterError;
777 fn from_str(from: &str) -> Result<Self, Self::Err> {
778 from.parse::<usize>()
779 .ok()
780 .and_then(|num| match num {
781 0 => Some(LevelFilter::OFF),
782 1 => Some(LevelFilter::ERROR),
783 2 => Some(LevelFilter::WARN),
784 3 => Some(LevelFilter::INFO),
785 4 => Some(LevelFilter::DEBUG),
786 5 => Some(LevelFilter::TRACE),
787 _ => None,
788 })
789 .or_else(|| match from {
790 "" => Some(LevelFilter::ERROR),
791 s if s.eq_ignore_ascii_case("error") => Some(LevelFilter::ERROR),
792 s if s.eq_ignore_ascii_case("warn") => Some(LevelFilter::WARN),
793 s if s.eq_ignore_ascii_case("info") => Some(LevelFilter::INFO),
794 s if s.eq_ignore_ascii_case("debug") => Some(LevelFilter::DEBUG),
795 s if s.eq_ignore_ascii_case("trace") => Some(LevelFilter::TRACE),
796 s if s.eq_ignore_ascii_case("off") => Some(LevelFilter::OFF),
797 _ => None,
798 })
799 .ok_or(ParseLevelFilterError(()))
800 }
801}
802
803/// Returned if parsing a `Level` fails.
804#[derive(Debug)]
805pub struct ParseLevelError {
806 _p: (),
807}
808
809impl fmt::Display for ParseLevelError {
810 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
811 f.pad(
812 "error parsing level: expected one of \"error\", \"warn\", \
813 \"info\", \"debug\", \"trace\", or a number 1-5",
814 )
815 }
816}
817
818impl fmt::Display for ParseLevelFilterError {
819 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
820 f.pad(
821 "error parsing level filter: expected one of \"off\", \"error\", \
822 \"warn\", \"info\", \"debug\", \"trace\", or a number 0-5",
823 )
824 }
825}
826
827#[cfg(feature = "std")]
828impl std::error::Error for ParseLevelFilterError {}
829
830// ==== Level and LevelFilter comparisons ====
831
832// /!\ BIG, IMPORTANT WARNING /!\
833// Do NOT mess with these implementations! They are hand-written for a reason!
834//
835// Since comparing `Level`s and `LevelFilter`s happens in a *very* hot path
836// (potentially, every time a span or event macro is hit, regardless of whether
837// or not is enabled), we *need* to ensure that these comparisons are as fast as
838// possible. Therefore, we have some requirements:
839//
840// 1. We want to do our best to ensure that rustc will generate integer-integer
841// comparisons wherever possible.
842//
843// The derived `Ord`/`PartialOrd` impls for `LevelFilter` will not do this,
844// because `LevelFilter`s are represented by `Option<Level>`, rather than as
845// a separate `#[repr(usize)]` enum. This was (unfortunately) necessary for
846// backwards-compatibility reasons, as the `tracing` crate's original
847// version of `LevelFilter` defined `const fn` conversions between `Level`s
848// and `LevelFilter`, so we're stuck with the `Option<Level>` repr.
849// Therefore, we need hand-written `PartialOrd` impls that cast both sides of
850// the comparison to `usize`s, to force the compiler to generate integer
851// compares.
852//
853// 2. The hottest `Level`/`LevelFilter` comparison, the one that happens every
854// time a callsite is hit, occurs *within the `tracing` crate's macros*.
855// This means that the comparison is happening *inside* a crate that
856// *depends* on `tracing-core`, not in `tracing-core` itself. The compiler
857// will only inline function calls across crate boundaries if the called
858// function is annotated with an `#[inline]` attribute, and we *definitely*
859// want the comparison functions to be inlined: as previously mentioned, they
860// should compile down to a single integer comparison on release builds, and
861// it seems really sad to push an entire stack frame to call a function
862// consisting of one `cmp` instruction!
863//
864// Therefore, we need to ensure that all the comparison methods have
865// `#[inline]` or `#[inline(always)]` attributes. It's not sufficient to just
866// add the attribute to `partial_cmp` in a manual implementation of the
867// trait, since it's the comparison operators (`lt`, `le`, `gt`, and `ge`)
868// that will actually be *used*, and the default implementation of *those*
869// methods, which calls `partial_cmp`, does not have an inline annotation.
870//
871// 3. We need the comparisons to be inverted. The discriminants for the
872// `LevelInner` enum are assigned in "backwards" order, with `TRACE` having
873// the *lowest* value. However, we want `TRACE` to compare greater-than all
874// other levels.
875//
876// Why are the numeric values inverted? In order to ensure that `LevelFilter`
877// (which, as previously mentioned, *has* to be internally represented by an
878// `Option<Level>`) compiles down to a single integer value. This is
879// necessary for storing the global max in an `AtomicUsize`, and for ensuring
880// that we use fast integer-integer comparisons, as mentioned previously. In
881// order to ensure this, we exploit the niche optimization. The niche
882// optimization for `Option<{enum with a numeric repr}>` will choose
883// `(HIGHEST_DISCRIMINANT_VALUE + 1)` as the representation for `None`.
884// Therefore, the integer representation of `LevelFilter::OFF` (which is
885// `None`) will be the number 5. `OFF` must compare higher than every other
886// level in order for it to filter as expected. Since we want to use a single
887// `cmp` instruction, we can't special-case the integer value of `OFF` to
888// compare higher, as that will generate more code. Instead, we need it to be
889// on one end of the enum, with `ERROR` on the opposite end, so we assign the
890// value 0 to `ERROR`.
891//
892// This *does* mean that when parsing `LevelFilter`s or `Level`s from
893// `String`s, the integer values are inverted, but that doesn't happen in a
894// hot path.
895//
896// Note that we manually invert the comparisons by swapping the left-hand and
897// right-hand side. Using `Ordering::reverse` generates significantly worse
898// code (per Matt Godbolt's Compiler Explorer).
899//
900// Anyway, that's a brief history of why this code is the way it is. Don't
901// change it unless you know what you're doing.
902
903impl PartialEq<LevelFilter> for Level {
904 #[inline(always)]
905 fn eq(&self, other: &LevelFilter) -> bool {
906 self.0 as usize == filter_as_usize(&other.0)
907 }
908}
909
910impl PartialOrd for Level {
911 #[inline(always)]
912 fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> {
913 Some(self.cmp(other))
914 }
915
916 #[inline(always)]
917 fn lt(&self, other: &Level) -> bool {
918 (other.0 as usize) < (self.0 as usize)
919 }
920
921 #[inline(always)]
922 fn le(&self, other: &Level) -> bool {
923 (other.0 as usize) <= (self.0 as usize)
924 }
925
926 #[inline(always)]
927 fn gt(&self, other: &Level) -> bool {
928 (other.0 as usize) > (self.0 as usize)
929 }
930
931 #[inline(always)]
932 fn ge(&self, other: &Level) -> bool {
933 (other.0 as usize) >= (self.0 as usize)
934 }
935}
936
937impl Ord for Level {
938 #[inline(always)]
939 fn cmp(&self, other: &Self) -> cmp::Ordering {
940 (other.0 as usize).cmp(&(self.0 as usize))
941 }
942}
943
944impl PartialOrd<LevelFilter> for Level {
945 #[inline(always)]
946 fn partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering> {
947 Some(filter_as_usize(&other.0).cmp(&(self.0 as usize)))
948 }
949
950 #[inline(always)]
951 fn lt(&self, other: &LevelFilter) -> bool {
952 filter_as_usize(&other.0) < (self.0 as usize)
953 }
954
955 #[inline(always)]
956 fn le(&self, other: &LevelFilter) -> bool {
957 filter_as_usize(&other.0) <= (self.0 as usize)
958 }
959
960 #[inline(always)]
961 fn gt(&self, other: &LevelFilter) -> bool {
962 filter_as_usize(&other.0) > (self.0 as usize)
963 }
964
965 #[inline(always)]
966 fn ge(&self, other: &LevelFilter) -> bool {
967 filter_as_usize(&other.0) >= (self.0 as usize)
968 }
969}
970
971#[inline(always)]
972fn filter_as_usize(x: &Option<Level>) -> usize {
973 match x {
974 Some(Level(f: &LevelInner)) => *f as usize,
975 None => LevelFilter::OFF_USIZE,
976 }
977}
978
979impl PartialEq<Level> for LevelFilter {
980 #[inline(always)]
981 fn eq(&self, other: &Level) -> bool {
982 filter_as_usize(&self.0) == other.0 as usize
983 }
984}
985
986impl PartialOrd for LevelFilter {
987 #[inline(always)]
988 fn partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering> {
989 Some(self.cmp(other))
990 }
991
992 #[inline(always)]
993 fn lt(&self, other: &LevelFilter) -> bool {
994 filter_as_usize(&other.0) < filter_as_usize(&self.0)
995 }
996
997 #[inline(always)]
998 fn le(&self, other: &LevelFilter) -> bool {
999 filter_as_usize(&other.0) <= filter_as_usize(&self.0)
1000 }
1001
1002 #[inline(always)]
1003 fn gt(&self, other: &LevelFilter) -> bool {
1004 filter_as_usize(&other.0) > filter_as_usize(&self.0)
1005 }
1006
1007 #[inline(always)]
1008 fn ge(&self, other: &LevelFilter) -> bool {
1009 filter_as_usize(&other.0) >= filter_as_usize(&self.0)
1010 }
1011}
1012
1013impl Ord for LevelFilter {
1014 #[inline(always)]
1015 fn cmp(&self, other: &Self) -> cmp::Ordering {
1016 filter_as_usize(&other.0).cmp(&filter_as_usize(&self.0))
1017 }
1018}
1019
1020impl PartialOrd<Level> for LevelFilter {
1021 #[inline(always)]
1022 fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> {
1023 Some((other.0 as usize).cmp(&filter_as_usize(&self.0)))
1024 }
1025
1026 #[inline(always)]
1027 fn lt(&self, other: &Level) -> bool {
1028 (other.0 as usize) < filter_as_usize(&self.0)
1029 }
1030
1031 #[inline(always)]
1032 fn le(&self, other: &Level) -> bool {
1033 (other.0 as usize) <= filter_as_usize(&self.0)
1034 }
1035
1036 #[inline(always)]
1037 fn gt(&self, other: &Level) -> bool {
1038 (other.0 as usize) > filter_as_usize(&self.0)
1039 }
1040
1041 #[inline(always)]
1042 fn ge(&self, other: &Level) -> bool {
1043 (other.0 as usize) >= filter_as_usize(&self.0)
1044 }
1045}
1046
1047#[cfg(test)]
1048mod tests {
1049 use super::*;
1050 use crate::stdlib::mem;
1051
1052 #[test]
1053 fn level_from_str() {
1054 assert_eq!("error".parse::<Level>().unwrap(), Level::ERROR);
1055 assert_eq!("4".parse::<Level>().unwrap(), Level::DEBUG);
1056 assert!("0".parse::<Level>().is_err())
1057 }
1058
1059 #[test]
1060 fn filter_level_conversion() {
1061 let mapping = [
1062 (LevelFilter::OFF, None),
1063 (LevelFilter::ERROR, Some(Level::ERROR)),
1064 (LevelFilter::WARN, Some(Level::WARN)),
1065 (LevelFilter::INFO, Some(Level::INFO)),
1066 (LevelFilter::DEBUG, Some(Level::DEBUG)),
1067 (LevelFilter::TRACE, Some(Level::TRACE)),
1068 ];
1069 for (filter, level) in mapping.iter() {
1070 assert_eq!(filter.into_level(), *level);
1071 match level {
1072 Some(level) => {
1073 let actual: LevelFilter = (*level).into();
1074 assert_eq!(actual, *filter);
1075 }
1076 None => {
1077 let actual: LevelFilter = None.into();
1078 assert_eq!(actual, *filter);
1079 }
1080 }
1081 }
1082 }
1083
1084 #[test]
1085 fn level_filter_is_usize_sized() {
1086 assert_eq!(
1087 mem::size_of::<LevelFilter>(),
1088 mem::size_of::<usize>(),
1089 "`LevelFilter` is no longer `usize`-sized! global MAX_LEVEL may now be invalid!"
1090 )
1091 }
1092
1093 #[test]
1094 fn level_filter_reprs() {
1095 let mapping = [
1096 (LevelFilter::OFF, LevelInner::Error as usize + 1),
1097 (LevelFilter::ERROR, LevelInner::Error as usize),
1098 (LevelFilter::WARN, LevelInner::Warn as usize),
1099 (LevelFilter::INFO, LevelInner::Info as usize),
1100 (LevelFilter::DEBUG, LevelInner::Debug as usize),
1101 (LevelFilter::TRACE, LevelInner::Trace as usize),
1102 ];
1103 for &(filter, expected) in &mapping {
1104 let repr = unsafe {
1105 // safety: The entire purpose of this test is to assert that the
1106 // actual repr matches what we expect it to be --- we're testing
1107 // that *other* unsafe code is sound using the transmuted value.
1108 // We're not going to do anything with it that might be unsound.
1109 mem::transmute::<LevelFilter, usize>(filter)
1110 };
1111 assert_eq!(expected, repr, "repr changed for {:?}", filter)
1112 }
1113 }
1114}
1115