Skip to content

Commit 09adf54

Browse files
committed
fix: non-deferred interleaved span enter events
1 parent fcd9eed commit 09adf54

File tree

3 files changed

+178
-62
lines changed

3 files changed

+178
-62
lines changed

examples/concurrent_eager.rs

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use std::{
2+
future::Future,
3+
pin::Pin,
4+
task::{Context, Poll},
5+
};
6+
7+
use futures::{pin_mut, FutureExt};
8+
use tracing::Instrument;
9+
use tracing_subscriber::{layer::SubscriberExt, registry::Registry};
10+
use tracing_tree::HierarchicalLayer;
11+
12+
fn main() {
13+
let layer = HierarchicalLayer::default()
14+
.with_writer(std::io::stdout)
15+
.with_indent_lines(true)
16+
.with_indent_amount(4)
17+
.with_thread_names(true)
18+
.with_thread_ids(true)
19+
.with_span_retrace(true)
20+
.with_deferred_spans(false)
21+
.with_targets(true);
22+
23+
let subscriber = Registry::default().with(layer);
24+
tracing::subscriber::set_global_default(subscriber).unwrap();
25+
#[cfg(feature = "tracing-log")]
26+
tracing_log::LogTracer::init().unwrap();
27+
28+
let fut_a = spawn_fut("a", a);
29+
pin_mut!(fut_a);
30+
31+
let waker = futures::task::noop_waker();
32+
let mut cx = Context::from_waker(&waker);
33+
assert!(fut_a.poll_unpin(&mut cx).is_pending());
34+
35+
let fut_b = spawn_fut("b", b);
36+
pin_mut!(fut_b);
37+
38+
assert!(fut_b.poll_unpin(&mut cx).is_pending());
39+
40+
assert!(fut_a.poll_unpin(&mut cx).is_pending());
41+
assert!(fut_b.poll_unpin(&mut cx).is_pending());
42+
43+
assert!(fut_a.poll_unpin(&mut cx).is_ready());
44+
assert!(fut_b.poll_unpin(&mut cx).is_ready());
45+
}
46+
47+
fn spawn_fut<F: Fn() -> Fut, Fut: Future<Output = ()>>(
48+
key: &'static str,
49+
inner: F,
50+
) -> impl Future<Output = ()> {
51+
let span = tracing::info_span!("spawn_fut", key);
52+
53+
async move {
54+
countdown(1).await;
55+
56+
inner().await;
57+
}
58+
.instrument(span)
59+
}
60+
61+
fn a() -> impl Future<Output = ()> {
62+
let span = tracing::info_span!("a");
63+
64+
async move {
65+
countdown(1).await;
66+
tracing::info!("a");
67+
}
68+
.instrument(span)
69+
}
70+
71+
fn b() -> impl Future<Output = ()> {
72+
let span = tracing::info_span!("b");
73+
74+
async move {
75+
countdown(1).await;
76+
tracing::info!("b");
77+
}
78+
.instrument(span)
79+
}
80+
81+
fn countdown(count: u32) -> impl Future<Output = ()> {
82+
CountdownFuture { count }
83+
}
84+
85+
struct CountdownFuture {
86+
count: u32,
87+
}
88+
89+
impl Future for CountdownFuture {
90+
type Output = ();
91+
92+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
93+
if self.count == 0 {
94+
Poll::Ready(())
95+
} else {
96+
self.count -= 1;
97+
cx.waker().wake_by_ref();
98+
Poll::Pending
99+
}
100+
}
101+
}

examples/concurrent_eager.stdout

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
1:main┐concurrent_eager::spawn_fut key="a"
2+
1:main┐concurrent_eager::spawn_fut key="b"
3+
1:main┐concurrent_eager::spawn_fut key="a"
4+
1:main├───┐concurrent_eager::a
5+
1:main┐concurrent_eager::spawn_fut key="b"
6+
1:main├───┐concurrent_eager::b
7+
1:main┐concurrent_eager::spawn_fut key="a"
8+
1:main├───┐concurrent_eager::a
9+
1:main│ ├─── Xms INFO concurrent_eager a
10+
1:main├───┘
11+
1:main┐concurrent_eager::spawn_fut key="b"
12+
1:main├───┐concurrent_eager::b
13+
1:main│ ├─── Xms INFO concurrent_eager b
14+
1:main├───┘
15+
1:main┘
16+
1:main┘

src/lib.rs

+61-62
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ where
267267
Ok(())
268268
}
269269

270-
/// If `span_retrace` ensures that `new_span` is properly printed before an event
270+
/// Ensures that `new_span` and all its ancestors are properly printed before an event
271271
fn write_retrace_span<'a, S>(
272272
&self,
273273
new_span: &SpanRef<'a, S>,
@@ -276,61 +276,55 @@ where
276276
) where
277277
S: Subscriber + for<'new_span> LookupSpan<'new_span>,
278278
{
279-
let should_write = if self.config.deferred_spans {
280-
if let Some(data) = new_span.extensions_mut().get_mut::<Data>() {
281-
!data.written
282-
} else {
283-
false
284-
}
285-
} else {
286-
false
287-
};
288-
289279
// Also handle deferred spans along with retrace since deferred spans may need to print
290280
// multiple spans at once as a whole tree can be deferred
291-
if self.config.span_retrace || should_write {
292-
let old_span_id = bufs.current_span.replace((new_span.id()).clone());
293-
let old_span_id = old_span_id.as_ref();
294-
295-
if Some(&new_span.id()) != old_span_id {
296-
let old_span = old_span_id.as_ref().and_then(|v| ctx.span(v));
297-
let old_path = old_span.as_ref().map(scope_path).into_iter().flatten();
298-
299-
let new_path = scope_path(new_span);
300-
301-
// Print the path from the common base of the two spans
302-
let new_path = DifferenceIter::new(old_path, new_path, |v| v.id());
303-
304-
for (i, span) in new_path.enumerate() {
305-
// Mark traversed spans as *written*
306-
let was_written = if let Some(data) = span.extensions_mut().get_mut::<Data>() {
307-
mem::replace(&mut data.written, true)
308-
} else {
309-
// `on_new_span` was not called, before
310-
// Consider if this should panic instead, which is *technically* correct but is
311-
// bad behavior for a logging layer in production.
312-
false
313-
};
314-
315-
// Print the previous span before entering a new deferred or retraced span
316-
if i == 0 && self.config.verbose_entry {
317-
if let Some(parent) = &span.parent() {
318-
self.write_span_info(parent, bufs, SpanMode::PreOpen);
319-
}
281+
//
282+
// If a another event occurs right after a previous event in the same span, this will
283+
// simply print nothing since the path to the common lowest ancestor is empty
284+
// if self.config.span_retrace || self.config.deferred_spans {
285+
let old_span_id = bufs.current_span.replace((new_span.id()).clone());
286+
let old_span_id = old_span_id.as_ref();
287+
let new_span_id = new_span.id();
288+
289+
if Some(&new_span_id) != old_span_id {
290+
let old_span = old_span_id.as_ref().and_then(|v| ctx.span(v));
291+
let old_path = old_span.as_ref().map(scope_path).into_iter().flatten();
292+
293+
let new_path = scope_path(new_span);
294+
295+
// Print the path from the common base of the two spans
296+
let new_path = DifferenceIter::new(old_path, new_path, |v| v.id());
297+
298+
for (i, span) in new_path.enumerate() {
299+
// Mark traversed spans as *written*
300+
let was_written = if let Some(data) = span.extensions_mut().get_mut::<Data>() {
301+
mem::replace(&mut data.written, true)
302+
} else {
303+
// `on_new_span` was not called, before
304+
// Consider if this should panic instead, which is *technically* correct but is
305+
// bad behavior for a logging layer in production.
306+
false
307+
};
308+
309+
// Print the previous span before entering a new deferred or retraced span
310+
if i == 0 && self.config.verbose_entry {
311+
if let Some(parent) = &span.parent() {
312+
self.write_span_info(parent, bufs, SpanMode::PreOpen);
320313
}
321-
let verbose = self.config.verbose_entry && i == 0;
322-
323-
self.write_span_info(
324-
&span,
325-
bufs,
326-
if was_written {
327-
SpanMode::Retrace { verbose }
328-
} else {
329-
SpanMode::Open { verbose }
330-
},
331-
)
332314
}
315+
let verbose = self.config.verbose_entry && i == 0;
316+
317+
self.write_span_info(
318+
&span,
319+
bufs,
320+
if was_written {
321+
SpanMode::Retrace { verbose }
322+
} else {
323+
SpanMode::Open { verbose }
324+
},
325+
)
333326
}
327+
// }
334328
}
335329
}
336330

@@ -491,22 +485,25 @@ where
491485

492486
let bufs = &mut *self.bufs.lock().unwrap();
493487

494-
// Store the most recently entered span
495-
bufs.current_span = Some(span.id());
496-
497488
if self.config.verbose_entry {
498489
if let Some(span) = span.parent() {
499490
self.write_span_info(&span, bufs, SpanMode::PreOpen);
500491
}
501492
}
502493

503-
self.write_span_info(
504-
&span,
505-
bufs,
506-
SpanMode::Open {
507-
verbose: self.config.verbose_entry,
508-
},
509-
);
494+
if self.config.span_retrace {
495+
self.write_retrace_span(&span, bufs, &ctx);
496+
} else {
497+
// Store the most recently entered span
498+
bufs.current_span = Some(span.id());
499+
self.write_span_info(
500+
&span,
501+
bufs,
502+
SpanMode::Open {
503+
verbose: self.config.verbose_entry,
504+
},
505+
);
506+
}
510507
}
511508

512509
fn on_event(&self, event: &Event<'_>, ctx: Context<S>) {
@@ -518,7 +515,9 @@ where
518515
let bufs = &mut *guard;
519516

520517
if let Some(new_span) = &span {
521-
self.write_retrace_span(new_span, bufs, &ctx);
518+
if self.config.span_retrace || self.config.deferred_spans {
519+
self.write_retrace_span(new_span, bufs, &ctx);
520+
}
522521
}
523522

524523
let mut event_buf = &mut bufs.current_buf;

0 commit comments

Comments
 (0)