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 | 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 | |
335 | impl<'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 | |
368 | impl 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 | |
408 | impl 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 | |
443 | impl<'a> Eq for Metadata<'a> {} |
444 | |
445 | impl<'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 | |
501 | impl 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 | |
537 | impl 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" )))] |
551 | impl crate::stdlib::error::Error for ParseLevelError {} |
552 | |
553 | impl 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)] |
579 | enum 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 | |
604 | impl From<Level> for LevelFilter { |
605 | #[inline ] |
606 | fn from(level: Level) -> Self { |
607 | Self::from_level(level) |
608 | } |
609 | } |
610 | |
611 | impl From<Option<Level>> for LevelFilter { |
612 | #[inline ] |
613 | fn from(level: Option<Level>) -> Self { |
614 | Self(level) |
615 | } |
616 | } |
617 | |
618 | impl From<LevelFilter> for Option<Level> { |
619 | #[inline ] |
620 | fn from(filter: LevelFilter) -> Self { |
621 | filter.into_level() |
622 | } |
623 | } |
624 | |
625 | impl 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 | |
749 | impl 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 | |
762 | impl 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 | |
775 | impl 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)] |
805 | pub struct ParseLevelError { |
806 | _p: (), |
807 | } |
808 | |
809 | impl 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 | |
818 | impl 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" )] |
828 | impl 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 | |
903 | impl 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 | |
910 | impl 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 | |
937 | impl 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 | |
944 | impl 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)] |
972 | fn 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 | |
979 | impl 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 | |
986 | impl 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 | |
1013 | impl 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 | |
1020 | impl 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)] |
1048 | mod 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 | |