Skip to content

Commit 07af5f8

Browse files
akinnanehawkw
andcommitted
subscriber: fix span data for new, exit, and close events (#1334)
* subscriber: fix span data for new, exit, and close events New, exit and close span events are generated while the current context is set to either `None` or the parent span of the span the event relates to. This causes spans data to be absent from the JSON output in the case of the `None`, or causes the span data to reference the parent's span data. Changing the way the current span is determined allows the correct span to be identified for these events. Trying to access the events `.parent()` allows access of the correct span for the `on_event` actions, while using `.current_span()` works for normal events. Ref: #1032 * Fix style * subscriber: improve test for #1333 Based on feedback by @hawkw, I've improved the test for #1333 to parse the json output. This is more specifc for the bug and allows easier testing of the different span `on_events`. Ref: #1333 (review) * subscriber: improve #1334 tests covering all span states Use the `on_records` test method check all events have the correct context as described in the PR. * Apply suggestions from code review Co-authored-by: Eliza Weisman <eliza@buoyant.io>
1 parent 073c842 commit 07af5f8

File tree

2 files changed

+160
-90
lines changed

2 files changed

+160
-90
lines changed

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

Lines changed: 155 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,10 @@ where
212212

213213
let current_span = if self.format.display_current_span || self.format.display_span_list
214214
{
215-
ctx.ctx.current_span().id().and_then(|id| ctx.ctx.span(id))
215+
event
216+
.parent()
217+
.and_then(|id| ctx.span(id))
218+
.or_else(|| ctx.lookup_current())
216219
} else {
217220
None
218221
};
@@ -501,11 +504,11 @@ impl<'a> fmt::Debug for WriteAdaptor<'a> {
501504

502505
#[cfg(test)]
503506
mod test {
504-
use crate::fmt::{format::FmtSpan, test::MockWriter, time::FormatTime};
507+
use super::*;
508+
use crate::fmt::{format::FmtSpan, test::MockMakeWriter, time::FormatTime, SubscriberBuilder};
505509
use lazy_static::lazy_static;
506-
use tracing::{self, subscriber::with_default};
507-
508510
use std::{fmt, sync::Mutex};
511+
use tracing::{self, subscriber::with_default};
509512

510513
struct MockTime;
511514
impl FormatTime for MockTime {
@@ -514,18 +517,23 @@ mod test {
514517
}
515518
}
516519

520+
fn subscriber() -> SubscriberBuilder<JsonFields, Format<Json>> {
521+
SubscriberBuilder::default().json()
522+
}
523+
517524
#[test]
518525
fn json() {
519526
lazy_static! {
520-
static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
527+
static ref BUF: Mutex<Vec<u8>> = Mutex::new(Vec::new());
521528
}
522529

523-
let make_writer = || MockWriter::new(&BUF);
524-
525530
let expected =
526531
"{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"tracing_subscriber::fmt::format::json::test\",\"fields\":{\"message\":\"some json test\"}}\n";
527-
528-
test_json(make_writer, expected, &BUF, false, true, true, || {
532+
let subscriber = subscriber()
533+
.flatten_event(false)
534+
.with_current_span(true)
535+
.with_span_list(true);
536+
test_json(expected, subscriber, &BUF, || {
529537
let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
530538
let _guard = span.enter();
531539
tracing::info!("some json test");
@@ -535,15 +543,16 @@ mod test {
535543
#[test]
536544
fn json_flattened_event() {
537545
lazy_static! {
538-
static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
546+
static ref BUF: Mutex<Vec<u8>> = Mutex::new(Vec::new());
539547
}
540548

541-
let make_writer = || MockWriter::new(&BUF);
542-
543549
let expected =
544550
"{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"tracing_subscriber::fmt::format::json::test\",\"message\":\"some json test\"}\n";
545-
546-
test_json(make_writer, expected, &BUF, true, true, true, || {
551+
let subscriber = subscriber()
552+
.flatten_event(true)
553+
.with_current_span(true)
554+
.with_span_list(true);
555+
test_json(expected, subscriber, &BUF, || {
547556
let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
548557
let _guard = span.enter();
549558
tracing::info!("some json test");
@@ -553,15 +562,16 @@ mod test {
553562
#[test]
554563
fn json_disabled_current_span_event() {
555564
lazy_static! {
556-
static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
565+
static ref BUF: Mutex<Vec<u8>> = Mutex::new(Vec::new());
557566
}
558567

559-
let make_writer = || MockWriter::new(&BUF);
560-
561568
let expected =
562569
"{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"tracing_subscriber::fmt::format::json::test\",\"fields\":{\"message\":\"some json test\"}}\n";
563-
564-
test_json(make_writer, expected, &BUF, false, false, true, || {
570+
let subscriber = subscriber()
571+
.flatten_event(false)
572+
.with_current_span(false)
573+
.with_span_list(true);
574+
test_json(expected, subscriber, &BUF, || {
565575
let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
566576
let _guard = span.enter();
567577
tracing::info!("some json test");
@@ -571,15 +581,16 @@ mod test {
571581
#[test]
572582
fn json_disabled_span_list_event() {
573583
lazy_static! {
574-
static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
584+
static ref BUF: Mutex<Vec<u8>> = Mutex::new(Vec::new());
575585
}
576586

577-
let make_writer = || MockWriter::new(&BUF);
578-
579587
let expected =
580588
"{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"target\":\"tracing_subscriber::fmt::format::json::test\",\"fields\":{\"message\":\"some json test\"}}\n";
581-
582-
test_json(make_writer, expected, &BUF, false, true, false, || {
589+
let subscriber = subscriber()
590+
.flatten_event(false)
591+
.with_current_span(true)
592+
.with_span_list(false);
593+
test_json(expected, subscriber, &BUF, || {
583594
let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
584595
let _guard = span.enter();
585596
tracing::info!("some json test");
@@ -589,15 +600,16 @@ mod test {
589600
#[test]
590601
fn json_nested_span() {
591602
lazy_static! {
592-
static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
603+
static ref BUF: Mutex<Vec<u8>> = Mutex::new(Vec::new());
593604
}
594605

595-
let make_writer = || MockWriter::new(&BUF);
596-
597606
let expected =
598607
"{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":43,\"name\":\"nested_json_span\",\"number\":4},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3},{\"answer\":43,\"name\":\"nested_json_span\",\"number\":4}],\"target\":\"tracing_subscriber::fmt::format::json::test\",\"fields\":{\"message\":\"some json test\"}}\n";
599-
600-
test_json(make_writer, expected, &BUF, false, true, true, || {
608+
let subscriber = subscriber()
609+
.flatten_event(false)
610+
.with_current_span(true)
611+
.with_span_list(true);
612+
test_json(expected, subscriber, &BUF, || {
601613
let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
602614
let _guard = span.enter();
603615
let span = tracing::span!(
@@ -614,15 +626,16 @@ mod test {
614626
#[test]
615627
fn json_no_span() {
616628
lazy_static! {
617-
static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
629+
static ref BUF: Mutex<Vec<u8>> = Mutex::new(Vec::new());
618630
}
619631

620-
let make_writer = || MockWriter::new(&BUF);
621-
622632
let expected =
623633
"{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"target\":\"tracing_subscriber::fmt::format::json::test\",\"fields\":{\"message\":\"some json test\"}}\n";
624-
625-
test_json(make_writer, expected, &BUF, false, true, true, || {
634+
let subscriber = subscriber()
635+
.flatten_event(false)
636+
.with_current_span(true)
637+
.with_span_list(true);
638+
test_json(expected, subscriber, &BUF, || {
626639
tracing::info!("some json test");
627640
});
628641
}
@@ -632,31 +645,16 @@ mod test {
632645
// This test reproduces issue #707, where using `Span::record` causes
633646
// any events inside the span to be ignored.
634647
lazy_static! {
635-
static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
648+
static ref BUF: Mutex<Vec<u8>> = Mutex::new(Vec::new());
636649
}
637650

638-
let make_writer = || MockWriter::new(&BUF);
639-
let subscriber = crate::fmt().json().with_writer(make_writer).finish();
640-
641-
let parse_buf = || -> serde_json::Value {
642-
let buf = String::from_utf8(BUF.try_lock().unwrap().to_vec()).unwrap();
643-
let json = buf
644-
.lines()
645-
.last()
646-
.expect("expected at least one line to be written!");
647-
match serde_json::from_str(&json) {
648-
Ok(v) => v,
649-
Err(e) => panic!(
650-
"assertion failed: JSON shouldn't be malformed\n error: {}\n json: {}",
651-
e, json
652-
),
653-
}
654-
};
651+
let buffer = MockMakeWriter::new(&BUF);
652+
let subscriber = crate::fmt().json().with_writer(buffer.clone()).finish();
655653

656654
with_default(subscriber, || {
657655
tracing::info!("an event outside the root span");
658656
assert_eq!(
659-
parse_buf()["fields"]["message"],
657+
parse_as_json(&buffer)["fields"]["message"],
660658
"an event outside the root span"
661659
);
662660

@@ -666,73 +664,140 @@ mod test {
666664

667665
tracing::info!("an event inside the root span");
668666
assert_eq!(
669-
parse_buf()["fields"]["message"],
667+
parse_as_json(&buffer)["fields"]["message"],
670668
"an event inside the root span"
671669
);
672670
});
673671
}
674672

675673
#[test]
676-
fn json_span_event() {
674+
fn json_span_event_show_correct_context() {
675+
lazy_static! {
676+
static ref BUF: Mutex<Vec<u8>> = Mutex::new(Vec::new());
677+
}
678+
679+
let buffer = MockMakeWriter::new(&BUF);
680+
let subscriber = subscriber()
681+
.with_writer(buffer.clone())
682+
.flatten_event(false)
683+
.with_current_span(true)
684+
.with_span_list(false)
685+
.with_span_events(FmtSpan::FULL)
686+
.finish();
687+
688+
with_default(subscriber, || {
689+
let context = "parent";
690+
let parent_span = tracing::info_span!("parent_span", context);
691+
692+
let event = parse_as_json(&buffer);
693+
assert_eq!(event["fields"]["message"], "new");
694+
assert_eq!(event["span"]["context"], "parent");
695+
696+
let _parent_enter = parent_span.enter();
697+
let event = parse_as_json(&buffer);
698+
assert_eq!(event["fields"]["message"], "enter");
699+
assert_eq!(event["span"]["context"], "parent");
700+
701+
let context = "child";
702+
let child_span = tracing::info_span!("child_span", context);
703+
let event = parse_as_json(&buffer);
704+
assert_eq!(event["fields"]["message"], "new");
705+
assert_eq!(event["span"]["context"], "child");
706+
707+
let _child_enter = child_span.enter();
708+
let event = parse_as_json(&buffer);
709+
assert_eq!(event["fields"]["message"], "enter");
710+
assert_eq!(event["span"]["context"], "child");
711+
712+
drop(_child_enter);
713+
let event = parse_as_json(&buffer);
714+
assert_eq!(event["fields"]["message"], "exit");
715+
assert_eq!(event["span"]["context"], "child");
716+
717+
drop(child_span);
718+
let event = parse_as_json(&buffer);
719+
assert_eq!(event["fields"]["message"], "close");
720+
assert_eq!(event["span"]["context"], "child");
721+
722+
drop(_parent_enter);
723+
let event = parse_as_json(&buffer);
724+
assert_eq!(event["fields"]["message"], "exit");
725+
assert_eq!(event["span"]["context"], "parent");
726+
727+
drop(parent_span);
728+
let event = parse_as_json(&buffer);
729+
assert_eq!(event["fields"]["message"], "close");
730+
assert_eq!(event["span"]["context"], "parent");
731+
});
732+
}
733+
734+
#[test]
735+
fn json_span_event_with_no_fields() {
677736
// Check span events serialize correctly.
678737
// Discussion: https://github.com/tokio-rs/tracing/issues/829#issuecomment-661984255
679-
//
680738
lazy_static! {
681-
static ref BUF: Mutex<Vec<u8>> = Mutex::new(vec![]);
739+
static ref BUF: Mutex<Vec<u8>> = Mutex::new(Vec::new());
682740
}
683-
let expected = r#"{"timestamp":"fake time","level":"INFO","fields":{"message":"enter"},"target":"tracing_subscriber::fmt::format::json::test"}"#;
684741

685-
let make_writer = || MockWriter::new(&BUF);
686-
let subscriber = crate::fmt::Subscriber::builder()
687-
.json()
742+
let buffer = MockMakeWriter::new(&BUF);
743+
let subscriber = subscriber()
744+
.with_writer(buffer.clone())
688745
.flatten_event(false)
689746
.with_current_span(false)
690747
.with_span_list(false)
691-
.with_span_events(FmtSpan::ENTER)
692-
.with_writer(make_writer)
693-
.with_timer(MockTime)
748+
.with_span_events(FmtSpan::FULL)
694749
.finish();
695750

696751
with_default(subscriber, || {
697-
tracing::info_span!("valid_json").in_scope(|| {});
752+
let span = tracing::info_span!("valid_json");
753+
assert_eq!(parse_as_json(&buffer)["fields"]["message"], "new");
754+
755+
let _enter = span.enter();
756+
assert_eq!(parse_as_json(&buffer)["fields"]["message"], "enter");
757+
758+
drop(_enter);
759+
assert_eq!(parse_as_json(&buffer)["fields"]["message"], "exit");
760+
761+
drop(span);
762+
assert_eq!(parse_as_json(&buffer)["fields"]["message"], "close");
698763
});
764+
}
699765

700-
let actual = String::from_utf8(BUF.try_lock().unwrap().to_vec()).unwrap();
701-
assert_eq!(
702-
serde_json::from_str::<std::collections::HashMap<&str, serde_json::Value>>(expected)
703-
.unwrap(),
704-
serde_json::from_str(actual.as_str()).unwrap()
705-
);
766+
fn parse_as_json(buffer: &MockMakeWriter<'_>) -> serde_json::Value {
767+
let buf = String::from_utf8(buffer.buf().to_vec()).unwrap();
768+
let json = buf
769+
.lines()
770+
.last()
771+
.expect("expected at least one line to be written!");
772+
match serde_json::from_str(&json) {
773+
Ok(v) => v,
774+
Err(e) => panic!(
775+
"assertion failed: JSON shouldn't be malformed\n error: {}\n json: {}",
776+
e, json
777+
),
778+
}
706779
}
707780

708-
#[cfg(feature = "json")]
709-
fn test_json<T, U>(
710-
make_writer: T,
781+
fn test_json<T>(
711782
expected: &str,
712-
buf: &Mutex<Vec<u8>>,
713-
flatten_event: bool,
714-
display_current_span: bool,
715-
display_span_list: bool,
716-
producer: impl FnOnce() -> U,
717-
) where
718-
T: crate::fmt::MakeWriter + Send + Sync + 'static,
719-
{
720-
let subscriber = crate::fmt::Subscriber::builder()
721-
.json()
722-
.flatten_event(flatten_event)
723-
.with_current_span(display_current_span)
724-
.with_span_list(display_span_list)
725-
.with_writer(make_writer)
783+
builder: crate::fmt::SubscriberBuilder<JsonFields, Format<Json>>,
784+
buf: &'static Mutex<Vec<u8>>,
785+
producer: impl FnOnce() -> T,
786+
) {
787+
let make_writer = MockMakeWriter::new(&buf);
788+
let subscriber = builder
789+
.with_writer(make_writer.clone())
726790
.with_timer(MockTime)
727791
.finish();
728792

729793
with_default(subscriber, producer);
730794

731-
let actual = String::from_utf8(buf.try_lock().unwrap().to_vec()).unwrap();
795+
let buf = make_writer.buf();
796+
let actual = std::str::from_utf8(&buf[..]).unwrap();
732797
assert_eq!(
733798
serde_json::from_str::<std::collections::HashMap<&str, serde_json::Value>>(expected)
734799
.unwrap(),
735-
serde_json::from_str(actual.as_str()).unwrap()
800+
serde_json::from_str(actual).unwrap()
736801
);
737802
}
738803
}

tracing-subscriber/src/fmt/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,7 @@ mod test {
11761176
}
11771177
}
11781178

1179+
#[derive(Clone)]
11791180
pub(crate) struct MockMakeWriter<'a> {
11801181
buf: &'a Mutex<Vec<u8>>,
11811182
}
@@ -1184,6 +1185,10 @@ mod test {
11841185
pub(crate) fn new(buf: &'a Mutex<Vec<u8>>) -> Self {
11851186
Self { buf }
11861187
}
1188+
1189+
pub(crate) fn buf(&self) -> MutexGuard<'a, Vec<u8>> {
1190+
self.buf.lock().unwrap()
1191+
}
11871192
}
11881193

11891194
impl<'a> MakeWriter for MockMakeWriter<'a> {

0 commit comments

Comments
 (0)