Skip to content

Commit 7bc225a

Browse files
authored
subscriber: handle explicit event parents properly in formatters (#767)
## Motivation Currently, the default formatter implementations in `tracing-subscriber`'s `fmt` module do not handle explicitly set parent spans for events, such as ```rust let span = tracing::info_span!("some_interesting_span"); tracing::info!(parent: &span, "something is happening!"); ``` Instead, when formatting the span context of an event, the context is _always_ generated from the current span, even when the event has an overridden parent. This is not correct. ## Solution This branch changes the default context formatters to use the explicit parent ID, if it is present. Otherwise, the contexual parent is used, as it was previously. I've also added tests ensuring that this works correctly, and removed some workarounds for the previous incorrect behavior from the examples. Fixes #766 Signed-off-by: Eliza Weisman <[email protected]>
1 parent 0b7594d commit 7bc225a

File tree

5 files changed

+126
-32
lines changed

5 files changed

+126
-32
lines changed

examples/examples/tower-client.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,7 @@ fn req_span<A>(req: &Request<A>) -> tracing::Span {
1515
req.version = ?req.version(),
1616
headers = ?req.headers()
1717
);
18-
{
19-
// TODO: this is a workaround because tracing_subscriber::fmt::Layer doesn't honor
20-
// overridden span parents.
21-
let _enter = span.enter();
22-
tracing::info!(parent: &span, "sending request");
23-
}
18+
tracing::info!(parent: &span, "sending request");
2419
span
2520
}
2621

examples/examples/tower-load.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,11 @@ fn req_span<A>(req: &Request<A>) -> Span {
383383
req.method = ?req.method(),
384384
req.path = ?req.uri().path(),
385385
);
386-
debug!(message = "received request.", req.headers = ?req.headers(), req.version = ?req.version());
386+
debug!(
387+
parent: &span,
388+
message = "received request.",
389+
req.headers = ?req.headers(),
390+
req.version = ?req.version(),
391+
);
387392
span
388393
}

examples/examples/tower-server.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,7 @@ fn req_span<A>(req: &Request<A>) -> tracing::Span {
1818
req.version = ?req.version(),
1919
req.headers = ?req.headers()
2020
);
21-
{
22-
// TODO: this is a workaround because tracing_subscriber::fmt::Layer doesn't honor
23-
// overridden span parents.
24-
let _enter = span.enter();
25-
}
21+
tracing::info!(parent: &span, "received request");
2622
span
2723
}
2824

tracing-subscriber/src/fmt/format/mod.rs

Lines changed: 117 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ use crate::{
77
registry::LookupSpan,
88
};
99

10-
use std::fmt::{self, Write};
10+
use std::{
11+
fmt::{self, Write},
12+
iter,
13+
};
1114
use tracing_core::{
1215
field::{self, Field, Visit},
1316
span, Event, Level, Subscriber,
@@ -344,11 +347,11 @@ where
344347
let full_ctx = {
345348
#[cfg(feature = "ansi")]
346349
{
347-
FullCtx::new(ctx, self.ansi)
350+
FullCtx::new(ctx, event.parent(), self.ansi)
348351
}
349352
#[cfg(not(feature = "ansi"))]
350353
{
351-
FullCtx::new(&ctx)
354+
FullCtx::new(ctx, event.parent())
352355
}
353356
};
354357

@@ -401,11 +404,11 @@ where
401404
let fmt_ctx = {
402405
#[cfg(feature = "ansi")]
403406
{
404-
FmtCtx::new(&ctx, self.ansi)
407+
FmtCtx::new(&ctx, event.parent(), self.ansi)
405408
}
406409
#[cfg(not(feature = "ansi"))]
407410
{
408-
FmtCtx::new(&ctx)
411+
FmtCtx::new(&ctx, event.parent())
409412
}
410413
};
411414
write!(writer, "{}", fmt_ctx)?;
@@ -575,6 +578,7 @@ impl<'a> fmt::Debug for DefaultVisitor<'a> {
575578

576579
struct FmtCtx<'a, S, N> {
577580
ctx: &'a FmtContext<'a, S, N>,
581+
span: Option<&'a span::Id>,
578582
#[cfg(feature = "ansi")]
579583
ansi: bool,
580584
}
@@ -585,13 +589,17 @@ where
585589
N: for<'writer> FormatFields<'writer> + 'static,
586590
{
587591
#[cfg(feature = "ansi")]
588-
pub(crate) fn new(ctx: &'a FmtContext<'_, S, N>, ansi: bool) -> Self {
589-
Self { ctx, ansi }
592+
pub(crate) fn new(
593+
ctx: &'a FmtContext<'_, S, N>,
594+
span: Option<&'a span::Id>,
595+
ansi: bool,
596+
) -> Self {
597+
Self { ctx, ansi, span }
590598
}
591599

592600
#[cfg(not(feature = "ansi"))]
593-
pub(crate) fn new(ctx: &'a FmtContext<'_, S, N>) -> Self {
594-
Self { ctx }
601+
pub(crate) fn new(ctx: &'a FmtContext<'_, S, N>, span: Option<&'a span::Id>) -> Self {
602+
Self { ctx, span }
595603
}
596604

597605
fn bold(&self) -> Style {
@@ -615,10 +623,19 @@ where
615623
let bold = self.bold();
616624
let mut seen = false;
617625

618-
self.ctx.visit_spans(|span| {
626+
let span = self
627+
.span
628+
.and_then(|id| self.ctx.ctx.span(&id))
629+
.or_else(|| self.ctx.ctx.lookup_current());
630+
631+
let scope = span
632+
.into_iter()
633+
.flat_map(|span| span.from_root().chain(iter::once(span)));
634+
635+
for span in scope {
619636
seen = true;
620-
write!(f, "{}:", bold.paint(span.metadata().name()))
621-
})?;
637+
write!(f, "{}:", bold.paint(span.metadata().name()))?;
638+
}
622639

623640
if seen {
624641
f.write_char(' ')?;
@@ -633,6 +650,7 @@ where
633650
N: for<'writer> FormatFields<'writer> + 'static,
634651
{
635652
ctx: &'a FmtContext<'a, S, N>,
653+
span: Option<&'a span::Id>,
636654
#[cfg(feature = "ansi")]
637655
ansi: bool,
638656
}
@@ -643,13 +661,17 @@ where
643661
N: for<'writer> FormatFields<'writer> + 'static,
644662
{
645663
#[cfg(feature = "ansi")]
646-
pub(crate) fn new(ctx: &'a FmtContext<'a, S, N>, ansi: bool) -> Self {
647-
Self { ctx, ansi }
664+
pub(crate) fn new(
665+
ctx: &'a FmtContext<'a, S, N>,
666+
span: Option<&'a span::Id>,
667+
ansi: bool,
668+
) -> Self {
669+
Self { ctx, span, ansi }
648670
}
649671

650672
#[cfg(not(feature = "ansi"))]
651-
pub(crate) fn new(ctx: &'a FmtContext<'a, S, N>) -> Self {
652-
Self { ctx }
673+
pub(crate) fn new(ctx: &'a FmtContext<'a, S, N>, span: Option<&'a span::Id>) -> Self {
674+
Self { ctx, span }
653675
}
654676

655677
fn bold(&self) -> Style {
@@ -673,7 +695,16 @@ where
673695
let bold = self.bold();
674696
let mut seen = false;
675697

676-
self.ctx.visit_spans(|span| {
698+
let span = self
699+
.span
700+
.and_then(|id| self.ctx.ctx.span(&id))
701+
.or_else(|| self.ctx.ctx.lookup_current());
702+
703+
let scope = span
704+
.into_iter()
705+
.flat_map(|span| span.from_root().chain(iter::once(span)));
706+
707+
for span in scope {
677708
write!(f, "{}", bold.paint(span.metadata().name()))?;
678709
seen = true;
679710

@@ -684,8 +715,8 @@ where
684715
if !fields.is_empty() {
685716
write!(f, "{}{}{}", bold.paint("{"), fields, bold.paint("}"))?;
686717
}
687-
f.write_char(':')
688-
})?;
718+
f.write_char(':')?;
719+
}
689720

690721
if seen {
691722
f.write_char(' ')?;
@@ -928,4 +959,71 @@ mod test {
928959
actual.as_str()
929960
);
930961
}
962+
963+
#[test]
964+
fn overridden_parents() {
965+
lazy_static! {
966+
static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
967+
}
968+
969+
let make_writer = || MockWriter::new(&BUF);
970+
let subscriber = crate::fmt::Subscriber::builder()
971+
.with_writer(make_writer)
972+
.with_level(false)
973+
.with_ansi(false)
974+
.with_timer(MockTime)
975+
.finish();
976+
977+
with_default(subscriber, || {
978+
let span1 = tracing::info_span!("span1");
979+
let span2 = tracing::info_span!(parent: &span1, "span2");
980+
tracing::info!(parent: &span2, "hello");
981+
});
982+
let actual = String::from_utf8(BUF.try_lock().unwrap().to_vec()).unwrap();
983+
assert_eq!(
984+
"fake time span1:span2: tracing_subscriber::fmt::format::test: hello\n",
985+
actual.as_str()
986+
);
987+
}
988+
989+
#[test]
990+
fn overridden_parents_in_scope() {
991+
lazy_static! {
992+
static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
993+
}
994+
995+
let make_writer = || MockWriter::new(&BUF);
996+
let subscriber = crate::fmt::Subscriber::builder()
997+
.with_writer(make_writer)
998+
.with_level(false)
999+
.with_ansi(false)
1000+
.with_timer(MockTime)
1001+
.finish();
1002+
1003+
let actual = || {
1004+
let mut buf = BUF.try_lock().unwrap();
1005+
let val = String::from_utf8(buf.to_vec()).unwrap();
1006+
buf.clear();
1007+
val
1008+
};
1009+
1010+
with_default(subscriber, || {
1011+
let span1 = tracing::info_span!("span1");
1012+
let span2 = tracing::info_span!(parent: &span1, "span2");
1013+
let span3 = tracing::info_span!("span3");
1014+
let _e3 = span3.enter();
1015+
1016+
tracing::info!("hello");
1017+
assert_eq!(
1018+
"fake time span3: tracing_subscriber::fmt::format::test: hello\n",
1019+
actual().as_str()
1020+
);
1021+
1022+
tracing::info!(parent: &span2, "hello");
1023+
assert_eq!(
1024+
"fake time span1:span2: tracing_subscriber::fmt::format::test: hello\n",
1025+
actual().as_str()
1026+
);
1027+
});
1028+
}
9311029
}

tracing-subscriber/src/fmt/time.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ impl FormatTime for SystemTime {
118118

119119
#[cfg(not(feature = "chrono"))]
120120
impl FormatTime for SystemTime {
121-
fn format_time(&self, w: &mut fmt::Write) -> fmt::Result {
121+
fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result {
122122
write!(w, "{:?}", std::time::SystemTime::now())
123123
}
124124
}

0 commit comments

Comments
 (0)