Skip to content

Commit cdb2c5a

Browse files
authored
Merge pull request #78 from ten3roberts/fix-interleaved-eager
Fix interleaved non-deferred spans
2 parents fcd9eed + 757f154 commit cdb2c5a

File tree

5 files changed

+187
-70
lines changed

5 files changed

+187
-70
lines changed

examples/concurrent_eager.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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_verbose_entry(true)
22+
.with_targets(true);
23+
24+
let subscriber = Registry::default().with(layer);
25+
tracing::subscriber::set_global_default(subscriber).unwrap();
26+
#[cfg(feature = "tracing-log")]
27+
tracing_log::LogTracer::init().unwrap();
28+
29+
let fut_a = spawn_fut("a", a);
30+
pin_mut!(fut_a);
31+
32+
let waker = futures::task::noop_waker();
33+
let mut cx = Context::from_waker(&waker);
34+
assert!(fut_a.poll_unpin(&mut cx).is_pending());
35+
36+
let fut_b = spawn_fut("b", b);
37+
pin_mut!(fut_b);
38+
39+
assert!(fut_b.poll_unpin(&mut cx).is_pending());
40+
41+
assert!(fut_a.poll_unpin(&mut cx).is_pending());
42+
assert!(fut_b.poll_unpin(&mut cx).is_pending());
43+
44+
assert!(fut_a.poll_unpin(&mut cx).is_ready());
45+
assert!(fut_b.poll_unpin(&mut cx).is_ready());
46+
}
47+
48+
fn spawn_fut<F: Fn() -> Fut, Fut: Future<Output = ()>>(
49+
key: &'static str,
50+
inner: F,
51+
) -> impl Future<Output = ()> {
52+
let span = tracing::info_span!("spawn_fut", key);
53+
54+
async move {
55+
countdown(1).await;
56+
57+
inner().await;
58+
}
59+
.instrument(span)
60+
}
61+
62+
fn a() -> impl Future<Output = ()> {
63+
let span = tracing::info_span!("a");
64+
65+
async move {
66+
countdown(1).await;
67+
tracing::info!("a");
68+
}
69+
.instrument(span)
70+
}
71+
72+
fn b() -> impl Future<Output = ()> {
73+
let span = tracing::info_span!("b");
74+
75+
async move {
76+
countdown(1).await;
77+
tracing::info!("b");
78+
}
79+
.instrument(span)
80+
}
81+
82+
fn countdown(count: u32) -> impl Future<Output = ()> {
83+
CountdownFuture { count }
84+
}
85+
86+
struct CountdownFuture {
87+
count: u32,
88+
}
89+
90+
impl Future for CountdownFuture {
91+
type Output = ();
92+
93+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
94+
if self.count == 0 {
95+
Poll::Ready(())
96+
} else {
97+
self.count -= 1;
98+
cx.waker().wake_by_ref();
99+
Poll::Pending
100+
}
101+
}
102+
}

examples/concurrent_eager.stdout

Lines changed: 16 additions & 0 deletions
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┘

examples/deferred.stdout

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
-> This prints before the span open message
2-
1:main┐open(v): deferred::hierarchical-example version=0.1
2+
1:main┐open: deferred::hierarchical-example version=0.1
33
1:main├─┐open: deferred::server host="localhost", port=8080
44
1:main│ ├─ Xms INFO deferred starting
55
1:main│ ├─ Xs INFO deferred listening

src/format.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ impl Buffers {
246246
}
247247

248248
indent_block(
249-
&mut self.current_buf,
249+
&self.current_buf,
250250
&mut self.indent_buf,
251251
indent % config.wraparound,
252252
config.indent_amount,
@@ -479,7 +479,7 @@ fn indent_block_with_lines(
479479
}
480480

481481
fn indent_block(
482-
block: &mut String,
482+
block: &str,
483483
buf: &mut String,
484484
mut indent: usize,
485485
indent_amount: usize,

src/lib.rs

Lines changed: 66 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use format::{write_span_mode, Buffers, ColorLevel, Config, FmtEvent, SpanMode};
66

77
use nu_ansi_term::{Color, Style};
88
use std::{
9-
fmt::{self, Write as _},
9+
fmt::{self, Write},
1010
io::{self, IsTerminal},
1111
iter::Fuse,
1212
mem,
@@ -267,69 +267,64 @@ 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>,
274274
bufs: &mut Buffers,
275275
ctx: &'a Context<S>,
276+
pre_open: bool,
276277
) where
277278
S: Subscriber + for<'new_span> LookupSpan<'new_span>,
278279
{
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-
289280
// Also handle deferred spans along with retrace since deferred spans may need to print
290281
// 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-
}
282+
//
283+
// If a another event occurs right after a previous event in the same span, this will
284+
// simply print nothing since the path to the common lowest ancestor is empty
285+
// if self.config.span_retrace || self.config.deferred_spans {
286+
let old_span_id = bufs.current_span.replace((new_span.id()).clone());
287+
let old_span_id = old_span_id.as_ref();
288+
let new_span_id = new_span.id();
289+
290+
if Some(&new_span_id) != old_span_id {
291+
let old_span = old_span_id.as_ref().and_then(|v| ctx.span(v));
292+
let old_path = old_span.as_ref().map(scope_path).into_iter().flatten();
293+
294+
let new_path = scope_path(new_span);
295+
296+
// Print the path from the common base of the two spans
297+
let new_path = DifferenceIter::new(old_path, new_path, |v| v.id());
298+
299+
for (i, span) in new_path.enumerate() {
300+
// Mark traversed spans as *written*
301+
let was_written = if let Some(data) = span.extensions_mut().get_mut::<Data>() {
302+
mem::replace(&mut data.written, true)
303+
} else {
304+
// `on_new_span` was not called, before
305+
// Consider if this should panic instead, which is *technically* correct but is
306+
// bad behavior for a logging layer in production.
307+
false
308+
};
309+
310+
// Print the parent of the first span
311+
let mut verbose = false;
312+
if i == 0 && pre_open {
313+
if let Some(span) = span.parent() {
314+
verbose = true;
315+
self.write_span_info(&span, bufs, SpanMode::PreOpen);
320316
}
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-
)
332317
}
318+
319+
self.write_span_info(
320+
&span,
321+
bufs,
322+
if was_written {
323+
SpanMode::Retrace { verbose }
324+
} else {
325+
SpanMode::Open { verbose }
326+
},
327+
)
333328
}
334329
}
335330
}
@@ -491,22 +486,24 @@ where
491486

492487
let bufs = &mut *self.bufs.lock().unwrap();
493488

494-
// Store the most recently entered span
495-
bufs.current_span = Some(span.id());
496-
497-
if self.config.verbose_entry {
498-
if let Some(span) = span.parent() {
499-
self.write_span_info(&span, bufs, SpanMode::PreOpen);
489+
if self.config.span_retrace {
490+
self.write_retrace_span(&span, bufs, &ctx, self.config.verbose_entry);
491+
} else {
492+
if self.config.verbose_entry {
493+
if let Some(span) = span.parent() {
494+
self.write_span_info(&span, bufs, SpanMode::PreOpen);
495+
}
500496
}
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+
);
501506
}
502-
503-
self.write_span_info(
504-
&span,
505-
bufs,
506-
SpanMode::Open {
507-
verbose: self.config.verbose_entry,
508-
},
509-
);
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, self.config.verbose_entry);
520+
}
522521
}
523522

524523
let mut event_buf = &mut bufs.current_buf;

0 commit comments

Comments
 (0)