1 use super::{Format, FormatEvent, FormatFields, FormatTime, Writer}; 2 use crate::{ 3 field::{RecordFields, VisitOutput}, 4 fmt::{ 5 fmt_layer::{FmtContext, FormattedFields}, 6 writer::WriteAdaptor, 7 }, 8 registry::LookupSpan, 9 }; 10 use serde::ser::{SerializeMap, Serializer as _}; 11 use serde_json::Serializer; 12 use std::{ 13 collections::BTreeMap, 14 fmt::{self, Write}, 15 }; 16 use tracing_core::{ 17 field::{self, Field}, 18 span::Record, 19 Event, Subscriber, 20 }; 21 use tracing_serde::AsSerde; 22 23 #[cfg(feature = "tracing-log")] 24 use tracing_log::NormalizeEvent; 25 26 /// Marker for `Format` that indicates that the verbose JSON log format should be used. 27 /// 28 /// The full format includes fields from all entered spans. 29 /// 30 /// # Example Output 31 /// 32 /// ```json 33 /// { 34 /// "timestamp":"Feb 20 11:28:15.096", 35 /// "level":"INFO", 36 /// "fields":{"message":"some message","key":"value"} 37 /// "target":"mycrate", 38 /// "span":{name":"leaf"}, 39 /// "spans":[{"name":"root"},{"name":"leaf"}], 40 /// } 41 /// ``` 42 /// 43 /// # Options 44 /// 45 /// - [`Json::flatten_event`] can be used to enable flattening event fields into 46 /// the root 47 /// - [`Json::with_current_span`] can be used to control logging of the current 48 /// span 49 /// - [`Json::with_span_list`] can be used to control logging of the span list 50 /// object. 51 /// 52 /// By default, event fields are not flattened, and both current span and span 53 /// list are logged. 54 /// 55 /// [`Json::flatten_event`]: #method.flatten_event 56 /// [`Json::with_current_span`]: #method.with_current_span 57 /// [`Json::with_span_list`]: #method.with_span_list 58 #[derive(Debug, Copy, Clone, Eq, PartialEq)] 59 pub struct Json { 60 pub(crate) flatten_event: bool, 61 pub(crate) display_current_span: bool, 62 pub(crate) display_span_list: bool, 63 } 64 65 impl Json { 66 /// If set to `true` event metadata will be flattened into the root object. flatten_event(&mut self, flatten_event: bool)67 pub fn flatten_event(&mut self, flatten_event: bool) { 68 self.flatten_event = flatten_event; 69 } 70 71 /// If set to `false`, formatted events won't contain a field for the current span. with_current_span(&mut self, display_current_span: bool)72 pub fn with_current_span(&mut self, display_current_span: bool) { 73 self.display_current_span = display_current_span; 74 } 75 76 /// If set to `false`, formatted events won't contain a list of all currently 77 /// entered spans. Spans are logged in a list from root to leaf. with_span_list(&mut self, display_span_list: bool)78 pub fn with_span_list(&mut self, display_span_list: bool) { 79 self.display_span_list = display_span_list; 80 } 81 } 82 83 struct SerializableContext<'a, 'b, Span, N>( 84 &'b crate::layer::Context<'a, Span>, 85 std::marker::PhantomData<N>, 86 ) 87 where 88 Span: Subscriber + for<'lookup> crate::registry::LookupSpan<'lookup>, 89 N: for<'writer> FormatFields<'writer> + 'static; 90 91 impl<'a, 'b, Span, N> serde::ser::Serialize for SerializableContext<'a, 'b, Span, N> 92 where 93 Span: Subscriber + for<'lookup> crate::registry::LookupSpan<'lookup>, 94 N: for<'writer> FormatFields<'writer> + 'static, 95 { serialize<Ser>(&self, serializer_o: Ser) -> Result<Ser::Ok, Ser::Error> where Ser: serde::ser::Serializer,96 fn serialize<Ser>(&self, serializer_o: Ser) -> Result<Ser::Ok, Ser::Error> 97 where 98 Ser: serde::ser::Serializer, 99 { 100 use serde::ser::SerializeSeq; 101 let mut serializer = serializer_o.serialize_seq(None)?; 102 103 if let Some(leaf_span) = self.0.lookup_current() { 104 for span in leaf_span.scope().from_root() { 105 serializer.serialize_element(&SerializableSpan(&span, self.1))?; 106 } 107 } 108 109 serializer.end() 110 } 111 } 112 113 struct SerializableSpan<'a, 'b, Span, N>( 114 &'b crate::registry::SpanRef<'a, Span>, 115 std::marker::PhantomData<N>, 116 ) 117 where 118 Span: for<'lookup> crate::registry::LookupSpan<'lookup>, 119 N: for<'writer> FormatFields<'writer> + 'static; 120 121 impl<'a, 'b, Span, N> serde::ser::Serialize for SerializableSpan<'a, 'b, Span, N> 122 where 123 Span: for<'lookup> crate::registry::LookupSpan<'lookup>, 124 N: for<'writer> FormatFields<'writer> + 'static, 125 { serialize<Ser>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> where Ser: serde::ser::Serializer,126 fn serialize<Ser>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> 127 where 128 Ser: serde::ser::Serializer, 129 { 130 let mut serializer = serializer.serialize_map(None)?; 131 132 let ext = self.0.extensions(); 133 let data = ext 134 .get::<FormattedFields<N>>() 135 .expect("Unable to find FormattedFields in extensions; this is a bug"); 136 137 // TODO: let's _not_ do this, but this resolves 138 // https://github.com/tokio-rs/tracing/issues/391. 139 // We should probably rework this to use a `serde_json::Value` or something 140 // similar in a JSON-specific layer, but I'd (david) 141 // rather have a uglier fix now rather than shipping broken JSON. 142 match serde_json::from_str::<serde_json::Value>(data) { 143 Ok(serde_json::Value::Object(fields)) => { 144 for field in fields { 145 serializer.serialize_entry(&field.0, &field.1)?; 146 } 147 } 148 // We have fields for this span which are valid JSON but not an object. 149 // This is probably a bug, so panic if we're in debug mode 150 Ok(_) if cfg!(debug_assertions) => panic!( 151 "span '{}' had malformed fields! this is a bug.\n error: invalid JSON object\n fields: {:?}", 152 self.0.metadata().name(), 153 data 154 ), 155 // If we *aren't* in debug mode, it's probably best not to 156 // crash the program, let's log the field found but also an 157 // message saying it's type is invalid 158 Ok(value) => { 159 serializer.serialize_entry("field", &value)?; 160 serializer.serialize_entry("field_error", "field was no a valid object")? 161 } 162 // We have previously recorded fields for this span 163 // should be valid JSON. However, they appear to *not* 164 // be valid JSON. This is almost certainly a bug, so 165 // panic if we're in debug mode 166 Err(e) if cfg!(debug_assertions) => panic!( 167 "span '{}' had malformed fields! this is a bug.\n error: {}\n fields: {:?}", 168 self.0.metadata().name(), 169 e, 170 data 171 ), 172 // If we *aren't* in debug mode, it's probably best not 173 // crash the program, but let's at least make sure it's clear 174 // that the fields are not supposed to be missing. 175 Err(e) => serializer.serialize_entry("field_error", &format!("{}", e))?, 176 }; 177 serializer.serialize_entry("name", self.0.metadata().name())?; 178 serializer.end() 179 } 180 } 181 182 impl<S, N, T> FormatEvent<S, N> for Format<Json, T> 183 where 184 S: Subscriber + for<'lookup> LookupSpan<'lookup>, 185 N: for<'writer> FormatFields<'writer> + 'static, 186 T: FormatTime, 187 { format_event( &self, ctx: &FmtContext<'_, S, N>, mut writer: Writer<'_>, event: &Event<'_>, ) -> fmt::Result where S: Subscriber + for<'a> LookupSpan<'a>,188 fn format_event( 189 &self, 190 ctx: &FmtContext<'_, S, N>, 191 mut writer: Writer<'_>, 192 event: &Event<'_>, 193 ) -> fmt::Result 194 where 195 S: Subscriber + for<'a> LookupSpan<'a>, 196 { 197 let mut timestamp = String::new(); 198 self.timer.format_time(&mut Writer::new(&mut timestamp))?; 199 200 #[cfg(feature = "tracing-log")] 201 let normalized_meta = event.normalized_metadata(); 202 #[cfg(feature = "tracing-log")] 203 let meta = normalized_meta.as_ref().unwrap_or_else(|| event.metadata()); 204 #[cfg(not(feature = "tracing-log"))] 205 let meta = event.metadata(); 206 207 let mut visit = || { 208 let mut serializer = Serializer::new(WriteAdaptor::new(&mut writer)); 209 210 let mut serializer = serializer.serialize_map(None)?; 211 212 if self.display_timestamp { 213 serializer.serialize_entry("timestamp", ×tamp)?; 214 } 215 216 if self.display_level { 217 serializer.serialize_entry("level", &meta.level().as_serde())?; 218 } 219 220 let format_field_marker: std::marker::PhantomData<N> = std::marker::PhantomData; 221 222 let current_span = if self.format.display_current_span || self.format.display_span_list 223 { 224 event 225 .parent() 226 .and_then(|id| ctx.span(id)) 227 .or_else(|| ctx.lookup_current()) 228 } else { 229 None 230 }; 231 232 if self.format.flatten_event { 233 let mut visitor = tracing_serde::SerdeMapVisitor::new(serializer); 234 event.record(&mut visitor); 235 236 serializer = visitor.take_serializer()?; 237 } else { 238 use tracing_serde::fields::AsMap; 239 serializer.serialize_entry("fields", &event.field_map())?; 240 }; 241 242 if self.display_target { 243 serializer.serialize_entry("target", meta.target())?; 244 } 245 246 if self.format.display_current_span { 247 if let Some(ref span) = current_span { 248 serializer 249 .serialize_entry("span", &SerializableSpan(span, format_field_marker)) 250 .unwrap_or(()); 251 } 252 } 253 254 if self.format.display_span_list && current_span.is_some() { 255 serializer.serialize_entry( 256 "spans", 257 &SerializableContext(&ctx.ctx, format_field_marker), 258 )?; 259 } 260 261 if self.display_thread_name { 262 let current_thread = std::thread::current(); 263 match current_thread.name() { 264 Some(name) => { 265 serializer.serialize_entry("threadName", name)?; 266 } 267 // fall-back to thread id when name is absent and ids are not enabled 268 None if !self.display_thread_id => { 269 serializer 270 .serialize_entry("threadName", &format!("{:?}", current_thread.id()))?; 271 } 272 _ => {} 273 } 274 } 275 276 if self.display_thread_id { 277 serializer 278 .serialize_entry("threadId", &format!("{:?}", std::thread::current().id()))?; 279 } 280 281 serializer.end() 282 }; 283 284 visit().map_err(|_| fmt::Error)?; 285 writeln!(writer) 286 } 287 } 288 289 impl Default for Json { default() -> Json290 fn default() -> Json { 291 Json { 292 flatten_event: false, 293 display_current_span: true, 294 display_span_list: true, 295 } 296 } 297 } 298 299 /// The JSON [`FormatFields`] implementation. 300 /// 301 /// [`FormatFields`]: trait.FormatFields.html 302 #[derive(Debug)] 303 pub struct JsonFields { 304 // reserve the ability to add fields to this without causing a breaking 305 // change in the future. 306 _private: (), 307 } 308 309 impl JsonFields { 310 /// Returns a new JSON [`FormatFields`] implementation. 311 /// 312 /// [`FormatFields`]: trait.FormatFields.html new() -> Self313 pub fn new() -> Self { 314 Self { _private: () } 315 } 316 } 317 318 impl Default for JsonFields { default() -> Self319 fn default() -> Self { 320 Self::new() 321 } 322 } 323 324 impl<'a> FormatFields<'a> for JsonFields { 325 /// Format the provided `fields` to the provided `writer`, returning a result. format_fields<R: RecordFields>(&self, mut writer: Writer<'_>, fields: R) -> fmt::Result326 fn format_fields<R: RecordFields>(&self, mut writer: Writer<'_>, fields: R) -> fmt::Result { 327 let mut v = JsonVisitor::new(&mut writer); 328 fields.record(&mut v); 329 v.finish() 330 } 331 332 /// Record additional field(s) on an existing span. 333 /// 334 /// By default, this appends a space to the current set of fields if it is 335 /// non-empty, and then calls `self.format_fields`. If different behavior is 336 /// required, the default implementation of this method can be overridden. add_fields( &self, current: &'a mut FormattedFields<Self>, fields: &Record<'_>, ) -> fmt::Result337 fn add_fields( 338 &self, 339 current: &'a mut FormattedFields<Self>, 340 fields: &Record<'_>, 341 ) -> fmt::Result { 342 if current.is_empty() { 343 // If there are no previously recorded fields, we can just reuse the 344 // existing string. 345 let mut writer = current.as_writer(); 346 let mut v = JsonVisitor::new(&mut writer); 347 fields.record(&mut v); 348 v.finish()?; 349 return Ok(()); 350 } 351 352 // If fields were previously recorded on this span, we need to parse 353 // the current set of fields as JSON, add the new fields, and 354 // re-serialize them. Otherwise, if we just appended the new fields 355 // to a previously serialized JSON object, we would end up with 356 // malformed JSON. 357 // 358 // XXX(eliza): this is far from efficient, but unfortunately, it is 359 // necessary as long as the JSON formatter is implemented on top of 360 // an interface that stores all formatted fields as strings. 361 // 362 // We should consider reimplementing the JSON formatter as a 363 // separate layer, rather than a formatter for the `fmt` layer — 364 // then, we could store fields as JSON values, and add to them 365 // without having to parse and re-serialize. 366 let mut new = String::new(); 367 let map: BTreeMap<&'_ str, serde_json::Value> = 368 serde_json::from_str(current).map_err(|_| fmt::Error)?; 369 let mut v = JsonVisitor::new(&mut new); 370 v.values = map; 371 fields.record(&mut v); 372 v.finish()?; 373 current.fields = new; 374 375 Ok(()) 376 } 377 } 378 379 /// The [visitor] produced by [`JsonFields`]'s [`MakeVisitor`] implementation. 380 /// 381 /// [visitor]: ../../field/trait.Visit.html 382 /// [`JsonFields`]: struct.JsonFields.html 383 /// [`MakeVisitor`]: ../../field/trait.MakeVisitor.html 384 pub struct JsonVisitor<'a> { 385 values: BTreeMap<&'a str, serde_json::Value>, 386 writer: &'a mut dyn Write, 387 } 388 389 impl<'a> fmt::Debug for JsonVisitor<'a> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result390 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 391 f.write_fmt(format_args!("JsonVisitor {{ values: {:?} }}", self.values)) 392 } 393 } 394 395 impl<'a> JsonVisitor<'a> { 396 /// Returns a new default visitor that formats to the provided `writer`. 397 /// 398 /// # Arguments 399 /// - `writer`: the writer to format to. 400 /// - `is_empty`: whether or not any fields have been previously written to 401 /// that writer. new(writer: &'a mut dyn Write) -> Self402 pub fn new(writer: &'a mut dyn Write) -> Self { 403 Self { 404 values: BTreeMap::new(), 405 writer, 406 } 407 } 408 } 409 410 impl<'a> crate::field::VisitFmt for JsonVisitor<'a> { writer(&mut self) -> &mut dyn fmt::Write411 fn writer(&mut self) -> &mut dyn fmt::Write { 412 self.writer 413 } 414 } 415 416 impl<'a> crate::field::VisitOutput<fmt::Result> for JsonVisitor<'a> { finish(self) -> fmt::Result417 fn finish(self) -> fmt::Result { 418 let inner = || { 419 let mut serializer = Serializer::new(WriteAdaptor::new(self.writer)); 420 let mut ser_map = serializer.serialize_map(None)?; 421 422 for (k, v) in self.values { 423 ser_map.serialize_entry(k, &v)?; 424 } 425 426 ser_map.end() 427 }; 428 429 if inner().is_err() { 430 Err(fmt::Error) 431 } else { 432 Ok(()) 433 } 434 } 435 } 436 437 impl<'a> field::Visit for JsonVisitor<'a> { 438 /// Visit a double precision floating point value. record_f64(&mut self, field: &Field, value: f64)439 fn record_f64(&mut self, field: &Field, value: f64) { 440 self.values 441 .insert(field.name(), serde_json::Value::from(value)); 442 } 443 444 /// Visit a signed 64-bit integer value. record_i64(&mut self, field: &Field, value: i64)445 fn record_i64(&mut self, field: &Field, value: i64) { 446 self.values 447 .insert(field.name(), serde_json::Value::from(value)); 448 } 449 450 /// Visit an unsigned 64-bit integer value. record_u64(&mut self, field: &Field, value: u64)451 fn record_u64(&mut self, field: &Field, value: u64) { 452 self.values 453 .insert(field.name(), serde_json::Value::from(value)); 454 } 455 456 /// Visit a boolean value. record_bool(&mut self, field: &Field, value: bool)457 fn record_bool(&mut self, field: &Field, value: bool) { 458 self.values 459 .insert(field.name(), serde_json::Value::from(value)); 460 } 461 462 /// Visit a string value. record_str(&mut self, field: &Field, value: &str)463 fn record_str(&mut self, field: &Field, value: &str) { 464 self.values 465 .insert(field.name(), serde_json::Value::from(value)); 466 } 467 record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)468 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { 469 match field.name() { 470 // Skip fields that are actually log metadata that have already been handled 471 #[cfg(feature = "tracing-log")] 472 name if name.starts_with("log.") => (), 473 name if name.starts_with("r#") => { 474 self.values 475 .insert(&name[2..], serde_json::Value::from(format!("{:?}", value))); 476 } 477 name => { 478 self.values 479 .insert(name, serde_json::Value::from(format!("{:?}", value))); 480 } 481 }; 482 } 483 } 484 #[cfg(test)] 485 mod test { 486 use super::*; 487 use crate::fmt::{format::FmtSpan, test::MockMakeWriter, time::FormatTime, SubscriberBuilder}; 488 use tracing::{self, subscriber::with_default}; 489 490 use std::fmt; 491 492 struct MockTime; 493 impl FormatTime for MockTime { format_time(&self, w: &mut Writer<'_>) -> fmt::Result494 fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result { 495 write!(w, "fake time") 496 } 497 } 498 subscriber() -> SubscriberBuilder<JsonFields, Format<Json>>499 fn subscriber() -> SubscriberBuilder<JsonFields, Format<Json>> { 500 SubscriberBuilder::default().json() 501 } 502 503 #[test] json()504 fn json() { 505 let expected = 506 "{\"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"; 507 let subscriber = subscriber() 508 .flatten_event(false) 509 .with_current_span(true) 510 .with_span_list(true); 511 test_json(expected, subscriber, || { 512 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3); 513 let _guard = span.enter(); 514 tracing::info!("some json test"); 515 }); 516 } 517 518 #[test] json_flattened_event()519 fn json_flattened_event() { 520 let expected = 521 "{\"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"; 522 523 let subscriber = subscriber() 524 .flatten_event(true) 525 .with_current_span(true) 526 .with_span_list(true); 527 test_json(expected, subscriber, || { 528 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3); 529 let _guard = span.enter(); 530 tracing::info!("some json test"); 531 }); 532 } 533 534 #[test] json_disabled_current_span_event()535 fn json_disabled_current_span_event() { 536 let expected = 537 "{\"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"; 538 let subscriber = subscriber() 539 .flatten_event(false) 540 .with_current_span(false) 541 .with_span_list(true); 542 test_json(expected, subscriber, || { 543 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3); 544 let _guard = span.enter(); 545 tracing::info!("some json test"); 546 }); 547 } 548 549 #[test] json_disabled_span_list_event()550 fn json_disabled_span_list_event() { 551 let expected = 552 "{\"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"; 553 let subscriber = subscriber() 554 .flatten_event(false) 555 .with_current_span(true) 556 .with_span_list(false); 557 test_json(expected, subscriber, || { 558 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3); 559 let _guard = span.enter(); 560 tracing::info!("some json test"); 561 }); 562 } 563 564 #[test] json_nested_span()565 fn json_nested_span() { 566 let expected = 567 "{\"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"; 568 let subscriber = subscriber() 569 .flatten_event(false) 570 .with_current_span(true) 571 .with_span_list(true); 572 test_json(expected, subscriber, || { 573 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3); 574 let _guard = span.enter(); 575 let span = tracing::span!( 576 tracing::Level::INFO, 577 "nested_json_span", 578 answer = 43, 579 number = 4 580 ); 581 let _guard = span.enter(); 582 tracing::info!("some json test"); 583 }); 584 } 585 586 #[test] json_no_span()587 fn json_no_span() { 588 let expected = 589 "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"target\":\"tracing_subscriber::fmt::format::json::test\",\"fields\":{\"message\":\"some json test\"}}\n"; 590 let subscriber = subscriber() 591 .flatten_event(false) 592 .with_current_span(true) 593 .with_span_list(true); 594 test_json(expected, subscriber, || { 595 tracing::info!("some json test"); 596 }); 597 } 598 599 #[test] record_works()600 fn record_works() { 601 // This test reproduces issue #707, where using `Span::record` causes 602 // any events inside the span to be ignored. 603 604 let make_writer = MockMakeWriter::default(); 605 let subscriber = crate::fmt() 606 .json() 607 .with_writer(make_writer.clone()) 608 .finish(); 609 610 with_default(subscriber, || { 611 tracing::info!("an event outside the root span"); 612 assert_eq!( 613 parse_as_json(&make_writer)["fields"]["message"], 614 "an event outside the root span" 615 ); 616 617 let span = tracing::info_span!("the span", na = tracing::field::Empty); 618 span.record("na", &"value"); 619 let _enter = span.enter(); 620 621 tracing::info!("an event inside the root span"); 622 assert_eq!( 623 parse_as_json(&make_writer)["fields"]["message"], 624 "an event inside the root span" 625 ); 626 }); 627 } 628 629 #[test] json_span_event_show_correct_context()630 fn json_span_event_show_correct_context() { 631 let buffer = MockMakeWriter::default(); 632 let subscriber = subscriber() 633 .with_writer(buffer.clone()) 634 .flatten_event(false) 635 .with_current_span(true) 636 .with_span_list(false) 637 .with_span_events(FmtSpan::FULL) 638 .finish(); 639 640 with_default(subscriber, || { 641 let context = "parent"; 642 let parent_span = tracing::info_span!("parent_span", context); 643 644 let event = parse_as_json(&buffer); 645 assert_eq!(event["fields"]["message"], "new"); 646 assert_eq!(event["span"]["context"], "parent"); 647 648 let _parent_enter = parent_span.enter(); 649 let event = parse_as_json(&buffer); 650 assert_eq!(event["fields"]["message"], "enter"); 651 assert_eq!(event["span"]["context"], "parent"); 652 653 let context = "child"; 654 let child_span = tracing::info_span!("child_span", context); 655 let event = parse_as_json(&buffer); 656 assert_eq!(event["fields"]["message"], "new"); 657 assert_eq!(event["span"]["context"], "child"); 658 659 let _child_enter = child_span.enter(); 660 let event = parse_as_json(&buffer); 661 assert_eq!(event["fields"]["message"], "enter"); 662 assert_eq!(event["span"]["context"], "child"); 663 664 drop(_child_enter); 665 let event = parse_as_json(&buffer); 666 assert_eq!(event["fields"]["message"], "exit"); 667 assert_eq!(event["span"]["context"], "child"); 668 669 drop(child_span); 670 let event = parse_as_json(&buffer); 671 assert_eq!(event["fields"]["message"], "close"); 672 assert_eq!(event["span"]["context"], "child"); 673 674 drop(_parent_enter); 675 let event = parse_as_json(&buffer); 676 assert_eq!(event["fields"]["message"], "exit"); 677 assert_eq!(event["span"]["context"], "parent"); 678 679 drop(parent_span); 680 let event = parse_as_json(&buffer); 681 assert_eq!(event["fields"]["message"], "close"); 682 assert_eq!(event["span"]["context"], "parent"); 683 }); 684 } 685 686 #[test] json_span_event_with_no_fields()687 fn json_span_event_with_no_fields() { 688 // Check span events serialize correctly. 689 // Discussion: https://github.com/tokio-rs/tracing/issues/829#issuecomment-661984255 690 let buffer = MockMakeWriter::default(); 691 let subscriber = subscriber() 692 .with_writer(buffer.clone()) 693 .flatten_event(false) 694 .with_current_span(false) 695 .with_span_list(false) 696 .with_span_events(FmtSpan::FULL) 697 .finish(); 698 699 with_default(subscriber, || { 700 let span = tracing::info_span!("valid_json"); 701 assert_eq!(parse_as_json(&buffer)["fields"]["message"], "new"); 702 703 let _enter = span.enter(); 704 assert_eq!(parse_as_json(&buffer)["fields"]["message"], "enter"); 705 706 drop(_enter); 707 assert_eq!(parse_as_json(&buffer)["fields"]["message"], "exit"); 708 709 drop(span); 710 assert_eq!(parse_as_json(&buffer)["fields"]["message"], "close"); 711 }); 712 } 713 parse_as_json(buffer: &MockMakeWriter) -> serde_json::Value714 fn parse_as_json(buffer: &MockMakeWriter) -> serde_json::Value { 715 let buf = String::from_utf8(buffer.buf().to_vec()).unwrap(); 716 let json = buf 717 .lines() 718 .last() 719 .expect("expected at least one line to be written!"); 720 match serde_json::from_str(json) { 721 Ok(v) => v, 722 Err(e) => panic!( 723 "assertion failed: JSON shouldn't be malformed\n error: {}\n json: {}", 724 e, json 725 ), 726 } 727 } 728 test_json<T>( expected: &str, builder: crate::fmt::SubscriberBuilder<JsonFields, Format<Json>>, producer: impl FnOnce() -> T, )729 fn test_json<T>( 730 expected: &str, 731 builder: crate::fmt::SubscriberBuilder<JsonFields, Format<Json>>, 732 producer: impl FnOnce() -> T, 733 ) { 734 let make_writer = MockMakeWriter::default(); 735 let subscriber = builder 736 .with_writer(make_writer.clone()) 737 .with_timer(MockTime) 738 .finish(); 739 740 with_default(subscriber, producer); 741 742 let buf = make_writer.buf(); 743 let actual = std::str::from_utf8(&buf[..]).unwrap(); 744 assert_eq!( 745 serde_json::from_str::<std::collections::HashMap<&str, serde_json::Value>>(expected) 746 .unwrap(), 747 serde_json::from_str(actual).unwrap() 748 ); 749 } 750 } 751