core: add Subscriber impl for Box<dyn Subscriber + ...> (#1358)

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.
This commit is contained in:
Eliza Weisman 2021-04-27 09:30:09 -07:00
parent 1e8446eaa0
commit e63d8e454b

View File

@ -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.
///
@ -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)
}
}