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. |
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 | #[inline ] |
277 | pub fn fields(&self) -> &field::FieldSet { |
278 | &self.fields |
279 | } |
280 | |
281 | /// Returns the level of verbosity of the described span or event. |
282 | pub fn level(&self) -> &Level { |
283 | &self.level |
284 | } |
285 | |
286 | /// Returns the name of the span. |
287 | 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. |
296 | 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. |
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 |
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. |
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 ] |
321 | pub fn callsite(&self) -> callsite::Identifier { |
322 | self.fields.callsite() |
323 | } |
324 | |
325 | /// Returns true if the callsite kind is `Event`. |
326 | pub fn is_event(&self) -> bool { |
327 | self.kind.is_event() |
328 | } |
329 | |
330 | /// Return true if the callsite kind is `Span`. |
331 | pub fn is_span(&self) -> bool { |
332 | self.kind.is_span() |
333 | } |
334 | } |
335 | |
336 | impl<'a> fmt::Debug for Metadata<'a> { |
337 | 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` |
386 | 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` |
391 | 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` |
396 | 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. |
404 | pub const fn hint(self) -> Self { |
405 | Self(self.0 | Self::HINT_BIT) |
406 | } |
407 | } |
408 | |
409 | impl fmt::Debug for Kind { |
410 | 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 ] |
448 | 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. |
527 | 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 { |
539 | 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; |
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: &str if s.eq_ignore_ascii_case("error" ) => Ok(Level::ERROR), |
569 | s: &str if s.eq_ignore_ascii_case("warn" ) => Ok(Level::WARN), |
570 | s: &str if s.eq_ignore_ascii_case("info" ) => Ok(Level::INFO), |
571 | s: &str if s.eq_ignore_ascii_case("debug" ) => Ok(Level::DEBUG), |
572 | s: &str 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 ] |
607 | fn from(level: Level) -> Self { |
608 | Self::from_level(level) |
609 | } |
610 | } |
611 | |
612 | impl From<Option<Level>> for LevelFilter { |
613 | #[inline ] |
614 | fn from(level: Option<Level>) -> Self { |
615 | Self(level) |
616 | } |
617 | } |
618 | |
619 | impl From<LevelFilter> for Option<Level> { |
620 | #[inline ] |
621 | 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`. |
654 | 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 |
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)] |
697 | 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 | |
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 { |
751 | 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 { |
764 | 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; |
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 { |
811 | 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 { |
820 | 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)] |
906 | 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)] |
913 | fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> { |
914 | Some(self.cmp(other)) |
915 | } |
916 | |
917 | #[inline (always)] |
918 | fn lt(&self, other: &Level) -> bool { |
919 | (other.0 as usize) < (self.0 as usize) |
920 | } |
921 | |
922 | #[inline (always)] |
923 | fn le(&self, other: &Level) -> bool { |
924 | (other.0 as usize) <= (self.0 as usize) |
925 | } |
926 | |
927 | #[inline (always)] |
928 | fn gt(&self, other: &Level) -> bool { |
929 | (other.0 as usize) > (self.0 as usize) |
930 | } |
931 | |
932 | #[inline (always)] |
933 | 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)] |
940 | 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)] |
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)] |
952 | fn lt(&self, other: &LevelFilter) -> bool { |
953 | filter_as_usize(&other.0) < (self.0 as usize) |
954 | } |
955 | |
956 | #[inline (always)] |
957 | fn le(&self, other: &LevelFilter) -> bool { |
958 | filter_as_usize(&other.0) <= (self.0 as usize) |
959 | } |
960 | |
961 | #[inline (always)] |
962 | fn gt(&self, other: &LevelFilter) -> bool { |
963 | filter_as_usize(&other.0) > (self.0 as usize) |
964 | } |
965 | |
966 | #[inline (always)] |
967 | fn ge(&self, other: &LevelFilter) -> bool { |
968 | filter_as_usize(&other.0) >= (self.0 as usize) |
969 | } |
970 | } |
971 | |
972 | #[inline (always)] |
973 | fn filter_as_usize(x: &Option<Level>) -> usize { |
974 | match x { |
975 | Some(Level(f: &LevelInner)) => *f as usize, |
976 | None => LevelFilter::OFF_USIZE, |
977 | } |
978 | } |
979 | |
980 | impl PartialEq<Level> for LevelFilter { |
981 | #[inline (always)] |
982 | 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)] |
989 | fn partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering> { |
990 | Some(self.cmp(other)) |
991 | } |
992 | |
993 | #[inline (always)] |
994 | fn lt(&self, other: &LevelFilter) -> bool { |
995 | filter_as_usize(&other.0) < filter_as_usize(&self.0) |
996 | } |
997 | |
998 | #[inline (always)] |
999 | fn le(&self, other: &LevelFilter) -> bool { |
1000 | filter_as_usize(&other.0) <= filter_as_usize(&self.0) |
1001 | } |
1002 | |
1003 | #[inline (always)] |
1004 | fn gt(&self, other: &LevelFilter) -> bool { |
1005 | filter_as_usize(&other.0) > filter_as_usize(&self.0) |
1006 | } |
1007 | |
1008 | #[inline (always)] |
1009 | 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)] |
1016 | 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)] |
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)] |
1028 | fn lt(&self, other: &Level) -> bool { |
1029 | (other.0 as usize) < filter_as_usize(&self.0) |
1030 | } |
1031 | |
1032 | #[inline (always)] |
1033 | fn le(&self, other: &Level) -> bool { |
1034 | (other.0 as usize) <= filter_as_usize(&self.0) |
1035 | } |
1036 | |
1037 | #[inline (always)] |
1038 | fn gt(&self, other: &Level) -> bool { |
1039 | (other.0 as usize) > filter_as_usize(&self.0) |
1040 | } |
1041 | |
1042 | #[inline (always)] |
1043 | 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 ] |
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 ] |
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 ] |
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 ] |
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 | |