Skip to content

Commit 101dc89

Browse files
authored
Honor explicit parent spans for events (#92)
## Motivation Currently, when an event is created, no matter what is set as its parent, `OpenTelemetryLayer` will call `lookup_current` and use that as the parent span. It should honor the configured parent, if any, or be ignored, if the parent is explicitly set to `None`. ## Solution The code is changed so that the parent is correctly resolved. The logic is somewhat similar to `OpenTelemetryLayer::parent_context`.
1 parent 8b20ca4 commit 101dc89

File tree

2 files changed

+104
-1
lines changed

2 files changed

+104
-1
lines changed

src/layer.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,12 @@ where
996996
/// [`Error`]: opentelemetry::trace::StatusCode::Error
997997
fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
998998
// Ignore events that are not in the context of a span
999-
if let Some(span) = ctx.lookup_current() {
999+
if let Some(span) = event.parent().and_then(|id| ctx.span(id)).or_else(|| {
1000+
event
1001+
.is_contextual()
1002+
.then(|| ctx.lookup_current())
1003+
.flatten()
1004+
}) {
10001005
// Performing read operations before getting a write lock to avoid a deadlock
10011006
// See https://github.com/tokio-rs/tracing/issues/763
10021007
#[cfg(feature = "tracing-log")]

tests/parents.rs

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
use futures_util::future::BoxFuture;
2+
use opentelemetry::trace::TracerProvider as _;
3+
use opentelemetry_sdk::{
4+
export::trace::{ExportResult, SpanData, SpanExporter},
5+
trace::{Tracer, TracerProvider},
6+
};
7+
use std::sync::{Arc, Mutex};
8+
use tracing::level_filters::LevelFilter;
9+
use tracing::Subscriber;
10+
use tracing_opentelemetry::layer;
11+
use tracing_subscriber::prelude::*;
12+
13+
#[derive(Clone, Default, Debug)]
14+
struct TestExporter(Arc<Mutex<Vec<SpanData>>>);
15+
16+
impl SpanExporter for TestExporter {
17+
fn export(&mut self, mut batch: Vec<SpanData>) -> BoxFuture<'static, ExportResult> {
18+
let spans = self.0.clone();
19+
Box::pin(async move {
20+
if let Ok(mut inner) = spans.lock() {
21+
inner.append(&mut batch);
22+
}
23+
Ok(())
24+
})
25+
}
26+
}
27+
28+
fn test_tracer() -> (Tracer, TracerProvider, TestExporter, impl Subscriber) {
29+
let exporter = TestExporter::default();
30+
let provider = TracerProvider::builder()
31+
.with_simple_exporter(exporter.clone())
32+
.build();
33+
let tracer = provider.tracer("test");
34+
35+
let subscriber = tracing_subscriber::registry()
36+
.with(layer().with_tracer(tracer.clone()).with_filter(LevelFilter::DEBUG))
37+
.with(tracing_subscriber::fmt::layer().with_filter(LevelFilter::TRACE));
38+
39+
(tracer, provider, exporter, subscriber)
40+
}
41+
42+
#[test]
43+
fn explicit_parents_of_events() {
44+
let (_tracer, provider, exporter, subscriber) = test_tracer();
45+
46+
tracing::subscriber::with_default(subscriber, || {
47+
let root = tracing::debug_span!("root").entered();
48+
49+
tracing::debug!("1");
50+
tracing::debug!(parent: &root, "2");
51+
tracing::debug!(parent: None, "3");
52+
53+
let child = tracing::debug_span!(parent: &root, "child");
54+
child.in_scope(|| {
55+
tracing::debug!("4");
56+
tracing::debug!(parent: &root, "5");
57+
tracing::debug!(parent: &child, "6");
58+
tracing::debug!(parent: None, "7");
59+
});
60+
61+
tracing::debug!("8");
62+
tracing::debug!(parent: &root, "9");
63+
tracing::debug!(parent: &child, "10");
64+
tracing::debug!(parent: None, "11");
65+
66+
let root = root.exit();
67+
68+
tracing::debug!("12");
69+
tracing::debug!(parent: &root, "13");
70+
tracing::debug!(parent: &child, "14");
71+
tracing::debug!(parent: None, "15");
72+
});
73+
74+
drop(provider); // flush all spans
75+
let spans = exporter.0.lock().unwrap();
76+
77+
assert_eq!(spans.len(), 2);
78+
79+
{
80+
// Check the root span
81+
let expected_root_events = ["1", "2", "5", "8", "9", "13"];
82+
83+
let root_span = spans.iter().find(|s| s.name == "root").unwrap();
84+
let actual_events: Vec<_> = root_span.events.iter().map(|event| event.name.to_string()).collect();
85+
86+
assert_eq!(&expected_root_events, &actual_events[..]);
87+
}
88+
89+
{
90+
// Check the child span
91+
let expected_child_events = ["4", "6", "10", "14"];
92+
93+
let child_span = spans.iter().find(|s| s.name == "child").unwrap();
94+
let actual_events: Vec<_> = child_span.events.iter().map(|event| event.name.to_string()).collect();
95+
96+
assert_eq!(&expected_child_events, &actual_events[..]);
97+
}
98+
}

0 commit comments

Comments
 (0)