Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

View File

@@ -0,0 +1,433 @@
use tracing_core::{metadata::Metadata, span, subscriber::Subscriber, Event};
use crate::registry::{self, LookupSpan, SpanRef};
#[cfg(all(feature = "registry", feature = "std"))]
use crate::{filter::FilterId, registry::Registry};
/// Represents information about the current context provided to [`Layer`]s by the
/// wrapped [`Subscriber`].
///
/// To access [stored data] keyed by a span ID, implementors of the `Layer`
/// trait should ensure that the `Subscriber` type parameter is *also* bound by the
/// [`LookupSpan`]:
///
/// ```rust
/// use tracing::Subscriber;
/// use tracing_subscriber::{Layer, registry::LookupSpan};
///
/// pub struct MyLayer;
///
/// impl<S> Layer<S> for MyLayer
/// where
/// S: Subscriber + for<'a> LookupSpan<'a>,
/// {
/// // ...
/// }
/// ```
///
/// [`Layer`]: super::Layer
/// [`Subscriber`]: tracing_core::Subscriber
/// [stored data]: crate::registry::SpanRef
/// [`LookupSpan`]: crate::registry::LookupSpan
#[derive(Debug)]
pub struct Context<'a, S> {
subscriber: Option<&'a S>,
/// The bitmask of all [`Filtered`] layers that currently apply in this
/// context. If there is only a single [`Filtered`] wrapping the layer that
/// produced this context, then this is that filter's ID. Otherwise, if we
/// are in a nested tree with multiple filters, this is produced by
/// [`and`]-ing together the [`FilterId`]s of each of the filters that wrap
/// the current layer.
///
/// [`Filtered`]: crate::filter::Filtered
/// [`FilterId`]: crate::filter::FilterId
/// [`and`]: crate::filter::FilterId::and
#[cfg(all(feature = "registry", feature = "std"))]
filter: FilterId,
}
// === impl Context ===
impl<'a, S> Context<'a, S>
where
S: Subscriber,
{
pub(super) fn new(subscriber: &'a S) -> Self {
Self {
subscriber: Some(subscriber),
#[cfg(feature = "registry")]
filter: FilterId::none(),
}
}
/// Returns the wrapped subscriber's view of the current span.
#[inline]
pub fn current_span(&self) -> span::Current {
self.subscriber
.map(Subscriber::current_span)
// TODO: this would be more correct as "unknown", so perhaps
// `tracing-core` should make `Current::unknown()` public?
.unwrap_or_else(span::Current::none)
}
/// Returns whether the wrapped subscriber would enable the current span.
#[inline]
pub fn enabled(&self, metadata: &Metadata<'_>) -> bool {
self.subscriber
.map(|subscriber| subscriber.enabled(metadata))
// If this context is `None`, we are registering a callsite, so
// return `true` so that the layer does not incorrectly assume that
// the inner subscriber has disabled this metadata.
// TODO(eliza): would it be more correct for this to return an `Option`?
.unwrap_or(true)
}
/// Records the provided `event` with the wrapped subscriber.
///
/// # Notes
///
/// - The subscriber is free to expect that the event's callsite has been
/// [registered][register], and may panic or fail to observe the event if this is
/// not the case. The `tracing` crate's macros ensure that all events are
/// registered, but if the event is constructed through other means, the
/// user is responsible for ensuring that [`register_callsite`][register]
/// has been called prior to calling this method.
/// - This does _not_ call [`enabled`] on the inner subscriber. If the
/// caller wishes to apply the wrapped subscriber's filter before choosing
/// whether to record the event, it may first call [`Context::enabled`] to
/// check whether the event would be enabled. This allows `Layer`s to
/// elide constructing the event if it would not be recorded.
///
/// [register]: tracing_core::subscriber::Subscriber::register_callsite()
/// [`enabled`]: tracing_core::subscriber::Subscriber::enabled()
/// [`Context::enabled`]: Context::enabled()
#[inline]
pub fn event(&self, event: &Event<'_>) {
if let Some(subscriber) = self.subscriber {
subscriber.event(event);
}
}
/// Returns a [`SpanRef`] for the parent span of the given [`Event`], if
/// it has a parent.
///
/// If the event has an explicitly overridden parent, this method returns
/// a reference to that span. If the event's parent is the current span,
/// this returns a reference to the current span, if there is one. If this
/// returns `None`, then either the event's parent was explicitly set to
/// `None`, or the event's parent was defined contextually, but no span
/// is currently entered.
///
/// Compared to [`Context::current_span`] and [`Context::lookup_current`],
/// this respects overrides provided by the [`Event`].
///
/// Compared to [`Event::parent`], this automatically falls back to the contextual
/// span, if required.
///
/// ```rust
/// use tracing::{Event, Subscriber};
/// use tracing_subscriber::{
/// layer::{Context, Layer},
/// prelude::*,
/// registry::LookupSpan,
/// };
///
/// struct PrintingLayer;
/// impl<S> Layer<S> for PrintingLayer
/// where
/// S: Subscriber + for<'lookup> LookupSpan<'lookup>,
/// {
/// fn on_event(&self, event: &Event, ctx: Context<S>) {
/// let span = ctx.event_span(event);
/// println!("Event in span: {:?}", span.map(|s| s.name()));
/// }
/// }
///
/// tracing::subscriber::with_default(tracing_subscriber::registry().with(PrintingLayer), || {
/// tracing::info!("no span");
/// // Prints: Event in span: None
///
/// let span = tracing::info_span!("span");
/// tracing::info!(parent: &span, "explicitly specified");
/// // Prints: Event in span: Some("span")
///
/// let _guard = span.enter();
/// tracing::info!("contextual span");
/// // Prints: Event in span: Some("span")
/// });
/// ```
///
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: This requires the wrapped subscriber to
/// implement the <a href="../registry/trait.LookupSpan.html"><code>
/// LookupSpan</code></a> trait. See the documentation on
/// <a href="./struct.Context.html"><code>Context</code>'s
/// declaration</a> for details.
/// </pre>
#[inline]
pub fn event_span(&self, event: &Event<'_>) -> Option<SpanRef<'_, S>>
where
S: for<'lookup> LookupSpan<'lookup>,
{
if event.is_root() {
None
} else if event.is_contextual() {
self.lookup_current()
} else {
// TODO(eliza): this should handle parent IDs
event.parent().and_then(|id| self.span(id))
}
}
/// Returns metadata for the span with the given `id`, if it exists.
///
/// If this returns `None`, then no span exists for that ID (either it has
/// closed or the ID is invalid).
#[inline]
pub fn metadata(&self, id: &span::Id) -> Option<&'static Metadata<'static>>
where
S: for<'lookup> LookupSpan<'lookup>,
{
let span = self.span(id)?;
Some(span.metadata())
}
/// Returns [stored data] for the span with the given `id`, if it exists.
///
/// If this returns `None`, then no span exists for that ID (either it has
/// closed or the ID is invalid).
///
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: This requires the wrapped subscriber to
/// implement the <a href="../registry/trait.LookupSpan.html"><code>
/// LookupSpan</code></a> trait. See the documentation on
/// <a href="./struct.Context.html"><code>Context</code>'s
/// declaration</a> for details.
/// </pre>
///
/// [stored data]: crate::registry::SpanRef
#[inline]
pub fn span(&self, id: &span::Id) -> Option<registry::SpanRef<'_, S>>
where
S: for<'lookup> LookupSpan<'lookup>,
{
let span = self.subscriber.as_ref()?.span(id)?;
#[cfg(all(feature = "registry", feature = "std"))]
return span.try_with_filter(self.filter);
#[cfg(not(feature = "registry"))]
Some(span)
}
/// Returns `true` if an active span exists for the given `Id`.
///
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: This requires the wrapped subscriber to
/// implement the <a href="../registry/trait.LookupSpan.html"><code>
/// LookupSpan</code></a> trait. See the documentation on
/// <a href="./struct.Context.html"><code>Context</code>'s
/// declaration</a> for details.
/// </pre>
#[inline]
pub fn exists(&self, id: &span::Id) -> bool
where
S: for<'lookup> LookupSpan<'lookup>,
{
self.subscriber.as_ref().and_then(|s| s.span(id)).is_some()
}
/// Returns [stored data] for the span that the wrapped subscriber considers
/// to be the current.
///
/// If this returns `None`, then we are not currently within a span.
///
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: This requires the wrapped subscriber to
/// implement the <a href="../registry/trait.LookupSpan.html"><code>
/// LookupSpan</code></a> trait. See the documentation on
/// <a href="./struct.Context.html"><code>Context</code>'s
/// declaration</a> for details.
/// </pre>
///
/// [stored data]: crate::registry::SpanRef
#[inline]
pub fn lookup_current(&self) -> Option<registry::SpanRef<'_, S>>
where
S: for<'lookup> LookupSpan<'lookup>,
{
let subscriber = *self.subscriber.as_ref()?;
let current = subscriber.current_span();
let id = current.id()?;
let span = subscriber.span(id);
debug_assert!(
span.is_some(),
"the subscriber should have data for the current span ({:?})!",
id,
);
// If we found a span, and our per-layer filter enables it, return that
// span!
#[cfg(all(feature = "registry", feature = "std"))]
{
if let Some(span) = span?.try_with_filter(self.filter) {
Some(span)
} else {
// Otherwise, the span at the *top* of the stack is disabled by
// per-layer filtering, but there may be additional spans in the stack.
//
// Currently, `LookupSpan` doesn't have a nice way of exposing access to
// the whole span stack. However, if we can downcast the innermost
// subscriber to a a `Registry`, we can iterate over its current span
// stack.
//
// TODO(eliza): when https://github.com/tokio-rs/tracing/issues/1459 is
// implemented, change this to use that instead...
self.lookup_current_filtered(subscriber)
}
}
#[cfg(not(feature = "registry"))]
span
}
/// Slow path for when the current span is disabled by PLF and we have a
/// registry.
// This is called by `lookup_current` in the case that per-layer filtering
// is in use. `lookup_current` is allowed to be inlined, but this method is
// factored out to prevent the loop and (potentially-recursive) subscriber
// downcasting from being inlined if `lookup_current` is inlined.
#[inline(never)]
#[cfg(all(feature = "registry", feature = "std"))]
fn lookup_current_filtered<'lookup>(
&self,
subscriber: &'lookup S,
) -> Option<registry::SpanRef<'lookup, S>>
where
S: LookupSpan<'lookup>,
{
let registry = (subscriber as &dyn Subscriber).downcast_ref::<Registry>()?;
registry
.span_stack()
.iter()
.find_map(|id| subscriber.span(id)?.try_with_filter(self.filter))
}
/// Returns an iterator over the [stored data] for all the spans in the
/// current context, starting with the specified span and ending with the
/// root of the trace tree.
///
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: This returns the spans in reverse order (from leaf to root). Use
/// <a href="../registry/struct.Scope.html#method.from_root"><code>Scope::from_root</code></a>
/// in case root-to-leaf ordering is desired.
/// </pre>
///
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: This requires the wrapped subscriber to
/// implement the <a href="../registry/trait.LookupSpan.html"><code>
/// LookupSpan</code></a> trait. See the documentation on
/// <a href="./struct.Context.html"><code>Context</code>'s
/// declaration</a> for details.
/// </pre>
///
/// [stored data]: crate::registry::SpanRef
pub fn span_scope(&self, id: &span::Id) -> Option<registry::Scope<'_, S>>
where
S: for<'lookup> LookupSpan<'lookup>,
{
Some(self.span(id)?.scope())
}
/// Returns an iterator over the [stored data] for all the spans in the
/// current context, starting with the parent span of the specified event,
/// and ending with the root of the trace tree and ending with the current span.
///
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: Compared to <a href="#method.scope"><code>scope</code></a> this
/// returns the spans in reverse order (from leaf to root). Use
/// <a href="../registry/struct.Scope.html#method.from_root"><code>Scope::from_root</code></a>
/// in case root-to-leaf ordering is desired.
/// </pre>
///
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: This requires the wrapped subscriber to
/// implement the <a href="../registry/trait.LookupSpan.html"><code>
/// LookupSpan</code></a> trait. See the documentation on
/// <a href="./struct.Context.html"><code>Context</code>'s
/// declaration</a> for details.
/// </pre>
///
/// [stored data]: crate::registry::SpanRef
pub fn event_scope(&self, event: &Event<'_>) -> Option<registry::Scope<'_, S>>
where
S: for<'lookup> LookupSpan<'lookup>,
{
Some(self.event_span(event)?.scope())
}
#[cfg(all(feature = "registry", feature = "std"))]
pub(crate) fn with_filter(self, filter: FilterId) -> Self {
// If we already have our own `FilterId`, combine it with the provided
// one. That way, the new `FilterId` will consider a span to be disabled
// if it was disabled by the given `FilterId` *or* any `FilterId`s for
// layers "above" us in the stack.
//
// See the doc comment for `FilterId::and` for details.
let filter = self.filter.and(filter);
Self { filter, ..self }
}
#[cfg(all(feature = "registry", feature = "std"))]
pub(crate) fn is_enabled_for(&self, span: &span::Id, filter: FilterId) -> bool
where
S: for<'lookup> LookupSpan<'lookup>,
{
self.is_enabled_inner(span, filter).unwrap_or(false)
}
#[cfg(all(feature = "registry", feature = "std"))]
pub(crate) fn if_enabled_for(self, span: &span::Id, filter: FilterId) -> Option<Self>
where
S: for<'lookup> LookupSpan<'lookup>,
{
if self.is_enabled_inner(span, filter)? {
Some(self.with_filter(filter))
} else {
None
}
}
#[cfg(all(feature = "registry", feature = "std"))]
fn is_enabled_inner(&self, span: &span::Id, filter: FilterId) -> Option<bool>
where
S: for<'lookup> LookupSpan<'lookup>,
{
Some(self.span(span)?.is_enabled_for(filter))
}
}
impl<S> Context<'_, S> {
pub(crate) fn none() -> Self {
Self {
subscriber: None,
#[cfg(feature = "registry")]
filter: FilterId::none(),
}
}
}
impl<S> Clone for Context<'_, S> {
#[inline]
fn clone(&self) -> Self {
let subscriber = self.subscriber.as_ref().copied();
Context {
subscriber,
#[cfg(all(feature = "registry", feature = "std"))]
filter: self.filter,
}
}
}

View File

@@ -0,0 +1,554 @@
use tracing_core::{metadata::Metadata, span, Dispatch, Event, Interest, LevelFilter, Subscriber};
use crate::{
filter,
layer::{Context, Layer},
registry::LookupSpan,
};
#[cfg(all(feature = "registry", feature = "std"))]
use crate::{filter::FilterId, registry::Registry};
use core::{
any::{Any, TypeId},
cmp, fmt,
marker::PhantomData,
};
/// A [`Subscriber`] composed of a `Subscriber` wrapped by one or more
/// [`Layer`]s.
///
/// [`Layer`]: crate::Layer
/// [`Subscriber`]: tracing_core::Subscriber
#[derive(Clone)]
pub struct Layered<L, I, S = I> {
/// The layer.
layer: L,
/// The inner value that `self.layer` was layered onto.
///
/// If this is also a `Layer`, then this `Layered` will implement `Layer`.
/// If this is a `Subscriber`, then this `Layered` will implement
/// `Subscriber` instead.
inner: I,
// These booleans are used to determine how to combine `Interest`s and max
// level hints when per-layer filters are in use.
/// Is `self.inner` a `Registry`?
///
/// If so, when combining `Interest`s, we want to "bubble up" its
/// `Interest`.
inner_is_registry: bool,
/// Does `self.layer` have per-layer filters?
///
/// This will be true if:
/// - `self.inner` is a `Filtered`.
/// - `self.inner` is a tree of `Layered`s where _all_ arms of those
/// `Layered`s have per-layer filters.
///
/// Otherwise, if it's a `Layered` with one per-layer filter in one branch,
/// but a non-per-layer-filtered layer in the other branch, this will be
/// _false_, because the `Layered` is already handling the combining of
/// per-layer filter `Interest`s and max level hints with its non-filtered
/// `Layer`.
has_layer_filter: bool,
/// Does `self.inner` have per-layer filters?
///
/// This is determined according to the same rules as
/// `has_layer_filter` above.
inner_has_layer_filter: bool,
_s: PhantomData<fn(S)>,
}
// === impl Layered ===
impl<L, S> Layered<L, S>
where
L: Layer<S>,
S: 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 T))
}
}
}
}
impl<L, S> Subscriber for Layered<L, S>
where
L: Layer<S>,
S: Subscriber,
{
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
self.pick_interest(self.layer.register_callsite(metadata), || {
self.inner.register_callsite(metadata)
})
}
fn enabled(&self, metadata: &Metadata<'_>) -> bool {
if self.layer.enabled(metadata, self.ctx()) {
// if the outer layer enables the callsite metadata, ask the subscriber.
self.inner.enabled(metadata)
} else {
// otherwise, the callsite is disabled by the layer
// If per-layer filters are in use, and we are short-circuiting
// (rather than calling into the inner type), clear the current
// per-layer filter `enabled` state.
#[cfg(feature = "registry")]
filter::FilterState::clear_enabled();
false
}
}
fn max_level_hint(&self) -> Option<LevelFilter> {
self.pick_level_hint(
self.layer.max_level_hint(),
self.inner.max_level_hint(),
super::subscriber_is_none(&self.inner),
)
}
fn new_span(&self, span: &span::Attributes<'_>) -> span::Id {
let id = self.inner.new_span(span);
self.layer.on_new_span(span, &id, self.ctx());
id
}
fn record(&self, span: &span::Id, values: &span::Record<'_>) {
self.inner.record(span, values);
self.layer.on_record(span, values, self.ctx());
}
fn record_follows_from(&self, span: &span::Id, follows: &span::Id) {
self.inner.record_follows_from(span, follows);
self.layer.on_follows_from(span, follows, self.ctx());
}
fn event_enabled(&self, event: &Event<'_>) -> bool {
if self.layer.event_enabled(event, self.ctx()) {
// if the outer layer enables the event, ask the inner subscriber.
self.inner.event_enabled(event)
} else {
// otherwise, the event is disabled by this layer
false
}
}
fn event(&self, event: &Event<'_>) {
self.inner.event(event);
self.layer.on_event(event, self.ctx());
}
fn enter(&self, span: &span::Id) {
self.inner.enter(span);
self.layer.on_enter(span, self.ctx());
}
fn exit(&self, span: &span::Id) {
self.inner.exit(span);
self.layer.on_exit(span, self.ctx());
}
fn clone_span(&self, old: &span::Id) -> span::Id {
let new = self.inner.clone_span(old);
if &new != old {
self.layer.on_id_change(old, &new, self.ctx())
};
new
}
#[inline]
fn drop_span(&self, id: span::Id) {
self.try_close(id);
}
fn try_close(&self, id: span::Id) -> bool {
#[cfg(all(feature = "registry", feature = "std"))]
let subscriber = &self.inner as &dyn Subscriber;
#[cfg(all(feature = "registry", feature = "std"))]
let mut guard = subscriber
.downcast_ref::<Registry>()
.map(|registry| registry.start_close(id.clone()));
if self.inner.try_close(id.clone()) {
// If we have a registry's close guard, indicate that the span is
// closing.
#[cfg(all(feature = "registry", feature = "std"))]
{
if let Some(g) = guard.as_mut() {
g.set_closing()
};
}
self.layer.on_close(id, self.ctx());
true
} else {
false
}
}
#[inline]
fn current_span(&self) -> span::Current {
self.inner.current_span()
}
#[doc(hidden)]
unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
// Unlike the implementation of `Layer` for `Layered`, we don't have to
// handle the "magic PLF downcast marker" here. If a `Layered`
// implements `Subscriber`, we already know that the `inner` branch is
// going to contain something that doesn't have per-layer filters (the
// actual root `Subscriber`). Thus, a `Layered` that implements
// `Subscriber` will always be propagating the root subscriber's
// `Interest`/level hint, even if it includes a `Layer` that has
// per-layer filters, because it will only ever contain layers where
// _one_ child has per-layer filters.
//
// The complex per-layer filter detection logic is only relevant to
// *trees* of layers, which involve the `Layer` implementation for
// `Layered`, not *lists* of layers, where every `Layered` implements
// `Subscriber`. Of course, a linked list can be thought of as a
// degenerate tree...but luckily, we are able to make a type-level
// distinction between individual `Layered`s that are definitely
// list-shaped (their inner child implements `Subscriber`), and
// `Layered`s that might be tree-shaped (the inner child is also a
// `Layer`).
// If downcasting to `Self`, return a pointer to `self`.
if id == TypeId::of::<Self>() {
return Some(self as *const _ as *const ());
}
self.layer
.downcast_raw(id)
.or_else(|| self.inner.downcast_raw(id))
}
}
impl<S, A, B> Layer<S> for Layered<A, B, S>
where
A: Layer<S>,
B: Layer<S>,
S: Subscriber,
{
fn on_register_dispatch(&self, subscriber: &Dispatch) {
self.layer.on_register_dispatch(subscriber);
self.inner.on_register_dispatch(subscriber);
}
fn on_layer(&mut self, subscriber: &mut S) {
self.layer.on_layer(subscriber);
self.inner.on_layer(subscriber);
}
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
self.pick_interest(self.layer.register_callsite(metadata), || {
self.inner.register_callsite(metadata)
})
}
fn enabled(&self, metadata: &Metadata<'_>, ctx: Context<'_, S>) -> bool {
if self.layer.enabled(metadata, ctx.clone()) {
// if the outer subscriber enables the callsite metadata, ask the inner layer.
self.inner.enabled(metadata, ctx)
} else {
// otherwise, the callsite is disabled by this layer
false
}
}
fn max_level_hint(&self) -> Option<LevelFilter> {
self.pick_level_hint(
self.layer.max_level_hint(),
self.inner.max_level_hint(),
super::layer_is_none(&self.inner),
)
}
#[inline]
fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) {
self.inner.on_new_span(attrs, id, ctx.clone());
self.layer.on_new_span(attrs, id, ctx);
}
#[inline]
fn on_record(&self, span: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) {
self.inner.on_record(span, values, ctx.clone());
self.layer.on_record(span, values, ctx);
}
#[inline]
fn on_follows_from(&self, span: &span::Id, follows: &span::Id, ctx: Context<'_, S>) {
self.inner.on_follows_from(span, follows, ctx.clone());
self.layer.on_follows_from(span, follows, ctx);
}
#[inline]
fn event_enabled(&self, event: &Event<'_>, ctx: Context<'_, S>) -> bool {
if self.layer.event_enabled(event, ctx.clone()) {
// if the outer layer enables the event, ask the inner subscriber.
self.inner.event_enabled(event, ctx)
} else {
// otherwise, the event is disabled by this layer
false
}
}
#[inline]
fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
self.inner.on_event(event, ctx.clone());
self.layer.on_event(event, ctx);
}
#[inline]
fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
self.inner.on_enter(id, ctx.clone());
self.layer.on_enter(id, ctx);
}
#[inline]
fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
self.inner.on_exit(id, ctx.clone());
self.layer.on_exit(id, ctx);
}
#[inline]
fn on_close(&self, id: span::Id, ctx: Context<'_, S>) {
self.inner.on_close(id.clone(), ctx.clone());
self.layer.on_close(id, ctx);
}
#[inline]
fn on_id_change(&self, old: &span::Id, new: &span::Id, ctx: Context<'_, S>) {
self.inner.on_id_change(old, new, ctx.clone());
self.layer.on_id_change(old, new, ctx);
}
#[doc(hidden)]
unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
match id {
// If downcasting to `Self`, return a pointer to `self`.
id if id == TypeId::of::<Self>() => Some(self as *const _ as *const ()),
// Oh, we're looking for per-layer filters!
//
// This should only happen if we are inside of another `Layered`,
// and it's trying to determine how it should combine `Interest`s
// and max level hints.
//
// In that case, this `Layered` should be considered to be
// "per-layer filtered" if *both* the outer layer and the inner
// layer/subscriber have per-layer filters. Otherwise, this `Layered
// should *not* be considered per-layer filtered (even if one or the
// other has per layer filters). If only one `Layer` is per-layer
// filtered, *this* `Layered` will handle aggregating the `Interest`
// and level hints on behalf of its children, returning the
// aggregate (which is the value from the &non-per-layer-filtered*
// child).
//
// Yes, this rule *is* slightly counter-intuitive, but it's
// necessary due to a weird edge case that can occur when two
// `Layered`s where one side is per-layer filtered and the other
// isn't are `Layered` together to form a tree. If we didn't have
// this rule, we would actually end up *ignoring* `Interest`s from
// the non-per-layer-filtered layers, since both branches would
// claim to have PLF.
//
// If you don't understand this...that's fine, just don't mess with
// it. :)
id if filter::is_plf_downcast_marker(id) => {
self.layer.downcast_raw(id).and(self.inner.downcast_raw(id))
}
// Otherwise, try to downcast both branches normally...
_ => self
.layer
.downcast_raw(id)
.or_else(|| self.inner.downcast_raw(id)),
}
}
}
impl<'a, L, S> LookupSpan<'a> for Layered<L, S>
where
S: Subscriber + LookupSpan<'a>,
{
type Data = S::Data;
fn span_data(&'a self, id: &span::Id) -> Option<Self::Data> {
self.inner.span_data(id)
}
#[cfg(all(feature = "registry", feature = "std"))]
fn register_filter(&mut self) -> FilterId {
self.inner.register_filter()
}
}
impl<L, S> Layered<L, S>
where
S: Subscriber,
{
fn ctx(&self) -> Context<'_, S> {
Context::new(&self.inner)
}
}
impl<A, B, S> Layered<A, B, S>
where
A: Layer<S>,
S: Subscriber,
{
pub(super) fn new(layer: A, inner: B, inner_has_layer_filter: bool) -> Self {
#[cfg(all(feature = "registry", feature = "std"))]
let inner_is_registry = TypeId::of::<S>() == TypeId::of::<crate::registry::Registry>();
#[cfg(not(all(feature = "registry", feature = "std")))]
let inner_is_registry = false;
let inner_has_layer_filter = inner_has_layer_filter || inner_is_registry;
let has_layer_filter = filter::layer_has_plf(&layer);
Self {
layer,
inner,
has_layer_filter,
inner_has_layer_filter,
inner_is_registry,
_s: PhantomData,
}
}
fn pick_interest(&self, outer: Interest, inner: impl FnOnce() -> Interest) -> Interest {
if self.has_layer_filter {
return inner();
}
// If the outer layer has disabled the callsite, return now so that
// the inner layer/subscriber doesn't get its hopes up.
if outer.is_never() {
// If per-layer filters are in use, and we are short-circuiting
// (rather than calling into the inner type), clear the current
// per-layer filter interest state.
#[cfg(feature = "registry")]
filter::FilterState::take_interest();
return outer;
}
// The `inner` closure will call `inner.register_callsite()`. We do this
// before the `if` statement to ensure that the inner subscriber is
// informed that the callsite exists regardless of the outer layer's
// filtering decision.
let inner = inner();
if outer.is_sometimes() {
// if this interest is "sometimes", return "sometimes" to ensure that
// filters are reevaluated.
return outer;
}
// If there is a per-layer filter in the `inner` stack, and it returns
// `never`, change the interest to `sometimes`, because the `outer`
// layer didn't return `never`. This means that _some_ layer still wants
// to see that callsite, even though the inner stack's per-layer filter
// didn't want it. Therefore, returning `sometimes` will ensure
// `enabled` is called so that the per-layer filter can skip that
// span/event, while the `outer` layer still gets to see it.
if inner.is_never() && self.inner_has_layer_filter {
return Interest::sometimes();
}
// otherwise, allow the inner subscriber or subscriber to weigh in.
inner
}
fn pick_level_hint(
&self,
outer_hint: Option<LevelFilter>,
inner_hint: Option<LevelFilter>,
inner_is_none: bool,
) -> Option<LevelFilter> {
if self.inner_is_registry {
return outer_hint;
}
if self.has_layer_filter && self.inner_has_layer_filter {
return Some(cmp::max(outer_hint?, inner_hint?));
}
if self.has_layer_filter && inner_hint.is_none() {
return None;
}
if self.inner_has_layer_filter && outer_hint.is_none() {
return None;
}
// If the layer is `Option::None`, then we
// want to short-circuit the layer underneath, if it
// returns `None`, to override the `None` layer returning
// `Some(OFF)`, which should ONLY apply when there are
// no other layers that return `None`. Note this
// `None` does not == `Some(TRACE)`, it means
// something more like: "whatever all the other
// layers agree on, default to `TRACE` if none
// have an opinion". We also choose do this AFTER
// we check for per-layer filters, which
// have their own logic.
//
// Also note that this does come at some perf cost, but
// this function is only called on initialization and
// subscriber reloading.
if super::layer_is_none(&self.layer) {
return cmp::max(outer_hint, Some(inner_hint?));
}
// Similarly, if the layer on the inside is `None` and it returned an
// `Off` hint, we want to override that with the outer hint.
if inner_is_none && inner_hint == Some(LevelFilter::OFF) {
return outer_hint;
}
cmp::max(outer_hint, inner_hint)
}
}
impl<A, B, S> fmt::Debug for Layered<A, B, S>
where
A: fmt::Debug,
B: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(all(feature = "registry", feature = "std"))]
let alt = f.alternate();
let mut s = f.debug_struct("Layered");
// These additional fields are more verbose and usually only necessary
// for internal debugging purposes, so only print them if alternate mode
// is enabled.
#[cfg(all(feature = "registry", feature = "std"))]
{
if alt {
s.field("inner_is_registry", &self.inner_is_registry)
.field("has_layer_filter", &self.has_layer_filter)
.field("inner_has_layer_filter", &self.inner_has_layer_filter);
}
}
s.field("layer", &self.layer)
.field("inner", &self.inner)
.finish()
}
}

1910
vendor/tracing-subscriber/src/layer/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,308 @@
use super::*;
use tracing_core::subscriber::NoSubscriber;
#[derive(Debug)]
pub(crate) struct NopLayer;
impl<S: Subscriber> Layer<S> for NopLayer {}
#[allow(dead_code)]
struct NopLayer2;
impl<S: Subscriber> Layer<S> for NopLayer2 {}
/// A layer that holds a string.
///
/// Used to test that pointers returned by downcasting are actually valid.
struct StringLayer(&'static str);
impl<S: Subscriber> Layer<S> for StringLayer {}
struct StringLayer2(&'static str);
impl<S: Subscriber> Layer<S> for StringLayer2 {}
struct StringLayer3(&'static str);
impl<S: Subscriber> Layer<S> for StringLayer3 {}
pub(crate) struct StringSubscriber(&'static str);
impl Subscriber for StringSubscriber {
fn register_callsite(&self, _: &'static Metadata<'static>) -> Interest {
Interest::never()
}
fn enabled(&self, _: &Metadata<'_>) -> bool {
false
}
fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
span::Id::from_u64(1)
}
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) {}
}
fn assert_subscriber(_s: impl Subscriber) {}
fn assert_layer<S: Subscriber>(_l: &impl Layer<S>) {}
#[test]
fn layer_is_subscriber() {
let s = NopLayer.with_subscriber(NoSubscriber::default());
assert_subscriber(s)
}
#[test]
fn two_layers_are_subscriber() {
let s = NopLayer
.and_then(NopLayer)
.with_subscriber(NoSubscriber::default());
assert_subscriber(s)
}
#[test]
fn three_layers_are_subscriber() {
let s = NopLayer
.and_then(NopLayer)
.and_then(NopLayer)
.with_subscriber(NoSubscriber::default());
assert_subscriber(s)
}
#[test]
fn three_layers_are_layer() {
let layers = NopLayer.and_then(NopLayer).and_then(NopLayer);
assert_layer(&layers);
let _ = layers.with_subscriber(NoSubscriber::default());
}
#[test]
#[cfg(feature = "alloc")]
fn box_layer_is_layer() {
use alloc::boxed::Box;
let l: Box<dyn Layer<NoSubscriber> + Send + Sync> = Box::new(NopLayer);
assert_layer(&l);
l.with_subscriber(NoSubscriber::default());
}
#[test]
fn downcasts_to_subscriber() {
let s = NopLayer
.and_then(NopLayer)
.and_then(NopLayer)
.with_subscriber(StringSubscriber("subscriber"));
let subscriber =
<dyn Subscriber>::downcast_ref::<StringSubscriber>(&s).expect("subscriber should downcast");
assert_eq!(subscriber.0, "subscriber");
}
#[test]
fn downcasts_to_layer() {
let s = StringLayer("layer_1")
.and_then(StringLayer2("layer_2"))
.and_then(StringLayer3("layer_3"))
.with_subscriber(NoSubscriber::default());
let layer = <dyn Subscriber>::downcast_ref::<StringLayer>(&s).expect("layer 1 should downcast");
assert_eq!(layer.0, "layer_1");
let layer =
<dyn Subscriber>::downcast_ref::<StringLayer2>(&s).expect("layer 2 should downcast");
assert_eq!(layer.0, "layer_2");
let layer =
<dyn Subscriber>::downcast_ref::<StringLayer3>(&s).expect("layer 3 should downcast");
assert_eq!(layer.0, "layer_3");
}
#[cfg(all(feature = "registry", feature = "std"))]
mod registry_tests {
use super::*;
use crate::registry::LookupSpan;
#[test]
fn context_event_span() {
use std::sync::{Arc, Mutex};
let last_event_span = Arc::new(Mutex::new(None));
struct RecordingLayer {
last_event_span: Arc<Mutex<Option<&'static str>>>,
}
impl<S> Layer<S> for RecordingLayer
where
S: Subscriber + for<'lookup> LookupSpan<'lookup>,
{
fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
let span = ctx.event_span(event);
*self.last_event_span.lock().unwrap() = span.map(|s| s.name());
}
}
tracing::subscriber::with_default(
crate::registry().with(RecordingLayer {
last_event_span: last_event_span.clone(),
}),
|| {
tracing::info!("no span");
assert_eq!(*last_event_span.lock().unwrap(), None);
let parent = tracing::info_span!("explicit");
tracing::info!(parent: &parent, "explicit span");
assert_eq!(*last_event_span.lock().unwrap(), Some("explicit"));
let _guard = tracing::info_span!("contextual").entered();
tracing::info!("contextual span");
assert_eq!(*last_event_span.lock().unwrap(), Some("contextual"));
},
);
}
/// Tests for how max-level hints are calculated when combining layers
/// with and without per-layer filtering.
mod max_level_hints {
use super::*;
use crate::filter::*;
#[test]
fn mixed_with_unfiltered() {
let subscriber = crate::registry()
.with(NopLayer)
.with(NopLayer.with_filter(LevelFilter::INFO));
assert_eq!(subscriber.max_level_hint(), None);
}
#[test]
fn mixed_with_unfiltered_layered() {
let subscriber = crate::registry().with(NopLayer).with(
NopLayer
.with_filter(LevelFilter::INFO)
.and_then(NopLayer.with_filter(LevelFilter::TRACE)),
);
assert_eq!(dbg!(subscriber).max_level_hint(), None);
}
#[test]
fn mixed_interleaved() {
let subscriber = crate::registry()
.with(NopLayer)
.with(NopLayer.with_filter(LevelFilter::INFO))
.with(NopLayer)
.with(NopLayer.with_filter(LevelFilter::INFO));
assert_eq!(dbg!(subscriber).max_level_hint(), None);
}
#[test]
fn mixed_layered() {
let subscriber = crate::registry()
.with(NopLayer.with_filter(LevelFilter::INFO).and_then(NopLayer))
.with(NopLayer.and_then(NopLayer.with_filter(LevelFilter::INFO)));
assert_eq!(dbg!(subscriber).max_level_hint(), None);
}
#[test]
fn plf_only_unhinted() {
let subscriber = crate::registry()
.with(NopLayer.with_filter(LevelFilter::INFO))
.with(NopLayer.with_filter(filter_fn(|_| true)));
assert_eq!(dbg!(subscriber).max_level_hint(), None);
}
#[test]
fn plf_only_unhinted_nested_outer() {
// if a nested tree of per-layer filters has an _outer_ filter with
// no max level hint, it should return `None`.
let subscriber = crate::registry()
.with(
NopLayer
.with_filter(LevelFilter::INFO)
.and_then(NopLayer.with_filter(LevelFilter::WARN)),
)
.with(
NopLayer
.with_filter(filter_fn(|_| true))
.and_then(NopLayer.with_filter(LevelFilter::DEBUG)),
);
assert_eq!(dbg!(subscriber).max_level_hint(), None);
}
#[test]
fn plf_only_unhinted_nested_inner() {
// If a nested tree of per-layer filters has an _inner_ filter with
// no max-level hint, but the _outer_ filter has a max level hint,
// it should pick the outer hint. This is because the outer filter
// will disable the spans/events before they make it to the inner
// filter.
let subscriber = dbg!(crate::registry().with(
NopLayer
.with_filter(filter_fn(|_| true))
.and_then(NopLayer.with_filter(filter_fn(|_| true)))
.with_filter(LevelFilter::INFO),
));
assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::INFO));
}
#[test]
fn unhinted_nested_inner() {
let subscriber = dbg!(crate::registry()
.with(NopLayer.and_then(NopLayer).with_filter(LevelFilter::INFO))
.with(
NopLayer
.with_filter(filter_fn(|_| true))
.and_then(NopLayer.with_filter(filter_fn(|_| true)))
.with_filter(LevelFilter::WARN),
));
assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::INFO));
}
#[test]
fn unhinted_nested_inner_mixed() {
let subscriber = dbg!(crate::registry()
.with(
NopLayer
.and_then(NopLayer.with_filter(filter_fn(|_| true)))
.with_filter(LevelFilter::INFO)
)
.with(
NopLayer
.with_filter(filter_fn(|_| true))
.and_then(NopLayer.with_filter(filter_fn(|_| true)))
.with_filter(LevelFilter::WARN),
));
assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::INFO));
}
#[test]
fn plf_only_picks_max() {
let subscriber = crate::registry()
.with(NopLayer.with_filter(LevelFilter::WARN))
.with(NopLayer.with_filter(LevelFilter::DEBUG));
assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::DEBUG));
}
#[test]
fn many_plf_only_picks_max() {
let subscriber = crate::registry()
.with(NopLayer.with_filter(LevelFilter::WARN))
.with(NopLayer.with_filter(LevelFilter::DEBUG))
.with(NopLayer.with_filter(LevelFilter::INFO))
.with(NopLayer.with_filter(LevelFilter::ERROR));
assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::DEBUG));
}
#[test]
fn nested_plf_only_picks_max() {
let subscriber = crate::registry()
.with(
NopLayer.with_filter(LevelFilter::INFO).and_then(
NopLayer
.with_filter(LevelFilter::WARN)
.and_then(NopLayer.with_filter(LevelFilter::DEBUG)),
),
)
.with(
NopLayer
.with_filter(LevelFilter::INFO)
.and_then(NopLayer.with_filter(LevelFilter::ERROR)),
);
assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::DEBUG));
}
}
}