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 1e8446e commit e63d8e4
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 e63d8e4

Please sign in to comment.