Skip to content

Commit

Permalink
tracing: make it possible to use remote IDs as parent span ID
Browse files Browse the repository at this point in the history
  • Loading branch information
mladedav committed Apr 25, 2024
1 parent 908cc43 commit 7d8973b
Show file tree
Hide file tree
Showing 17 changed files with 228 additions and 61 deletions.
4 changes: 2 additions & 2 deletions tracing-attributes/tests/parents.rs
@@ -1,4 +1,4 @@
use tracing::{collect::with_default, Id, Level};
use tracing::{collect::with_default, Level, ParentId};
use tracing_attributes::instrument;
use tracing_mock::*;

Expand All @@ -8,7 +8,7 @@ fn with_default_parent() {}
#[instrument(parent = parent_span, skip(parent_span))]
fn with_explicit_parent<P>(parent_span: P)
where
P: Into<Option<Id>>,
P: Into<ParentId>,
{
}

Expand Down
16 changes: 8 additions & 8 deletions tracing-core/src/event.rs
@@ -1,6 +1,6 @@
//! Events represent single points in time during the execution of a program.
use crate::parent::Parent;
use crate::span::Id;
use crate::span::ParentId;
use crate::{field, Metadata};

/// `Event`s represent single points in time where something occurred during the
Expand Down Expand Up @@ -51,13 +51,13 @@ impl<'a> Event<'a> {
/// provided metadata and set of values.
#[inline]
pub fn new_child_of(
parent: impl Into<Option<Id>>,
parent: impl Into<ParentId>,
metadata: &'static Metadata<'static>,
fields: &'a field::ValueSet<'a>,
) -> Self {
let parent = match parent.into() {
Some(p) => Parent::Explicit(p),
None => Parent::Root,
ParentId::None => Parent::Root,
parent => Parent::Explicit(parent),
};
Event {
fields,
Expand All @@ -69,7 +69,7 @@ impl<'a> Event<'a> {
/// Constructs a new `Event` with the specified metadata and set of values,
/// and observes it with the current collector and an explicit parent.
pub fn child_of(
parent: impl Into<Option<Id>>,
parent: impl Into<ParentId>,
metadata: &'static Metadata<'static>,
fields: &'a field::ValueSet<'_>,
) {
Expand Down Expand Up @@ -119,10 +119,10 @@ impl<'a> Event<'a> {
///
/// Otherwise (if the new event is a root or is a child of the current span),
/// returns `None`.
pub fn parent(&self) -> Option<&Id> {
pub fn parent(&self) -> &ParentId {
match self.parent {
Parent::Explicit(ref p) => Some(p),
_ => None,
Parent::Explicit(ref p) => p,
_ => &ParentId::None,
}
}
}
4 changes: 2 additions & 2 deletions tracing-core/src/parent.rs
@@ -1,4 +1,4 @@
use crate::span::Id;
use crate::span::ParentId;

#[derive(Debug)]
pub(crate) enum Parent {
Expand All @@ -7,5 +7,5 @@ pub(crate) enum Parent {
/// The new span will be rooted in the current span.
Current,
/// The new span has an explicitly-specified parent.
Explicit(Id),
Explicit(ParentId),
}
128 changes: 120 additions & 8 deletions tracing-core/src/span.rs
Expand Up @@ -16,6 +16,94 @@ use crate::{field, Metadata};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Id(NonZeroU64);

/// Identifies a span outside the cotext of a collector.
///
/// This ID may have come from outside of the process and should identify a
/// single span created in some other context.
///
/// A concrete implementation may be `traceId` and `spanId` of an OpenTelemetry
/// span which was generated in another application which called an API
/// instrumented with `tracing`.
///
/// Subscribers can handle the remote parent by providing the information or its
/// `Debug` representation to the user, but the `Registry` will not be able to
/// look this span up even if it implements `LookupSpan`. There can also be
/// specialized subscribers which downcast the ID to the correct type and then
/// can handle it in a special way.
///
/// Note that `tracing` does not provide globally unique IDs to spans and
/// therefore these should not be used as a `RemoteId` to be sent to other
/// applications.
pub trait RemoteId: std::fmt::Debug + Send + Sync + 'static {
/// Clones the `RemoteId` into a new allocation. If the type itself is
/// `Clone`, this should be as simple as `Box::new(self.clone())`.
///
/// This clone has to go through a `Box` instead of simply requiring the
/// `RemoteId` to also implement `Clone` because this trait needs to be
/// object-safe.
fn clone_boxed(&self) -> Box<dyn RemoteId>;
}

/// Identifies a span that is parent of the given span or event, if such span exists.
///
/// The parent span may be tracked in the same [`Collect`](crate::Collect) or it
/// may come from a remote context, possibly even from an application not using
/// `tracing` at all.
#[derive(Debug)]
pub enum ParentId {
/// There is no parent. A span without a parent is a root span.
None,
/// The parent is tracked in the same [`Collect`](crate::Collect) and
/// originates in the same context as the child span.
Local(Id),
/// The parent is tracked outside the [`Collect`](crate::Collect) that
/// tracks the child span. The parent may be from different
/// [`Collect`](crate::Collect), different application and possibly even
/// different language.
Remote(Box<dyn RemoteId>),
}

impl ParentId {
/// Returns a reference to a [`span::Id`](crate::span::Id) of the parent
/// span if it is tracked locally. Returns `None` for both root spans and
/// spans that have remote parents.
pub fn local(&self) -> Option<&Id> {
if let ParentId::Local(id) = self {
Some(id)
} else {
None
}
}
}

impl Clone for ParentId {
fn clone(&self) -> Self {
match self {
Self::None => Self::None,
Self::Local(id) => Self::Local(id.clone()),
Self::Remote(remote) => Self::Remote(remote.clone_boxed()),
}
}
}

impl From<Id> for ParentId {
fn from(value: Id) -> Self {
ParentId::Local(value)
}
}

impl From<&Id> for ParentId {
fn from(value: &Id) -> Self {
ParentId::Local(value.clone())
}
}

impl From<Option<Id>> for ParentId {
fn from(value: Option<Id>) -> Self {
value.map_or(ParentId::None, ParentId::Local)
}
}

/// Attributes provided to a collector describing a new span when it is
/// created.
#[derive(Debug)]
Expand Down Expand Up @@ -127,7 +215,7 @@ impl<'a> Attributes<'a> {
/// Returns `Attributes` describing a new child span of the specified
/// parent span, with the provided metadata and values.
pub fn child_of(
parent: Id,
parent: ParentId,
metadata: &'static Metadata<'static>,
values: &'a field::ValueSet<'a>,
) -> Self {
Expand Down Expand Up @@ -169,10 +257,10 @@ impl<'a> Attributes<'a> {
///
/// Otherwise (if the new span is a root or is a child of the current span),
/// returns `None`.
pub fn parent(&self) -> Option<&Id> {
pub fn parent(&self) -> &ParentId {
match self.parent {
Parent::Explicit(ref p) => Some(p),
_ => None,
Parent::Explicit(ref p) => p,
Parent::Current | Parent::Root => &ParentId::None,
}
}

Expand Down Expand Up @@ -293,23 +381,23 @@ impl Current {
pub fn into_inner(self) -> Option<(Id, &'static Metadata<'static>)> {
match self.inner {
CurrentInner::Current { id, metadata } => Some((id, metadata)),
_ => None,
CurrentInner::None | CurrentInner::Unknown => None,
}
}

/// Borrows the `Id` of the current span, if one exists and is known.
pub fn id(&self) -> Option<&Id> {
match self.inner {
CurrentInner::Current { ref id, .. } => Some(id),
_ => None,
CurrentInner::None | CurrentInner::Unknown => None,
}
}

/// Borrows the `Metadata` of the current span, if one exists and is known.
pub fn metadata(&self) -> Option<&'static Metadata<'static>> {
match self.inner {
CurrentInner::Current { metadata, .. } => Some(metadata),
_ => None,
CurrentInner::None | CurrentInner::Unknown => None,
}
}
}
Expand All @@ -330,7 +418,7 @@ impl From<Current> for Option<Id> {
fn from(cur: Current) -> Self {
match cur.inner {
CurrentInner::Current { id, .. } => Some(id),
_ => None,
CurrentInner::None | CurrentInner::Unknown => None,
}
}
}
Expand All @@ -340,3 +428,27 @@ impl<'a> From<&'a Current> for Option<&'static Metadata<'static>> {
cur.metadata()
}
}

// impl<'a> From<&'a Current> for &'a ParentId {
// fn from(cur: &'a Current) -> Self {
// cur.id()
// }
// }

impl<'a> From<&'a Current> for ParentId {
fn from(cur: &'a Current) -> Self {
match cur.id().cloned() {
Some(id) => ParentId::Local(id),
None => ParentId::None,
}
}
}

impl From<Current> for ParentId {
fn from(cur: Current) -> Self {
match cur.inner {
CurrentInner::Current { id, .. } => ParentId::Local(id),
CurrentInner::None | CurrentInner::Unknown => ParentId::None,
}
}
}
14 changes: 8 additions & 6 deletions tracing-mock/src/collector.rs
Expand Up @@ -154,7 +154,7 @@ use std::{
use tracing::{
collect::Interest,
level_filters::LevelFilter,
span::{self, Attributes, Id},
span::{self, Attributes, Id, ParentId},
Collect, Event, Metadata,
};

Expand Down Expand Up @@ -1037,11 +1037,12 @@ where
let get_parent_name = || {
let stack = self.current.lock().unwrap();
let spans = self.spans.lock().unwrap();
event
.parent()
.and_then(|id| spans.get(id))
.or_else(|| stack.last().and_then(|id| spans.get(id)))
.map(|s| s.name.to_string())
let id = match event.parent() {
ParentId::None => stack.last(),
ParentId::Local(id) => Some(id),
ParentId::Remote(_) => None,
};
id.and_then(|id| spans.get(id)).map(|s| s.name.to_string())
};
expected.check(event, get_parent_name, &self.name);
}
Expand Down Expand Up @@ -1103,6 +1104,7 @@ where
let get_parent_name = || {
let stack = self.current.lock().unwrap();
span.parent()
.local()
.and_then(|id| spans.get(id))
.or_else(|| stack.last().and_then(|id| spans.get(id)))
.map(|s| s.name.to_string())
Expand Down
2 changes: 1 addition & 1 deletion tracing-mock/src/event.rs
Expand Up @@ -581,7 +581,7 @@ impl ExpectedEvent {
let actual_parent = get_parent_name();
expected_parent.check_parent_name(
actual_parent.as_deref(),
event.parent().cloned(),
event.parent().local().cloned(),
event.metadata().name(),
collector_name,
)
Expand Down
2 changes: 1 addition & 1 deletion tracing-mock/src/span.rs
Expand Up @@ -715,7 +715,7 @@ impl NewSpan {
let actual_parent = get_parent_name();
expected_parent.check_parent_name(
actual_parent.as_deref(),
span.parent().cloned(),
span.parent().local().cloned(),
format_args!("span `{}`", name),
collector_name,
)
Expand Down
1 change: 1 addition & 0 deletions tracing-mock/src/subscriber.rs
Expand Up @@ -939,6 +939,7 @@ where
if let Expect::NewSpan(mut expected) = expected.pop_front().unwrap() {
let get_parent_name = || {
span.parent()
.local()
.and_then(|id| cx.span(id))
.or_else(|| cx.lookup_current())
.map(|span| span.name().to_string())
Expand Down
33 changes: 30 additions & 3 deletions tracing-serde/src/lib.rs
Expand Up @@ -174,15 +174,18 @@
use core::fmt;

use serde::{
ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeTupleStruct, Serializer},
ser::{
SerializeMap, SerializeSeq, SerializeStruct, SerializeTupleStruct, SerializeTupleVariant,
Serializer,
},
Serialize,
};

use tracing_core::{
event::Event,
field::{Field, FieldSet, Visit},
metadata::{Level, Metadata},
span::{Attributes, Id, Record},
span::{Attributes, Id, ParentId, Record},
};

pub mod fields;
Expand Down Expand Up @@ -253,6 +256,30 @@ impl<'a> Serialize for SerializeId<'a> {
}
}

#[derive(Debug)]
pub struct SerializeParentId<'a>(&'a ParentId);

impl<'a> Serialize for SerializeParentId<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match &self.0 {
ParentId::None => serializer.serialize_unit_variant("ParentId", 0, "None"),
ParentId::Local(id) => {
let mut state = serializer.serialize_tuple_variant("ParentId", 1, "Local", 1)?;
state.serialize_field(&SerializeId(id))?;
state.end()
}
ParentId::Remote(remote_id) => {
let mut state = serializer.serialize_tuple_variant("ParentId", 2, "Remote", 1)?;
state.serialize_field(&format_args!("{:?}", remote_id))?;
state.end()
}
}
}
}

#[derive(Debug)]
pub struct SerializeMetadata<'a>(&'a Metadata<'a>);

Expand Down Expand Up @@ -306,7 +333,7 @@ impl<'a> Serialize for SerializeAttributes<'a> {
{
let mut serializer = serializer.serialize_struct("Attributes", 3)?;
serializer.serialize_field("metadata", &SerializeMetadata(self.0.metadata()))?;
serializer.serialize_field("parent", &self.0.parent().map(SerializeId))?;
serializer.serialize_field("parent", &SerializeParentId(self.0.parent()))?;
serializer.serialize_field("is_root", &self.0.is_root())?;

let mut visitor = SerdeStructVisitor {
Expand Down
1 change: 1 addition & 0 deletions tracing-subscriber/src/fmt/format/json.rs
Expand Up @@ -237,6 +237,7 @@ where
{
event
.parent()
.local()
.and_then(|id| ctx.span(id))
.or_else(|| ctx.lookup_current())
} else {
Expand Down
1 change: 1 addition & 0 deletions tracing-subscriber/src/fmt/format/pretty.rs
Expand Up @@ -284,6 +284,7 @@ where
let bold = writer.bold();
let span = event
.parent()
.local()
.and_then(|id| ctx.span(id))
.or_else(|| ctx.lookup_current());

Expand Down

0 comments on commit 7d8973b

Please sign in to comment.