trace: Allow specifying a new span's parent (#923)

This branch allows users of `tokio-trace` to explicitly set a span's
parent, or indicate that a span should be a new root of its own trace
tree. A `parent: ` key has been added to the `span!` macros. When a span
is provided, that span will be set as the parent, while `parent: None`
will result in a new root span. No `parent:` key results in the current
behaviour.

A new type, `span::Attributes`, was added to `tokio-trace-core` to act
as an arguments struct for the `Subscriber::new_span` method. This will
allow future fields to be added without causing breaking API changes.
The `Attributes` struct currently contains the new span's metadata,
`ValueSet`, and parent.

Finally, the `span::Span` type in `-core` was renamed to `span::Id`, for
consistency with `tokio-trace` and to differentiate it from
`span::Attributes`. This name was chosen primarily due to precedent in
other tracing systems.

Closes #920 

Signed-off-by: Eliza Weisman <[email protected]>
This commit is contained in:
Eliza Weisman
2019-03-01 11:29:11 -08:00
committed by GitHub
parent 43d69d77e2
commit 5ff6e37c59
15 changed files with 671 additions and 103 deletions
+4 -4
View File
@@ -15,8 +15,8 @@ use tokio_trace::{field, span, Event, Id, Metadata};
struct EnabledSubscriber;
impl tokio_trace::Subscriber for EnabledSubscriber {
fn new_span(&self, span: &Metadata, values: &field::ValueSet) -> Id {
let _ = (span, values);
fn new_span(&self, span: &span::Attributes) -> Id {
let _ = span;
Id::from_u64(0)
}
@@ -59,9 +59,9 @@ impl<'a> field::Record for Recorder<'a> {
}
impl tokio_trace::Subscriber for RecordingSubscriber {
fn new_span(&self, _span: &Metadata, values: &field::ValueSet) -> Id {
fn new_span(&self, span: &span::Attributes) -> Id {
let mut recorder = Recorder(self.0.lock().unwrap());
values.record(&mut recorder);
span.values().record(&mut recorder);
Id::from_u64(0)
}
+2 -2
View File
@@ -77,8 +77,8 @@ impl Subscriber for CounterSubscriber {
interest
}
fn new_span(&self, _new_span: &Metadata, values: &field::ValueSet) -> Id {
values.record(&mut self.recorder());
fn new_span(&self, new_span: &span::Attributes) -> Id {
new_span.values().record(&mut self.recorder());
let id = self.ids.fetch_add(1, Ordering::SeqCst);
Id::from_u64(id as u64)
}
@@ -206,14 +206,12 @@ impl Subscriber for SloggishSubscriber {
true
}
fn new_span(
&self,
span: &tokio_trace::Metadata,
values: &tokio_trace::field::ValueSet,
) -> tokio_trace::Id {
fn new_span(&self, span: &tokio_trace::span::Attributes) -> tokio_trace::Id {
let meta = span.metadata();
let values = span.values();
let next = self.ids.fetch_add(1, Ordering::SeqCst) as u64;
let id = tokio_trace::Id::from_u64(next);
let span = Span::new(self.current.id(), span, values);
let span = Span::new(self.current.id(), meta, values);
self.spans.lock().unwrap().insert(id.clone(), span);
id
}
+151 -10
View File
@@ -247,9 +247,9 @@
//! #[macro_use]
//! extern crate tokio_trace;
//! # pub struct FooSubscriber;
//! # use tokio_trace::{span::Id, Metadata, field::ValueSet};
//! # use tokio_trace::{span::{Id, Attributes}, Metadata, field::ValueSet};
//! # impl tokio_trace::Subscriber for FooSubscriber {
//! # fn new_span(&self, _: &Metadata, _: &ValueSet) -> Id { Id::from_u64(0) }
//! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) }
//! # fn record(&self, _: &Id, _: &ValueSet) {}
//! # fn event(&self, _: &tokio_trace::Event) {}
//! # fn record_follows_from(&self, _: &Id, _: &Id) {}
@@ -488,12 +488,30 @@ macro_rules! callsite {
/// ```
#[macro_export]
macro_rules! span {
(target: $target:expr, level: $lvl:expr, $name:expr, $($k:ident $( = $val:expr )* ),*,) => {
span!(target: $target, level: $lvl, $name, $($k $( = $val)*),*)
(
target: $target:expr,
level: $lvl:expr,
parent: $parent:expr,
$name:expr,
$($k:ident $( = $val:expr )* ),*,
) => {
span!(
target: $target,
level: $lvl,
parent: $parent,
$name,
$($k $( = $val)*),*
)
};
(target: $target:expr, level: $lvl:expr, $name:expr, $($k:ident $( = $val:expr )* ),*) => {
(
target: $target:expr,
level: $lvl:expr,
parent: $parent:expr,
$name:expr,
$($k:ident $( = $val:expr )* ),*
) => {
{
use $crate::{callsite, field::{Value, ValueSet, AsField}, Span};
use $crate::callsite;
use $crate::callsite::Callsite;
let callsite = callsite! {
name: $name,
@@ -503,17 +521,135 @@ macro_rules! span {
};
if is_enabled!(callsite) {
let meta = callsite.metadata();
Span::new(meta, &valueset!(meta.fields(), $($k $( = $val)*),*))
$crate::Span::child_of(
$parent,
meta,
&valueset!(meta.fields(), $($k $( = $val)*),*),
)
} else {
Span::new_disabled()
$crate::Span::new_disabled()
}
}
};
(
target: $target:expr,
level: $lvl:expr,
$name:expr,
$($k:ident $( = $val:expr )* ),*
) => {
{
use $crate::callsite;
use $crate::callsite::Callsite;
let callsite = callsite! {
name: $name,
target: $target,
level: $lvl,
fields: $($k),*
};
if is_enabled!(callsite) {
let meta = callsite.metadata();
$crate::Span::new(
meta,
&valueset!(meta.fields(), $($k $( = $val)*),*),
)
} else {
$crate::Span::new_disabled()
}
}
};
(target: $target:expr, level: $lvl:expr, parent: $parent:expr, $name:expr) => {
span!(target: $target, level: $lvl, parent: $parent, $name,)
};
(level: $lvl:expr, parent: $parent:expr, $name:expr, $($k:ident $( = $val:expr )* ),*,) => {
span!(
target: module_path!(),
level: $lvl,
parent: $parent,
$name,
$($k $( = $val)*),*
)
};
(level: $lvl:expr, parent: $parent:expr, $name:expr, $($k:ident $( = $val:expr )* ),*) => {
span!(
target: module_path!(),
level: $lvl,
parent: $parent,
$name,
$($k $( = $val)*),*
)
};
(level: $lvl:expr, parent: $parent:expr, $name:expr) => {
span!(target: module_path!(), level: $lvl, parent: $parent, $name,)
};
(parent: $parent:expr, $name:expr, $($k:ident $( = $val:expr)*),*,) => {
span!(
target: module_path!(),
level: $crate::Level::TRACE,
parent: $parent,
$name,
$($k $( = $val)*),*
)
};
(parent: $parent:expr, $name:expr, $($k:ident $( = $val:expr)*),*) => {
span!(
target: module_path!(),
level: $crate::Level::TRACE,
parent: $parent,
$name,
$($k $( = $val)*),*
)
};
(parent: $parent:expr, $name:expr) => {
span!(
target: module_path!(),
level: $crate::Level::TRACE,
parent: $parent,
$name,
)
};
(
target: $target:expr,
level: $lvl:expr,
$name:expr,
$($k:ident $( = $val:expr )* ),*,
) => {
span!(
target: $target,
level: $lvl,
$name,
$($k $( = $val)*),*
)
};
(
target: $target:expr,
level: $lvl:expr,
$name:expr,
$($k:ident $( = $val:expr )* ),*
) => {
span!(
target: $target,
level: $lvl,
$name,
$($k $( = $val)*),*
)
};
(target: $target:expr, level: $lvl:expr, $name:expr) => {
span!(target: $target, level: $lvl, $name,)
};
(target: $target:expr, level: $lvl:expr, $name:expr,) => {
span!(
target: $target,
level: $lvl,
$name,
)
};
(level: $lvl:expr, $name:expr, $($k:ident $( = $val:expr )* ),*,) => {
span!(target: module_path!(), level: $lvl, $name, $($k $( = $val)*),*)
span!(
target: module_path!(),
level: $lvl,
$name,
$($k $( = $val)*),*
)
};
(level: $lvl:expr, $name:expr, $($k:ident $( = $val:expr )* ),*) => {
span!(target: module_path!(), level: $lvl, $name, $($k $( = $val)*),*)
@@ -525,7 +661,12 @@ macro_rules! span {
span!(target: module_path!(), level: $crate::Level::TRACE, $name, $($k $( = $val)*),*)
};
($name:expr, $($k:ident $( = $val:expr)*),*) => {
span!(target: module_path!(), level: $crate::Level::TRACE, $name, $($k $( = $val)*),*)
span!(
target: module_path!(),
level: $crate::Level::TRACE,
$name,
$($k $( = $val)*),*
)
};
($name:expr) => { span!(target: module_path!(), level: $crate::Level::TRACE, $name,) };
}
+57 -11
View File
@@ -135,8 +135,7 @@
//! the data for future use, record it in some manner, or discard it completely.
//!
//! [`Subscriber`]: ::Subscriber
// TODO: remove this re-export?
pub use tokio_trace_core::span::Span as Id;
pub use tokio_trace_core::span::{Attributes, Id};
use std::{
borrow::Borrow,
@@ -209,7 +208,8 @@ struct Entered<'a> {
// ===== impl Span =====
impl<'a> Span<'a> {
/// Constructs a new `Span` with the given [metadata] and set of [field values].
/// Constructs a new `Span` with the given [metadata] and set of [field
/// values].
///
/// The new span will be constructed by the currently-active [`Subscriber`],
/// with the current span as its parent (if one exists).
@@ -223,14 +223,42 @@ impl<'a> Span<'a> {
/// [`follows_from`]: ::span::Span::follows_from
#[inline]
pub fn new(meta: &'a Metadata<'a>, values: &field::ValueSet) -> Span<'a> {
let inner = dispatcher::with(move |dispatch| {
let id = dispatch.new_span(meta, values);
Some(Inner::new(id, dispatch, meta))
});
Self {
inner,
is_closed: false,
}
let new_span = Attributes::new(meta, values);
Self::make(meta, new_span)
}
/// Constructs a new `Span` as the root of its own trace tree, with the
/// given [metadata] and set of [field values].
///
/// After the span is constructed, [field values] and/or [`follows_from`]
/// annotations may be added to it.
///
/// [metadata]: ::metadata::Metadata
/// [field values]: ::field::ValueSet
/// [`follows_from`]: ::span::Span::follows_from
#[inline]
pub fn new_root(meta: &'a Metadata<'a>, values: &field::ValueSet) -> Span<'a> {
Self::make(meta, Attributes::new_root(meta, values))
}
/// Constructs a new `Span` as child of the given parent span, with the
/// given [metadata] and set of [field values].
///
/// After the span is constructed, [field values] and/or [`follows_from`]
/// annotations may be added to it.
///
/// [metadata]: ::metadata::Metadata
/// [field values]: ::field::ValueSet
/// [`follows_from`]: ::span::Span::follows_from
pub fn child_of<I>(parent: I, meta: &'a Metadata<'a>, values: &field::ValueSet) -> Span<'a>
where
I: Into<Option<Id>>,
{
let new_span = match parent.into() {
Some(parent) => Attributes::child_of(parent, meta, values),
None => Attributes::new_root(meta, values),
};
Self::make(meta, new_span)
}
/// Constructs a new disabled span.
@@ -242,6 +270,18 @@ impl<'a> Span<'a> {
}
}
#[inline(always)]
fn make(meta: &'a Metadata<'a>, new_span: Attributes) -> Span<'a> {
let inner = dispatcher::with(move |dispatch| {
let id = dispatch.new_span(&new_span);
Some(Inner::new(id, dispatch, meta))
});
Self {
inner,
is_closed: false,
}
}
/// Executes the given function in the context of this span.
///
/// If this span is enabled, then this function enters the span, invokes
@@ -380,6 +420,12 @@ impl<'a> fmt::Debug for Span<'a> {
}
}
impl<'a> Into<Option<Id>> for &'a Span<'a> {
fn into(self) -> Option<Id> {
self.id()
}
}
// ===== impl Inner =====
impl<'a> Inner<'a> {
+57
View File
@@ -22,6 +22,63 @@ fn span() {
span!("bar",);
}
#[test]
fn span_root() {
span!(target: "foo_events", level: tokio_trace::Level::DEBUG, parent: None, "foo", bar = 2, baz = 3);
span!(target: "foo_events", level: tokio_trace::Level::DEBUG, parent: None, "foo", bar = 2, baz = 4,);
span!(target: "foo_events", level: tokio_trace::Level::DEBUG, parent: None, "foo");
span!(target: "foo_events", level: tokio_trace::Level::DEBUG, parent: None, "bar",);
span!(
level: tokio_trace::Level::DEBUG,
parent: None,
"foo",
bar = 2,
baz = 3
);
span!(
level: tokio_trace::Level::DEBUG,
parent: None,
"foo",
bar = 2,
baz = 4,
);
span!(level: tokio_trace::Level::DEBUG, parent: None, "foo");
span!(level: tokio_trace::Level::DEBUG, parent: None, "bar",);
span!(parent: None, "foo", bar = 2, baz = 3);
span!(parent: None, "foo", bar = 2, baz = 4,);
span!(parent: None, "foo");
span!(parent: None, "bar",);
}
#[test]
fn span_with_parent() {
let p = span!("im_a_parent!");
span!(target: "foo_events", level: tokio_trace::Level::DEBUG, parent: &p, "foo", bar = 2, baz = 3);
span!(target: "foo_events", level: tokio_trace::Level::DEBUG, parent: &p, "foo", bar = 2, baz = 4,);
span!(target: "foo_events", level: tokio_trace::Level::DEBUG, parent: &p, "foo");
span!(target: "foo_events", level: tokio_trace::Level::DEBUG, parent: &p, "bar",);
span!(
level: tokio_trace::Level::DEBUG,
parent: &p,
"foo",
bar = 2,
baz = 3
);
span!(
level: tokio_trace::Level::DEBUG,
parent: &p,
"foo",
bar = 2,
baz = 4,
);
span!(level: tokio_trace::Level::DEBUG, parent: &p, "foo");
span!(level: tokio_trace::Level::DEBUG, parent: &p, "bar",);
span!(parent: &p, "foo", bar = 2, baz = 3);
span!(parent: &p, "foo", bar = 2, baz = 4,);
span!(parent: &p, "foo");
span!(parent: &p, "bar",);
}
#[test]
fn event() {
event!(tokio_trace::Level::DEBUG, foo = 3, bar = 2, baz = false);
+105
View File
@@ -476,3 +476,108 @@ fn new_span_with_target_and_log_level() {
handle.assert_finished();
}
#[test]
fn explicit_root_span_is_root() {
let (subscriber, handle) = subscriber::mock()
.new_span(span::mock().named("foo").with_explicit_parent(None))
.done()
.run_with_handle();
with_default(subscriber, || {
span!(parent: None, "foo");
});
handle.assert_finished();
}
#[test]
fn explicit_root_span_is_root_regardless_of_ctx() {
let (subscriber, handle) = subscriber::mock()
.new_span(span::mock().named("foo"))
.enter(span::mock().named("foo"))
.new_span(span::mock().named("bar").with_explicit_parent(None))
.exit(span::mock().named("foo"))
.done()
.run_with_handle();
with_default(subscriber, || {
span!("foo").enter(|| {
span!(parent: None, "bar");
})
});
handle.assert_finished();
}
#[test]
fn explicit_child() {
let (subscriber, handle) = subscriber::mock()
.new_span(span::mock().named("foo"))
.new_span(span::mock().named("bar").with_explicit_parent(Some("foo")))
.done()
.run_with_handle();
with_default(subscriber, || {
let foo = span!("foo");
span!(parent: foo.id(), "bar");
});
handle.assert_finished();
}
#[test]
fn explicit_child_regardless_of_ctx() {
let (subscriber, handle) = subscriber::mock()
.new_span(span::mock().named("foo"))
.new_span(span::mock().named("bar"))
.enter(span::mock().named("bar"))
.new_span(span::mock().named("baz").with_explicit_parent(Some("foo")))
.exit(span::mock().named("bar"))
.done()
.run_with_handle();
with_default(subscriber, || {
let foo = span!("foo");
span!("bar").enter(|| span!(parent: foo.id(), "baz"))
});
handle.assert_finished();
}
#[test]
fn contextual_root() {
let (subscriber, handle) = subscriber::mock()
.new_span(span::mock().named("foo").with_contextual_parent(None))
.done()
.run_with_handle();
with_default(subscriber, || {
span!("foo");
});
handle.assert_finished();
}
#[test]
fn contextual_child() {
let (subscriber, handle) = subscriber::mock()
.new_span(span::mock().named("foo"))
.enter(span::mock().named("foo"))
.new_span(
span::mock()
.named("bar")
.with_contextual_parent(Some("foo")),
)
.exit(span::mock().named("foo"))
.done()
.run_with_handle();
with_default(subscriber, || {
span!("foo").enter(|| {
span!("bar");
})
});
handle.assert_finished();
}
+2
View File
@@ -4,3 +4,5 @@ pub mod field;
mod metadata;
pub mod span;
pub mod subscriber;
extern crate tokio_trace_core;
+68
View File
@@ -11,10 +11,19 @@ pub struct MockSpan {
pub(in support) metadata: metadata::Expect,
}
#[derive(Debug, Eq, PartialEq)]
pub(in support) enum Parent {
ContextualRoot,
Contextual(String),
ExplicitRoot,
Explicit(String),
}
#[derive(Debug, Default, Eq, PartialEq)]
pub struct NewSpan {
pub(in support) span: MockSpan,
pub(in support) fields: field::Expect,
pub(in support) parent: Option<Parent>,
}
pub fn mock() -> MockSpan {
@@ -60,6 +69,30 @@ impl MockSpan {
}
}
pub fn with_explicit_parent(self, parent: Option<&str>) -> NewSpan {
let parent = match parent {
Some(name) => Parent::Explicit(name.into()),
None => Parent::ExplicitRoot,
};
NewSpan {
parent: Some(parent),
span: self,
..Default::default()
}
}
pub fn with_contextual_parent(self, parent: Option<&str>) -> NewSpan {
let parent = match parent {
Some(name) => Parent::Contextual(name.into()),
None => Parent::ContextualRoot,
};
NewSpan {
parent: Some(parent),
span: self,
..Default::default()
}
}
pub fn name(&self) -> Option<&str> {
self.metadata.name.as_ref().map(String::as_ref)
}
@@ -71,6 +104,7 @@ impl MockSpan {
NewSpan {
span: self,
fields: fields.into(),
..Default::default()
}
}
@@ -98,6 +132,40 @@ impl Into<NewSpan> for MockSpan {
}
}
impl NewSpan {
pub fn with_explicit_parent(self, parent: Option<&str>) -> NewSpan {
let parent = match parent {
Some(name) => Parent::Explicit(name.into()),
None => Parent::ExplicitRoot,
};
NewSpan {
parent: Some(parent),
..self
}
}
pub fn with_contextual_parent(self, parent: Option<&str>) -> NewSpan {
let parent = match parent {
Some(name) => Parent::Contextual(name.into()),
None => Parent::ContextualRoot,
};
NewSpan {
parent: Some(parent),
..self
}
}
pub fn with_field<I>(self, fields: I) -> NewSpan
where
I: Into<field::Expect>,
{
NewSpan {
fields: fields.into(),
..self
}
}
}
impl fmt::Display for NewSpan {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "a new span{}", self.span.metadata)?;
+60 -3
View File
@@ -12,7 +12,11 @@ use std::{
Arc, Mutex,
},
};
use tokio_trace::{field, Event, Id, Metadata, Subscriber};
use tokio_trace::{
field,
span::{Attributes, Id},
Event, Metadata, Subscriber,
};
#[derive(Debug, Eq, PartialEq)]
enum Expect {
@@ -34,6 +38,7 @@ struct SpanState {
struct Running<F: Fn(&Metadata) -> bool> {
spans: Mutex<HashMap<Id, SpanState>>,
expected: Arc<Mutex<VecDeque<Expect>>>,
current: Mutex<Vec<Id>>,
ids: AtomicUsize,
filter: F,
}
@@ -120,6 +125,7 @@ impl<F: Fn(&Metadata) -> bool> MockSubscriber<F> {
let subscriber = Running {
spans: Mutex::new(HashMap::new()),
expected,
current: Mutex::new(Vec::new()),
ids: AtomicUsize::new(0),
filter: self.filter,
};
@@ -172,7 +178,10 @@ impl<F: Fn(&Metadata) -> bool> Subscriber for Running<F> {
// TODO: it should be possible to expect spans to follow from other spans
}
fn new_span(&self, meta: &Metadata, values: &field::ValueSet) -> Id {
fn new_span(&self, span: &Attributes) -> Id {
use span::Parent;
let meta = span.metadata();
let values = span.values();
let id = self.ids.fetch_add(1, Ordering::SeqCst);
let id = Id::from_u64(id as u64);
println!(
@@ -186,6 +195,7 @@ impl<F: Fn(&Metadata) -> bool> Subscriber for Running<F> {
Some(Expect::NewSpan(_)) => true,
_ => false,
};
let mut spans = self.spans.lock().unwrap();
if was_expected {
if let Expect::NewSpan(mut expected) = expected.pop_front().unwrap() {
let name = meta.name();
@@ -196,9 +206,47 @@ impl<F: Fn(&Metadata) -> bool> Subscriber for Running<F> {
let mut checker = expected.fields.checker(format!("{}", name));
values.record(&mut checker);
checker.finish();
match expected.parent {
Some(Parent::ExplicitRoot) => {
assert!(
span.is_root(),
"expected {:?} to be an explicit root span",
name
);
}
Some(Parent::Explicit(expected_parent)) => {
let actual_parent =
span.parent().and_then(|id| spans.get(id)).map(|s| s.name);
assert_eq!(Some(expected_parent.as_ref()), actual_parent);
}
Some(Parent::ContextualRoot) => {
assert!(
span.is_contextual(),
"expected {:?} to have a contextual parent",
name
);
assert!(
self.current.lock().unwrap().last().is_none(),
"expected {:?} to be a root, but we were inside a span",
name
);
}
Some(Parent::Contextual(expected_parent)) => {
assert!(
span.is_contextual(),
"expected {:?} to have a contextual parent",
name
);
let stack = self.current.lock().unwrap();
let actual_parent =
stack.last().and_then(|id| spans.get(id)).map(|s| s.name);
assert_eq!(Some(expected_parent.as_ref()), actual_parent);
}
None => {}
}
}
}
self.spans.lock().unwrap().insert(
spans.insert(
id.clone(),
SpanState {
name: meta.name(),
@@ -222,6 +270,7 @@ impl<F: Fn(&Metadata) -> bool> Subscriber for Running<F> {
Some(ex) => ex.bad(format_args!("entered span {:?}", span.name)),
}
};
self.current.lock().unwrap().push(id.clone());
}
fn exit(&self, id: &Id) {
@@ -236,6 +285,14 @@ impl<F: Fn(&Metadata) -> bool> Subscriber for Running<F> {
if let Some(name) = expected_span.name() {
assert_eq!(name, span.name);
}
let curr = self.current.lock().unwrap().pop();
assert_eq!(
Some(id),
curr.as_ref(),
"exited span {:?}, but the current span was {:?}",
span.name,
curr.as_ref().and_then(|id| spans.get(id)).map(|s| s.name)
);
}
Some(ex) => ex.bad(format_args!("exited span {:?}", span.name)),
};
+26 -31
View File
@@ -1,8 +1,8 @@
//! Dispatches trace events to `Subscriber`s.
use {
callsite, field,
callsite, field, span,
subscriber::{self, Subscriber},
Event, Metadata, Span,
Event, Metadata,
};
use std::{
@@ -23,12 +23,12 @@ thread_local! {
/// Sets this dispatch as the default for the duration of a closure.
///
/// The default dispatcher is used when creating a new [`Span`] or
/// The default dispatcher is used when creating a new [span] or
/// [`Event`], _if no span is currently executing_. If a span is currently
/// executing, new spans or events are dispatched to the subscriber that
/// tagged that span, instead.
///
/// [`Span`]: ::span::Span
/// [span]: ../span/index.html
/// [`Subscriber`]: ::Subscriber
/// [`Event`]: ::Event
pub fn with_default<T>(dispatcher: Dispatch, f: impl FnOnce() -> T) -> T {
@@ -97,16 +97,16 @@ impl Dispatch {
self.subscriber.register_callsite(metadata)
}
/// Record the construction of a new [`Span`], returning a new ID for the
/// Record the construction of a new span, returning a new [ID] for the
/// span being constructed.
///
/// This calls the [`new_span`](::Subscriber::new_span)
/// function on the `Subscriber` that this `Dispatch` forwards to.
///
/// [`Span`]: ::span::Span
/// [ID]: ../span/struct.Id.html
#[inline]
pub fn new_span(&self, metadata: &Metadata, values: &field::ValueSet) -> Span {
self.subscriber.new_span(metadata, values)
pub fn new_span(&self, span: &span::Attributes) -> span::Id {
self.subscriber.new_span(span)
}
/// Record a set of values on a span.
@@ -114,7 +114,7 @@ impl Dispatch {
/// This calls the [`record`](::Subscriber::record)
/// function on the `Subscriber` that this `Dispatch` forwards to.
#[inline]
pub fn record(&self, span: &Span, values: &field::ValueSet) {
pub fn record(&self, span: &span::Id, values: &field::ValueSet) {
self.subscriber.record(span, &values)
}
@@ -124,7 +124,7 @@ impl Dispatch {
/// This calls the [`record_follows_from`](::Subscriber::record_follows_from)
/// function on the `Subscriber` that this `Dispatch` forwards to.
#[inline]
pub fn record_follows_from(&self, span: &Span, follows: &Span) {
pub fn record_follows_from(&self, span: &span::Id, follows: &span::Id) {
self.subscriber.record_follows_from(span, follows)
}
@@ -151,29 +151,25 @@ impl Dispatch {
self.subscriber.event(event)
}
/// Records that a [`Span`] has been entered.
/// Records that a span has been entered.
///
/// This calls the [`enter`](::Subscriber::enter) function on the
/// `Subscriber` that this `Dispatch` forwards to.
///
/// [`Span`]: ::span::Span
#[inline]
pub fn enter(&self, span: &Span) {
pub fn enter(&self, span: &span::Id) {
self.subscriber.enter(span)
}
/// Records that a [`Span`] has been exited.
/// Records that a span has been exited.
///
/// This calls the [`exit`](::Subscriber::exit) function on the `Subscriber`
/// that this `Dispatch` forwards to.
///
/// [`Span`]: ::span::Span
#[inline]
pub fn exit(&self, span: &Span) {
pub fn exit(&self, span: &span::Id) {
self.subscriber.exit(span)
}
/// Notifies the subscriber that a [`Span`] has been cloned.
/// Notifies the subscriber that a [span ID] has been cloned.
///
/// This function is guaranteed to only be called with span IDs that were
/// returned by this `Dispatch`'s `new_span` function.
@@ -181,14 +177,13 @@ impl Dispatch {
/// This calls the [`clone_span`](::Subscriber::clone_span) function on
/// the `Subscriber` that this `Dispatch` forwards to.
///
/// [`Span`]: ::span::Span
/// [span ID]: ../span/struct.Id.html
#[inline]
pub fn clone_span(&self, id: &Span) -> Span {
pub fn clone_span(&self, id: &span::Id) -> span::Id {
self.subscriber.clone_span(&id)
}
/// Notifies the subscriber that a [`Span`] handle with the given [`Id`] has
/// been dropped.
/// Notifies the subscriber that a [span ID] handle has been dropped.
///
/// This function is guaranteed to only be called with span IDs that were
/// returned by this `Dispatch`'s `new_span` function.
@@ -196,9 +191,9 @@ impl Dispatch {
/// This calls the [`drop_span`](::Subscriber::drop_span) function on
/// the `Subscriber` that this `Dispatch` forwards to.
///
/// [`Span`]: ::span::Span
/// [span ID]: ../span/struct.Id.html
#[inline]
pub fn drop_span(&self, id: Span) {
pub fn drop_span(&self, id: span::Id) {
self.subscriber.drop_span(id)
}
}
@@ -226,23 +221,23 @@ impl Subscriber for NoSubscriber {
subscriber::Interest::never()
}
fn new_span(&self, _meta: &Metadata, _vals: &field::ValueSet) -> Span {
Span::from_u64(0)
fn new_span(&self, _: &span::Attributes) -> span::Id {
span::Id::from_u64(0)
}
fn event(&self, _event: &Event) {}
fn record(&self, _span: &Span, _values: &field::ValueSet) {}
fn record(&self, _span: &span::Id, _values: &field::ValueSet) {}
fn record_follows_from(&self, _span: &Span, _follows: &Span) {}
fn record_follows_from(&self, _span: &span::Id, _follows: &span::Id) {}
#[inline]
fn enabled(&self, _metadata: &Metadata) -> bool {
false
}
fn enter(&self, _span: &Span) {}
fn exit(&self, _span: &Span) {}
fn enter(&self, _span: &span::Id) {}
fn exit(&self, _span: &span::Id) {}
}
impl Registrar {
-1
View File
@@ -176,7 +176,6 @@ pub use self::{
event::Event,
field::Field,
metadata::{Level, Metadata},
span::Span,
subscriber::{Interest, Subscriber},
};
+1 -1
View File
@@ -124,7 +124,7 @@ pub struct Metadata<'a> {
pub fields: field::FieldSet,
}
/// Describes the level of verbosity of a `Span`.
/// Describes the level of verbosity of a span or event.
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct Level(LevelInner);
+109 -9
View File
@@ -1,23 +1,41 @@
//! Spans represent periods of time in the execution of a program.
/// Identifies a span within the context of a process.
///
/// Span IDs are used primarily to determine if two handles refer to the same
/// span, without requiring the comparison of the span's fields.
use {field, Metadata};
/// Identifies a span within the context of a subscriber.
///
/// They are generated by [`Subscriber`](::Subscriber)s for each span as it is
/// created, through the [`new_id`](::Subscriber::new_span_id) trait
/// created, by the [`new_span`](::Subscriber::new_span) trait
/// method. See the documentation for that method for more information on span
/// ID generation.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Span(u64);
pub struct Id(u64);
// ===== impl Id =====
/// Attributes provided to a `Subscriber` describing a new span when it is
/// created.
#[derive(Debug)]
pub struct Attributes<'a> {
metadata: &'a Metadata<'a>,
values: &'a field::ValueSet<'a>,
parent: Parent,
}
impl Span {
#[derive(Debug)]
enum Parent {
/// The new span will be a root span.
Root,
/// The new span will be rooted in the current span.
Current,
/// The new span has an explicitly-specified parent.
Explicit(Id),
}
// ===== impl Span =====
impl Id {
/// Constructs a new span ID from the given `u64`.
pub fn from_u64(u: u64) -> Self {
Span(u)
Id(u)
}
/// Returns the span's ID as a `u64`.
@@ -25,3 +43,85 @@ impl Span {
self.0
}
}
// ===== impl Attributes =====
impl<'a> Attributes<'a> {
/// Returns `Attributes` describing a new child span of the current span,
/// with the provided metadata and values.
pub fn new(metadata: &'a Metadata<'a>, values: &'a field::ValueSet<'a>) -> Self {
Attributes {
metadata,
values,
parent: Parent::Current,
}
}
/// Returns `Attributes` describing a new span at the root of its own trace
/// tree, with the provided metadata and values.
pub fn new_root(metadata: &'a Metadata<'a>, values: &'a field::ValueSet<'a>) -> Self {
Attributes {
metadata,
values,
parent: Parent::Root,
}
}
/// Returns `Attributes` describing a new child span of the specified
/// parent span, with the provided metadata and values.
pub fn child_of(
parent: Id,
metadata: &'a Metadata<'a>,
values: &'a field::ValueSet<'a>,
) -> Self {
Attributes {
metadata,
values,
parent: Parent::Explicit(parent),
}
}
/// Returns a reference to the new span's metadata.
pub fn metadata(&self) -> &Metadata<'a> {
self.metadata
}
/// Returns a reference to a `ValueSet` containing any values the new span
/// was created with.
pub fn values(&self) -> &field::ValueSet<'a> {
self.values
}
/// Returns true if the new span shoold be a root.
pub fn is_root(&self) -> bool {
match self.parent {
Parent::Root => true,
_ => false,
}
}
/// Returns true if the new span's parent should be determined based on the
/// current context.
///
/// If this is true and the current thread is currently inside a span, then
/// that span should be the new span's parent. Otherwise, if the current
/// thread is _not_ inside a span, then the new span will be the root of its
/// own trace tree.
pub fn is_contextual(&self) -> bool {
match self.parent {
Parent::Current => true,
_ => false,
}
}
/// Returns the new span's explicitly-specified parent, if there is one.
///
/// Otherwise (if the new span is a root or is a child of the current span),
/// returns false.
pub fn parent(&self) -> Option<&Id> {
match self.parent {
Parent::Explicit(ref p) => Some(p),
_ => None,
}
}
}
+25 -25
View File
@@ -1,5 +1,5 @@
//! Subscribers collect and record trace data.
use {field, Event, Metadata, Span};
use {field, span, Event, Metadata};
/// Trait representing the functions required to collect trace data.
///
@@ -106,7 +106,7 @@ pub trait Subscriber {
/// [metadata]: ::Metadata
fn enabled(&self, metadata: &Metadata) -> bool;
/// Record the construction of a new [`Span`], returning a new ID for the
/// Record the construction of a new span, returning a new [span ID] for the
/// span being constructed.
///
/// The provided `ValueSet` contains any field values that were provided
@@ -122,10 +122,10 @@ pub trait Subscriber {
/// return a distinct ID every time this function is called, regardless of
/// the metadata.
///
/// [`Span`]: ::span::Span
/// [span ID]: ../span/struct.Id.html
/// [recorder]: ::field::Record
/// [`record` method]: ::field::ValueSet::record
fn new_span(&self, metadata: &Metadata, values: &field::ValueSet) -> Span;
fn new_span(&self, span: &span::Attributes) -> span::Id;
// === Notification methods ===============================================
@@ -136,7 +136,7 @@ pub trait Subscriber {
///
/// [recorder]: ::field::Record
/// [`record` method]: ::field::ValueSet::record
fn record(&self, span: &Span, values: &field::ValueSet);
fn record(&self, span: &span::Id, values: &field::ValueSet);
/// Adds an indication that `span` follows from the span with the id
/// `follows`.
@@ -156,7 +156,7 @@ pub trait Subscriber {
/// subscriber knows about, or if a cyclical relationship would be created
/// (i.e., some span _a_ which proceeds some other span _b_ may not also
/// follow from _b_), it may silently do nothing.
fn record_follows_from(&self, span: &Span, follows: &Span);
fn record_follows_from(&self, span: &span::Id, follows: &span::Id);
/// Records that an [`Event`] has occurred.
///
@@ -169,29 +169,29 @@ pub trait Subscriber {
/// [`record` method]: ::event::Event::record
fn event(&self, event: &Event);
/// Records that a [`Span`] has been entered.
/// Records that a spanhas been entered.
///
/// When entering a span, this method is called to notify the subscriber
/// that the span has been entered. The subscriber is provided with the ID
/// of the entered span, and should update any internal state tracking the
/// current span accordingly.
/// that the span has been entered. The subscriber is provided with the
/// [span ID] of the entered span, and should update any internal state
/// tracking the current span accordingly.
///
/// [`Span`]: ::span::Span
fn enter(&self, span: &Span);
/// [span ID]: ../span/struct.Id.html
fn enter(&self, span: &span::Id);
/// Records that a [`Span`] has been exited.
/// Records that a span has been exited.
///
/// When entering a span, this method is called to notify the subscriber
/// that the span has been exited. The subscriber is provided with the ID
/// of the exited span, and should update any internal state tracking the
/// current span accordingly.
/// that the span has been exited. The subscriber is provided with the
/// [span ID] of the exited span, and should update any internal state
/// tracking the current span accordingly.
///
/// Exiting a span does not imply that the span will not be re-entered.
///
/// [`Span`]: ::span::Span
fn exit(&self, span: &Span);
/// [span ID]: ../span/struct.Id.html
fn exit(&self, span: &span::Id);
/// Notifies the subscriber that a [`Span`] has been cloned.
/// Notifies the subscriber that a [span ID] has been cloned.
///
/// This function is guaranteed to only be called with span IDs that were
/// returned by this subscriber's `new_span` function.
@@ -209,20 +209,20 @@ pub trait Subscriber {
/// kind this can be used as a hook to "clone" the pointer, depending on
/// what that means for the specified pointer.
///
/// [`Span`]: ::span::Span,
/// [span ID]: ../span/struct.Id.html
/// [`drop_span`]: ::subscriber::Subscriber::drop_span
fn clone_span(&self, id: &Span) -> Span {
fn clone_span(&self, id: &span::Id) -> span::Id {
id.clone()
}
/// Notifies the subscriber that a [`Span`] has been dropped.
/// Notifies the subscriber that a [span ID] has been dropped.
///
/// This function is guaranteed to only be called with span IDs that were
/// returned by this subscriber's `new_span` function.
///
/// It's guaranteed that if this function has been called once more than the
/// number of times `clone_span` was called with the same `id`, then no more
/// `Span`s using that `id` exist. This means that it can be used in
/// spans using that `id` exist. This means that it can be used in
/// conjunction with [`clone_span`] to track the number of handles
/// capable of `enter`ing a span. When all the handles have been dropped
/// (i.e., `drop_span` has been called one more time than `clone_span` for a
@@ -235,9 +235,9 @@ pub trait Subscriber {
/// inside of a `drop_span` function may cause a double panic, if the span
/// was dropped due to a thread unwinding.
///
/// [`Span`]: ::span::Span,
/// [span ID]: ../span/struct.Id.html
/// [`drop_span`]: ::subscriber::Subscriber::drop_span
fn drop_span(&self, id: Span) {
fn drop_span(&self, id: span::Id) {
let _ = id;
}
}