Skip to content

Commit

Permalink
core: add Subscriber impl for Box<dyn Subscriber + ...> (#1358)
Browse files Browse the repository at this point in the history
In some cases, users may wish to erase the type of a `Subscriber`
implementation, such as when it is dynamically constructed from a
complex parameterized type. When doing so, it's important to ensure that
all trait methods with default implementations are properly forwarded to
the inner erased type. For example, if the type does not implement
`try_close`, but the inner erased subscriber does, then the the
subscriber will not be notified when spans close — which could result in
a memory leak.

To avoid potential footguns resulting from users implementing
type-erased subscribers incorrectly, this branch adds a new `impl
Subscriber for Box<dyn Subscriber + Send + Sync + 'static>` in
`tracing-core`. This is also somewhat more ergonomic than any solution
in another crate, since the implementation  is for `Box<dyn Subscriber +
...>` directly, rather than some `BoxedSubscriber` newtype.
  • Loading branch information
hawkw committed Apr 30, 2021
1 parent e2eb189 commit 1316eaf
Showing 1 changed file with 81 additions and 1 deletion.
82 changes: 81 additions & 1 deletion tracing-core/src/subscriber.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
//! Subscribers collect and record trace data.
use crate::{span, Event, LevelFilter, Metadata};

use crate::stdlib::any::{Any, TypeId};
use crate::stdlib::{
any::{Any, TypeId},
boxed::Box,
};

/// Trait representing the functions required to collect trace data.
///
Expand Down Expand Up @@ -559,3 +562,80 @@ impl Interest {
}
}
}

impl Subscriber for Box<dyn Subscriber + Send + Sync + 'static> {
#[inline]
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
self.as_ref().register_callsite(metadata)
}

#[inline]
fn enabled(&self, metadata: &Metadata<'_>) -> bool {
self.as_ref().enabled(metadata)
}

#[inline]
fn max_level_hint(&self) -> Option<LevelFilter> {
self.as_ref().max_level_hint()
}

#[inline]
fn new_span(&self, span: &span::Attributes<'_>) -> span::Id {
self.as_ref().new_span(span)
}

#[inline]
fn record(&self, span: &span::Id, values: &span::Record<'_>) {
self.as_ref().record(span, values)
}

#[inline]
fn record_follows_from(&self, span: &span::Id, follows: &span::Id) {
self.as_ref().record_follows_from(span, follows)
}

#[inline]
fn event(&self, event: &Event<'_>) {
self.as_ref().event(event)
}

#[inline]
fn enter(&self, span: &span::Id) {
self.as_ref().enter(span)
}

#[inline]
fn exit(&self, span: &span::Id) {
self.as_ref().exit(span)
}

#[inline]
fn clone_span(&self, id: &span::Id) -> span::Id {
self.as_ref().clone_span(id)
}

#[inline]
fn try_close(&self, id: span::Id) -> bool {
self.as_ref().try_close(id)
}

#[inline]
#[allow(deprecated)]
fn drop_span(&self, id: span::Id) {
self.as_ref().try_close(id);
}

#[inline]
fn current_span(&self) -> span::Current {
self.as_ref().current_span()
}

#[inline]
unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
if id == TypeId::of::<Self>() {
return Some(self as *const Self as *const _);
}

self.as_ref().downcast_raw(id)
}
}

0 comments on commit 1316eaf

Please sign in to comment.