Skip to content

Commit

Permalink
## Motivation (#1374)
Browse files Browse the repository at this point in the history
Users may wish to erase the type of a `Collect`
implementation, such as when it is dynamically constructed from a
complex parameterized type. PR #1358 added a `Collect` implementation
for `Box<dyn Collect + Send + Sync + 'static>`, allowing the use of
type-erased trait objects. In some cases, it may also be useful to share
a type-erased collector, _without_ using `Dispatch` --- such as when
different sets of `tracing-subscriber` subscribers are layered on one
shared collector.

## Solution

This branch builds on #1358 by adding an `impl Collect for Arc<dyn
Collect + Send + Sync + 'static>`. I also added quick tests for both
`Arc`ed and `Box`ed collectors.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
  • Loading branch information
hawkw authored Apr 28, 2021
1 parent 7fc6a06 commit eaaf8fd
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 7 deletions.
67 changes: 67 additions & 0 deletions tracing-core/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,3 +622,70 @@ impl Collect for alloc::boxed::Box<dyn Collect + Send + Sync + 'static> {
self.as_ref().downcast_raw(id)
}
}

#[cfg(feature = "alloc")]
impl Collect for alloc::sync::Arc<dyn Collect + 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]
unsafe fn downcast_raw(&self, id: TypeId) -> Option<NonNull<()>> {
if id == TypeId::of::<Self>() {
return Some(NonNull::from(self).cast());
}

self.as_ref().downcast_raw(id)
}
}
93 changes: 86 additions & 7 deletions tracing/tests/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@
extern crate tracing;
use tracing::{
collect::{with_default, Collect, Interest},
span, Event, Level, Metadata,
field::display,
span::{Attributes, Id, Record},
Event, Level, Metadata,
};

mod support;

use self::support::*;

#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
#[test]
fn event_macros_dont_infinite_loop() {
Expand All @@ -32,25 +38,98 @@ fn event_macros_dont_infinite_loop() {
true
}

fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
span::Id::from_u64(0xAAAA)
fn new_span(&self, _: &Attributes<'_>) -> Id {
Id::from_u64(0xAAAA)
}

fn record(&self, _: &span::Id, _: &span::Record<'_>) {}
fn record(&self, _: &Id, _: &Record<'_>) {}

fn record_follows_from(&self, _: &span::Id, _: &span::Id) {}
fn record_follows_from(&self, _: &Id, _: &Id) {}

fn event(&self, event: &Event<'_>) {
assert!(event.metadata().fields().iter().any(|f| f.name() == "foo"));
event!(Level::TRACE, baz = false);
}

fn enter(&self, _: &span::Id) {}
fn enter(&self, _: &Id) {}

fn exit(&self, _: &span::Id) {}
fn exit(&self, _: &Id) {}
}

with_default(TestCollector, || {
event!(Level::TRACE, foo = false);
})
}

#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
#[test]
fn boxed_collector() {
let (collector, handle) = collector::mock()
.new_span(
span::mock().named("foo").with_field(
field::mock("bar")
.with_value(&display("hello from my span"))
.only(),
),
)
.enter(span::mock().named("foo"))
.exit(span::mock().named("foo"))
.drop_span(span::mock().named("foo"))
.done()
.run_with_handle();
let collector: Box<dyn Collect + Send + Sync + 'static> = Box::new(collector);

with_default(collector, || {
let from = "my span";
let span = span!(
Level::TRACE,
"foo",
bar = format_args!("hello from {}", from)
);
span.in_scope(|| {});
});

handle.assert_finished();
}

#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
#[test]
fn arced_collector() {
use std::sync::Arc;

let (collector, handle) = collector::mock()
.new_span(
span::mock().named("foo").with_field(
field::mock("bar")
.with_value(&display("hello from my span"))
.only(),
),
)
.enter(span::mock().named("foo"))
.exit(span::mock().named("foo"))
.drop_span(span::mock().named("foo"))
.event(
event::mock()
.with_fields(field::mock("message").with_value(&display("hello from my event"))),
)
.done()
.run_with_handle();
let collector: Arc<dyn Collect + Send + Sync + 'static> = Arc::new(collector);

// Test using a clone of the `Arc`ed collector
with_default(collector.clone(), || {
let from = "my span";
let span = span!(
Level::TRACE,
"foo",
bar = format_args!("hello from {}", from)
);
span.in_scope(|| {});
});

with_default(collector, || {
tracing::info!("hello from my event");
});

handle.assert_finished();
}

0 comments on commit eaaf8fd

Please sign in to comment.