diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/tracing/src/span.rs | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/tracing/src/span.rs')
-rw-r--r-- | third_party/rust/tracing/src/span.rs | 1623 |
1 files changed, 1623 insertions, 0 deletions
diff --git a/third_party/rust/tracing/src/span.rs b/third_party/rust/tracing/src/span.rs new file mode 100644 index 0000000000..58822f4d9b --- /dev/null +++ b/third_party/rust/tracing/src/span.rs @@ -0,0 +1,1623 @@ +//! Spans represent periods of time in which a program was executing in a +//! particular context. +//! +//! A span consists of [fields], user-defined key-value pairs of arbitrary data +//! that describe the context the span represents, and a set of fixed attributes +//! that describe all `tracing` spans and events. Attributes describing spans +//! include: +//! +//! - An [`Id`] assigned by the subscriber that uniquely identifies it in relation +//! to other spans. +//! - The span's [parent] in the trace tree. +//! - [Metadata] that describes static characteristics of all spans +//! originating from that callsite, such as its name, source code location, +//! [verbosity level], and the names of its fields. +//! +//! # Creating Spans +//! +//! Spans are created using the [`span!`] macro. This macro is invoked with the +//! following arguments, in order: +//! +//! - The [`target`] and/or [`parent`][parent] attributes, if the user wishes to +//! override their default values. +//! - The span's [verbosity level] +//! - A string literal providing the span's name. +//! - Finally, between zero and 32 arbitrary key/value fields. +//! +//! [`target`]: super::Metadata::target +//! +//! For example: +//! ```rust +//! use tracing::{span, Level}; +//! +//! /// Construct a new span at the `INFO` level named "my_span", with a single +//! /// field named answer , with the value `42`. +//! let my_span = span!(Level::INFO, "my_span", answer = 42); +//! ``` +//! +//! The documentation for the [`span!`] macro provides additional examples of +//! the various options that exist when creating spans. +//! +//! The [`trace_span!`], [`debug_span!`], [`info_span!`], [`warn_span!`], and +//! [`error_span!`] exist as shorthand for constructing spans at various +//! verbosity levels. +//! +//! ## Recording Span Creation +//! +//! The [`Attributes`] type contains data associated with a span, and is +//! provided to the [`Subscriber`] when a new span is created. It contains +//! the span's metadata, the ID of [the span's parent][parent] if one was +//! explicitly set, and any fields whose values were recorded when the span was +//! constructed. The subscriber, which is responsible for recording `tracing` +//! data, can then store or record these values. +//! +//! # The Span Lifecycle +//! +//! ## Entering a Span +//! +//! A thread of execution is said to _enter_ a span when it begins executing, +//! and _exit_ the span when it switches to another context. Spans may be +//! entered through the [`enter`], [`entered`], and [`in_scope`] methods. +//! +//! The [`enter`] method enters a span, returning a [guard] that exits the span +//! when dropped +//! ``` +//! # use tracing::{span, Level}; +//! let my_var: u64 = 5; +//! let my_span = span!(Level::TRACE, "my_span", my_var); +//! +//! // `my_span` exists but has not been entered. +//! +//! // Enter `my_span`... +//! let _enter = my_span.enter(); +//! +//! // Perform some work inside of the context of `my_span`... +//! // Dropping the `_enter` guard will exit the span. +//!``` +//! +//! <div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;"> +//! <strong>Warning</strong>: In asynchronous code that uses async/await syntax, +//! <code>Span::enter</code> may produce incorrect traces if the returned drop +//! guard is held across an await point. See +//! <a href="struct.Span.html#in-asynchronous-code">the method documentation</a> +//! for details. +//! </pre></div> +//! +//! The [`entered`] method is analogous to [`enter`], but moves the span into +//! the returned guard, rather than borrowing it. This allows creating and +//! entering a span in a single expression: +//! +//! ``` +//! # use tracing::{span, Level}; +//! // Create a span and enter it, returning a guard: +//! let span = span!(Level::INFO, "my_span").entered(); +//! +//! // We are now inside the span! Like `enter()`, the guard returned by +//! // `entered()` will exit the span when it is dropped... +//! +//! // ...but, it can also be exited explicitly, returning the `Span` +//! // struct: +//! let span = span.exit(); +//! ``` +//! +//! Finally, [`in_scope`] takes a closure or function pointer and executes it +//! inside the span: +//! +//! ``` +//! # use tracing::{span, Level}; +//! let my_var: u64 = 5; +//! let my_span = span!(Level::TRACE, "my_span", my_var = &my_var); +//! +//! my_span.in_scope(|| { +//! // perform some work in the context of `my_span`... +//! }); +//! +//! // Perform some work outside of the context of `my_span`... +//! +//! my_span.in_scope(|| { +//! // Perform some more work in the context of `my_span`. +//! }); +//! ``` +//! +//! <pre class="ignore" style="white-space:normal;font:inherit;"> +//! <strong>Note</strong>: Since entering a span takes <code>&self</code>, and +//! <code>Span</code>s are <code>Clone</code>, <code>Send</code>, and +//! <code>Sync</code>, it is entirely valid for multiple threads to enter the +//! same span concurrently. +//! </pre> +//! +//! ## Span Relationships +//! +//! Spans form a tree structure — unless it is a root span, all spans have a +//! _parent_, and may have one or more _children_. When a new span is created, +//! the current span becomes the new span's parent. The total execution time of +//! a span consists of the time spent in that span and in the entire subtree +//! represented by its children. Thus, a parent span always lasts for at least +//! as long as the longest-executing span in its subtree. +//! +//! ``` +//! # use tracing::{Level, span}; +//! // this span is considered the "root" of a new trace tree: +//! span!(Level::INFO, "root").in_scope(|| { +//! // since we are now inside "root", this span is considered a child +//! // of "root": +//! span!(Level::DEBUG, "outer_child").in_scope(|| { +//! // this span is a child of "outer_child", which is in turn a +//! // child of "root": +//! span!(Level::TRACE, "inner_child").in_scope(|| { +//! // and so on... +//! }); +//! }); +//! // another span created here would also be a child of "root". +//! }); +//!``` +//! +//! In addition, the parent of a span may be explicitly specified in +//! the `span!` macro. For example: +//! +//! ```rust +//! # use tracing::{Level, span}; +//! // Create, but do not enter, a span called "foo". +//! let foo = span!(Level::INFO, "foo"); +//! +//! // Create and enter a span called "bar". +//! let bar = span!(Level::INFO, "bar"); +//! let _enter = bar.enter(); +//! +//! // Although we have currently entered "bar", "baz"'s parent span +//! // will be "foo". +//! let baz = span!(parent: &foo, Level::INFO, "baz"); +//! ``` +//! +//! A child span should typically be considered _part_ of its parent. For +//! example, if a subscriber is recording the length of time spent in various +//! spans, it should generally include the time spent in a span's children as +//! part of that span's duration. +//! +//! In addition to having zero or one parent, a span may also _follow from_ any +//! number of other spans. This indicates a causal relationship between the span +//! and the spans that it follows from, but a follower is *not* typically +//! considered part of the duration of the span it follows. Unlike the parent, a +//! span may record that it follows from another span after it is created, using +//! the [`follows_from`] method. +//! +//! As an example, consider a listener task in a server. As the listener accepts +//! incoming connections, it spawns new tasks that handle those connections. We +//! might want to have a span representing the listener, and instrument each +//! spawned handler task with its own span. We would want our instrumentation to +//! record that the handler tasks were spawned as a result of the listener task. +//! However, we might not consider the handler tasks to be _part_ of the time +//! spent in the listener task, so we would not consider those spans children of +//! the listener span. Instead, we would record that the handler tasks follow +//! from the listener, recording the causal relationship but treating the spans +//! as separate durations. +//! +//! ## Closing Spans +//! +//! Execution may enter and exit a span multiple times before that span is +//! _closed_. Consider, for example, a future which has an associated +//! span and enters that span every time it is polled: +//! ```rust +//! # use std::future::Future; +//! # use std::task::{Context, Poll}; +//! # use std::pin::Pin; +//! struct MyFuture { +//! // data +//! span: tracing::Span, +//! } +//! +//! impl Future for MyFuture { +//! type Output = (); +//! +//! fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> { +//! let _enter = self.span.enter(); +//! // Do actual future work... +//! # Poll::Ready(()) +//! } +//! } +//! ``` +//! +//! If this future was spawned on an executor, it might yield one or more times +//! before `poll` returns [`Poll::Ready`]. If the future were to yield, then +//! the executor would move on to poll the next future, which may _also_ enter +//! an associated span or series of spans. Therefore, it is valid for a span to +//! be entered repeatedly before it completes. Only the time when that span or +//! one of its children was the current span is considered to be time spent in +//! that span. A span which is not executing and has not yet been closed is said +//! to be _idle_. +//! +//! Because spans may be entered and exited multiple times before they close, +//! [`Subscriber`]s have separate trait methods which are called to notify them +//! of span exits and when span handles are dropped. When execution exits a +//! span, [`exit`] will always be called with that span's ID to notify the +//! subscriber that the span has been exited. When span handles are dropped, the +//! [`drop_span`] method is called with that span's ID. The subscriber may use +//! this to determine whether or not the span will be entered again. +//! +//! If there is only a single handle with the capacity to exit a span, dropping +//! that handle "closes" the span, since the capacity to enter it no longer +//! exists. For example: +//! ``` +//! # use tracing::{Level, span}; +//! { +//! span!(Level::TRACE, "my_span").in_scope(|| { +//! // perform some work in the context of `my_span`... +//! }); // --> Subscriber::exit(my_span) +//! +//! // The handle to `my_span` only lives inside of this block; when it is +//! // dropped, the subscriber will be informed via `drop_span`. +//! +//! } // --> Subscriber::drop_span(my_span) +//! ``` +//! +//! However, if multiple handles exist, the span can still be re-entered even if +//! one or more is dropped. For determining when _all_ handles to a span have +//! been dropped, `Subscriber`s have a [`clone_span`] method, which is called +//! every time a span handle is cloned. Combined with `drop_span`, this may be +//! used to track the number of handles to a given span — if `drop_span` has +//! been called one more time than the number of calls to `clone_span` for a +//! given ID, then no more handles to the span with that ID exist. The +//! subscriber may then treat it as closed. +//! +//! # When to use spans +//! +//! As a rule of thumb, spans should be used to represent discrete units of work +//! (e.g., a given request's lifetime in a server) or periods of time spent in a +//! given context (e.g., time spent interacting with an instance of an external +//! system, such as a database). +//! +//! Which scopes in a program correspond to new spans depend somewhat on user +//! intent. For example, consider the case of a loop in a program. Should we +//! construct one span and perform the entire loop inside of that span, like: +//! +//! ```rust +//! # use tracing::{Level, span}; +//! # let n = 1; +//! let span = span!(Level::TRACE, "my_loop"); +//! let _enter = span.enter(); +//! for i in 0..n { +//! # let _ = i; +//! // ... +//! } +//! ``` +//! Or, should we create a new span for each iteration of the loop, as in: +//! ```rust +//! # use tracing::{Level, span}; +//! # let n = 1u64; +//! for i in 0..n { +//! let span = span!(Level::TRACE, "my_loop", iteration = i); +//! let _enter = span.enter(); +//! // ... +//! } +//! ``` +//! +//! Depending on the circumstances, we might want to do either, or both. For +//! example, if we want to know how long was spent in the loop overall, we would +//! create a single span around the entire loop; whereas if we wanted to know how +//! much time was spent in each individual iteration, we would enter a new span +//! on every iteration. +//! +//! [fields]: super::field +//! [Metadata]: super::Metadata +//! [verbosity level]: super::Level +//! [`Poll::Ready`]: std::task::Poll::Ready +//! [`span!`]: super::span! +//! [`trace_span!`]: super::trace_span! +//! [`debug_span!`]: super::debug_span! +//! [`info_span!`]: super::info_span! +//! [`warn_span!`]: super::warn_span! +//! [`error_span!`]: super::error_span! +//! [`clone_span`]: super::subscriber::Subscriber::clone_span() +//! [`drop_span`]: super::subscriber::Subscriber::drop_span() +//! [`exit`]: super::subscriber::Subscriber::exit +//! [`Subscriber`]: super::subscriber::Subscriber +//! [`enter`]: Span::enter() +//! [`entered`]: Span::entered() +//! [`in_scope`]: Span::in_scope() +//! [`follows_from`]: Span::follows_from() +//! [guard]: Entered +//! [parent]: #span-relationships +pub use tracing_core::span::{Attributes, Id, Record}; + +use crate::stdlib::{ + cmp, fmt, + hash::{Hash, Hasher}, + marker::PhantomData, + mem, + ops::Deref, +}; +use crate::{ + dispatcher::{self, Dispatch}, + field, Metadata, +}; + +/// Trait implemented by types which have a span `Id`. +pub trait AsId: crate::sealed::Sealed { + /// Returns the `Id` of the span that `self` corresponds to, or `None` if + /// this corresponds to a disabled span. + fn as_id(&self) -> Option<&Id>; +} + +/// A handle representing a span, with the capability to enter the span if it +/// exists. +/// +/// If the span was rejected by the current `Subscriber`'s filter, entering the +/// span will silently do nothing. Thus, the handle can be used in the same +/// manner regardless of whether or not the trace is currently being collected. +#[derive(Clone)] +pub struct Span { + /// A handle used to enter the span when it is not executing. + /// + /// If this is `None`, then the span has either closed or was never enabled. + inner: Option<Inner>, + /// Metadata describing the span. + /// + /// This might be `Some` even if `inner` is `None`, in the case that the + /// span is disabled but the metadata is needed for `log` support. + meta: Option<&'static Metadata<'static>>, +} + +/// A handle representing the capacity to enter a span which is known to exist. +/// +/// Unlike `Span`, this type is only constructed for spans which _have_ been +/// enabled by the current filter. This type is primarily used for implementing +/// span handles; users should typically not need to interact with it directly. +#[derive(Debug)] +pub(crate) struct Inner { + /// The span's ID, as provided by `subscriber`. + id: Id, + + /// The subscriber that will receive events relating to this span. + /// + /// This should be the same subscriber that provided this span with its + /// `id`. + subscriber: Dispatch, +} + +/// A guard representing a span which has been entered and is currently +/// executing. +/// +/// When the guard is dropped, the span will be exited. +/// +/// This is returned by the [`Span::enter`] function. +/// +/// [`Span::enter`]: super::Span::enter +#[derive(Debug)] +#[must_use = "once a span has been entered, it should be exited"] +pub struct Entered<'a> { + span: &'a Span, +} + +/// An owned version of [`Entered`], a guard representing a span which has been +/// entered and is currently executing. +/// +/// When the guard is dropped, the span will be exited. +/// +/// This is returned by the [`Span::entered`] function. +/// +/// [`Span::entered`]: super::Span::entered() +#[derive(Debug)] +#[must_use = "once a span has been entered, it should be exited"] +pub struct EnteredSpan { + span: Span, + + /// ```compile_fail + /// use tracing::span::*; + /// trait AssertSend: Send {} + /// + /// impl AssertSend for EnteredSpan {} + /// ``` + _not_send: PhantomNotSend, +} + +/// `log` target for all span lifecycle (creation/enter/exit/close) records. +#[cfg(feature = "log")] +const LIFECYCLE_LOG_TARGET: &str = "tracing::span"; +/// `log` target for span activity (enter/exit) records. +#[cfg(feature = "log")] +const ACTIVITY_LOG_TARGET: &str = "tracing::span::active"; + +// ===== impl Span ===== + +impl Span { + /// Constructs a new `Span` with the given [metadata] and set of + /// [field values]. + /// + /// The new span will be constructed by the currently-active [`Subscriber`], + /// with the current span as its parent (if one exists). + /// + /// After the span is constructed, [field values] and/or [`follows_from`] + /// annotations may be added to it. + /// + /// [metadata]: super::Metadata + /// [`Subscriber`]: super::subscriber::Subscriber + /// [field values]: super::field::ValueSet + /// [`follows_from`]: super::Span::follows_from + pub fn new(meta: &'static Metadata<'static>, values: &field::ValueSet<'_>) -> Span { + dispatcher::get_default(|dispatch| Self::new_with(meta, values, dispatch)) + } + + #[inline] + #[doc(hidden)] + pub fn new_with( + meta: &'static Metadata<'static>, + values: &field::ValueSet<'_>, + dispatch: &Dispatch, + ) -> Span { + let new_span = Attributes::new(meta, values); + Self::make_with(meta, new_span, dispatch) + } + + /// Constructs a new `Span` as the root of its own trace tree, with the + /// given [metadata] and set of [field values]. + /// + /// After the span is constructed, [field values] and/or [`follows_from`] + /// annotations may be added to it. + /// + /// [metadata]: super::Metadata + /// [field values]: super::field::ValueSet + /// [`follows_from`]: super::Span::follows_from + pub fn new_root(meta: &'static Metadata<'static>, values: &field::ValueSet<'_>) -> Span { + dispatcher::get_default(|dispatch| Self::new_root_with(meta, values, dispatch)) + } + + #[inline] + #[doc(hidden)] + pub fn new_root_with( + meta: &'static Metadata<'static>, + values: &field::ValueSet<'_>, + dispatch: &Dispatch, + ) -> Span { + let new_span = Attributes::new_root(meta, values); + Self::make_with(meta, new_span, dispatch) + } + + /// Constructs a new `Span` as child of the given parent span, with the + /// given [metadata] and set of [field values]. + /// + /// After the span is constructed, [field values] and/or [`follows_from`] + /// annotations may be added to it. + /// + /// [metadata]: super::Metadata + /// [field values]: super::field::ValueSet + /// [`follows_from`]: super::Span::follows_from + pub fn child_of( + parent: impl Into<Option<Id>>, + meta: &'static Metadata<'static>, + values: &field::ValueSet<'_>, + ) -> Span { + let mut parent = parent.into(); + dispatcher::get_default(move |dispatch| { + Self::child_of_with(Option::take(&mut parent), meta, values, dispatch) + }) + } + + #[inline] + #[doc(hidden)] + pub fn child_of_with( + parent: impl Into<Option<Id>>, + meta: &'static Metadata<'static>, + values: &field::ValueSet<'_>, + dispatch: &Dispatch, + ) -> Span { + let new_span = match parent.into() { + Some(parent) => Attributes::child_of(parent, meta, values), + None => Attributes::new_root(meta, values), + }; + Self::make_with(meta, new_span, dispatch) + } + + /// Constructs a new disabled span with the given `Metadata`. + /// + /// This should be used when a span is constructed from a known callsite, + /// but the subscriber indicates that it is disabled. + /// + /// Entering, exiting, and recording values on this span will not notify the + /// `Subscriber` but _may_ record log messages if the `log` feature flag is + /// enabled. + #[inline(always)] + pub fn new_disabled(meta: &'static Metadata<'static>) -> Span { + Self { + inner: None, + meta: Some(meta), + } + } + + /// Constructs a new span that is *completely disabled*. + /// + /// This can be used rather than `Option<Span>` to represent cases where a + /// span is not present. + /// + /// Entering, exiting, and recording values on this span will do nothing. + #[inline(always)] + pub const fn none() -> Span { + Self { + inner: None, + meta: None, + } + } + + /// Returns a handle to the span [considered by the `Subscriber`] to be the + /// current span. + /// + /// If the subscriber indicates that it does not track the current span, or + /// that the thread from which this function is called is not currently + /// inside a span, the returned span will be disabled. + /// + /// [considered by the `Subscriber`]: + /// super::subscriber::Subscriber::current_span + pub fn current() -> Span { + dispatcher::get_default(|dispatch| { + if let Some((id, meta)) = dispatch.current_span().into_inner() { + let id = dispatch.clone_span(&id); + Self { + inner: Some(Inner::new(id, dispatch)), + meta: Some(meta), + } + } else { + Self::none() + } + }) + } + + fn make_with( + meta: &'static Metadata<'static>, + new_span: Attributes<'_>, + dispatch: &Dispatch, + ) -> Span { + let attrs = &new_span; + let id = dispatch.new_span(attrs); + let inner = Some(Inner::new(id, dispatch)); + + let span = Self { + inner, + meta: Some(meta), + }; + + if_log_enabled! { *meta.level(), { + let target = if attrs.is_empty() { + LIFECYCLE_LOG_TARGET + } else { + meta.target() + }; + let values = attrs.values(); + span.log( + target, + level_to_log!(*meta.level()), + format_args!("++ {};{}", meta.name(), crate::log::LogValueSet { values, is_first: false }), + ); + }} + + span + } + + /// Enters this span, returning a guard that will exit the span when dropped. + /// + /// If this span is enabled by the current subscriber, then this function will + /// call [`Subscriber::enter`] with the span's [`Id`], and dropping the guard + /// will call [`Subscriber::exit`]. If the span is disabled, this does + /// nothing. + /// + /// # In Asynchronous Code + /// + /// **Warning**: in asynchronous code that uses [async/await syntax][syntax], + /// `Span::enter` should be used very carefully or avoided entirely. Holding + /// the drop guard returned by `Span::enter` across `.await` points will + /// result in incorrect traces. For example, + /// + /// ``` + /// # use tracing::info_span; + /// # async fn some_other_async_function() {} + /// async fn my_async_function() { + /// let span = info_span!("my_async_function"); + /// + /// // WARNING: This span will remain entered until this + /// // guard is dropped... + /// let _enter = span.enter(); + /// // ...but the `await` keyword may yield, causing the + /// // runtime to switch to another task, while remaining in + /// // this span! + /// some_other_async_function().await + /// + /// // ... + /// } + /// ``` + /// + /// The drop guard returned by `Span::enter` exits the span when it is + /// dropped. When an async function or async block yields at an `.await` + /// point, the current scope is _exited_, but values in that scope are + /// **not** dropped (because the async block will eventually resume + /// execution from that await point). This means that _another_ task will + /// begin executing while _remaining_ in the entered span. This results in + /// an incorrect trace. + /// + /// Instead of using `Span::enter` in asynchronous code, prefer the + /// following: + /// + /// * To enter a span for a synchronous section of code within an async + /// block or function, prefer [`Span::in_scope`]. Since `in_scope` takes a + /// synchronous closure and exits the span when the closure returns, the + /// span will always be exited before the next await point. For example: + /// ``` + /// # use tracing::info_span; + /// # async fn some_other_async_function(_: ()) {} + /// async fn my_async_function() { + /// let span = info_span!("my_async_function"); + /// + /// let some_value = span.in_scope(|| { + /// // run some synchronous code inside the span... + /// }); + /// + /// // This is okay! The span has already been exited before we reach + /// // the await point. + /// some_other_async_function(some_value).await; + /// + /// // ... + /// } + /// ``` + /// * For instrumenting asynchronous code, `tracing` provides the + /// [`Future::instrument` combinator][instrument] for + /// attaching a span to a future (async function or block). This will + /// enter the span _every_ time the future is polled, and exit it whenever + /// the future yields. + /// + /// `Instrument` can be used with an async block inside an async function: + /// ```ignore + /// # use tracing::info_span; + /// use tracing::Instrument; + /// + /// # async fn some_other_async_function() {} + /// async fn my_async_function() { + /// let span = info_span!("my_async_function"); + /// async move { + /// // This is correct! If we yield here, the span will be exited, + /// // and re-entered when we resume. + /// some_other_async_function().await; + /// + /// //more asynchronous code inside the span... + /// + /// } + /// // instrument the async block with the span... + /// .instrument(span) + /// // ...and await it. + /// .await + /// } + /// ``` + /// + /// It can also be used to instrument calls to async functions at the + /// callsite: + /// ```ignore + /// # use tracing::debug_span; + /// use tracing::Instrument; + /// + /// # async fn some_other_async_function() {} + /// async fn my_async_function() { + /// let some_value = some_other_async_function() + /// .instrument(debug_span!("some_other_async_function")) + /// .await; + /// + /// // ... + /// } + /// ``` + /// + /// * The [`#[instrument]` attribute macro][attr] can automatically generate + /// correct code when used on an async function: + /// + /// ```ignore + /// # async fn some_other_async_function() {} + /// #[tracing::instrument(level = "info")] + /// async fn my_async_function() { + /// + /// // This is correct! If we yield here, the span will be exited, + /// // and re-entered when we resume. + /// some_other_async_function().await; + /// + /// // ... + /// + /// } + /// ``` + /// + /// [syntax]: https://rust-lang.github.io/async-book/01_getting_started/04_async_await_primer.html + /// [`Span::in_scope`]: Span::in_scope() + /// [instrument]: crate::Instrument + /// [attr]: macro@crate::instrument + /// + /// # Examples + /// + /// ``` + /// # use tracing::{span, Level}; + /// let span = span!(Level::INFO, "my_span"); + /// let guard = span.enter(); + /// + /// // code here is within the span + /// + /// drop(guard); + /// + /// // code here is no longer within the span + /// + /// ``` + /// + /// Guards need not be explicitly dropped: + /// + /// ``` + /// # use tracing::trace_span; + /// fn my_function() -> String { + /// // enter a span for the duration of this function. + /// let span = trace_span!("my_function"); + /// let _enter = span.enter(); + /// + /// // anything happening in functions we call is still inside the span... + /// my_other_function(); + /// + /// // returning from the function drops the guard, exiting the span. + /// return "Hello world".to_owned(); + /// } + /// + /// fn my_other_function() { + /// // ... + /// } + /// ``` + /// + /// Sub-scopes may be created to limit the duration for which the span is + /// entered: + /// + /// ``` + /// # use tracing::{info, info_span}; + /// let span = info_span!("my_great_span"); + /// + /// { + /// let _enter = span.enter(); + /// + /// // this event occurs inside the span. + /// info!("i'm in the span!"); + /// + /// // exiting the scope drops the guard, exiting the span. + /// } + /// + /// // this event is not inside the span. + /// info!("i'm outside the span!") + /// ``` + /// + /// [`Subscriber::enter`]: super::subscriber::Subscriber::enter() + /// [`Subscriber::exit`]: super::subscriber::Subscriber::exit() + /// [`Id`]: super::Id + #[inline(always)] + pub fn enter(&self) -> Entered<'_> { + self.do_enter(); + Entered { span: self } + } + + /// Enters this span, consuming it and returning a [guard][`EnteredSpan`] + /// that will exit the span when dropped. + /// + /// <pre class="compile_fail" style="white-space:normal;font:inherit;"> + /// <strong>Warning</strong>: In asynchronous code that uses async/await syntax, + /// <code>Span::entered</code> may produce incorrect traces if the returned drop + /// guard is held across an await point. See <a href="#in-asynchronous-code">the + /// <code>Span::enter</code> documentation</a> for details. + /// </pre> + /// + /// + /// If this span is enabled by the current subscriber, then this function will + /// call [`Subscriber::enter`] with the span's [`Id`], and dropping the guard + /// will call [`Subscriber::exit`]. If the span is disabled, this does + /// nothing. + /// + /// This is similar to the [`Span::enter`] method, except that it moves the + /// span by value into the returned guard, rather than borrowing it. + /// Therefore, this method can be used to create and enter a span in a + /// single expression, without requiring a `let`-binding. For example: + /// + /// ``` + /// # use tracing::info_span; + /// let _span = info_span!("something_interesting").entered(); + /// ``` + /// rather than: + /// ``` + /// # use tracing::info_span; + /// let span = info_span!("something_interesting"); + /// let _e = span.enter(); + /// ``` + /// + /// Furthermore, `entered` may be used when the span must be stored in some + /// other struct or be passed to a function while remaining entered. + /// + /// <pre class="ignore" style="white-space:normal;font:inherit;"> + /// <strong>Note</strong>: The returned <a href="../struct.EnteredSpan.html"> + /// <code>EnteredSpan</a></code> guard does not implement <code>Send</code>. + /// Dropping the guard will exit <em>this</em> span, and if the guard is sent + /// to another thread and dropped there, that thread may never have entered + /// this span. Thus, <code>EnteredSpan</code>s should not be sent between threads. + /// </pre> + /// + /// [syntax]: https://rust-lang.github.io/async-book/01_getting_started/04_async_await_primer.html + /// + /// # Examples + /// + /// The returned guard can be [explicitly exited][EnteredSpan::exit], + /// returning the un-entered span: + /// + /// ``` + /// # use tracing::{Level, span}; + /// let span = span!(Level::INFO, "doing_something").entered(); + /// + /// // code here is within the span + /// + /// // explicitly exit the span, returning it + /// let span = span.exit(); + /// + /// // code here is no longer within the span + /// + /// // enter the span again + /// let span = span.entered(); + /// + /// // now we are inside the span once again + /// ``` + /// + /// Guards need not be explicitly dropped: + /// + /// ``` + /// # use tracing::trace_span; + /// fn my_function() -> String { + /// // enter a span for the duration of this function. + /// let span = trace_span!("my_function").entered(); + /// + /// // anything happening in functions we call is still inside the span... + /// my_other_function(); + /// + /// // returning from the function drops the guard, exiting the span. + /// return "Hello world".to_owned(); + /// } + /// + /// fn my_other_function() { + /// // ... + /// } + /// ``` + /// + /// Since the [`EnteredSpan`] guard can dereference to the [`Span`] itself, + /// the span may still be accessed while entered. For example: + /// + /// ```rust + /// # use tracing::info_span; + /// use tracing::field; + /// + /// // create the span with an empty field, and enter it. + /// let span = info_span!("my_span", some_field = field::Empty).entered(); + /// + /// // we can still record a value for the field while the span is entered. + /// span.record("some_field", &"hello world!"); + /// ``` + /// + + /// [`Subscriber::enter`]: super::subscriber::Subscriber::enter() + /// [`Subscriber::exit`]: super::subscriber::Subscriber::exit() + /// [`Id`]: super::Id + #[inline(always)] + pub fn entered(self) -> EnteredSpan { + self.do_enter(); + EnteredSpan { + span: self, + _not_send: PhantomNotSend, + } + } + + /// Returns this span, if it was [enabled] by the current [`Subscriber`], or + /// the [current span] (whose lexical distance may be further than expected), + /// if this span [is disabled]. + /// + /// This method can be useful when propagating spans to spawned threads or + /// [async tasks]. Consider the following: + /// + /// ``` + /// let _parent_span = tracing::info_span!("parent").entered(); + /// + /// // ... + /// + /// let child_span = tracing::debug_span!("child"); + /// + /// std::thread::spawn(move || { + /// let _entered = child_span.entered(); + /// + /// tracing::info!("spawned a thread!"); + /// + /// // ... + /// }); + /// ``` + /// + /// If the current [`Subscriber`] enables the [`DEBUG`] level, then both + /// the "parent" and "child" spans will be enabled. Thus, when the "spawaned + /// a thread!" event occurs, it will be inside of the "child" span. Because + /// "parent" is the parent of "child", the event will _also_ be inside of + /// "parent". + /// + /// However, if the [`Subscriber`] only enables the [`INFO`] level, the "child" + /// span will be disabled. When the thread is spawned, the + /// `child_span.entered()` call will do nothing, since "child" is not + /// enabled. In this case, the "spawned a thread!" event occurs outside of + /// *any* span, since the "child" span was responsible for propagating its + /// parent to the spawned thread. + /// + /// If this is not the desired behavior, `Span::or_current` can be used to + /// ensure that the "parent" span is propagated in both cases, either as a + /// parent of "child" _or_ directly. For example: + /// + /// ``` + /// let _parent_span = tracing::info_span!("parent").entered(); + /// + /// // ... + /// + /// // If DEBUG is enabled, then "child" will be enabled, and `or_current` + /// // returns "child". Otherwise, if DEBUG is not enabled, "child" will be + /// // disabled, and `or_current` returns "parent". + /// let child_span = tracing::debug_span!("child").or_current(); + /// + /// std::thread::spawn(move || { + /// let _entered = child_span.entered(); + /// + /// tracing::info!("spawned a thread!"); + /// + /// // ... + /// }); + /// ``` + /// + /// When spawning [asynchronous tasks][async tasks], `Span::or_current` can + /// be used similarly, in combination with [`instrument`]: + /// + /// ``` + /// use tracing::Instrument; + /// # // lol + /// # mod tokio { + /// # pub(super) fn spawn(_: impl std::future::Future) {} + /// # } + /// + /// let _parent_span = tracing::info_span!("parent").entered(); + /// + /// // ... + /// + /// let child_span = tracing::debug_span!("child"); + /// + /// tokio::spawn( + /// async { + /// tracing::info!("spawned a task!"); + /// + /// // ... + /// + /// }.instrument(child_span.or_current()) + /// ); + /// ``` + /// + /// In general, `or_current` should be preferred over nesting an + /// [`instrument`] call inside of an [`in_current_span`] call, as using + /// `or_current` will be more efficient. + /// + /// ``` + /// use tracing::Instrument; + /// # // lol + /// # mod tokio { + /// # pub(super) fn spawn(_: impl std::future::Future) {} + /// # } + /// async fn my_async_fn() { + /// // ... + /// } + /// + /// let _parent_span = tracing::info_span!("parent").entered(); + /// + /// // Do this: + /// tokio::spawn( + /// my_async_fn().instrument(tracing::debug_span!("child").or_current()) + /// ); + /// + /// // ...rather than this: + /// tokio::spawn( + /// my_async_fn() + /// .instrument(tracing::debug_span!("child")) + /// .in_current_span() + /// ); + /// ``` + /// + /// [enabled]: crate::Subscriber::enabled + /// [`Subscriber`]: crate::Subscriber + /// [current span]: Span::current + /// [is disabled]: Span::is_disabled + /// [`INFO`]: crate::Level::INFO + /// [`DEBUG`]: crate::Level::DEBUG + /// [async tasks]: std::task + /// [`instrument`]: crate::instrument::Instrument::instrument + /// [`in_current_span`]: crate::instrument::Instrument::in_current_span + pub fn or_current(self) -> Self { + if self.is_disabled() { + return Self::current(); + } + self + } + + #[inline(always)] + fn do_enter(&self) { + if let Some(inner) = self.inner.as_ref() { + inner.subscriber.enter(&inner.id); + } + + if_log_enabled! { crate::Level::TRACE, { + if let Some(_meta) = self.meta { + self.log(ACTIVITY_LOG_TARGET, log::Level::Trace, format_args!("-> {};", _meta.name())); + } + }} + } + + // Called from [`Entered`] and [`EnteredSpan`] drops. + // + // Running this behaviour on drop rather than with an explicit function + // call means that spans may still be exited when unwinding. + #[inline(always)] + fn do_exit(&self) { + if let Some(inner) = self.inner.as_ref() { + inner.subscriber.exit(&inner.id); + } + + if_log_enabled! { crate::Level::TRACE, { + if let Some(_meta) = self.meta { + self.log(ACTIVITY_LOG_TARGET, log::Level::Trace, format_args!("<- {};", _meta.name())); + } + }} + } + + /// Executes the given function in the context of this span. + /// + /// If this span is enabled, then this function enters the span, invokes `f` + /// and then exits the span. If the span is disabled, `f` will still be + /// invoked, but in the context of the currently-executing span (if there is + /// one). + /// + /// Returns the result of evaluating `f`. + /// + /// # Examples + /// + /// ``` + /// # use tracing::{trace, span, Level}; + /// let my_span = span!(Level::TRACE, "my_span"); + /// + /// my_span.in_scope(|| { + /// // this event occurs within the span. + /// trace!("i'm in the span!"); + /// }); + /// + /// // this event occurs outside the span. + /// trace!("i'm not in the span!"); + /// ``` + /// + /// Calling a function and returning the result: + /// ``` + /// # use tracing::{info_span, Level}; + /// fn hello_world() -> String { + /// "Hello world!".to_owned() + /// } + /// + /// let span = info_span!("hello_world"); + /// // the span will be entered for the duration of the call to + /// // `hello_world`. + /// let a_string = span.in_scope(hello_world); + /// + pub fn in_scope<F: FnOnce() -> T, T>(&self, f: F) -> T { + let _enter = self.enter(); + f() + } + + /// Returns a [`Field`][super::field::Field] for the field with the + /// given `name`, if one exists, + pub fn field<Q: ?Sized>(&self, field: &Q) -> Option<field::Field> + where + Q: field::AsField, + { + self.metadata().and_then(|meta| field.as_field(meta)) + } + + /// Returns true if this `Span` has a field for the given + /// [`Field`][super::field::Field] or field name. + #[inline] + pub fn has_field<Q: ?Sized>(&self, field: &Q) -> bool + where + Q: field::AsField, + { + self.field(field).is_some() + } + + /// Records that the field described by `field` has the value `value`. + /// + /// This may be used with [`field::Empty`] to declare fields whose values + /// are not known when the span is created, and record them later: + /// ``` + /// use tracing::{trace_span, field}; + /// + /// // Create a span with two fields: `greeting`, with the value "hello world", and + /// // `parting`, without a value. + /// let span = trace_span!("my_span", greeting = "hello world", parting = field::Empty); + /// + /// // ... + /// + /// // Now, record a value for parting as well. + /// // (note that the field name is passed as a string slice) + /// span.record("parting", "goodbye world!"); + /// ``` + /// However, it may also be used to record a _new_ value for a field whose + /// value was already recorded: + /// ``` + /// use tracing::info_span; + /// # fn do_something() -> Result<(), ()> { Err(()) } + /// + /// // Initially, let's assume that our attempt to do something is going okay... + /// let span = info_span!("doing_something", is_okay = true); + /// let _e = span.enter(); + /// + /// match do_something() { + /// Ok(something) => { + /// // ... + /// } + /// Err(_) => { + /// // Things are no longer okay! + /// span.record("is_okay", false); + /// } + /// } + /// ``` + /// + /// <pre class="ignore" style="white-space:normal;font:inherit;"> + /// <strong>Note</strong>: The fields associated with a span are part + /// of its <a href="../struct.Metadata.html"><code>Metadata</code></a>. + /// The <a href="../struct.Metadata.html"><code>Metadata</code></a> + /// describing a particular span is constructed statically when the span + /// is created and cannot be extended later to add new fields. Therefore, + /// you cannot record a value for a field that was not specified when the + /// span was created: + /// </pre> + /// + /// ``` + /// use tracing::{trace_span, field}; + /// + /// // Create a span with two fields: `greeting`, with the value "hello world", and + /// // `parting`, without a value. + /// let span = trace_span!("my_span", greeting = "hello world", parting = field::Empty); + /// + /// // ... + /// + /// // Now, you try to record a value for a new field, `new_field`, which was not + /// // declared as `Empty` or populated when you created `span`. + /// // You won't get any error, but the assignment will have no effect! + /// span.record("new_field", "interesting_value_you_really_need"); + /// + /// // Instead, all fields that may be recorded after span creation should be declared up front, + /// // using field::Empty when a value is not known, as we did for `parting`. + /// // This `record` call will indeed replace field::Empty with "you will be remembered". + /// span.record("parting", "you will be remembered"); + /// ``` + /// + /// [`field::Empty`]: super::field::Empty + /// [`Metadata`]: super::Metadata + pub fn record<Q: ?Sized, V>(&self, field: &Q, value: V) -> &Self + where + Q: field::AsField, + V: field::Value, + { + if let Some(meta) = self.meta { + if let Some(field) = field.as_field(meta) { + self.record_all( + &meta + .fields() + .value_set(&[(&field, Some(&value as &dyn field::Value))]), + ); + } + } + + self + } + + /// Records all the fields in the provided `ValueSet`. + pub fn record_all(&self, values: &field::ValueSet<'_>) -> &Self { + let record = Record::new(values); + if let Some(ref inner) = self.inner { + inner.record(&record); + } + + if let Some(_meta) = self.meta { + if_log_enabled! { *_meta.level(), { + let target = if record.is_empty() { + LIFECYCLE_LOG_TARGET + } else { + _meta.target() + }; + self.log( + target, + level_to_log!(*_meta.level()), + format_args!("{};{}", _meta.name(), crate::log::LogValueSet { values, is_first: false }), + ); + }} + } + + self + } + + /// Returns `true` if this span was disabled by the subscriber and does not + /// exist. + /// + /// See also [`is_none`]. + /// + /// [`is_none`]: Span::is_none() + #[inline] + pub fn is_disabled(&self) -> bool { + self.inner.is_none() + } + + /// Returns `true` if this span was constructed by [`Span::none`] and is + /// empty. + /// + /// If `is_none` returns `true` for a given span, then [`is_disabled`] will + /// also return `true`. However, when a span is disabled by the subscriber + /// rather than constructed by `Span::none`, this method will return + /// `false`, while `is_disabled` will return `true`. + /// + /// [`Span::none`]: Span::none() + /// [`is_disabled`]: Span::is_disabled() + #[inline] + pub fn is_none(&self) -> bool { + self.is_disabled() && self.meta.is_none() + } + + /// Indicates that the span with the given ID has an indirect causal + /// relationship with this span. + /// + /// 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 this span is disabled, or the resulting follows-from relationship + /// would be invalid, this function will do nothing. + /// + /// # Examples + /// + /// Setting a `follows_from` relationship with a `Span`: + /// ``` + /// # use tracing::{span, Id, Level, Span}; + /// let span1 = span!(Level::INFO, "span_1"); + /// let span2 = span!(Level::DEBUG, "span_2"); + /// span2.follows_from(span1); + /// ``` + /// + /// Setting a `follows_from` relationship with the current span: + /// ``` + /// # use tracing::{span, Id, Level, Span}; + /// let span = span!(Level::INFO, "hello!"); + /// span.follows_from(Span::current()); + /// ``` + /// + /// Setting a `follows_from` relationship with a `Span` reference: + /// ``` + /// # use tracing::{span, Id, Level, Span}; + /// let span = span!(Level::INFO, "hello!"); + /// let curr = Span::current(); + /// span.follows_from(&curr); + /// ``` + /// + /// Setting a `follows_from` relationship with an `Id`: + /// ``` + /// # use tracing::{span, Id, Level, Span}; + /// let span = span!(Level::INFO, "hello!"); + /// let id = span.id(); + /// span.follows_from(id); + /// ``` + pub fn follows_from(&self, from: impl Into<Option<Id>>) -> &Self { + if let Some(ref inner) = self.inner { + if let Some(from) = from.into() { + inner.follows_from(&from); + } + } + self + } + + /// Returns this span's `Id`, if it is enabled. + pub fn id(&self) -> Option<Id> { + self.inner.as_ref().map(Inner::id) + } + + /// Returns this span's `Metadata`, if it is enabled. + pub fn metadata(&self) -> Option<&'static Metadata<'static>> { + self.meta + } + + #[cfg(feature = "log")] + #[inline] + fn log(&self, target: &str, level: log::Level, message: fmt::Arguments<'_>) { + if let Some(meta) = self.meta { + if level_to_log!(*meta.level()) <= log::max_level() { + let logger = log::logger(); + let log_meta = log::Metadata::builder().level(level).target(target).build(); + if logger.enabled(&log_meta) { + if let Some(ref inner) = self.inner { + logger.log( + &log::Record::builder() + .metadata(log_meta) + .module_path(meta.module_path()) + .file(meta.file()) + .line(meta.line()) + .args(format_args!("{} span={}", message, inner.id.into_u64())) + .build(), + ); + } else { + logger.log( + &log::Record::builder() + .metadata(log_meta) + .module_path(meta.module_path()) + .file(meta.file()) + .line(meta.line()) + .args(message) + .build(), + ); + } + } + } + } + } + + /// Invokes a function with a reference to this span's ID and subscriber. + /// + /// if this span is enabled, the provided function is called, and the result is returned. + /// If the span is disabled, the function is not called, and this method returns `None` + /// instead. + pub fn with_subscriber<T>(&self, f: impl FnOnce((&Id, &Dispatch)) -> T) -> Option<T> { + self.inner + .as_ref() + .map(|inner| f((&inner.id, &inner.subscriber))) + } +} + +impl cmp::PartialEq for Span { + fn eq(&self, other: &Self) -> bool { + match (&self.meta, &other.meta) { + (Some(this), Some(that)) => { + this.callsite() == that.callsite() && self.inner == other.inner + } + _ => false, + } + } +} + +impl Hash for Span { + fn hash<H: Hasher>(&self, hasher: &mut H) { + self.inner.hash(hasher); + } +} + +impl fmt::Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut span = f.debug_struct("Span"); + if let Some(meta) = self.meta { + span.field("name", &meta.name()) + .field("level", &meta.level()) + .field("target", &meta.target()); + + if let Some(ref inner) = self.inner { + span.field("id", &inner.id()); + } else { + span.field("disabled", &true); + } + + if let Some(ref path) = meta.module_path() { + span.field("module_path", &path); + } + + if let Some(ref line) = meta.line() { + span.field("line", &line); + } + + if let Some(ref file) = meta.file() { + span.field("file", &file); + } + } else { + span.field("none", &true); + } + + span.finish() + } +} + +impl<'a> From<&'a Span> for Option<&'a Id> { + fn from(span: &'a Span) -> Self { + span.inner.as_ref().map(|inner| &inner.id) + } +} + +impl<'a> From<&'a Span> for Option<Id> { + fn from(span: &'a Span) -> Self { + span.inner.as_ref().map(Inner::id) + } +} + +impl From<Span> for Option<Id> { + fn from(span: Span) -> Self { + span.inner.as_ref().map(Inner::id) + } +} + +impl<'a> From<&'a EnteredSpan> for Option<&'a Id> { + fn from(span: &'a EnteredSpan) -> Self { + span.inner.as_ref().map(|inner| &inner.id) + } +} + +impl<'a> From<&'a EnteredSpan> for Option<Id> { + fn from(span: &'a EnteredSpan) -> Self { + span.inner.as_ref().map(Inner::id) + } +} + +impl Drop for Span { + #[inline(always)] + fn drop(&mut self) { + if let Some(Inner { + ref id, + ref subscriber, + }) = self.inner + { + subscriber.try_close(id.clone()); + } + + if_log_enabled! { crate::Level::TRACE, { + if let Some(meta) = self.meta { + self.log( + LIFECYCLE_LOG_TARGET, + log::Level::Trace, + format_args!("-- {};", meta.name()), + ); + } + }} + } +} + +// ===== impl Inner ===== + +impl Inner { + /// Indicates that the span with the given ID has an indirect causal + /// relationship with this span. + /// + /// 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 this span is disabled, this function will do nothing. Otherwise, it + /// returns `Ok(())` if the other span was added as a precedent of this + /// span, or an error if this was not possible. + fn follows_from(&self, from: &Id) { + self.subscriber.record_follows_from(&self.id, from) + } + + /// Returns the span's ID. + fn id(&self) -> Id { + self.id.clone() + } + + fn record(&self, values: &Record<'_>) { + self.subscriber.record(&self.id, values) + } + + fn new(id: Id, subscriber: &Dispatch) -> Self { + Inner { + id, + subscriber: subscriber.clone(), + } + } +} + +impl cmp::PartialEq for Inner { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl Hash for Inner { + fn hash<H: Hasher>(&self, state: &mut H) { + self.id.hash(state); + } +} + +impl Clone for Inner { + fn clone(&self) -> Self { + Inner { + id: self.subscriber.clone_span(&self.id), + subscriber: self.subscriber.clone(), + } + } +} + +// ===== impl Entered ===== + +impl EnteredSpan { + /// Returns this span's `Id`, if it is enabled. + pub fn id(&self) -> Option<Id> { + self.inner.as_ref().map(Inner::id) + } + + /// Exits this span, returning the underlying [`Span`]. + #[inline] + pub fn exit(mut self) -> Span { + // One does not simply move out of a struct with `Drop`. + let span = mem::replace(&mut self.span, Span::none()); + span.do_exit(); + span + } +} + +impl Deref for EnteredSpan { + type Target = Span; + + #[inline] + fn deref(&self) -> &Span { + &self.span + } +} + +impl<'a> Drop for Entered<'a> { + #[inline(always)] + fn drop(&mut self) { + self.span.do_exit() + } +} + +impl Drop for EnteredSpan { + #[inline(always)] + fn drop(&mut self) { + self.span.do_exit() + } +} + +/// Technically, `EnteredSpan` _can_ implement both `Send` *and* +/// `Sync` safely. It doesn't, because it has a `PhantomNotSend` field, +/// specifically added in order to make it `!Send`. +/// +/// Sending an `EnteredSpan` guard between threads cannot cause memory unsafety. +/// However, it *would* result in incorrect behavior, so we add a +/// `PhantomNotSend` to prevent it from being sent between threads. This is +/// because it must be *dropped* on the same thread that it was created; +/// otherwise, the span will never be exited on the thread where it was entered, +/// and it will attempt to exit the span on a thread that may never have entered +/// it. However, we still want them to be `Sync` so that a struct holding an +/// `Entered` guard can be `Sync`. +/// +/// Thus, this is totally safe. +#[derive(Debug)] +struct PhantomNotSend { + ghost: PhantomData<*mut ()>, +} + +#[allow(non_upper_case_globals)] +const PhantomNotSend: PhantomNotSend = PhantomNotSend { ghost: PhantomData }; + +/// # Safety +/// +/// Trivially safe, as `PhantomNotSend` doesn't have any API. +unsafe impl Sync for PhantomNotSend {} + +#[cfg(test)] +mod test { + use super::*; + + trait AssertSend: Send {} + impl AssertSend for Span {} + + trait AssertSync: Sync {} + impl AssertSync for Span {} + impl AssertSync for Entered<'_> {} + impl AssertSync for EnteredSpan {} + + #[test] + fn test_record_backwards_compat() { + Span::current().record("some-key", &"some text"); + Span::current().record("some-key", &false); + } +} |