mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-24 00:00:11 +02:00
## Motivation To ease the implementation of `Subscriber::register_callsite`, a field should be added to `Metadata` to indicate if this callsite is an event or a span. ## Solution A new struct, `Kind`, is added to the `metadata` module in `tokio-trace-core`, and a `Kind` field is added to the `Metadata` struct. Macros which construct `metadata` now require a `Kind`. `Kind` is represented as a struct with a private inner enum to allow new `Kind`s to be added without breaking changes. However, the _addition_ of the kind field _is_ a breaking change. While this could be done in a backward-compatible way, it would permit the construction of metadata with unknown kinds, and since the next `tokio-trace-core` release will be a breaking change, I opted to make the breaking change instead. New API tests for the `callsite!` and `metadata!` macros have been added to guard against future API breakage. Fixes: #986 Closes: #1008 Co-Authored-By: csmoe <[email protected]>
350 lines
12 KiB
Rust
350 lines
12 KiB
Rust
//! Metadata describing trace data.
|
|
use super::{
|
|
callsite::{self, Callsite},
|
|
field,
|
|
};
|
|
use std::fmt;
|
|
|
|
/// Metadata describing a [span] or [event].
|
|
///
|
|
/// This includes the source code location where the span occurred, the names of
|
|
/// its fields, et cetera.
|
|
///
|
|
/// Metadata is used by [`Subscriber`]s when filtering spans and events, and it
|
|
/// may also be used as part of their data payload.
|
|
///
|
|
/// When created by the `event!` or `span!` macro, the metadata describing a
|
|
/// particular event or span is constructed statically and exists as a single
|
|
/// static instance. Thus, the overhead of creating the metadata is
|
|
/// _significantly_ lower than that of creating the actual span. Therefore,
|
|
/// filtering is based on metadata, rather than on the constructed span.
|
|
///
|
|
/// **Note**: Although instances of `Metadata` cannot be compared directly, they
|
|
/// provide a method [`Metadata::id()`] which returns an an opaque [callsite
|
|
/// identifier] which uniquely identifies the callsite where the metadata
|
|
/// originated. This can be used for determining if two Metadata correspond to
|
|
/// the same callsite.
|
|
///
|
|
/// [span]: ../span
|
|
/// [`Subscriber`]: ../subscriber/trait.Subscriber.html
|
|
/// [`Metadata::id()`]: struct.Metadata.html#method.id
|
|
/// [callsite identifier]: ../callsite/struct.Identifier.html
|
|
// TODO: When `const fn` is stable, make this type's fields private.
|
|
pub struct Metadata<'a> {
|
|
/// The name of the span described by this metadata.
|
|
///
|
|
/// **Warning**: The fields on this type are currently `pub` because it must
|
|
/// be able to be constructed statically by macros. However, when `const
|
|
/// fn`s are available on stable Rust, this will no longer be necessary.
|
|
/// Thus, these fields are *not* considered stable public API, and they may
|
|
/// change warning. Do not rely on any fields on `Metadata`. When
|
|
/// constructing new `Metadata`, use the `metadata!` macro or the
|
|
/// `Metadata::new` constructor instead!
|
|
#[doc(hidden)]
|
|
pub name: &'static str,
|
|
|
|
/// The part of the system that the span that this metadata describes
|
|
/// occurred in.
|
|
///
|
|
/// Typically, this is the module path, but alternate targets may be set
|
|
/// when spans or events are constructed.
|
|
///
|
|
/// **Warning**: The fields on this type are currently `pub` because it must
|
|
/// be able to be constructed statically by macros. However, when `const
|
|
/// fn`s are available on stable Rust, this will no longer be necessary.
|
|
/// Thus, these fields are *not* considered stable public API, and they may
|
|
/// change warning. Do not rely on any fields on `Metadata`. When
|
|
/// constructing new `Metadata`, use the `metadata!` macro or the
|
|
/// `Metadata::new` constructor instead!
|
|
#[doc(hidden)]
|
|
pub target: &'a str,
|
|
|
|
/// The level of verbosity of the described span.
|
|
///
|
|
/// **Warning**: The fields on this type are currently `pub` because it must
|
|
/// be able to be constructed statically by macros. However, when `const
|
|
/// fn`s are available on stable Rust, this will no longer be necessary.
|
|
/// Thus, these fields are *not* considered stable public API, and they may
|
|
/// change warning. Do not rely on any fields on `Metadata`. When
|
|
/// constructing new `Metadata`, use the `metadata!` macro or the
|
|
/// `Metadata::new` constructor instead!
|
|
#[doc(hidden)]
|
|
pub level: Level,
|
|
|
|
/// The name of the Rust module where the span occurred, or `None` if this
|
|
/// could not be determined.
|
|
///
|
|
/// **Warning**: The fields on this type are currently `pub` because it must
|
|
/// be able to be constructed statically by macros. However, when `const
|
|
/// fn`s are available on stable Rust, this will no longer be necessary.
|
|
/// Thus, these fields are *not* considered stable public API, and they may
|
|
/// change warning. Do not rely on any fields on `Metadata`. When
|
|
/// constructing new `Metadata`, use the `metadata!` macro or the
|
|
/// `Metadata::new` constructor instead!
|
|
#[doc(hidden)]
|
|
pub module_path: Option<&'a str>,
|
|
|
|
/// The name of the source code file where the span occurred, or `None` if
|
|
/// this could not be determined.
|
|
///
|
|
/// **Warning**: The fields on this type are currently `pub` because it must
|
|
/// be able to be constructed statically by macros. However, when `const
|
|
/// fn`s are available on stable Rust, this will no longer be necessary.
|
|
/// Thus, these fields are *not* considered stable public API, and they may
|
|
/// change warning. Do not rely on any fields on `Metadata`. When
|
|
/// constructing new `Metadata`, use the `metadata!` macro or the
|
|
/// `Metadata::new` constructor instead!
|
|
#[doc(hidden)]
|
|
pub file: Option<&'a str>,
|
|
|
|
/// The line number in the source code file where the span occurred, or
|
|
/// `None` if this could not be determined.
|
|
///
|
|
/// **Warning**: The fields on this type are currently `pub` because it must
|
|
/// be able to be constructed statically by macros. However, when `const
|
|
/// fn`s are available on stable Rust, this will no longer be necessary.
|
|
/// Thus, these fields are *not* considered stable public API, and they may
|
|
/// change warning. Do not rely on any fields on `Metadata`. When
|
|
/// constructing new `Metadata`, use the `metadata!` macro or the
|
|
/// `Metadata::new` constructor instead!
|
|
#[doc(hidden)]
|
|
pub line: Option<u32>,
|
|
|
|
/// The names of the key-value fields attached to the described span or
|
|
/// event.
|
|
///
|
|
/// **Warning**: The fields on this type are currently `pub` because it must
|
|
/// be able to be constructed statically by macros. However, when `const
|
|
/// fn`s are available on stable Rust, this will no longer be necessary.
|
|
/// Thus, these fields are *not* considered stable public API, and they may
|
|
/// change warning. Do not rely on any fields on `Metadata`. When
|
|
/// constructing new `Metadata`, use the `metadata!` macro or the
|
|
/// `Metadata::new` constructor instead!
|
|
#[doc(hidden)]
|
|
pub fields: field::FieldSet,
|
|
|
|
/// The kind of the callsite.
|
|
///
|
|
/// **Warning**: The fields on this type are currently `pub` because it must
|
|
/// be able to be constructed statically by macros. However, when `const
|
|
/// fn`s are available on stable Rust, this will no longer be necessary.
|
|
/// Thus, these fields are *not* considered stable public API, and they may
|
|
/// change warning. Do not rely on any fields on `Metadata`. When
|
|
/// constructing new `Metadata`, use the `metadata!` macro or the
|
|
/// `Metadata::new` constructor instead!
|
|
#[doc(hidden)]
|
|
pub kind: Kind,
|
|
}
|
|
|
|
/// Indicate whether the callsite is a span or event.
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
pub struct Kind(KindInner);
|
|
|
|
/// Describes the level of verbosity of a span or event.
|
|
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
|
pub struct Level(LevelInner);
|
|
|
|
// ===== impl Metadata =====
|
|
|
|
impl<'a> Metadata<'a> {
|
|
/// Construct new metadata for a span, with a name, target, level, field
|
|
/// names, and optional source code location.
|
|
pub fn new(
|
|
name: &'static str,
|
|
target: &'a str,
|
|
level: Level,
|
|
module_path: Option<&'a str>,
|
|
file: Option<&'a str>,
|
|
line: Option<u32>,
|
|
field_names: &'static [&'static str],
|
|
callsite: &'static Callsite,
|
|
kind: Kind,
|
|
) -> Self {
|
|
Metadata {
|
|
name,
|
|
target,
|
|
level,
|
|
module_path,
|
|
file,
|
|
line,
|
|
fields: field::FieldSet {
|
|
names: field_names,
|
|
callsite: callsite::Identifier(callsite),
|
|
},
|
|
kind,
|
|
}
|
|
}
|
|
|
|
/// Returns the set of fields on the described span.
|
|
pub fn fields(&self) -> &field::FieldSet {
|
|
&self.fields
|
|
}
|
|
|
|
/// Returns the level of verbosity of the described span.
|
|
pub fn level(&self) -> &Level {
|
|
&self.level
|
|
}
|
|
|
|
/// Returns the name of the span.
|
|
pub fn name(&self) -> &'static str {
|
|
self.name
|
|
}
|
|
|
|
/// Returns a string describing the part of the system where the span or
|
|
/// event that this metadata describes occurred.
|
|
///
|
|
/// Typically, this is the module path, but alternate targets may be set
|
|
/// when spans or events are constructed.
|
|
pub fn target(&self) -> &'a str {
|
|
self.target
|
|
}
|
|
|
|
/// Returns the path to the Rust module where the span occurred, or
|
|
/// `None` if the module path is unknown.
|
|
pub fn module_path(&self) -> Option<&'a str> {
|
|
self.module_path
|
|
}
|
|
|
|
/// Returns the name of the source code file where the span
|
|
/// occurred, or `None` if the file is unknown
|
|
pub fn file(&self) -> Option<&'a str> {
|
|
self.file
|
|
}
|
|
|
|
/// Returns the line number in the source code file where the span
|
|
/// occurred, or `None` if the line number is unknown.
|
|
pub fn line(&self) -> Option<u32> {
|
|
self.line
|
|
}
|
|
|
|
/// Returns an opaque `Identifier` that uniquely identifies the callsite
|
|
/// this `Metadata` originated from.
|
|
#[inline]
|
|
pub fn callsite(&self) -> callsite::Identifier {
|
|
self.fields.callsite()
|
|
}
|
|
|
|
/// Returns true if the callsite kind is `Event`.
|
|
pub fn is_event(&self) -> bool {
|
|
self.kind.is_event()
|
|
}
|
|
|
|
/// Return true if the callsite kind is `Span`.
|
|
pub fn is_span(&self) -> bool {
|
|
self.kind.is_span()
|
|
}
|
|
}
|
|
|
|
impl<'a> fmt::Debug for Metadata<'a> {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let mut meta = f.debug_struct("Metadata");
|
|
meta.field("name", &self.name)
|
|
.field("target", &self.target)
|
|
.field("level", &self.level);
|
|
|
|
if let Some(path) = self.module_path() {
|
|
meta.field("module_path", &path);
|
|
}
|
|
|
|
match (self.file(), self.line()) {
|
|
(Some(file), Some(line)) => {
|
|
meta.field("location", &format_args!("{}:{}", file, line));
|
|
}
|
|
(Some(file), None) => {
|
|
meta.field("file", &format_args!("{}", file));
|
|
}
|
|
|
|
// Note: a line num with no file is a kind of weird case that _probably_ never occurs...
|
|
(None, Some(line)) => {
|
|
meta.field("line", &line);
|
|
}
|
|
(None, None) => {}
|
|
};
|
|
|
|
meta.field("fields", &format_args!("{}", self.fields))
|
|
.field("callsite", &self.callsite())
|
|
.field("kind", &self.kind)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
enum KindInner {
|
|
Event,
|
|
Span,
|
|
}
|
|
|
|
impl Kind {
|
|
/// `Event` callsite
|
|
pub const EVENT: Kind = Kind(KindInner::Event);
|
|
|
|
/// `Span` callsite
|
|
pub const SPAN: Kind = Kind(KindInner::Span);
|
|
|
|
/// Return true if the callsite kind is `Span`
|
|
pub fn is_span(&self) -> bool {
|
|
match self {
|
|
Kind(KindInner::Span) => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
/// Return true if the callsite kind is `Event`
|
|
pub fn is_event(&self) -> bool {
|
|
match self {
|
|
Kind(KindInner::Event) => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
// ===== impl Level =====
|
|
|
|
impl Level {
|
|
/// The "error" level.
|
|
///
|
|
/// Designates very serious errors.
|
|
pub const ERROR: Level = Level(LevelInner::Error);
|
|
/// The "warn" level.
|
|
///
|
|
/// Designates hazardous situations.
|
|
pub const WARN: Level = Level(LevelInner::Warn);
|
|
/// The "info" level.
|
|
///
|
|
/// Designates useful information.
|
|
pub const INFO: Level = Level(LevelInner::Info);
|
|
/// The "debug" level.
|
|
///
|
|
/// Designates lower priority information.
|
|
pub const DEBUG: Level = Level(LevelInner::Debug);
|
|
/// The "trace" level.
|
|
///
|
|
/// Designates very low priority, often extremely verbose, information.
|
|
pub const TRACE: Level = Level(LevelInner::Trace);
|
|
}
|
|
|
|
#[repr(usize)]
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
|
enum LevelInner {
|
|
/// The "error" level.
|
|
///
|
|
/// Designates very serious errors.
|
|
Error = 1,
|
|
/// The "warn" level.
|
|
///
|
|
/// Designates hazardous situations.
|
|
Warn,
|
|
/// The "info" level.
|
|
///
|
|
/// Designates useful information.
|
|
Info,
|
|
/// The "debug" level.
|
|
///
|
|
/// Designates lower priority information.
|
|
Debug,
|
|
/// The "trace" level.
|
|
///
|
|
/// Designates very low priority, often extremely verbose, information.
|
|
Trace,
|
|
}
|