Skip to content

Commit af13a08

Browse files
committed
record error sources for json format
1 parent 6e59a13 commit af13a08

File tree

2 files changed

+150
-12
lines changed

2 files changed

+150
-12
lines changed

tracing-serde/src/lib.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,43 @@ where
441441
self.state = self.serializer.serialize_entry(field.name(), &value)
442442
}
443443
}
444+
445+
fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
446+
if self.state.is_ok() {
447+
self.state = self
448+
.serializer
449+
.serialize_entry(field.name(), &format_args!("{}", value));
450+
451+
if self.state.is_ok() {
452+
if let Some(source) = value.source() {
453+
#[derive(Clone, Copy)]
454+
struct ErrorSourceSerializeSeq<'a> {
455+
current: &'a (dyn std::error::Error + 'static),
456+
}
457+
458+
impl serde::Serialize for ErrorSourceSerializeSeq<'_> {
459+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
460+
where
461+
S: serde::Serializer,
462+
{
463+
let mut seq = serializer.serialize_seq(None)?;
464+
let mut curr = Some(self.current);
465+
while let Some(curr_err) = curr {
466+
seq.serialize_element(&format_args!("{}", curr_err))?;
467+
curr = curr_err.source();
468+
}
469+
seq.end()
470+
}
471+
}
472+
473+
self.state = self.serializer.serialize_entry(
474+
&format_args!("{}.sources", field.name()),
475+
&ErrorSourceSerializeSeq { current: source },
476+
);
477+
}
478+
}
479+
}
480+
}
444481
}
445482

446483
/// Implements `tracing_core::field::Visit` for some `serde::ser::SerializeStruct`.

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

Lines changed: 113 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::{
99
};
1010
use serde::ser::{SerializeMap, Serializer as _};
1111
use serde_json::Serializer;
12+
use std::borrow::Cow;
1213
use std::{
1314
collections::BTreeMap,
1415
fmt::{self, Write},
@@ -405,7 +406,7 @@ impl<'a> FormatFields<'a> for JsonFields {
405406
// then, we could store fields as JSON values, and add to them
406407
// without having to parse and re-serialize.
407408
let mut new = String::new();
408-
let map: BTreeMap<&'_ str, serde_json::Value> =
409+
let map: BTreeMap<Cow<'_, str>, serde_json::Value> =
409410
serde_json::from_str(current).map_err(|_| fmt::Error)?;
410411
let mut v = JsonVisitor::new(&mut new);
411412
v.values = map;
@@ -422,7 +423,7 @@ impl<'a> FormatFields<'a> for JsonFields {
422423
/// [visitor]: crate::field::Visit
423424
/// [`MakeVisitor`]: crate::field::MakeVisitor
424425
pub struct JsonVisitor<'a> {
425-
values: BTreeMap<&'a str, serde_json::Value>,
426+
values: BTreeMap<Cow<'a, str>, serde_json::Value>,
426427
writer: &'a mut dyn Write,
427428
}
428429

@@ -460,7 +461,7 @@ impl crate::field::VisitOutput<fmt::Result> for JsonVisitor<'_> {
460461
let mut ser_map = serializer.serialize_map(None)?;
461462

462463
for (k, v) in self.values {
463-
ser_map.serialize_entry(k, &v)?;
464+
ser_map.serialize_entry(&*k, &v)?;
464465
}
465466

466467
ser_map.end()
@@ -498,36 +499,57 @@ impl field::Visit for JsonVisitor<'_> {
498499
/// Visit a double precision floating point value.
499500
fn record_f64(&mut self, field: &Field, value: f64) {
500501
self.values
501-
.insert(field.name(), serde_json::Value::from(value));
502+
.insert(field.name().into(), serde_json::Value::from(value));
502503
}
503504

504505
/// Visit a signed 64-bit integer value.
505506
fn record_i64(&mut self, field: &Field, value: i64) {
506507
self.values
507-
.insert(field.name(), serde_json::Value::from(value));
508+
.insert(field.name().into(), serde_json::Value::from(value));
508509
}
509510

510511
/// Visit an unsigned 64-bit integer value.
511512
fn record_u64(&mut self, field: &Field, value: u64) {
512513
self.values
513-
.insert(field.name(), serde_json::Value::from(value));
514+
.insert(field.name().into(), serde_json::Value::from(value));
514515
}
515516

516517
/// Visit a boolean value.
517518
fn record_bool(&mut self, field: &Field, value: bool) {
518519
self.values
519-
.insert(field.name(), serde_json::Value::from(value));
520+
.insert(field.name().into(), serde_json::Value::from(value));
520521
}
521522

522523
/// Visit a string value.
523524
fn record_str(&mut self, field: &Field, value: &str) {
524525
self.values
525-
.insert(field.name(), serde_json::Value::from(value));
526+
.insert(field.name().into(), serde_json::Value::from(value));
526527
}
527528

528529
fn record_bytes(&mut self, field: &Field, value: &[u8]) {
529530
self.values
530-
.insert(field.name(), serde_json::Value::from(value));
531+
.insert(field.name().into(), serde_json::Value::from(value));
532+
}
533+
534+
fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
535+
self.values.insert(
536+
field.name().into(),
537+
serde_json::Value::from(value.to_string()),
538+
);
539+
540+
if let Some(source) = value.source() {
541+
let mut sources = Vec::new();
542+
let mut curr = Some(source);
543+
while let Some(curr_err) = curr {
544+
sources.push(serde_json::Value::from(curr_err.to_string()));
545+
curr = curr_err.source();
546+
}
547+
548+
self.values.insert(
549+
format!("{}.sources", field.name()).into(),
550+
serde_json::Value::Array(sources),
551+
);
552+
}
531553
}
532554

533555
fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
@@ -536,12 +558,14 @@ impl field::Visit for JsonVisitor<'_> {
536558
#[cfg(feature = "tracing-log")]
537559
name if name.starts_with("log.") => (),
538560
name if name.starts_with("r#") => {
539-
self.values
540-
.insert(&name[2..], serde_json::Value::from(format!("{:?}", value)));
561+
self.values.insert(
562+
(&name[2..]).into(),
563+
serde_json::Value::from(format!("{:?}", value)),
564+
);
541565
}
542566
name => {
543567
self.values
544-
.insert(name, serde_json::Value::from(format!("{:?}", value)));
568+
.insert(name.into(), serde_json::Value::from(format!("{:?}", value)));
545569
}
546570
};
547571
}
@@ -827,6 +851,83 @@ mod test {
827851
});
828852
}
829853

854+
#[test]
855+
fn json_field_record_error() {
856+
let buffer = MockMakeWriter::default();
857+
let subscriber = crate::fmt()
858+
.json()
859+
.with_writer(buffer.clone())
860+
.with_span_events(FmtSpan::NEW)
861+
.finish();
862+
863+
#[derive(Debug)]
864+
struct Error {
865+
message: &'static str,
866+
source: Option<Box<Error>>,
867+
}
868+
869+
impl std::fmt::Display for Error {
870+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
871+
write!(f, "{}", self.message)
872+
}
873+
}
874+
875+
impl std::error::Error for Error {
876+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
877+
self.source.as_ref().map(|e| e.as_ref() as _)
878+
}
879+
}
880+
881+
let error = Error {
882+
message: "outer",
883+
source: Some(
884+
Error {
885+
message: "middle",
886+
source: Some(
887+
Error {
888+
message: "inner",
889+
source: None,
890+
}
891+
.into(),
892+
),
893+
}
894+
.into(),
895+
),
896+
};
897+
898+
with_default(subscriber, || {
899+
// Event: `tracing_serde::SerdeMapVisitor`
900+
{
901+
tracing::info!(error = &error as &dyn std::error::Error, "event");
902+
let event = parse_as_json(&buffer);
903+
904+
println!("event {:#?}", event);
905+
906+
assert_eq!(event["fields"]["message"], "event");
907+
assert_eq!(event["fields"]["error"], "outer");
908+
assert_eq!(
909+
event["fields"]["error.sources"].as_array().unwrap().len(),
910+
2
911+
);
912+
assert_eq!(event["fields"]["error.sources"][0], "middle");
913+
assert_eq!(event["fields"]["error.sources"][1], "inner");
914+
}
915+
916+
// Span: `tracing_subscriber::fmt::json::JsonVisitor`
917+
{
918+
let _span =
919+
tracing::info_span!("parent_span", error = &error as &dyn std::error::Error);
920+
let event = parse_as_json(&buffer);
921+
922+
assert_eq!(event["span"]["name"], "parent_span");
923+
assert_eq!(event["span"]["error"], "outer");
924+
assert_eq!(event["span"]["error.sources"].as_array().unwrap().len(), 2);
925+
assert_eq!(event["span"]["error.sources"][0], "middle");
926+
assert_eq!(event["span"]["error.sources"][1], "inner");
927+
}
928+
})
929+
}
930+
830931
fn parse_as_json(buffer: &MockMakeWriter) -> serde_json::Value {
831932
let buf = String::from_utf8(buffer.buf().to_vec()).unwrap();
832933
let json = buf

0 commit comments

Comments
 (0)