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