RPM build fix (reverted CI changes which will need to be un-reverted or made conditional) and vendor Rust dependencies to make builds much faster in any CI system.

This commit is contained in:
Adam Ierymenko
2022-06-08 07:32:16 -04:00
parent 373ca30269
commit d5ca4e5f52
12611 changed files with 2898014 additions and 284 deletions

View File

@@ -0,0 +1,618 @@
//! Callsites represent the source locations from which spans or events
//! originate.
//!
//! # What Are Callsites?
//!
//! Every span or event in `tracing` is associated with a [`Callsite`]. A
//! callsite is a small `static` value that is responsible for the following:
//!
//! * Storing the span or event's [`Metadata`],
//! * Uniquely [identifying](Identifier) the span or event definition,
//! * Caching the subscriber's [`Interest`][^1] in that span or event, to avoid
//! re-evaluating filters,
//! * Storing a [`Registration`] that allows the callsite to be part of a global
//! list of all callsites in the program.
//!
//! # Registering Callsites
//!
//! When a span or event is recorded for the first time, its callsite
//! [`register`]s itself with the global callsite registry. Registering a
//! callsite calls the [`Subscriber::register_callsite`][`register_callsite`]
//! method with that callsite's [`Metadata`] on every currently active
//! subscriber. This serves two primary purposes: informing subscribers of the
//! callsite's existence, and performing static filtering.
//!
//! ## Callsite Existence
//!
//! If a [`Subscriber`] implementation wishes to allocate storage for each
//! unique span/event location in the program, or pre-compute some value
//! that will be used to record that span or event in the future, it can
//! do so in its [`register_callsite`] method.
//!
//! ## Performing Static Filtering
//!
//! The [`register_callsite`] method returns an [`Interest`] value,
//! which indicates that the subscriber either [always] wishes to record
//! that span or event, [sometimes] wishes to record it based on a
//! dynamic filter evaluation, or [never] wishes to record it.
//!
//! When registering a new callsite, the [`Interest`]s returned by every
//! currently active subscriber are combined, and the result is stored at
//! each callsite. This way, when the span or event occurs in the
//! future, the cached [`Interest`] value can be checked efficiently
//! to determine if the span or event should be recorded, without
//! needing to perform expensive filtering (i.e. calling the
//! [`Subscriber::enabled`] method every time a span or event occurs).
//!
//! ### Rebuilding Cached Interest
//!
//! When a new [`Dispatch`] is created (i.e. a new subscriber becomes
//! active), any previously cached [`Interest`] values are re-evaluated
//! for all callsites in the program. This way, if the new subscriber
//! will enable a callsite that was not previously enabled, the
//! [`Interest`] in that callsite is updated. Similarly, when a
//! subscriber is dropped, the interest cache is also re-evaluated, so
//! that any callsites enabled only by that subscriber are disabled.
//!
//! In addition, the [`rebuild_interest_cache`] function in this module can be
//! used to manually invalidate all cached interest and re-register those
//! callsites. This function is useful in situations where a subscriber's
//! interest can change, but it does so relatively infrequently. The subscriber
//! may wish for its interest to be cached most of the time, and return
//! [`Interest::always`][always] or [`Interest::never`][never] in its
//! [`register_callsite`] method, so that its [`Subscriber::enabled`] method
//! doesn't need to be evaluated every time a span or event is recorded.
//! However, when the configuration changes, the subscriber can call
//! [`rebuild_interest_cache`] to re-evaluate the entire interest cache with its
//! new configuration. This is a relatively costly operation, but if the
//! configuration changes infrequently, it may be more efficient than calling
//! [`Subscriber::enabled`] frequently.
//!
//! # Implementing Callsites
//!
//! In most cases, instrumenting code using `tracing` should *not* require
//! implementing the [`Callsite`] trait directly. When using the [`tracing`
//! crate's macros][macros] or the [`#[instrument]` attribute][instrument], a
//! `Callsite` is automatically generated.
//!
//! However, code which provides alternative forms of `tracing` instrumentation
//! may need to interact with the callsite system directly. If
//! instrumentation-side code needs to produce a `Callsite` to emit spans or
//! events, the [`DefaultCallsite`] struct provided in this module is a
//! ready-made `Callsite` implementation that is suitable for most uses. When
//! possible, the use of `DefaultCallsite` should be preferred over implementing
//! [`Callsite`] for user types, as `DefaultCallsite` may benefit from
//! additional performance optimizations.
//!
//! [^1]: Returned by the [`Subscriber::register_callsite`][`register_callsite`]
//! method.
//!
//! [`Metadata`]: crate::metadata::Metadata
//! [`Interest`]: crate::subscriber::Interest
//! [`Subscriber`]: crate::subscriber::Subscriber
//! [`register_callsite`]: crate::subscriber::Subscriber::register_callsite
//! [`Subscriber::enabled`]: crate::subscriber::Subscriber::enabled
//! [always]: crate::subscriber::Interest::always
//! [sometimes]: crate::subscriber::Interest::sometimes
//! [never]: crate::subscriber::Interest::never
//! [`Dispatch`]: crate::dispatch::Dispatch
//! [macros]: https://docs.rs/tracing/latest/tracing/#macros
//! [instrument]: https://docs.rs/tracing/latest/tracing/attr.instrument.html
use crate::stdlib::{
any::TypeId,
fmt,
hash::{Hash, Hasher},
ptr,
sync::{
atomic::{AtomicBool, AtomicPtr, AtomicU8, Ordering},
Mutex,
},
vec::Vec,
};
use crate::{
dispatcher::Dispatch,
metadata::{LevelFilter, Metadata},
subscriber::Interest,
};
use self::dispatchers::Dispatchers;
/// Trait implemented by callsites.
///
/// These functions are only intended to be called by the callsite registry, which
/// correctly handles determining the common interest between all subscribers.
///
/// See the [module-level documentation](crate::callsite) for details on
/// callsites.
pub trait Callsite: Sync {
/// Sets the [`Interest`] for this callsite.
///
/// See the [documentation on callsite interest caching][cache-docs] for
/// details.
///
/// [`Interest`]: super::subscriber::Interest
/// [cache-docs]: crate::callsite#performing-static-filtering
fn set_interest(&self, interest: Interest);
/// Returns the [metadata] associated with the callsite.
///
/// [metadata]: super::metadata::Metadata
fn metadata(&self) -> &Metadata<'_>;
/// This method is an *internal implementation detail* of `tracing-core`. It
/// is *not* intended to be called or overridden from downstream code.
///
/// The `Private` type can only be constructed from within `tracing-core`.
/// Because this method takes a `Private` as an argument, it cannot be
/// called from (safe) code external to `tracing-core`. Because it must
/// *return* a `Private`, the only valid implementation possible outside of
/// `tracing-core` would have to always unconditionally panic.
///
/// THIS IS BY DESIGN. There is currently no valid reason for code outside
/// of `tracing-core` to override this method.
// TODO(eliza): this could be used to implement a public downcasting API
// for `&dyn Callsite`s in the future.
#[doc(hidden)]
#[inline]
fn private_type_id(&self, _: private::Private<()>) -> private::Private<TypeId>
where
Self: 'static,
{
private::Private(TypeId::of::<Self>())
}
}
/// Uniquely identifies a [`Callsite`]
///
/// Two `Identifier`s are equal if they both refer to the same callsite.
///
/// [`Callsite`]: super::callsite::Callsite
#[derive(Clone)]
pub struct Identifier(
/// **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 `Identifier`. When
/// constructing new `Identifier`s, use the `identify_callsite!` macro
/// instead.
#[doc(hidden)]
pub &'static dyn Callsite,
);
/// A default [`Callsite`] implementation.
#[derive(Debug)]
pub struct DefaultCallsite {
interest: AtomicU8,
registration: AtomicU8,
meta: &'static Metadata<'static>,
next: AtomicPtr<Self>,
}
/// Clear and reregister interest on every [`Callsite`]
///
/// This function is intended for runtime reconfiguration of filters on traces
/// when the filter recalculation is much less frequent than trace events are.
/// The alternative is to have the [`Subscriber`] that supports runtime
/// reconfiguration of filters always return [`Interest::sometimes()`] so that
/// [`enabled`] is evaluated for every event.
///
/// This function will also re-compute the global maximum level as determined by
/// the [`max_level_hint`] method. If a [`Subscriber`]
/// implementation changes the value returned by its `max_level_hint`
/// implementation at runtime, then it **must** call this function after that
/// value changes, in order for the change to be reflected.
///
/// See the [documentation on callsite interest caching][cache-docs] for
/// additional information on this function's usage.
///
/// [`max_level_hint`]: super::subscriber::Subscriber::max_level_hint
/// [`Callsite`]: super::callsite::Callsite
/// [`enabled`]: super::subscriber::Subscriber#tymethod.enabled
/// [`Interest::sometimes()`]: super::subscriber::Interest::sometimes
/// [`Subscriber`]: super::subscriber::Subscriber
/// [cache-docs]: crate::callsite#rebuilding-cached-interest
pub fn rebuild_interest_cache() {
CALLSITES.rebuild_interest(DISPATCHERS.rebuilder());
}
/// Register a new [`Callsite`] with the global registry.
///
/// This should be called once per callsite after the callsite has been
/// constructed.
///
/// See the [documentation on callsite registration][reg-docs] for details
/// on the global callsite registry.
///
/// [`Callsite`]: crate::callsite::Callsite
/// [reg-docs]: crate::callsite#registering-callsites
pub fn register(callsite: &'static dyn Callsite) {
rebuild_callsite_interest(callsite, &DISPATCHERS.rebuilder());
// Is this a `DefaultCallsite`? If so, use the fancy linked list!
if callsite.private_type_id(private::Private(())).0 == TypeId::of::<DefaultCallsite>() {
let callsite = unsafe {
// Safety: the pointer cast is safe because the type id of the
// provided callsite matches that of the target type for the cast
// (`DefaultCallsite`). Because user implementations of `Callsite`
// cannot override `private_type_id`, we can trust that the callsite
// is not lying about its type ID.
&*(callsite as *const dyn Callsite as *const DefaultCallsite)
};
CALLSITES.push_default(callsite);
return;
}
CALLSITES.push_dyn(callsite);
}
static CALLSITES: Callsites = Callsites {
list_head: AtomicPtr::new(ptr::null_mut()),
has_locked_callsites: AtomicBool::new(false),
};
static DISPATCHERS: Dispatchers = Dispatchers::new();
#[cfg(feature = "std")]
static LOCKED_CALLSITES: once_cell::sync::Lazy<Mutex<Vec<&'static dyn Callsite>>> =
once_cell::sync::Lazy::new(Default::default);
#[cfg(not(feature = "std"))]
crate::lazy_static! {
static ref LOCKED_CALLSITES: Mutex<Vec<&'static dyn Callsite>> = Mutex::new(Vec::new());
}
struct Callsites {
list_head: AtomicPtr<DefaultCallsite>,
has_locked_callsites: AtomicBool,
}
// === impl DefaultCallsite ===
impl DefaultCallsite {
const UNREGISTERED: u8 = 0;
const REGISTERING: u8 = 1;
const REGISTERED: u8 = 2;
const INTEREST_NEVER: u8 = 0;
const INTEREST_SOMETIMES: u8 = 1;
const INTEREST_ALWAYS: u8 = 2;
/// Returns a new `DefaultCallsite` with the specified `Metadata`.
pub const fn new(meta: &'static Metadata<'static>) -> Self {
Self {
interest: AtomicU8::new(0xFF),
meta,
next: AtomicPtr::new(ptr::null_mut()),
registration: AtomicU8::new(Self::UNREGISTERED),
}
}
/// Registers this callsite with the global callsite registry.
///
/// If the callsite is already registered, this does nothing. When using
/// [`DefaultCallsite`], this method should be preferred over
/// [`tracing_core::callsite::register`], as it ensures that the callsite is
/// only registered a single time.
///
/// Other callsite implementations will generally ensure that
/// callsites are not re-registered through another mechanism.
///
/// See the [documentation on callsite registration][reg-docs] for details
/// on the global callsite registry.
///
/// [`Callsite`]: crate::callsite::Callsite
/// [reg-docs]: crate::callsite#registering-callsites
#[inline(never)]
// This only happens once (or if the cached interest value was corrupted).
#[cold]
pub fn register(&'static self) -> Interest {
// Attempt to advance the registration state to `REGISTERING`...
match self.registration.compare_exchange(
Self::UNREGISTERED,
Self::REGISTERING,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
// Okay, we advanced the state, try to register the callsite.
rebuild_callsite_interest(self, &DISPATCHERS.rebuilder());
CALLSITES.push_default(self);
self.registration.store(Self::REGISTERED, Ordering::Release);
}
// Great, the callsite is already registered! Just load its
// previous cached interest.
Err(Self::REGISTERED) => {}
// Someone else is registering...
Err(_state) => {
debug_assert_eq!(
_state,
Self::REGISTERING,
"weird callsite registration state"
);
// Just hit `enabled` this time.
return Interest::sometimes();
}
}
match self.interest.load(Ordering::Relaxed) {
Self::INTEREST_NEVER => Interest::never(),
Self::INTEREST_ALWAYS => Interest::always(),
_ => Interest::sometimes(),
}
}
/// Returns the callsite's cached `Interest`, or registers it for the
/// first time if it has not yet been registered.
#[inline]
pub fn interest(&'static self) -> Interest {
match self.interest.load(Ordering::Relaxed) {
Self::INTEREST_NEVER => Interest::never(),
Self::INTEREST_SOMETIMES => Interest::sometimes(),
Self::INTEREST_ALWAYS => Interest::always(),
_ => self.register(),
}
}
}
impl Callsite for DefaultCallsite {
fn set_interest(&self, interest: Interest) {
let interest = match () {
_ if interest.is_never() => Self::INTEREST_NEVER,
_ if interest.is_always() => Self::INTEREST_ALWAYS,
_ => Self::INTEREST_SOMETIMES,
};
self.interest.store(interest, Ordering::SeqCst);
}
#[inline(always)]
fn metadata(&self) -> &Metadata<'static> {
self.meta
}
}
// ===== impl Identifier =====
impl PartialEq for Identifier {
fn eq(&self, other: &Identifier) -> bool {
core::ptr::eq(
self.0 as *const _ as *const (),
other.0 as *const _ as *const (),
)
}
}
impl Eq for Identifier {}
impl fmt::Debug for Identifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Identifier({:p})", self.0)
}
}
impl Hash for Identifier {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
(self.0 as *const dyn Callsite).hash(state)
}
}
// === impl Callsites ===
impl Callsites {
/// Rebuild `Interest`s for all callsites in the registry.
///
/// This also re-computes the max level hint.
fn rebuild_interest(&self, dispatchers: dispatchers::Rebuilder<'_>) {
let mut max_level = LevelFilter::OFF;
dispatchers.for_each(|dispatch| {
// If the subscriber did not provide a max level hint, assume
// that it may enable every level.
let level_hint = dispatch.max_level_hint().unwrap_or(LevelFilter::TRACE);
if level_hint > max_level {
max_level = level_hint;
}
});
self.for_each(|callsite| {
rebuild_callsite_interest(callsite, &dispatchers);
});
LevelFilter::set_max(max_level);
}
/// Push a `dyn Callsite` trait object to the callsite registry.
///
/// This will attempt to lock the callsites vector.
fn push_dyn(&self, callsite: &'static dyn Callsite) {
let mut lock = LOCKED_CALLSITES.lock().unwrap();
self.has_locked_callsites.store(true, Ordering::Release);
lock.push(callsite);
}
/// Push a `DefaultCallsite` to the callsite registry.
///
/// If we know the callsite being pushed is a `DefaultCallsite`, we can push
/// it to the linked list without having to acquire a lock.
fn push_default(&self, callsite: &'static DefaultCallsite) {
let mut head = self.list_head.load(Ordering::Acquire);
loop {
callsite.next.store(head, Ordering::Release);
assert_ne!(
callsite as *const _, head,
"Attempted to register a `DefaultCallsite` that already exists! \
This will cause an infinite loop when attempting to read from the \
callsite cache. This is likely a bug! You should only need to call \
`DefaultCallsite::register` once per `DefaultCallsite`."
);
match self.list_head.compare_exchange(
head,
callsite as *const _ as *mut _,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => {
break;
}
Err(current) => head = current,
}
}
}
/// Invokes the provided closure `f` with each callsite in the registry.
fn for_each(&self, mut f: impl FnMut(&'static dyn Callsite)) {
let mut head = self.list_head.load(Ordering::Acquire);
while let Some(cs) = unsafe { head.as_ref() } {
f(cs);
head = cs.next.load(Ordering::Acquire);
}
if self.has_locked_callsites.load(Ordering::Acquire) {
let locked = LOCKED_CALLSITES.lock().unwrap();
for &cs in locked.iter() {
f(cs);
}
}
}
}
pub(crate) fn register_dispatch(dispatch: &Dispatch) {
let dispatchers = DISPATCHERS.register_dispatch(dispatch);
CALLSITES.rebuild_interest(dispatchers);
}
fn rebuild_callsite_interest(
callsite: &'static dyn Callsite,
dispatchers: &dispatchers::Rebuilder<'_>,
) {
let meta = callsite.metadata();
let mut interest = None;
dispatchers.for_each(|dispatch| {
let this_interest = dispatch.register_callsite(meta);
interest = match interest.take() {
None => Some(this_interest),
Some(that_interest) => Some(that_interest.and(this_interest)),
}
});
let interest = interest.unwrap_or_else(Interest::never);
callsite.set_interest(interest)
}
mod private {
/// Don't call this function, it's private.
#[allow(missing_debug_implementations)]
pub struct Private<T>(pub(crate) T);
}
#[cfg(feature = "std")]
mod dispatchers {
use crate::dispatcher;
use once_cell::sync::Lazy;
use std::sync::{
atomic::{AtomicBool, Ordering},
RwLock, RwLockReadGuard, RwLockWriteGuard,
};
pub(super) struct Dispatchers {
has_just_one: AtomicBool,
}
static LOCKED_DISPATCHERS: Lazy<RwLock<Vec<dispatcher::Registrar>>> =
Lazy::new(Default::default);
pub(super) enum Rebuilder<'a> {
JustOne,
Read(RwLockReadGuard<'a, Vec<dispatcher::Registrar>>),
Write(RwLockWriteGuard<'a, Vec<dispatcher::Registrar>>),
}
impl Dispatchers {
pub(super) const fn new() -> Self {
Self {
has_just_one: AtomicBool::new(true),
}
}
pub(super) fn rebuilder(&self) -> Rebuilder<'_> {
if self.has_just_one.load(Ordering::SeqCst) {
return Rebuilder::JustOne;
}
Rebuilder::Read(LOCKED_DISPATCHERS.read().unwrap())
}
pub(super) fn register_dispatch(&self, dispatch: &dispatcher::Dispatch) -> Rebuilder<'_> {
let mut dispatchers = LOCKED_DISPATCHERS.write().unwrap();
dispatchers.retain(|d| d.upgrade().is_some());
dispatchers.push(dispatch.registrar());
self.has_just_one
.store(dispatchers.len() <= 1, Ordering::SeqCst);
Rebuilder::Write(dispatchers)
}
}
impl Rebuilder<'_> {
pub(super) fn for_each(&self, mut f: impl FnMut(&dispatcher::Dispatch)) {
let iter = match self {
Rebuilder::JustOne => {
dispatcher::get_default(f);
return;
}
Rebuilder::Read(vec) => vec.iter(),
Rebuilder::Write(vec) => vec.iter(),
};
iter.filter_map(dispatcher::Registrar::upgrade)
.for_each(|dispatch| f(&dispatch))
}
}
}
#[cfg(not(feature = "std"))]
mod dispatchers {
use crate::dispatcher;
pub(super) struct Dispatchers(());
pub(super) struct Rebuilder<'a>(Option<&'a dispatcher::Dispatch>);
impl Dispatchers {
pub(super) const fn new() -> Self {
Self(())
}
pub(super) fn rebuilder(&self) -> Rebuilder<'_> {
Rebuilder(None)
}
pub(super) fn register_dispatch<'dispatch>(
&self,
dispatch: &'dispatch dispatcher::Dispatch,
) -> Rebuilder<'dispatch> {
// nop; on no_std, there can only ever be one dispatcher
Rebuilder(Some(dispatch))
}
}
impl Rebuilder<'_> {
#[inline]
pub(super) fn for_each(&self, mut f: impl FnMut(&dispatcher::Dispatch)) {
if let Some(dispatch) = self.0 {
// we are rebuilding the interest cache because a new dispatcher
// is about to be set. on `no_std`, this should only happen
// once, because the new dispatcher will be the global default.
f(dispatch)
} else {
// otherwise, we are rebuilding the cache because the subscriber
// configuration changed, so use the global default.
// on no_std, there can only ever be one dispatcher
dispatcher::get_default(f)
}
}
}
}

View File

@@ -0,0 +1,896 @@
//! Dispatches trace events to [`Subscriber`]s.
//!
//! The _dispatcher_ is the component of the tracing system which is responsible
//! for forwarding trace data from the instrumentation points that generate it
//! to the subscriber that collects it.
//!
//! # Using the Trace Dispatcher
//!
//! Every thread in a program using `tracing` has a _default subscriber_. When
//! events occur, or spans are created, they are dispatched to the thread's
//! current subscriber.
//!
//! ## Setting the Default Subscriber
//!
//! By default, the current subscriber is an empty implementation that does
//! nothing. To use a subscriber implementation, it must be set as the default.
//! There are two methods for doing so: [`with_default`] and
//! [`set_global_default`]. `with_default` sets the default subscriber for the
//! duration of a scope, while `set_global_default` sets a default subscriber
//! for the entire process.
//!
//! To use either of these functions, we must first wrap our subscriber in a
//! [`Dispatch`], a cloneable, type-erased reference to a subscriber. For
//! example:
//! ```rust
//! # pub struct FooSubscriber;
//! # use tracing_core::{
//! # dispatcher, Event, Metadata,
//! # span::{Attributes, Id, Record}
//! # };
//! # impl tracing_core::Subscriber for FooSubscriber {
//! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) }
//! # fn record(&self, _: &Id, _: &Record) {}
//! # fn event(&self, _: &Event) {}
//! # fn record_follows_from(&self, _: &Id, _: &Id) {}
//! # fn enabled(&self, _: &Metadata) -> bool { false }
//! # fn enter(&self, _: &Id) {}
//! # fn exit(&self, _: &Id) {}
//! # }
//! # impl FooSubscriber { fn new() -> Self { FooSubscriber } }
//! use dispatcher::Dispatch;
//!
//! let my_subscriber = FooSubscriber::new();
//! let my_dispatch = Dispatch::new(my_subscriber);
//! ```
//! Then, we can use [`with_default`] to set our `Dispatch` as the default for
//! the duration of a block:
//! ```rust
//! # pub struct FooSubscriber;
//! # use tracing_core::{
//! # dispatcher, Event, Metadata,
//! # span::{Attributes, Id, Record}
//! # };
//! # impl tracing_core::Subscriber for FooSubscriber {
//! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) }
//! # fn record(&self, _: &Id, _: &Record) {}
//! # fn event(&self, _: &Event) {}
//! # fn record_follows_from(&self, _: &Id, _: &Id) {}
//! # fn enabled(&self, _: &Metadata) -> bool { false }
//! # fn enter(&self, _: &Id) {}
//! # fn exit(&self, _: &Id) {}
//! # }
//! # impl FooSubscriber { fn new() -> Self { FooSubscriber } }
//! # let my_subscriber = FooSubscriber::new();
//! # let my_dispatch = dispatcher::Dispatch::new(my_subscriber);
//! // no default subscriber
//!
//! # #[cfg(feature = "std")]
//! dispatcher::with_default(&my_dispatch, || {
//! // my_subscriber is the default
//! });
//!
//! // no default subscriber again
//! ```
//! It's important to note that `with_default` will not propagate the current
//! thread's default subscriber to any threads spawned within the `with_default`
//! block. To propagate the default subscriber to new threads, either use
//! `with_default` from the new thread, or use `set_global_default`.
//!
//! As an alternative to `with_default`, we can use [`set_global_default`] to
//! set a `Dispatch` as the default for all threads, for the lifetime of the
//! program. For example:
//! ```rust
//! # pub struct FooSubscriber;
//! # use tracing_core::{
//! # dispatcher, Event, Metadata,
//! # span::{Attributes, Id, Record}
//! # };
//! # impl tracing_core::Subscriber for FooSubscriber {
//! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) }
//! # fn record(&self, _: &Id, _: &Record) {}
//! # fn event(&self, _: &Event) {}
//! # fn record_follows_from(&self, _: &Id, _: &Id) {}
//! # fn enabled(&self, _: &Metadata) -> bool { false }
//! # fn enter(&self, _: &Id) {}
//! # fn exit(&self, _: &Id) {}
//! # }
//! # impl FooSubscriber { fn new() -> Self { FooSubscriber } }
//! # let my_subscriber = FooSubscriber::new();
//! # let my_dispatch = dispatcher::Dispatch::new(my_subscriber);
//! // no default subscriber
//!
//! dispatcher::set_global_default(my_dispatch)
//! // `set_global_default` will return an error if the global default
//! // subscriber has already been set.
//! .expect("global default was already set!");
//!
//! // `my_subscriber` is now the default
//! ```
//!
//! <pre class="ignore" style="white-space:normal;font:inherit;">
//! <strong>Note</strong>:the thread-local scoped dispatcher
//! (<a href="#fn.with_default"><code>with_default</code></a>) requires the
//! Rust standard library. <code>no_std</code> users should use
//! <a href="#fn.set_global_default"><code>set_global_default</code></a>
//! instead.
//! </pre>
//!
//! ## Accessing the Default Subscriber
//!
//! A thread's current default subscriber can be accessed using the
//! [`get_default`] function, which executes a closure with a reference to the
//! currently default `Dispatch`. This is used primarily by `tracing`
//! instrumentation.
//!
use crate::{
callsite, span,
subscriber::{self, NoSubscriber, Subscriber},
Event, LevelFilter, Metadata,
};
use crate::stdlib::{
any::Any,
fmt,
sync::{
atomic::{AtomicBool, AtomicUsize, Ordering},
Arc,
},
};
#[cfg(feature = "std")]
use crate::stdlib::{
cell::{Cell, RefCell, RefMut},
error,
sync::Weak,
};
/// `Dispatch` trace data to a [`Subscriber`].
///
#[derive(Clone)]
pub struct Dispatch {
subscriber: Arc<dyn Subscriber + Send + Sync>,
}
#[cfg(feature = "std")]
thread_local! {
static CURRENT_STATE: State = State {
default: RefCell::new(None),
can_enter: Cell::new(true),
};
}
static EXISTS: AtomicBool = AtomicBool::new(false);
static GLOBAL_INIT: AtomicUsize = AtomicUsize::new(UNINITIALIZED);
const UNINITIALIZED: usize = 0;
const INITIALIZING: usize = 1;
const INITIALIZED: usize = 2;
static mut GLOBAL_DISPATCH: Option<Dispatch> = None;
/// The dispatch state of a thread.
#[cfg(feature = "std")]
struct State {
/// This thread's current default dispatcher.
default: RefCell<Option<Dispatch>>,
/// Whether or not we can currently begin dispatching a trace event.
///
/// This is set to `false` when functions such as `enter`, `exit`, `event`,
/// and `new_span` are called on this thread's default dispatcher, to
/// prevent further trace events triggered inside those functions from
/// creating an infinite recursion. When we finish handling a dispatch, this
/// is set back to `true`.
can_enter: Cell<bool>,
}
/// While this guard is active, additional calls to subscriber functions on
/// the default dispatcher will not be able to access the dispatch context.
/// Dropping the guard will allow the dispatch context to be re-entered.
#[cfg(feature = "std")]
struct Entered<'a>(&'a State);
/// A guard that resets the current default dispatcher to the prior
/// default dispatcher when dropped.
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[derive(Debug)]
pub struct DefaultGuard(Option<Dispatch>);
/// Sets this dispatch as the default for the duration of a closure.
///
/// The default dispatcher is used when creating a new [span] or
/// [`Event`].
///
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: This function required the Rust standard library.
/// <code>no_std</code> users should use <a href="../fn.set_global_default.html">
/// <code>set_global_default</code></a> instead.
/// </pre>
///
/// [span]: super::span
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`Event`]: super::event::Event
/// [`set_global_default`]: super::set_global_default
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn with_default<T>(dispatcher: &Dispatch, f: impl FnOnce() -> T) -> T {
// When this guard is dropped, the default dispatcher will be reset to the
// prior default. Using this (rather than simply resetting after calling
// `f`) ensures that we always reset to the prior dispatcher even if `f`
// panics.
let _guard = set_default(dispatcher);
f()
}
/// Sets the dispatch as the default dispatch for the duration of the lifetime
/// of the returned DefaultGuard
///
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: This function required the Rust standard library.
/// <code>no_std</code> users should use <a href="../fn.set_global_default.html">
/// <code>set_global_default</code></a> instead.
/// </pre>
///
/// [`set_global_default`]: super::set_global_default
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[must_use = "Dropping the guard unregisters the dispatcher."]
pub fn set_default(dispatcher: &Dispatch) -> DefaultGuard {
// When this guard is dropped, the default dispatcher will be reset to the
// prior default. Using this ensures that we always reset to the prior
// dispatcher even if the thread calling this function panics.
State::set_default(dispatcher.clone())
}
/// Sets this dispatch as the global default for the duration of the entire program.
/// Will be used as a fallback if no thread-local dispatch has been set in a thread
/// (using `with_default`.)
///
/// Can only be set once; subsequent attempts to set the global default will fail.
/// Returns `Err` if the global default has already been set.
///
/// <div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;">
/// <strong>Warning</strong>: In general, libraries should <em>not</em> call
/// <code>set_global_default()</code>! Doing so will cause conflicts when
/// executables that depend on the library try to set the default later.
/// </pre></div>
///
/// [span]: super::span
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`Event`]: super::event::Event
pub fn set_global_default(dispatcher: Dispatch) -> Result<(), SetGlobalDefaultError> {
// if `compare_exchange` returns Result::Ok(_), then `new` has been set and
// `current`—now the prior value—has been returned in the `Ok()` branch.
if GLOBAL_INIT
.compare_exchange(
UNINITIALIZED,
INITIALIZING,
Ordering::SeqCst,
Ordering::SeqCst,
)
.is_ok()
{
unsafe {
GLOBAL_DISPATCH = Some(dispatcher);
}
GLOBAL_INIT.store(INITIALIZED, Ordering::SeqCst);
EXISTS.store(true, Ordering::Release);
Ok(())
} else {
Err(SetGlobalDefaultError { _no_construct: () })
}
}
/// Returns true if a `tracing` dispatcher has ever been set.
///
/// This may be used to completely elide trace points if tracing is not in use
/// at all or has yet to be initialized.
#[doc(hidden)]
#[inline(always)]
pub fn has_been_set() -> bool {
EXISTS.load(Ordering::Relaxed)
}
/// Returned if setting the global dispatcher fails.
#[derive(Debug)]
pub struct SetGlobalDefaultError {
_no_construct: (),
}
impl fmt::Display for SetGlobalDefaultError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("a global default trace dispatcher has already been set")
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl error::Error for SetGlobalDefaultError {}
/// Executes a closure with a reference to this thread's current [dispatcher].
///
/// Note that calls to `get_default` should not be nested; if this function is
/// called while inside of another `get_default`, that closure will be provided
/// with `Dispatch::none` rather than the previously set dispatcher.
///
/// [dispatcher]: super::dispatcher::Dispatch
#[cfg(feature = "std")]
pub fn get_default<T, F>(mut f: F) -> T
where
F: FnMut(&Dispatch) -> T,
{
CURRENT_STATE
.try_with(|state| {
if let Some(entered) = state.enter() {
return f(&*entered.current());
}
f(&Dispatch::none())
})
.unwrap_or_else(|_| f(&Dispatch::none()))
}
/// Executes a closure with a reference to this thread's current [dispatcher].
///
/// Note that calls to `get_default` should not be nested; if this function is
/// called while inside of another `get_default`, that closure will be provided
/// with `Dispatch::none` rather than the previously set dispatcher.
///
/// [dispatcher]: super::dispatcher::Dispatch
#[cfg(feature = "std")]
#[doc(hidden)]
#[inline(never)]
pub fn get_current<T>(f: impl FnOnce(&Dispatch) -> T) -> Option<T> {
CURRENT_STATE
.try_with(|state| {
let entered = state.enter()?;
Some(f(&*entered.current()))
})
.ok()?
}
/// Executes a closure with a reference to the current [dispatcher].
///
/// [dispatcher]: super::dispatcher::Dispatch
#[cfg(not(feature = "std"))]
#[doc(hidden)]
pub fn get_current<T>(f: impl FnOnce(&Dispatch) -> T) -> Option<T> {
let dispatch = get_global()?;
Some(f(&dispatch))
}
/// Executes a closure with a reference to the current [dispatcher].
///
/// [dispatcher]: super::dispatcher::Dispatch
#[cfg(not(feature = "std"))]
pub fn get_default<T, F>(mut f: F) -> T
where
F: FnMut(&Dispatch) -> T,
{
if let Some(d) = get_global() {
f(d)
} else {
f(&Dispatch::none())
}
}
fn get_global() -> Option<&'static Dispatch> {
if GLOBAL_INIT.load(Ordering::SeqCst) != INITIALIZED {
return None;
}
unsafe {
// This is safe given the invariant that setting the global dispatcher
// also sets `GLOBAL_INIT` to `INITIALIZED`.
Some(GLOBAL_DISPATCH.as_ref().expect(
"invariant violated: GLOBAL_DISPATCH must be initialized before GLOBAL_INIT is set",
))
}
}
#[cfg(feature = "std")]
pub(crate) struct Registrar(Weak<dyn Subscriber + Send + Sync>);
impl Dispatch {
/// Returns a new `Dispatch` that discards events and spans.
#[inline]
pub fn none() -> Self {
Dispatch {
subscriber: Arc::new(NoSubscriber::default()),
}
}
/// Returns a `Dispatch` that forwards to the given [`Subscriber`].
///
/// [`Subscriber`]: super::subscriber::Subscriber
pub fn new<S>(subscriber: S) -> Self
where
S: Subscriber + Send + Sync + 'static,
{
let me = Dispatch {
subscriber: Arc::new(subscriber),
};
callsite::register_dispatch(&me);
me
}
#[cfg(feature = "std")]
pub(crate) fn registrar(&self) -> Registrar {
Registrar(Arc::downgrade(&self.subscriber))
}
/// Registers a new callsite with this subscriber, returning whether or not
/// the subscriber is interested in being notified about the callsite.
///
/// This calls the [`register_callsite`] function on the [`Subscriber`]
/// that this `Dispatch` forwards to.
///
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`register_callsite`]: super::subscriber::Subscriber::register_callsite
#[inline]
pub fn register_callsite(&self, metadata: &'static Metadata<'static>) -> subscriber::Interest {
self.subscriber.register_callsite(metadata)
}
/// Returns the highest [verbosity level][level] that this [`Subscriber`] will
/// enable, or `None`, if the subscriber does not implement level-based
/// filtering or chooses not to implement this method.
///
/// This calls the [`max_level_hint`] function on the [`Subscriber`]
/// that this `Dispatch` forwards to.
///
/// [level]: super::Level
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`register_callsite`]: super::subscriber::Subscriber::max_level_hint
// TODO(eliza): consider making this a public API?
#[inline]
pub(crate) fn max_level_hint(&self) -> Option<LevelFilter> {
self.subscriber.max_level_hint()
}
/// Record the construction of a new span, returning a new [ID] for the
/// span being constructed.
///
/// This calls the [`new_span`] function on the [`Subscriber`] that this
/// `Dispatch` forwards to.
///
/// [ID]: super::span::Id
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`new_span`]: super::subscriber::Subscriber::new_span
#[inline]
pub fn new_span(&self, span: &span::Attributes<'_>) -> span::Id {
self.subscriber.new_span(span)
}
/// Record a set of values on a span.
///
/// This calls the [`record`] function on the [`Subscriber`] that this
/// `Dispatch` forwards to.
///
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`record`]: super::subscriber::Subscriber::record
#[inline]
pub fn record(&self, span: &span::Id, values: &span::Record<'_>) {
self.subscriber.record(span, values)
}
/// Adds an indication that `span` follows from the span with the id
/// `follows`.
///
/// This calls the [`record_follows_from`] function on the [`Subscriber`]
/// that this `Dispatch` forwards to.
///
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`record_follows_from`]: super::subscriber::Subscriber::record_follows_from
#[inline]
pub fn record_follows_from(&self, span: &span::Id, follows: &span::Id) {
self.subscriber.record_follows_from(span, follows)
}
/// Returns true if a span with the specified [metadata] would be
/// recorded.
///
/// This calls the [`enabled`] function on the [`Subscriber`] that this
/// `Dispatch` forwards to.
///
/// [metadata]: super::metadata::Metadata
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`enabled`]: super::subscriber::Subscriber::enabled
#[inline]
pub fn enabled(&self, metadata: &Metadata<'_>) -> bool {
self.subscriber.enabled(metadata)
}
/// Records that an [`Event`] has occurred.
///
/// This calls the [`event`] function on the [`Subscriber`] that this
/// `Dispatch` forwards to.
///
/// [`Event`]: super::event::Event
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`event`]: super::subscriber::Subscriber::event
#[inline]
pub fn event(&self, event: &Event<'_>) {
self.subscriber.event(event)
}
/// Records that a span has been can_enter.
///
/// This calls the [`enter`] function on the [`Subscriber`] that this
/// `Dispatch` forwards to.
///
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`enter`]: super::subscriber::Subscriber::enter
pub fn enter(&self, span: &span::Id) {
self.subscriber.enter(span);
}
/// Records that a span has been exited.
///
/// This calls the [`exit`] function on the [`Subscriber`] that this
/// `Dispatch` forwards to.
///
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`exit`]: super::subscriber::Subscriber::exit
pub fn exit(&self, span: &span::Id) {
self.subscriber.exit(span);
}
/// Notifies the subscriber that a [span ID] has been cloned.
///
/// This function must only be called with span IDs that were returned by
/// this `Dispatch`'s [`new_span`] function. The `tracing` crate upholds
/// this guarantee and any other libraries implementing instrumentation APIs
/// must as well.
///
/// This calls the [`clone_span`] function on the `Subscriber` that this
/// `Dispatch` forwards to.
///
/// [span ID]: super::span::Id
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`clone_span`]: super::subscriber::Subscriber::clone_span
/// [`new_span`]: super::subscriber::Subscriber::new_span
#[inline]
pub fn clone_span(&self, id: &span::Id) -> span::Id {
self.subscriber.clone_span(id)
}
/// Notifies the subscriber that a [span ID] has been dropped.
///
/// This function must only be called with span IDs that were returned by
/// this `Dispatch`'s [`new_span`] function. The `tracing` crate upholds
/// this guarantee and any other libraries implementing instrumentation APIs
/// must as well.
///
/// This calls the [`drop_span`] function on the [`Subscriber`] that this
/// `Dispatch` forwards to.
///
/// <pre class="compile_fail" style="white-space:normal;font:inherit;">
/// <strong>Deprecated</strong>: The <a href="#method.try_close"><code>
/// try_close</code></a> method is functionally identical, but returns
/// <code>true</code> if the span is now closed. It should be used
/// instead of this method.
/// </pre>
///
/// [span ID]: super::span::Id
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`drop_span`]: super::subscriber::Subscriber::drop_span
/// [`new_span`]: super::subscriber::Subscriber::new_span
/// [`try_close`]: Entered::try_close()
#[inline]
#[deprecated(since = "0.1.2", note = "use `Dispatch::try_close` instead")]
pub fn drop_span(&self, id: span::Id) {
#[allow(deprecated)]
self.subscriber.drop_span(id);
}
/// Notifies the subscriber that a [span ID] has been dropped, and returns
/// `true` if there are now 0 IDs referring to that span.
///
/// This function must only be called with span IDs that were returned by
/// this `Dispatch`'s [`new_span`] function. The `tracing` crate upholds
/// this guarantee and any other libraries implementing instrumentation APIs
/// must as well.
///
/// This calls the [`try_close`] function on the [`Subscriber`] that this
/// `Dispatch` forwards to.
///
/// [span ID]: super::span::Id
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`try_close`]: super::subscriber::Subscriber::try_close
/// [`new_span`]: super::subscriber::Subscriber::new_span
pub fn try_close(&self, id: span::Id) -> bool {
self.subscriber.try_close(id)
}
/// Returns a type representing this subscriber's view of the current span.
///
/// This calls the [`current`] function on the `Subscriber` that this
/// `Dispatch` forwards to.
///
/// [`current`]: super::subscriber::Subscriber::current_span
#[inline]
pub fn current_span(&self) -> span::Current {
self.subscriber.current_span()
}
/// Returns `true` if this `Dispatch` forwards to a `Subscriber` of type
/// `T`.
#[inline]
pub fn is<T: Any>(&self) -> bool {
<dyn Subscriber>::is::<T>(&*self.subscriber)
}
/// Returns some reference to the `Subscriber` this `Dispatch` forwards to
/// if it is of type `T`, or `None` if it isn't.
#[inline]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
<dyn Subscriber>::downcast_ref(&*self.subscriber)
}
}
impl Default for Dispatch {
/// Returns the current default dispatcher
fn default() -> Self {
get_default(|default| default.clone())
}
}
impl fmt::Debug for Dispatch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Dispatch")
.field(&format_args!("{:p}", self.subscriber))
.finish()
}
}
impl<S> From<S> for Dispatch
where
S: Subscriber + Send + Sync + 'static,
{
#[inline]
fn from(subscriber: S) -> Self {
Dispatch::new(subscriber)
}
}
#[cfg(feature = "std")]
impl Registrar {
pub(crate) fn upgrade(&self) -> Option<Dispatch> {
self.0.upgrade().map(|subscriber| Dispatch { subscriber })
}
}
// ===== impl State =====
#[cfg(feature = "std")]
impl State {
/// Replaces the current default dispatcher on this thread with the provided
/// dispatcher.Any
///
/// Dropping the returned `ResetGuard` will reset the default dispatcher to
/// the previous value.
#[inline]
fn set_default(new_dispatch: Dispatch) -> DefaultGuard {
let prior = CURRENT_STATE
.try_with(|state| {
state.can_enter.set(true);
state.default.replace(Some(new_dispatch))
})
.ok()
.flatten();
EXISTS.store(true, Ordering::Release);
DefaultGuard(prior)
}
#[inline]
fn enter(&self) -> Option<Entered<'_>> {
if self.can_enter.replace(false) {
Some(Entered(self))
} else {
None
}
}
}
// ===== impl Entered =====
#[cfg(feature = "std")]
impl<'a> Entered<'a> {
#[inline]
fn current(&self) -> RefMut<'a, Dispatch> {
let default = self.0.default.borrow_mut();
RefMut::map(default, |default| {
default.get_or_insert_with(|| get_global().cloned().unwrap_or_else(Dispatch::none))
})
}
}
#[cfg(feature = "std")]
impl<'a> Drop for Entered<'a> {
#[inline]
fn drop(&mut self) {
self.0.can_enter.set(true);
}
}
// ===== impl DefaultGuard =====
#[cfg(feature = "std")]
impl Drop for DefaultGuard {
#[inline]
fn drop(&mut self) {
// Replace the dispatcher and then drop the old one outside
// of the thread-local context. Dropping the dispatch may
// lead to the drop of a subscriber which, in the process,
// could then also attempt to access the same thread local
// state -- causing a clash.
let prev = CURRENT_STATE.try_with(|state| state.default.replace(self.0.take()));
drop(prev)
}
}
#[cfg(test)]
mod test {
use super::*;
#[cfg(feature = "std")]
use crate::stdlib::sync::atomic::{AtomicUsize, Ordering};
use crate::{
callsite::Callsite,
metadata::{Kind, Level, Metadata},
subscriber::Interest,
};
#[test]
fn dispatch_is() {
let dispatcher = Dispatch::new(NoSubscriber::default());
assert!(dispatcher.is::<NoSubscriber>());
}
#[test]
fn dispatch_downcasts() {
let dispatcher = Dispatch::new(NoSubscriber::default());
assert!(dispatcher.downcast_ref::<NoSubscriber>().is_some());
}
struct TestCallsite;
static TEST_CALLSITE: TestCallsite = TestCallsite;
static TEST_META: Metadata<'static> = metadata! {
name: "test",
target: module_path!(),
level: Level::DEBUG,
fields: &[],
callsite: &TEST_CALLSITE,
kind: Kind::EVENT
};
impl Callsite for TestCallsite {
fn set_interest(&self, _: Interest) {}
fn metadata(&self) -> &Metadata<'_> {
&TEST_META
}
}
#[test]
#[cfg(feature = "std")]
fn events_dont_infinite_loop() {
// This test ensures that an event triggered within a subscriber
// won't cause an infinite loop of events.
struct TestSubscriber;
impl Subscriber for TestSubscriber {
fn enabled(&self, _: &Metadata<'_>) -> bool {
true
}
fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
span::Id::from_u64(0xAAAA)
}
fn record(&self, _: &span::Id, _: &span::Record<'_>) {}
fn record_follows_from(&self, _: &span::Id, _: &span::Id) {}
fn event(&self, _: &Event<'_>) {
static EVENTS: AtomicUsize = AtomicUsize::new(0);
assert_eq!(
EVENTS.fetch_add(1, Ordering::Relaxed),
0,
"event method called twice!"
);
Event::dispatch(&TEST_META, &TEST_META.fields().value_set(&[]))
}
fn enter(&self, _: &span::Id) {}
fn exit(&self, _: &span::Id) {}
}
with_default(&Dispatch::new(TestSubscriber), || {
Event::dispatch(&TEST_META, &TEST_META.fields().value_set(&[]))
})
}
#[test]
#[cfg(feature = "std")]
fn spans_dont_infinite_loop() {
// This test ensures that a span created within a subscriber
// won't cause an infinite loop of new spans.
fn mk_span() {
get_default(|current| {
current.new_span(&span::Attributes::new(
&TEST_META,
&TEST_META.fields().value_set(&[]),
))
});
}
struct TestSubscriber;
impl Subscriber for TestSubscriber {
fn enabled(&self, _: &Metadata<'_>) -> bool {
true
}
fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
static NEW_SPANS: AtomicUsize = AtomicUsize::new(0);
assert_eq!(
NEW_SPANS.fetch_add(1, Ordering::Relaxed),
0,
"new_span method called twice!"
);
mk_span();
span::Id::from_u64(0xAAAA)
}
fn record(&self, _: &span::Id, _: &span::Record<'_>) {}
fn record_follows_from(&self, _: &span::Id, _: &span::Id) {}
fn event(&self, _: &Event<'_>) {}
fn enter(&self, _: &span::Id) {}
fn exit(&self, _: &span::Id) {}
}
with_default(&Dispatch::new(TestSubscriber), mk_span)
}
#[test]
fn default_no_subscriber() {
let default_dispatcher = Dispatch::default();
assert!(default_dispatcher.is::<NoSubscriber>());
}
#[cfg(feature = "std")]
#[test]
fn default_dispatch() {
struct TestSubscriber;
impl Subscriber for TestSubscriber {
fn enabled(&self, _: &Metadata<'_>) -> bool {
true
}
fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
span::Id::from_u64(0xAAAA)
}
fn record(&self, _: &span::Id, _: &span::Record<'_>) {}
fn record_follows_from(&self, _: &span::Id, _: &span::Id) {}
fn event(&self, _: &Event<'_>) {}
fn enter(&self, _: &span::Id) {}
fn exit(&self, _: &span::Id) {}
}
let guard = set_default(&Dispatch::new(TestSubscriber));
let default_dispatcher = Dispatch::default();
assert!(default_dispatcher.is::<TestSubscriber>());
drop(guard);
let default_dispatcher = Dispatch::default();
assert!(default_dispatcher.is::<NoSubscriber>());
}
}

128
zeroidc/vendor/tracing-core/src/event.rs vendored Normal file
View File

@@ -0,0 +1,128 @@
//! Events represent single points in time during the execution of a program.
use crate::parent::Parent;
use crate::span::Id;
use crate::{field, Metadata};
/// `Event`s represent single points in time where something occurred during the
/// execution of a program.
///
/// An `Event` can be compared to a log record in unstructured logging, but with
/// two key differences:
/// - `Event`s exist _within the context of a [span]_. Unlike log lines, they
/// may be located within the trace tree, allowing visibility into the
/// _temporal_ context in which the event occurred, as well as the source
/// code location.
/// - Like spans, `Event`s have structured key-value data known as _[fields]_,
/// which may include textual message. In general, a majority of the data
/// associated with an event should be in the event's fields rather than in
/// the textual message, as the fields are more structured.
///
/// [span]: super::span
/// [fields]: super::field
#[derive(Debug)]
pub struct Event<'a> {
fields: &'a field::ValueSet<'a>,
metadata: &'static Metadata<'static>,
parent: Parent,
}
impl<'a> Event<'a> {
/// Constructs a new `Event` with the specified metadata and set of values,
/// and observes it with the current subscriber.
pub fn dispatch(metadata: &'static Metadata<'static>, fields: &'a field::ValueSet<'_>) {
let event = Event::new(metadata, fields);
crate::dispatcher::get_default(|current| {
current.event(&event);
});
}
/// Returns a new `Event` in the current span, with the specified metadata
/// and set of values.
#[inline]
pub fn new(metadata: &'static Metadata<'static>, fields: &'a field::ValueSet<'a>) -> Self {
Event {
fields,
metadata,
parent: Parent::Current,
}
}
/// Returns a new `Event` as a child of the specified span, with the
/// provided metadata and set of values.
#[inline]
pub fn new_child_of(
parent: impl Into<Option<Id>>,
metadata: &'static Metadata<'static>,
fields: &'a field::ValueSet<'a>,
) -> Self {
let parent = match parent.into() {
Some(p) => Parent::Explicit(p),
None => Parent::Root,
};
Event {
fields,
metadata,
parent,
}
}
/// Constructs a new `Event` with the specified metadata and set of values,
/// and observes it with the current subscriber and an explicit parent.
pub fn child_of(
parent: impl Into<Option<Id>>,
metadata: &'static Metadata<'static>,
fields: &'a field::ValueSet<'_>,
) {
let event = Self::new_child_of(parent, metadata, fields);
crate::dispatcher::get_default(|current| {
current.event(&event);
});
}
/// Visits all the fields on this `Event` with the specified [visitor].
///
/// [visitor]: super::field::Visit
#[inline]
pub fn record(&self, visitor: &mut dyn field::Visit) {
self.fields.record(visitor);
}
/// Returns an iterator over the set of values on this `Event`.
pub fn fields(&self) -> field::Iter {
self.fields.field_set().iter()
}
/// Returns [metadata] describing this `Event`.
///
/// [metadata]: super::Metadata
pub fn metadata(&self) -> &'static Metadata<'static> {
self.metadata
}
/// Returns true if the new event should be a root.
pub fn is_root(&self) -> bool {
matches!(self.parent, Parent::Root)
}
/// Returns true if the new event's parent should be determined based on the
/// current context.
///
/// If this is true and the current thread is currently inside a span, then
/// that span should be the new event's parent. Otherwise, if the current
/// thread is _not_ inside a span, then the new event will be the root of its
/// own trace tree.
pub fn is_contextual(&self) -> bool {
matches!(self.parent, Parent::Current)
}
/// Returns the new event's explicitly-specified parent, if there is one.
///
/// Otherwise (if the new event is a root or is a child of the current span),
/// returns `None`.
pub fn parent(&self) -> Option<&Id> {
match self.parent {
Parent::Explicit(ref p) => Some(p),
_ => None,
}
}
}

1199
zeroidc/vendor/tracing-core/src/field.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
Copyright (c) 2010 The Rust Project Developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,30 @@
// Copyright 2016 lazy-static.rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use crate::spin::Once;
pub(crate) struct Lazy<T: Sync>(Once<T>);
impl<T: Sync> Lazy<T> {
pub(crate) const INIT: Self = Lazy(Once::INIT);
#[inline(always)]
pub(crate) fn get<F>(&'static self, builder: F) -> &T
where
F: FnOnce() -> T,
{
self.0.call_once(builder)
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! __lazy_static_create {
($NAME:ident, $T:ty) => {
static $NAME: $crate::lazy_static::lazy::Lazy<$T> = $crate::lazy_static::lazy::Lazy::INIT;
};
}

View File

@@ -0,0 +1,89 @@
// Copyright 2016 lazy-static.rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
/*!
A macro for declaring lazily evaluated statics.
Using this macro, it is possible to have `static`s that require code to be
executed at runtime in order to be initialized.
This includes anything requiring heap allocations, like vectors or hash maps,
as well as anything that requires function calls to be computed.
*/
#[path = "core_lazy.rs"]
pub(crate) mod lazy;
#[doc(hidden)]
pub(crate) use core::ops::Deref as __Deref;
#[macro_export]
#[doc(hidden)]
macro_rules! __lazy_static_internal {
// optional visibility restrictions are wrapped in `()` to allow for
// explicitly passing otherwise implicit information about private items
($(#[$attr:meta])* ($($vis:tt)*) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
$crate::__lazy_static_internal!(@MAKE TY, $(#[$attr])*, ($($vis)*), $N);
$crate::__lazy_static_internal!(@TAIL, $N : $T = $e);
$crate::lazy_static!($($t)*);
};
(@TAIL, $N:ident : $T:ty = $e:expr) => {
impl $crate::lazy_static::__Deref for $N {
type Target = $T;
fn deref(&self) -> &$T {
#[inline(always)]
fn __static_ref_initialize() -> $T { $e }
#[inline(always)]
fn __stability() -> &'static $T {
$crate::__lazy_static_create!(LAZY, $T);
LAZY.get(__static_ref_initialize)
}
__stability()
}
}
impl $crate::lazy_static::LazyStatic for $N {
fn initialize(lazy: &Self) {
let _ = &**lazy;
}
}
};
// `vis` is wrapped in `()` to prevent parsing ambiguity
(@MAKE TY, $(#[$attr:meta])*, ($($vis:tt)*), $N:ident) => {
#[allow(missing_copy_implementations)]
#[allow(non_camel_case_types)]
#[allow(dead_code)]
$(#[$attr])*
$($vis)* struct $N {__private_field: ()}
#[doc(hidden)]
$($vis)* static $N: $N = $N {__private_field: ()};
};
() => ()
}
#[macro_export]
#[doc(hidden)]
macro_rules! lazy_static {
($(#[$attr:meta])* static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
// use `()` to explicitly forward the information about private items
$crate::__lazy_static_internal!($(#[$attr])* () static ref $N : $T = $e; $($t)*);
};
($(#[$attr:meta])* pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
$crate::__lazy_static_internal!($(#[$attr])* (pub) static ref $N : $T = $e; $($t)*);
};
($(#[$attr:meta])* pub ($($vis:tt)+) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
$crate::__lazy_static_internal!($(#[$attr])* (pub ($($vis)+)) static ref $N : $T = $e; $($t)*);
};
() => ()
}
/// Support trait for enabling a few common operation on lazy static values.
///
/// This is implemented by each defined lazy static, and
/// used by the free functions in this crate.
pub(crate) trait LazyStatic {
#[doc(hidden)]
fn initialize(lazy: &Self);
}

298
zeroidc/vendor/tracing-core/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,298 @@
//! Core primitives for `tracing`.
//!
//! [`tracing`] is a framework for instrumenting Rust programs to collect
//! structured, event-based diagnostic information. This crate defines the core
//! primitives of `tracing`.
//!
//! This crate provides:
//!
//! * [`span::Id`] identifies a span within the execution of a program.
//!
//! * [`Event`] represents a single event within a trace.
//!
//! * [`Subscriber`], the trait implemented to collect trace data.
//!
//! * [`Metadata`] and [`Callsite`] provide information describing spans and
//! `Event`s.
//!
//! * [`Field`], [`FieldSet`], [`Value`], and [`ValueSet`] represent the
//! structured data attached to a span.
//!
//! * [`Dispatch`] allows spans and events to be dispatched to `Subscriber`s.
//!
//! In addition, it defines the global callsite registry and per-thread current
//! dispatcher which other components of the tracing system rely on.
//!
//! *Compiler support: [requires `rustc` 1.49+][msrv]*
//!
//! [msrv]: #supported-rust-versions
//!
//! ## Usage
//!
//! Application authors will typically not use this crate directly. Instead,
//! they will use the [`tracing`] crate, which provides a much more
//! fully-featured API. However, this crate's API will change very infrequently,
//! so it may be used when dependencies must be very stable.
//!
//! `Subscriber` implementations may depend on `tracing-core` rather than
//! `tracing`, as the additional APIs provided by `tracing` are primarily useful
//! for instrumenting libraries and applications, and are generally not
//! necessary for `Subscriber` implementations.
//!
//! The [`tokio-rs/tracing`] repository contains less stable crates designed to
//! be used with the `tracing` ecosystem. It includes a collection of
//! `Subscriber` implementations, as well as utility and adapter crates.
//!
//! ## Crate Feature Flags
//!
//! The following crate [feature flags] are available:
//!
//! * `std`: Depend on the Rust standard library (enabled by default).
//!
//! `no_std` users may disable this feature with `default-features = false`:
//!
//! ```toml
//! [dependencies]
//! tracing-core = { version = "0.1.22", default-features = false }
//! ```
//!
//! **Note**:`tracing-core`'s `no_std` support requires `liballoc`.
//!
//! ### Unstable Features
//!
//! These feature flags enable **unstable** features. The public API may break in 0.1.x
//! releases. To enable these features, the `--cfg tracing_unstable` must be passed to
//! `rustc` when compiling.
//!
//! The following unstable feature flags are currently available:
//!
//! * `valuable`: Enables support for recording [field values] using the
//! [`valuable`] crate.
//!
//! #### Enabling Unstable Features
//!
//! The easiest way to set the `tracing_unstable` cfg is to use the `RUSTFLAGS`
//! env variable when running `cargo` commands:
//!
//! ```shell
//! RUSTFLAGS="--cfg tracing_unstable" cargo build
//! ```
//! Alternatively, the following can be added to the `.cargo/config` file in a
//! project to automatically enable the cfg flag for that project:
//!
//! ```toml
//! [build]
//! rustflags = ["--cfg", "tracing_unstable"]
//! ```
//!
//! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
//! [field values]: crate::field
//! [`valuable`]: https://crates.io/crates/valuable
//!
//! ## Supported Rust Versions
//!
//! Tracing is built against the latest stable release. The minimum supported
//! version is 1.49. The current Tracing version is not guaranteed to build on
//! Rust versions earlier than the minimum supported version.
//!
//! Tracing follows the same compiler support policies as the rest of the Tokio
//! project. The current stable Rust compiler and the three most recent minor
//! versions before it will always be supported. For example, if the current
//! stable compiler version is 1.45, the minimum supported version will not be
//! increased past 1.42, three minor versions prior. Increasing the minimum
//! supported compiler version is not considered a semver breaking change as
//! long as doing so complies with this policy.
//!
//!
//! [`span::Id`]: span::Id
//! [`Event`]: event::Event
//! [`Subscriber`]: subscriber::Subscriber
//! [`Metadata`]: metadata::Metadata
//! [`Callsite`]: callsite::Callsite
//! [`Field`]: field::Field
//! [`FieldSet`]: field::FieldSet
//! [`Value`]: field::Value
//! [`ValueSet`]: field::ValueSet
//! [`Dispatch`]: dispatcher::Dispatch
//! [`tokio-rs/tracing`]: https://github.com/tokio-rs/tracing
//! [`tracing`]: https://crates.io/crates/tracing
#![doc(html_root_url = "https://docs.rs/tracing-core/0.1.22")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png",
issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/"
)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_cfg), deny(rustdoc::broken_intra_doc_links))]
#![warn(
missing_debug_implementations,
missing_docs,
rust_2018_idioms,
unreachable_pub,
bad_style,
const_err,
dead_code,
improper_ctypes,
non_shorthand_field_patterns,
no_mangle_generic_items,
overflowing_literals,
path_statements,
patterns_in_fns_without_body,
private_in_public,
unconditional_recursion,
unused,
unused_allocation,
unused_comparisons,
unused_parens,
while_true
)]
#[cfg(not(feature = "std"))]
extern crate alloc;
/// Statically constructs an [`Identifier`] for the provided [`Callsite`].
///
/// This may be used in contexts such as static initializers.
///
/// For example:
/// ```rust
/// use tracing_core::{callsite, identify_callsite};
/// # use tracing_core::{Metadata, subscriber::Interest};
/// # fn main() {
/// pub struct MyCallsite {
/// // ...
/// }
/// impl callsite::Callsite for MyCallsite {
/// # fn set_interest(&self, _: Interest) { unimplemented!() }
/// # fn metadata(&self) -> &Metadata { unimplemented!() }
/// // ...
/// }
///
/// static CALLSITE: MyCallsite = MyCallsite {
/// // ...
/// };
///
/// static CALLSITE_ID: callsite::Identifier = identify_callsite!(&CALLSITE);
/// # }
/// ```
///
/// [`Identifier`]: callsite::Identifier
/// [`Callsite`]: callsite::Callsite
#[macro_export]
macro_rules! identify_callsite {
($callsite:expr) => {
$crate::callsite::Identifier($callsite)
};
}
/// Statically constructs new span [metadata].
///
/// /// For example:
/// ```rust
/// # use tracing_core::{callsite::Callsite, subscriber::Interest};
/// use tracing_core::metadata;
/// use tracing_core::metadata::{Kind, Level, Metadata};
/// # fn main() {
/// # pub struct MyCallsite { }
/// # impl Callsite for MyCallsite {
/// # fn set_interest(&self, _: Interest) { unimplemented!() }
/// # fn metadata(&self) -> &Metadata { unimplemented!() }
/// # }
/// #
/// static FOO_CALLSITE: MyCallsite = MyCallsite {
/// // ...
/// };
///
/// static FOO_METADATA: Metadata = metadata!{
/// name: "foo",
/// target: module_path!(),
/// level: Level::DEBUG,
/// fields: &["bar", "baz"],
/// callsite: &FOO_CALLSITE,
/// kind: Kind::SPAN,
/// };
/// # }
/// ```
///
/// [metadata]: metadata::Metadata
/// [`Metadata::new`]: metadata::Metadata::new
#[macro_export]
macro_rules! metadata {
(
name: $name:expr,
target: $target:expr,
level: $level:expr,
fields: $fields:expr,
callsite: $callsite:expr,
kind: $kind:expr
) => {
$crate::metadata! {
name: $name,
target: $target,
level: $level,
fields: $fields,
callsite: $callsite,
kind: $kind,
}
};
(
name: $name:expr,
target: $target:expr,
level: $level:expr,
fields: $fields:expr,
callsite: $callsite:expr,
kind: $kind:expr,
) => {
$crate::metadata::Metadata::new(
$name,
$target,
$level,
Some(file!()),
Some(line!()),
Some(module_path!()),
$crate::field::FieldSet::new($fields, $crate::identify_callsite!($callsite)),
$kind,
)
};
}
// Facade module: `no_std` uses spinlocks, `std` uses the mutexes in the standard library
#[cfg(not(feature = "std"))]
#[macro_use]
mod lazy_static;
// Trimmed-down vendored version of spin 0.5.2 (0387621)
// Dependency of no_std lazy_static, not required in a std build
#[cfg(not(feature = "std"))]
pub(crate) mod spin;
#[cfg(not(feature = "std"))]
#[doc(hidden)]
pub type Once = self::spin::Once<()>;
#[cfg(feature = "std")]
pub use stdlib::sync::Once;
pub mod callsite;
pub mod dispatcher;
pub mod event;
pub mod field;
pub mod metadata;
mod parent;
pub mod span;
pub(crate) mod stdlib;
pub mod subscriber;
#[doc(inline)]
pub use self::{
callsite::Callsite,
dispatcher::Dispatch,
event::Event,
field::Field,
metadata::{Level, LevelFilter, Metadata},
subscriber::Subscriber,
};
pub use self::{metadata::Kind, subscriber::Interest};
mod sealed {
pub trait Sealed {}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
use crate::span::Id;
#[derive(Debug)]
pub(crate) enum Parent {
/// The new span will be a root span.
Root,
/// The new span will be rooted in the current span.
Current,
/// The new span has an explicitly-specified parent.
Explicit(Id),
}

341
zeroidc/vendor/tracing-core/src/span.rs vendored Normal file
View File

@@ -0,0 +1,341 @@
//! Spans represent periods of time in the execution of a program.
use crate::field::FieldSet;
use crate::parent::Parent;
use crate::stdlib::num::NonZeroU64;
use crate::{field, Metadata};
/// Identifies a span within the context of a subscriber.
///
/// They are generated by [`Subscriber`]s for each span as it is created, by
/// the [`new_span`] trait method. See the documentation for that method for
/// more information on span ID generation.
///
/// [`Subscriber`]: super::subscriber::Subscriber
/// [`new_span`]: super::subscriber::Subscriber::new_span
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Id(NonZeroU64);
/// Attributes provided to a `Subscriber` describing a new span when it is
/// created.
#[derive(Debug)]
pub struct Attributes<'a> {
metadata: &'static Metadata<'static>,
values: &'a field::ValueSet<'a>,
parent: Parent,
}
/// A set of fields recorded by a span.
#[derive(Debug)]
pub struct Record<'a> {
values: &'a field::ValueSet<'a>,
}
/// Indicates what [the `Subscriber` considers] the "current" span.
///
/// As subscribers may not track a notion of a current span, this has three
/// possible states:
/// - "unknown", indicating that the subscriber does not track a current span,
/// - "none", indicating that the current context is known to not be in a span,
/// - "some", with the current span's [`Id`] and [`Metadata`].
///
/// [the `Subscriber` considers]: super::subscriber::Subscriber::current_span
/// [`Metadata`]: super::metadata::Metadata
#[derive(Debug)]
pub struct Current {
inner: CurrentInner,
}
#[derive(Debug)]
enum CurrentInner {
Current {
id: Id,
metadata: &'static Metadata<'static>,
},
None,
Unknown,
}
// ===== impl Span =====
impl Id {
/// Constructs a new span ID from the given `u64`.
///
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: Span IDs must be greater than zero.
/// </pre>
///
/// # Panics
/// - If the provided `u64` is 0.
pub fn from_u64(u: u64) -> Self {
Id(NonZeroU64::new(u).expect("span IDs must be > 0"))
}
/// Constructs a new span ID from the given `NonZeroU64`.
///
/// Unlike [`Id::from_u64`](Id::from_u64()), this will never panic.
#[inline]
pub const fn from_non_zero_u64(id: NonZeroU64) -> Self {
Id(id)
}
// Allow `into` by-ref since we don't want to impl Copy for Id
#[allow(clippy::wrong_self_convention)]
/// Returns the span's ID as a `u64`.
pub fn into_u64(&self) -> u64 {
self.0.get()
}
// Allow `into` by-ref since we don't want to impl Copy for Id
#[allow(clippy::wrong_self_convention)]
/// Returns the span's ID as a `NonZeroU64`.
#[inline]
pub const fn into_non_zero_u64(&self) -> NonZeroU64 {
self.0
}
}
impl<'a> From<&'a Id> for Option<Id> {
fn from(id: &'a Id) -> Self {
Some(id.clone())
}
}
// ===== impl Attributes =====
impl<'a> Attributes<'a> {
/// Returns `Attributes` describing a new child span of the current span,
/// with the provided metadata and values.
pub fn new(metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>) -> Self {
Attributes {
metadata,
values,
parent: Parent::Current,
}
}
/// Returns `Attributes` describing a new span at the root of its own trace
/// tree, with the provided metadata and values.
pub fn new_root(metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>) -> Self {
Attributes {
metadata,
values,
parent: Parent::Root,
}
}
/// Returns `Attributes` describing a new child span of the specified
/// parent span, with the provided metadata and values.
pub fn child_of(
parent: Id,
metadata: &'static Metadata<'static>,
values: &'a field::ValueSet<'a>,
) -> Self {
Attributes {
metadata,
values,
parent: Parent::Explicit(parent),
}
}
/// Returns a reference to the new span's metadata.
pub fn metadata(&self) -> &'static Metadata<'static> {
self.metadata
}
/// Returns a reference to a `ValueSet` containing any values the new span
/// was created with.
pub fn values(&self) -> &field::ValueSet<'a> {
self.values
}
/// Returns true if the new span should be a root.
pub fn is_root(&self) -> bool {
matches!(self.parent, Parent::Root)
}
/// Returns true if the new span's parent should be determined based on the
/// current context.
///
/// If this is true and the current thread is currently inside a span, then
/// that span should be the new span's parent. Otherwise, if the current
/// thread is _not_ inside a span, then the new span will be the root of its
/// own trace tree.
pub fn is_contextual(&self) -> bool {
matches!(self.parent, Parent::Current)
}
/// Returns the new span's explicitly-specified parent, if there is one.
///
/// Otherwise (if the new span is a root or is a child of the current span),
/// returns `None`.
pub fn parent(&self) -> Option<&Id> {
match self.parent {
Parent::Explicit(ref p) => Some(p),
_ => None,
}
}
/// Records all the fields in this set of `Attributes` with the provided
/// [Visitor].
///
/// [visitor]: super::field::Visit
pub fn record(&self, visitor: &mut dyn field::Visit) {
self.values.record(visitor)
}
/// Returns `true` if this set of `Attributes` contains a value for the
/// given `Field`.
pub fn contains(&self, field: &field::Field) -> bool {
self.values.contains(field)
}
/// Returns true if this set of `Attributes` contains _no_ values.
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
/// Returns the set of all [fields] defined by this span's [`Metadata`].
///
/// Note that the [`FieldSet`] returned by this method includes *all* the
/// fields declared by this span, not just those with values that are recorded
/// as part of this set of `Attributes`. Other fields with values not present in
/// this `Attributes`' value set may [record] values later.
///
/// [fields]: crate::field
/// [record]: Attributes::record()
/// [`Metadata`]: crate::metadata::Metadata
/// [`FieldSet`]: crate::field::FieldSet
pub fn fields(&self) -> &FieldSet {
self.values.field_set()
}
}
// ===== impl Record =====
impl<'a> Record<'a> {
/// Constructs a new `Record` from a `ValueSet`.
pub fn new(values: &'a field::ValueSet<'a>) -> Self {
Self { values }
}
/// Records all the fields in this `Record` with the provided [Visitor].
///
/// [visitor]: super::field::Visit
pub fn record(&self, visitor: &mut dyn field::Visit) {
self.values.record(visitor)
}
/// Returns the number of fields that would be visited from this `Record`
/// when [`Record::record()`] is called
///
/// [`Record::record()`]: Record::record()
pub fn len(&self) -> usize {
self.values.len()
}
/// Returns `true` if this `Record` contains a value for the given `Field`.
pub fn contains(&self, field: &field::Field) -> bool {
self.values.contains(field)
}
/// Returns true if this `Record` contains _no_ values.
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
}
// ===== impl Current =====
impl Current {
/// Constructs a new `Current` that indicates the current context is a span
/// with the given `metadata` and `metadata`.
pub fn new(id: Id, metadata: &'static Metadata<'static>) -> Self {
Self {
inner: CurrentInner::Current { id, metadata },
}
}
/// Constructs a new `Current` that indicates the current context is *not*
/// in a span.
pub fn none() -> Self {
Self {
inner: CurrentInner::None,
}
}
/// Constructs a new `Current` that indicates the `Subscriber` does not
/// track a current span.
pub(crate) fn unknown() -> Self {
Self {
inner: CurrentInner::Unknown,
}
}
/// Returns `true` if the `Subscriber` that constructed this `Current` tracks a
/// current span.
///
/// If this returns `true` and [`id`], [`metadata`], or [`into_inner`]
/// return `None`, that indicates that we are currently known to *not* be
/// inside a span. If this returns `false`, those methods will also return
/// `None`, but in this case, that is because the subscriber does not keep
/// track of the currently-entered span.
///
/// [`id`]: Current::id()
/// [`metadata`]: Current::metadata()
/// [`into_inner`]: Current::into_inner()
pub fn is_known(&self) -> bool {
!matches!(self.inner, CurrentInner::Unknown)
}
/// Consumes `self` and returns the span `Id` and `Metadata` of the current
/// span, if one exists and is known.
pub fn into_inner(self) -> Option<(Id, &'static Metadata<'static>)> {
match self.inner {
CurrentInner::Current { id, metadata } => Some((id, metadata)),
_ => None,
}
}
/// Borrows the `Id` of the current span, if one exists and is known.
pub fn id(&self) -> Option<&Id> {
match self.inner {
CurrentInner::Current { ref id, .. } => Some(id),
_ => None,
}
}
/// Borrows the `Metadata` of the current span, if one exists and is known.
pub fn metadata(&self) -> Option<&'static Metadata<'static>> {
match self.inner {
CurrentInner::Current { metadata, .. } => Some(metadata),
_ => None,
}
}
}
impl<'a> From<&'a Current> for Option<&'a Id> {
fn from(cur: &'a Current) -> Self {
cur.id()
}
}
impl<'a> From<&'a Current> for Option<Id> {
fn from(cur: &'a Current) -> Self {
cur.id().cloned()
}
}
impl From<Current> for Option<Id> {
fn from(cur: Current) -> Self {
match cur.inner {
CurrentInner::Current { id, .. } => Some(id),
_ => None,
}
}
}
impl<'a> From<&'a Current> for Option<&'static Metadata<'static>> {
fn from(cur: &'a Current) -> Self {
cur.metadata()
}
}

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Mathijs van de Nes
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,7 @@
//! Synchronization primitives based on spinning
pub(crate) use mutex::*;
pub(crate) use once::Once;
mod mutex;
mod once;

View File

@@ -0,0 +1,118 @@
use core::cell::UnsafeCell;
use core::default::Default;
use core::fmt;
use core::hint;
use core::marker::Sync;
use core::ops::{Deref, DerefMut, Drop};
use core::option::Option::{self, None, Some};
use core::sync::atomic::{AtomicBool, Ordering};
/// This type provides MUTual EXclusion based on spinning.
pub(crate) struct Mutex<T: ?Sized> {
lock: AtomicBool,
data: UnsafeCell<T>,
}
/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
#[derive(Debug)]
pub(crate) struct MutexGuard<'a, T: ?Sized> {
lock: &'a AtomicBool,
data: &'a mut T,
}
// Same unsafe impls as `std::sync::Mutex`
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
impl<T> Mutex<T> {
/// Creates a new spinlock wrapping the supplied data.
pub(crate) const fn new(user_data: T) -> Mutex<T> {
Mutex {
lock: AtomicBool::new(false),
data: UnsafeCell::new(user_data),
}
}
}
impl<T: ?Sized> Mutex<T> {
fn obtain_lock(&self) {
while self
.lock
.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
// Wait until the lock looks unlocked before retrying
while self.lock.load(Ordering::Relaxed) {
hint::spin_loop();
}
}
}
/// Locks the spinlock and returns a guard.
///
/// The returned value may be dereferenced for data access
/// and the lock will be dropped when the guard falls out of scope.
pub(crate) fn lock(&self) -> MutexGuard<'_, T> {
self.obtain_lock();
MutexGuard {
lock: &self.lock,
data: unsafe { &mut *self.data.get() },
}
}
/// Tries to lock the mutex. If it is already locked, it will return None. Otherwise it returns
/// a guard within Some.
pub(crate) fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
if self
.lock
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
Some(MutexGuard {
lock: &self.lock,
data: unsafe { &mut *self.data.get() },
})
} else {
None
}
}
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.try_lock() {
Some(guard) => write!(f, "Mutex {{ data: ")
.and_then(|()| (&*guard).fmt(f))
.and_then(|()| write!(f, "}}")),
None => write!(f, "Mutex {{ <locked> }}"),
}
}
}
impl<T: ?Sized + Default> Default for Mutex<T> {
fn default() -> Mutex<T> {
Mutex::new(Default::default())
}
}
impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
type Target = T;
fn deref<'b>(&'b self) -> &'b T {
&*self.data
}
}
impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
fn deref_mut<'b>(&'b mut self) -> &'b mut T {
&mut *self.data
}
}
impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
/// The dropping of the MutexGuard will release the lock it was created from.
fn drop(&mut self) {
self.lock.store(false, Ordering::Release);
}
}

View File

@@ -0,0 +1,158 @@
use core::cell::UnsafeCell;
use core::fmt;
use core::hint::spin_loop;
use core::sync::atomic::{AtomicUsize, Ordering};
/// A synchronization primitive which can be used to run a one-time global
/// initialization. Unlike its std equivalent, this is generalized so that the
/// closure returns a value and it is stored. Once therefore acts something like
/// a future, too.
pub struct Once<T> {
state: AtomicUsize,
data: UnsafeCell<Option<T>>, // TODO remove option and use mem::uninitialized
}
impl<T: fmt::Debug> fmt::Debug for Once<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.r#try() {
Some(s) => write!(f, "Once {{ data: ")
.and_then(|()| s.fmt(f))
.and_then(|()| write!(f, "}}")),
None => write!(f, "Once {{ <uninitialized> }}"),
}
}
}
// Same unsafe impls as `std::sync::RwLock`, because this also allows for
// concurrent reads.
unsafe impl<T: Send + Sync> Sync for Once<T> {}
unsafe impl<T: Send> Send for Once<T> {}
// Four states that a Once can be in, encoded into the lower bits of `state` in
// the Once structure.
const INCOMPLETE: usize = 0x0;
const RUNNING: usize = 0x1;
const COMPLETE: usize = 0x2;
const PANICKED: usize = 0x3;
use core::hint::unreachable_unchecked as unreachable;
impl<T> Once<T> {
/// Initialization constant of `Once`.
pub const INIT: Self = Once {
state: AtomicUsize::new(INCOMPLETE),
data: UnsafeCell::new(None),
};
/// Creates a new `Once` value.
pub const fn new() -> Once<T> {
Self::INIT
}
fn force_get<'a>(&'a self) -> &'a T {
match unsafe { &*self.data.get() }.as_ref() {
None => unsafe { unreachable() },
Some(p) => p,
}
}
/// Performs an initialization routine once and only once. The given closure
/// will be executed if this is the first time `call_once` has been called,
/// and otherwise the routine will *not* be invoked.
///
/// This method will block the calling thread if another initialization
/// routine is currently running.
///
/// When this function returns, it is guaranteed that some initialization
/// has run and completed (it may not be the closure specified). The
/// returned pointer will point to the result from the closure that was
/// run.
pub fn call_once<'a, F>(&'a self, builder: F) -> &'a T
where
F: FnOnce() -> T,
{
let mut status = self.state.load(Ordering::SeqCst);
if status == INCOMPLETE {
status = match self.state.compare_exchange(
INCOMPLETE,
RUNNING,
Ordering::SeqCst,
Ordering::SeqCst,
) {
Ok(status) => {
debug_assert_eq!(
status, INCOMPLETE,
"if compare_exchange succeeded, previous status must be incomplete",
);
// We init
// We use a guard (Finish) to catch panics caused by builder
let mut finish = Finish {
state: &self.state,
panicked: true,
};
unsafe { *self.data.get() = Some(builder()) };
finish.panicked = false;
self.state.store(COMPLETE, Ordering::SeqCst);
// This next line is strictly an optimization
return self.force_get();
}
Err(status) => status,
}
}
loop {
match status {
INCOMPLETE => unreachable!(),
RUNNING => {
// We spin
spin_loop();
status = self.state.load(Ordering::SeqCst)
}
PANICKED => panic!("Once has panicked"),
COMPLETE => return self.force_get(),
_ => unsafe { unreachable() },
}
}
}
/// Returns a pointer iff the `Once` was previously initialized
pub fn r#try<'a>(&'a self) -> Option<&'a T> {
match self.state.load(Ordering::SeqCst) {
COMPLETE => Some(self.force_get()),
_ => None,
}
}
/// Like try, but will spin if the `Once` is in the process of being
/// initialized
pub fn wait<'a>(&'a self) -> Option<&'a T> {
loop {
match self.state.load(Ordering::SeqCst) {
INCOMPLETE => return None,
RUNNING => {
spin_loop() // We spin
}
COMPLETE => return Some(self.force_get()),
PANICKED => panic!("Once has panicked"),
_ => unsafe { unreachable() },
}
}
}
}
struct Finish<'a> {
state: &'a AtomicUsize,
panicked: bool,
}
impl<'a> Drop for Finish<'a> {
fn drop(&mut self) {
if self.panicked {
self.state.store(PANICKED, Ordering::SeqCst);
}
}
}

View File

@@ -0,0 +1,78 @@
//! Re-exports either the Rust `std` library or `core` and `alloc` when `std` is
//! disabled.
//!
//! `crate::stdlib::...` should be used rather than `std::` when adding code that
//! will be available with the standard library disabled.
//!
//! Note that this module is called `stdlib` rather than `std`, as Rust 1.34.0
//! does not permit redefining the name `stdlib` (although this works on the
//! latest stable Rust).
#[cfg(feature = "std")]
pub(crate) use std::*;
#[cfg(not(feature = "std"))]
pub(crate) use self::no_std::*;
#[cfg(not(feature = "std"))]
mod no_std {
// We pre-emptively export everything from libcore/liballoc, (even modules
// we aren't using currently) to make adding new code easier. Therefore,
// some of these imports will be unused.
#![allow(unused_imports)]
pub(crate) use core::{
any, array, ascii, cell, char, clone, cmp, convert, default, f32, f64, ffi, future, hash,
hint, i128, i16, i8, isize, iter, marker, mem, num, ops, option, pin, ptr, result, task,
time, u128, u16, u32, u8, usize,
};
pub(crate) use alloc::{boxed, collections, rc, string, vec};
pub(crate) mod borrow {
pub(crate) use alloc::borrow::*;
pub(crate) use core::borrow::*;
}
pub(crate) mod fmt {
pub(crate) use alloc::fmt::*;
pub(crate) use core::fmt::*;
}
pub(crate) mod slice {
pub(crate) use alloc::slice::*;
pub(crate) use core::slice::*;
}
pub(crate) mod str {
pub(crate) use alloc::str::*;
pub(crate) use core::str::*;
}
pub(crate) mod sync {
pub(crate) use crate::spin::MutexGuard;
pub(crate) use alloc::sync::*;
pub(crate) use core::sync::*;
/// This wraps `spin::Mutex` to return a `Result`, so that it can be
/// used with code written against `std::sync::Mutex`.
///
/// Since `spin::Mutex` doesn't support poisoning, the `Result` returned
/// by `lock` will always be `Ok`.
#[derive(Debug, Default)]
pub(crate) struct Mutex<T> {
inner: crate::spin::Mutex<T>,
}
impl<T> Mutex<T> {
pub(crate) fn new(data: T) -> Self {
Self {
inner: crate::spin::Mutex::new(data),
}
}
pub(crate) fn lock(&self) -> Result<MutexGuard<'_, T>, ()> {
Ok(self.inner.lock())
}
}
}
}

View File

@@ -0,0 +1,757 @@
//! Subscribers collect and record trace data.
use crate::{span, Event, LevelFilter, Metadata};
use crate::stdlib::{
any::{Any, TypeId},
boxed::Box,
sync::Arc,
};
/// Trait representing the functions required to collect trace data.
///
/// Crates that provide implementations of methods for collecting or recording
/// trace data should implement the `Subscriber` interface. This trait is
/// intended to represent fundamental primitives for collecting trace events and
/// spans — other libraries may offer utility functions and types to make
/// subscriber implementations more modular or improve the ergonomics of writing
/// subscribers.
///
/// A subscriber is responsible for the following:
/// - Registering new spans as they are created, and providing them with span
/// IDs. Implicitly, this means the subscriber may determine the strategy for
/// determining span equality.
/// - Recording the attachment of field values and follows-from annotations to
/// spans.
/// - Filtering spans and events, and determining when those filters must be
/// invalidated.
/// - Observing spans as they are entered, exited, and closed, and events as
/// they occur.
///
/// When a span is entered or exited, the subscriber is provided only with the
/// [ID] with which it tagged that span when it was created. This means
/// that it is up to the subscriber to determine whether and how span _data_ —
/// the fields and metadata describing the span — should be stored. The
/// [`new_span`] function is called when a new span is created, and at that
/// point, the subscriber _may_ choose to store the associated data if it will
/// be referenced again. However, if the data has already been recorded and will
/// not be needed by the implementations of `enter` and `exit`, the subscriber
/// may freely discard that data without allocating space to store it.
///
/// ## Overriding default impls
///
/// Some trait methods on `Subscriber` have default implementations, either in
/// order to reduce the surface area of implementing `Subscriber`, or for
/// backward-compatibility reasons. However, many subscribers will likely want
/// to override these default implementations.
///
/// The following methods are likely of interest:
///
/// - [`register_callsite`] is called once for each callsite from which a span
/// event may originate, and returns an [`Interest`] value describing whether or
/// not the subscriber wishes to see events or spans from that callsite. By
/// default, it calls [`enabled`], and returns `Interest::always()` if
/// `enabled` returns true, or `Interest::never()` if enabled returns false.
/// However, if the subscriber's interest can change dynamically at runtime,
/// it may want to override this function to return `Interest::sometimes()`.
/// Additionally, subscribers which wish to perform a behaviour once for each
/// callsite, such as allocating storage for data related to that callsite,
/// can perform it in `register_callsite`.
///
/// See also the [documentation on the callsite registry][cs-reg] for details
/// on [`register_callsite`].
///
/// - [`clone_span`] is called every time a span ID is cloned, and [`try_close`]
/// is called when a span ID is dropped. By default, these functions do
/// nothing. However, they can be used to implement reference counting for
/// spans, allowing subscribers to free storage for span data and to determine
/// when a span has _closed_ permanently (rather than being exited).
/// Subscribers which store per-span data or which need to track span closures
/// should override these functions together.
///
/// [ID]: super::span::Id
/// [`new_span`]: Subscriber::new_span
/// [`register_callsite`]: Subscriber::register_callsite
/// [`enabled`]: Subscriber::enabled
/// [`clone_span`]: Subscriber::clone_span
/// [`try_close`]: Subscriber::try_close
/// [cs-reg]: crate::callsite#registering-callsites
pub trait Subscriber: 'static {
// === Span registry methods ==============================================
/// Registers a new [callsite] with this subscriber, returning whether or not
/// the subscriber is interested in being notified about the callsite.
///
/// By default, this function assumes that the subscriber's [filter]
/// represents an unchanging view of its interest in the callsite. However,
/// if this is not the case, subscribers may override this function to
/// indicate different interests, or to implement behaviour that should run
/// once for every callsite.
///
/// This function is guaranteed to be called at least once per callsite on
/// every active subscriber. The subscriber may store the keys to fields it
/// cares about in order to reduce the cost of accessing fields by name,
/// preallocate storage for that callsite, or perform any other actions it
/// wishes to perform once for each callsite.
///
/// The subscriber should then return an [`Interest`], indicating
/// whether it is interested in being notified about that callsite in the
/// future. This may be `Always` indicating that the subscriber always
/// wishes to be notified about the callsite, and its filter need not be
/// re-evaluated; `Sometimes`, indicating that the subscriber may sometimes
/// care about the callsite but not always (such as when sampling), or
/// `Never`, indicating that the subscriber never wishes to be notified about
/// that callsite. If all active subscribers return `Never`, a callsite will
/// never be enabled unless a new subscriber expresses interest in it.
///
/// `Subscriber`s which require their filters to be run every time an event
/// occurs or a span is entered/exited should return `Interest::sometimes`.
/// If a subscriber returns `Interest::sometimes`, then its [`enabled`] method
/// will be called every time an event or span is created from that callsite.
///
/// For example, suppose a sampling subscriber is implemented by
/// incrementing a counter every time `enabled` is called and only returning
/// `true` when the counter is divisible by a specified sampling rate. If
/// that subscriber returns `Interest::always` from `register_callsite`, then
/// the filter will not be re-evaluated once it has been applied to a given
/// set of metadata. Thus, the counter will not be incremented, and the span
/// or event that corresponds to the metadata will never be `enabled`.
///
/// `Subscriber`s that need to change their filters occasionally should call
/// [`rebuild_interest_cache`] to re-evaluate `register_callsite` for all
/// callsites.
///
/// Similarly, if a `Subscriber` has a filtering strategy that can be
/// changed dynamically at runtime, it would need to re-evaluate that filter
/// if the cached results have changed.
///
/// A subscriber which manages fanout to multiple other subscribers
/// should proxy this decision to all of its child subscribers,
/// returning `Interest::never` only if _all_ such children return
/// `Interest::never`. If the set of subscribers to which spans are
/// broadcast may change dynamically, the subscriber should also never
/// return `Interest::Never`, as a new subscriber may be added that _is_
/// interested.
///
/// See the [documentation on the callsite registry][cs-reg] for more
/// details on how and when the `register_callsite` method is called.
///
/// # Notes
/// This function may be called again when a new subscriber is created or
/// when the registry is invalidated.
///
/// If a subscriber returns `Interest::never` for a particular callsite, it
/// _may_ still see spans and events originating from that callsite, if
/// another subscriber expressed interest in it.
///
/// [callsite]: crate::callsite
/// [filter]: Self::enabled
/// [metadata]: super::metadata::Metadata
/// [`enabled`]: Subscriber::enabled()
/// [`rebuild_interest_cache`]: super::callsite::rebuild_interest_cache
/// [cs-reg]: crate::callsite#registering-callsites
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
if self.enabled(metadata) {
Interest::always()
} else {
Interest::never()
}
}
/// Returns true if a span or event with the specified [metadata] would be
/// recorded.
///
/// By default, it is assumed that this filter needs only be evaluated once
/// for each callsite, so it is called by [`register_callsite`] when each
/// callsite is registered. The result is used to determine if the subscriber
/// is always [interested] or never interested in that callsite. This is intended
/// primarily as an optimization, so that expensive filters (such as those
/// involving string search, et cetera) need not be re-evaluated.
///
/// However, if the subscriber's interest in a particular span or event may
/// change, or depends on contexts only determined dynamically at runtime,
/// then the `register_callsite` method should be overridden to return
/// [`Interest::sometimes`]. In that case, this function will be called every
/// time that span or event occurs.
///
/// [metadata]: super::metadata::Metadata
/// [interested]: Interest
/// [`Interest::sometimes`]: Interest::sometimes
/// [`register_callsite`]: Subscriber::register_callsite()
fn enabled(&self, metadata: &Metadata<'_>) -> bool;
/// Returns the highest [verbosity level][level] that this `Subscriber` will
/// enable, or `None`, if the subscriber does not implement level-based
/// filtering or chooses not to implement this method.
///
/// If this method returns a [`Level`][level], it will be used as a hint to
/// determine the most verbose level that will be enabled. This will allow
/// spans and events which are more verbose than that level to be skipped
/// more efficiently. Subscribers which perform filtering are strongly
/// encouraged to provide an implementation of this method.
///
/// If the maximum level the subscriber will enable can change over the
/// course of its lifetime, it is free to return a different value from
/// multiple invocations of this method. However, note that changes in the
/// maximum level will **only** be reflected after the callsite [`Interest`]
/// cache is rebuilt, by calling the [`callsite::rebuild_interest_cache`][rebuild]
/// function. Therefore, if the subscriber will change the value returned by
/// this method, it is responsible for ensuring that
/// [`rebuild_interest_cache`][rebuild] is called after the value of the max
/// level changes.
///
/// [level]: super::Level
/// [rebuild]: super::callsite::rebuild_interest_cache
fn max_level_hint(&self) -> Option<LevelFilter> {
None
}
/// Visit the construction of a new span, returning a new [span ID] for the
/// span being constructed.
///
/// The provided [`Attributes`] contains any field values that were provided
/// when the span was created. The subscriber may pass a [visitor] to the
/// `Attributes`' [`record` method] to record these values.
///
/// IDs are used to uniquely identify spans and events within the context of a
/// subscriber, so span equality will be based on the returned ID. Thus, if
/// the subscriber wishes for all spans with the same metadata to be
/// considered equal, it should return the same ID every time it is given a
/// particular set of metadata. Similarly, if it wishes for two separate
/// instances of a span with the same metadata to *not* be equal, it should
/// return a distinct ID every time this function is called, regardless of
/// the metadata.
///
/// Note that the subscriber is free to assign span IDs based on whatever
/// scheme it sees fit. Any guarantees about uniqueness, ordering, or ID
/// reuse are left up to the subscriber implementation to determine.
///
/// [span ID]: super::span::Id
/// [`Attributes`]: super::span::Attributes
/// [visitor]: super::field::Visit
/// [`record` method]: super::span::Attributes::record
fn new_span(&self, span: &span::Attributes<'_>) -> span::Id;
// === Notification methods ===============================================
/// Record a set of values on a span.
///
/// This method will be invoked when value is recorded on a span.
/// Recording multiple values for the same field is possible,
/// but the actual behaviour is defined by the subscriber implementation.
///
/// Keep in mind that a span might not provide a value
/// for each field it declares.
///
/// The subscriber is expected to provide a [visitor] to the `Record`'s
/// [`record` method] in order to record the added values.
///
/// # Example
/// "foo = 3" will be recorded when [`record`] is called on the
/// `Attributes` passed to `new_span`.
/// Since values are not provided for the `bar` and `baz` fields,
/// the span's `Metadata` will indicate that it _has_ those fields,
/// but values for them won't be recorded at this time.
///
/// ```rust,ignore
/// # use tracing::span;
///
/// let mut span = span!("my_span", foo = 3, bar, baz);
///
/// // `Subscriber::record` will be called with a `Record`
/// // containing "bar = false"
/// span.record("bar", &false);
///
/// // `Subscriber::record` will be called with a `Record`
/// // containing "baz = "a string""
/// span.record("baz", &"a string");
/// ```
///
/// [visitor]: super::field::Visit
/// [`record`]: super::span::Attributes::record
/// [`record` method]: super::span::Record::record
fn record(&self, span: &span::Id, values: &span::Record<'_>);
/// Adds an indication that `span` follows from the span with the id
/// `follows`.
///
/// This relationship differs somewhat from the parent-child relationship: a
/// span may have any number of prior spans, rather than a single one; and
/// spans are not considered to be executing _inside_ of the spans they
/// follow from. This means that a span may close even if subsequent spans
/// that follow from it are still open, and time spent inside of a
/// subsequent span should not be included in the time its precedents were
/// executing. This is used to model causal relationships such as when a
/// single future spawns several related background tasks, et cetera.
///
/// If the subscriber has spans corresponding to the given IDs, it should
/// record this relationship in whatever way it deems necessary. Otherwise,
/// if one or both of the given span IDs do not correspond to spans that the
/// subscriber knows about, or if a cyclical relationship would be created
/// (i.e., some span _a_ which proceeds some other span _b_ may not also
/// follow from _b_), it may silently do nothing.
fn record_follows_from(&self, span: &span::Id, follows: &span::Id);
/// Records that an [`Event`] has occurred.
///
/// This method will be invoked when an Event is constructed by
/// the `Event`'s [`dispatch` method]. For example, this happens internally
/// when an event macro from `tracing` is called.
///
/// The key difference between this method and `record` is that `record` is
/// called when a value is recorded for a field defined by a span,
/// while `event` is called when a new event occurs.
///
/// The provided `Event` struct contains any field values attached to the
/// event. The subscriber may pass a [visitor] to the `Event`'s
/// [`record` method] to record these values.
///
/// [`Event`]: super::event::Event
/// [visitor]: super::field::Visit
/// [`record` method]: super::event::Event::record
/// [`dispatch` method]: super::event::Event::dispatch
fn event(&self, event: &Event<'_>);
/// Records that a span has been entered.
///
/// When entering a span, this method is called to notify the subscriber
/// that the span has been entered. The subscriber is provided with the
/// [span ID] of the entered span, and should update any internal state
/// tracking the current span accordingly.
///
/// [span ID]: super::span::Id
fn enter(&self, span: &span::Id);
/// Records that a span has been exited.
///
/// When exiting a span, this method is called to notify the subscriber
/// that the span has been exited. The subscriber is provided with the
/// [span ID] of the exited span, and should update any internal state
/// tracking the current span accordingly.
///
/// Exiting a span does not imply that the span will not be re-entered.
///
/// [span ID]: super::span::Id
fn exit(&self, span: &span::Id);
/// Notifies the subscriber that a [span ID] has been cloned.
///
/// This function is guaranteed to only be called with span IDs that were
/// returned by this subscriber's `new_span` function.
///
/// Note that the default implementation of this function this is just the
/// identity function, passing through the identifier. However, it can be
/// used in conjunction with [`try_close`] to track the number of handles
/// capable of `enter`ing a span. When all the handles have been dropped
/// (i.e., `try_close` has been called one more time than `clone_span` for a
/// given ID), the subscriber may assume that the span will not be entered
/// again. It is then free to deallocate storage for data associated with
/// that span, write data from that span to IO, and so on.
///
/// For more unsafe situations, however, if `id` is itself a pointer of some
/// kind this can be used as a hook to "clone" the pointer, depending on
/// what that means for the specified pointer.
///
/// [span ID]: super::span::Id
/// [`try_close`]: Subscriber::try_close
fn clone_span(&self, id: &span::Id) -> span::Id {
id.clone()
}
/// **This method is deprecated.**
///
/// Using `drop_span` may result in subscribers composed using
/// `tracing-subscriber` crate's `Layer` trait from observing close events.
/// Use [`try_close`] instead.
///
/// The default implementation of this function does nothing.
///
/// [`try_close`]: Subscriber::try_close
#[deprecated(since = "0.1.2", note = "use `Subscriber::try_close` instead")]
fn drop_span(&self, _id: span::Id) {}
/// Notifies the subscriber that a [span ID] has been dropped, and returns
/// `true` if there are now 0 IDs that refer to that span.
///
/// Higher-level libraries providing functionality for composing multiple
/// subscriber implementations may use this return value to notify any
/// "layered" subscribers that this subscriber considers the span closed.
///
/// The default implementation of this method calls the subscriber's
/// [`drop_span`] method and returns `false`. This means that, unless the
/// subscriber overrides the default implementation, close notifications
/// will never be sent to any layered subscribers. In general, if the
/// subscriber tracks reference counts, this method should be implemented,
/// rather than `drop_span`.
///
/// This function is guaranteed to only be called with span IDs that were
/// returned by this subscriber's `new_span` function.
///
/// It's guaranteed that if this function has been called once more than the
/// number of times `clone_span` was called with the same `id`, then no more
/// handles that can enter the span with that `id` exist. This means that it
/// can be used in conjunction with [`clone_span`] to track the number of
/// handles capable of `enter`ing a span. When all the handles have been
/// dropped (i.e., `try_close` has been called one more time than
/// `clone_span` for a given ID), the subscriber may assume that the span
/// will not be entered again, and should return `true`. It is then free to
/// deallocate storage for data associated with that span, write data from
/// that span to IO, and so on.
///
/// **Note**: since this function is called when spans are dropped,
/// implementations should ensure that they are unwind-safe. Panicking from
/// inside of a `try_close` function may cause a double panic, if the span
/// was dropped due to a thread unwinding.
///
/// [span ID]: super::span::Id
/// [`clone_span`]: Subscriber::clone_span
/// [`drop_span`]: Subscriber::drop_span
fn try_close(&self, id: span::Id) -> bool {
#[allow(deprecated)]
self.drop_span(id);
false
}
/// Returns a type representing this subscriber's view of the current span.
///
/// If subscribers track a current span, they should override this function
/// to return [`Current::new`] if the thread from which this method is
/// called is inside a span, or [`Current::none`] if the thread is not
/// inside a span.
///
/// By default, this returns a value indicating that the subscriber
/// does **not** track what span is current. If the subscriber does not
/// implement a current span, it should not override this method.
///
/// [`Current::new`]: super::span::Current#tymethod.new
/// [`Current::none`]: super::span::Current#tymethod.none
fn current_span(&self) -> span::Current {
span::Current::unknown()
}
// === Downcasting methods ================================================
/// If `self` is the same type as the provided `TypeId`, returns an untyped
/// `*const` pointer to that type. Otherwise, returns `None`.
///
/// If you wish to downcast a `Subscriber`, it is strongly advised to use
/// the safe API provided by [`downcast_ref`] instead.
///
/// This API is required for `downcast_raw` to be a trait method; a method
/// signature like [`downcast_ref`] (with a generic type parameter) is not
/// object-safe, and thus cannot be a trait method for `Subscriber`. This
/// means that if we only exposed `downcast_ref`, `Subscriber`
/// implementations could not override the downcasting behavior
///
/// This method may be overridden by "fan out" or "chained" subscriber
/// implementations which consist of multiple composed types. Such
/// subscribers might allow `downcast_raw` by returning references to those
/// component if they contain components with the given `TypeId`.
///
/// # Safety
///
/// The [`downcast_ref`] method expects that the pointer returned by
/// `downcast_raw` is non-null and points to a valid instance of the type
/// with the provided `TypeId`. Failure to ensure this will result in
/// undefined behaviour, so implementing `downcast_raw` is unsafe.
///
/// [`downcast_ref`]: #method.downcast_ref
unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
if id == TypeId::of::<Self>() {
Some(self as *const Self as *const ())
} else {
None
}
}
}
impl dyn Subscriber {
/// Returns `true` if this `Subscriber` is the same type as `T`.
pub fn is<T: Any>(&self) -> bool {
self.downcast_ref::<T>().is_some()
}
/// Returns some reference to this `Subscriber` value if it is of type `T`,
/// or `None` if it isn't.
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
unsafe {
let raw = self.downcast_raw(TypeId::of::<T>())?;
if raw.is_null() {
None
} else {
Some(&*(raw as *const _))
}
}
}
}
/// Indicates a [`Subscriber`]'s interest in a particular callsite.
///
/// `Subscriber`s return an `Interest` from their [`register_callsite`] methods
/// in order to determine whether that span should be enabled or disabled.
///
/// [`Subscriber`]: super::Subscriber
/// [`register_callsite`]: super::Subscriber::register_callsite
#[derive(Clone, Debug)]
pub struct Interest(InterestKind);
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
enum InterestKind {
Never = 0,
Sometimes = 1,
Always = 2,
}
impl Interest {
/// Returns an `Interest` indicating that the subscriber is never interested
/// in being notified about a callsite.
///
/// If all active subscribers are `never()` interested in a callsite, it will
/// be completely disabled unless a new subscriber becomes active.
#[inline]
pub fn never() -> Self {
Interest(InterestKind::Never)
}
/// Returns an `Interest` indicating the subscriber is sometimes interested
/// in being notified about a callsite.
///
/// If all active subscribers are `sometimes` or `never` interested in a
/// callsite, the currently active subscriber will be asked to filter that
/// callsite every time it creates a span. This will be the case until a new
/// subscriber expresses that it is `always` interested in the callsite.
#[inline]
pub fn sometimes() -> Self {
Interest(InterestKind::Sometimes)
}
/// Returns an `Interest` indicating the subscriber is always interested in
/// being notified about a callsite.
///
/// If any subscriber expresses that it is `always()` interested in a given
/// callsite, then the callsite will always be enabled.
#[inline]
pub fn always() -> Self {
Interest(InterestKind::Always)
}
/// Returns `true` if the subscriber is never interested in being notified
/// about this callsite.
#[inline]
pub fn is_never(&self) -> bool {
matches!(self.0, InterestKind::Never)
}
/// Returns `true` if the subscriber is sometimes interested in being notified
/// about this callsite.
#[inline]
pub fn is_sometimes(&self) -> bool {
matches!(self.0, InterestKind::Sometimes)
}
/// Returns `true` if the subscriber is always interested in being notified
/// about this callsite.
#[inline]
pub fn is_always(&self) -> bool {
matches!(self.0, InterestKind::Always)
}
/// Returns the common interest between these two Interests.
///
/// If both interests are the same, this propagates that interest.
/// Otherwise, if they differ, the result must always be
/// `Interest::sometimes` --- if the two subscribers differ in opinion, we
/// will have to ask the current subscriber what it thinks, no matter what.
pub(crate) fn and(self, rhs: Interest) -> Self {
if self.0 == rhs.0 {
self
} else {
Interest::sometimes()
}
}
}
/// A no-op [`Subscriber`].
///
/// [`NoSubscriber`] implements the [`Subscriber`] trait by never being enabled,
/// never being interested in any callsite, and dropping all spans and events.
#[derive(Copy, Clone, Debug, Default)]
pub struct NoSubscriber(());
impl Subscriber for NoSubscriber {
#[inline]
fn register_callsite(&self, _: &'static Metadata<'static>) -> Interest {
Interest::never()
}
fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
span::Id::from_u64(0xDEAD)
}
fn event(&self, _event: &Event<'_>) {}
fn record(&self, _span: &span::Id, _values: &span::Record<'_>) {}
fn record_follows_from(&self, _span: &span::Id, _follows: &span::Id) {}
#[inline]
fn enabled(&self, _metadata: &Metadata<'_>) -> bool {
false
}
fn enter(&self, _span: &span::Id) {}
fn exit(&self, _span: &span::Id) {}
}
impl Subscriber for Box<dyn Subscriber + Send + Sync + 'static> {
#[inline]
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
self.as_ref().register_callsite(metadata)
}
#[inline]
fn enabled(&self, metadata: &Metadata<'_>) -> bool {
self.as_ref().enabled(metadata)
}
#[inline]
fn max_level_hint(&self) -> Option<LevelFilter> {
self.as_ref().max_level_hint()
}
#[inline]
fn new_span(&self, span: &span::Attributes<'_>) -> span::Id {
self.as_ref().new_span(span)
}
#[inline]
fn record(&self, span: &span::Id, values: &span::Record<'_>) {
self.as_ref().record(span, values)
}
#[inline]
fn record_follows_from(&self, span: &span::Id, follows: &span::Id) {
self.as_ref().record_follows_from(span, follows)
}
#[inline]
fn event(&self, event: &Event<'_>) {
self.as_ref().event(event)
}
#[inline]
fn enter(&self, span: &span::Id) {
self.as_ref().enter(span)
}
#[inline]
fn exit(&self, span: &span::Id) {
self.as_ref().exit(span)
}
#[inline]
fn clone_span(&self, id: &span::Id) -> span::Id {
self.as_ref().clone_span(id)
}
#[inline]
fn try_close(&self, id: span::Id) -> bool {
self.as_ref().try_close(id)
}
#[inline]
#[allow(deprecated)]
fn drop_span(&self, id: span::Id) {
self.as_ref().try_close(id);
}
#[inline]
fn current_span(&self) -> span::Current {
self.as_ref().current_span()
}
#[inline]
unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
if id == TypeId::of::<Self>() {
return Some(self as *const Self as *const _);
}
self.as_ref().downcast_raw(id)
}
}
impl Subscriber for Arc<dyn Subscriber + Send + Sync + 'static> {
#[inline]
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
self.as_ref().register_callsite(metadata)
}
#[inline]
fn enabled(&self, metadata: &Metadata<'_>) -> bool {
self.as_ref().enabled(metadata)
}
#[inline]
fn max_level_hint(&self) -> Option<LevelFilter> {
self.as_ref().max_level_hint()
}
#[inline]
fn new_span(&self, span: &span::Attributes<'_>) -> span::Id {
self.as_ref().new_span(span)
}
#[inline]
fn record(&self, span: &span::Id, values: &span::Record<'_>) {
self.as_ref().record(span, values)
}
#[inline]
fn record_follows_from(&self, span: &span::Id, follows: &span::Id) {
self.as_ref().record_follows_from(span, follows)
}
#[inline]
fn event(&self, event: &Event<'_>) {
self.as_ref().event(event)
}
#[inline]
fn enter(&self, span: &span::Id) {
self.as_ref().enter(span)
}
#[inline]
fn exit(&self, span: &span::Id) {
self.as_ref().exit(span)
}
#[inline]
fn clone_span(&self, id: &span::Id) -> span::Id {
self.as_ref().clone_span(id)
}
#[inline]
fn try_close(&self, id: span::Id) -> bool {
self.as_ref().try_close(id)
}
#[inline]
#[allow(deprecated)]
fn drop_span(&self, id: span::Id) {
self.as_ref().try_close(id);
}
#[inline]
fn current_span(&self) -> span::Current {
self.as_ref().current_span()
}
#[inline]
unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
if id == TypeId::of::<Self>() {
return Some(self as *const Self as *const _);
}
self.as_ref().downcast_raw(id)
}
}