1 use super::{Format, FormatEvent, FormatFields, FormatTime, Writer}
;
3 field
::{RecordFields, VisitOutput}
,
5 fmt_layer
::{FmtContext, FormattedFields}
,
10 use serde
::ser
::{SerializeMap, Serializer as _}
;
11 use serde_json
::Serializer
;
13 collections
::BTreeMap
,
21 use tracing_serde
::AsSerde
;
23 #[cfg(feature = "tracing-log")]
24 use tracing_log
::NormalizeEvent
;
26 /// Marker for [`Format`] that indicates that the newline-delimited JSON log
27 /// format should be used.
29 /// This formatter is intended for production use with systems where structured
30 /// logs are consumed as JSON by analysis and viewing tools. The JSON output is
31 /// not optimized for human readability; instead, it should be pretty-printed
32 /// using external JSON tools such as `jq`, or using a JSON log viewer.
36 /// <pre><font color="#4E9A06"><b>:;</b></font> <font color="#4E9A06">cargo</font> run --example fmt-json
37 /// <font color="#4E9A06"><b> Finished</b></font> dev [unoptimized + debuginfo] target(s) in 0.08s
38 /// <font color="#4E9A06"><b> Running</b></font> `target/debug/examples/fmt-json`
39 /// {"timestamp":"2022-02-15T18:47:10.821315Z","level":"INFO","fields":{"message":"preparing to shave yaks","number_of_yaks":3},"target":"fmt_json"}
40 /// {"timestamp":"2022-02-15T18:47:10.821422Z","level":"INFO","fields":{"message":"shaving yaks"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]}
41 /// {"timestamp":"2022-02-15T18:47:10.821495Z","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":1,"name":"shave"}]}
42 /// {"timestamp":"2022-02-15T18:47:10.821546Z","level":"TRACE","fields":{"message":"yak shaved successfully"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":1,"name":"shave"}]}
43 /// {"timestamp":"2022-02-15T18:47:10.821598Z","level":"DEBUG","fields":{"yak":1,"shaved":true},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]}
44 /// {"timestamp":"2022-02-15T18:47:10.821637Z","level":"TRACE","fields":{"yaks_shaved":1},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]}
45 /// {"timestamp":"2022-02-15T18:47:10.821684Z","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":2,"name":"shave"}]}
46 /// {"timestamp":"2022-02-15T18:47:10.821727Z","level":"TRACE","fields":{"message":"yak shaved successfully"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":2,"name":"shave"}]}
47 /// {"timestamp":"2022-02-15T18:47:10.821773Z","level":"DEBUG","fields":{"yak":2,"shaved":true},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]}
48 /// {"timestamp":"2022-02-15T18:47:10.821806Z","level":"TRACE","fields":{"yaks_shaved":2},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]}
49 /// {"timestamp":"2022-02-15T18:47:10.821909Z","level":"TRACE","fields":{"message":"hello! I'm gonna shave a yak","excitement":"yay!"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":3,"name":"shave"}]}
50 /// {"timestamp":"2022-02-15T18:47:10.821956Z","level":"WARN","fields":{"message":"could not locate yak"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"},{"yak":3,"name":"shave"}]}
51 /// {"timestamp":"2022-02-15T18:47:10.822006Z","level":"DEBUG","fields":{"yak":3,"shaved":false},"target":"yak_events","spans":[{"yaks":3,"name":"shaving_yaks"}]}
52 /// {"timestamp":"2022-02-15T18:47:10.822041Z","level":"ERROR","fields":{"message":"failed to shave yak","yak":3,"error":"missing yak"},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]}
53 /// {"timestamp":"2022-02-15T18:47:10.822079Z","level":"TRACE","fields":{"yaks_shaved":2},"target":"fmt_json::yak_shave","spans":[{"yaks":3,"name":"shaving_yaks"}]}
54 /// {"timestamp":"2022-02-15T18:47:10.822117Z","level":"INFO","fields":{"message":"yak shaving completed","all_yaks_shaved":false},"target":"fmt_json"}
59 /// This formatter exposes additional options to configure the structure of the
60 /// output JSON objects:
62 /// - [`Json::flatten_event`] can be used to enable flattening event fields into
64 /// - [`Json::with_current_span`] can be used to control logging of the current
66 /// - [`Json::with_span_list`] can be used to control logging of the span list
69 /// By default, event fields are not flattened, and both current span and span
72 /// # Valuable Support
74 /// Experimental support is available for using the [`valuable`] crate to record
75 /// user-defined values as structured JSON. When the ["valuable" unstable
76 /// feature][unstable] is enabled, types implementing [`valuable::Valuable`] will
77 /// be recorded as structured JSON, rather than
78 /// using their [`std::fmt::Debug`] implementations.
80 /// **Note**: This is an experimental feature. [Unstable features][unstable]
81 /// must be enabled in order to use `valuable` support.
83 /// [`Json::flatten_event`]: #method.flatten_event
84 /// [`Json::with_current_span`]: #method.with_current_span
85 /// [`Json::with_span_list`]: #method.with_span_list
86 /// [`valuable`]: https://crates.io/crates/valuable
87 /// [unstable]: crate#unstable-features
88 /// [`valuable::Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html
89 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
91 pub(crate) flatten_event
: bool
,
92 pub(crate) display_current_span
: bool
,
93 pub(crate) display_span_list
: bool
,
97 /// If set to `true` event metadata will be flattened into the root object.
98 pub fn flatten_event(&mut self, flatten_event
: bool
) {
99 self.flatten_event
= flatten_event
;
102 /// If set to `false`, formatted events won't contain a field for the current span.
103 pub fn with_current_span(&mut self, display_current_span
: bool
) {
104 self.display_current_span
= display_current_span
;
107 /// If set to `false`, formatted events won't contain a list of all currently
108 /// entered spans. Spans are logged in a list from root to leaf.
109 pub fn with_span_list(&mut self, display_span_list
: bool
) {
110 self.display_span_list
= display_span_list
;
114 struct SerializableContext
<'a
, 'b
, Span
, N
>(
115 &'b
crate::layer
::Context
<'a
, Span
>,
116 std
::marker
::PhantomData
<N
>,
119 Span
: Subscriber
+ for<'lookup
> crate::registry
::LookupSpan
<'lookup
>,
120 N
: for<'writer
> FormatFields
<'writer
> + '
static;
122 impl<'a
, 'b
, Span
, N
> serde
::ser
::Serialize
for SerializableContext
<'a
, 'b
, Span
, N
>
124 Span
: Subscriber
+ for<'lookup
> crate::registry
::LookupSpan
<'lookup
>,
125 N
: for<'writer
> FormatFields
<'writer
> + '
static,
127 fn serialize
<Ser
>(&self, serializer_o
: Ser
) -> Result
<Ser
::Ok
, Ser
::Error
>
129 Ser
: serde
::ser
::Serializer
,
131 use serde
::ser
::SerializeSeq
;
132 let mut serializer
= serializer_o
.serialize_seq(None
)?
;
134 if let Some(leaf_span
) = self.0.lookup_current() {
135 for span
in leaf_span
.scope().from_root() {
136 serializer
.serialize_element(&SerializableSpan(&span
, self.1))?
;
144 struct SerializableSpan
<'a
, 'b
, Span
, N
>(
145 &'b
crate::registry
::SpanRef
<'a
, Span
>,
146 std
::marker
::PhantomData
<N
>,
149 Span
: for<'lookup
> crate::registry
::LookupSpan
<'lookup
>,
150 N
: for<'writer
> FormatFields
<'writer
> + '
static;
152 impl<'a
, 'b
, Span
, N
> serde
::ser
::Serialize
for SerializableSpan
<'a
, 'b
, Span
, N
>
154 Span
: for<'lookup
> crate::registry
::LookupSpan
<'lookup
>,
155 N
: for<'writer
> FormatFields
<'writer
> + '
static,
157 fn serialize
<Ser
>(&self, serializer
: Ser
) -> Result
<Ser
::Ok
, Ser
::Error
>
159 Ser
: serde
::ser
::Serializer
,
161 let mut serializer
= serializer
.serialize_map(None
)?
;
163 let ext
= self.0.extensions();
165 .get
::<FormattedFields
<N
>>()
166 .expect("Unable to find FormattedFields in extensions; this is a bug");
168 // TODO: let's _not_ do this, but this resolves
169 // https://github.com/tokio-rs/tracing/issues/391.
170 // We should probably rework this to use a `serde_json::Value` or something
171 // similar in a JSON-specific layer, but I'd (david)
172 // rather have a uglier fix now rather than shipping broken JSON.
173 match serde_json
::from_str
::<serde_json
::Value
>(data
) {
174 Ok(serde_json
::Value
::Object(fields
)) => {
175 for field
in fields
{
176 serializer
.serialize_entry(&field
.0, &field
.1)?
;
179 // We have fields for this span which are valid JSON but not an object.
180 // This is probably a bug, so panic if we're in debug mode
181 Ok(_
) if cfg
!(debug_assertions
) => panic
!(
182 "span '{}' had malformed fields! this is a bug.\n error: invalid JSON object\n fields: {:?}",
183 self.0.metadata().name(),
186 // If we *aren't* in debug mode, it's probably best not to
187 // crash the program, let's log the field found but also an
188 // message saying it's type is invalid
190 serializer
.serialize_entry("field", &value
)?
;
191 serializer
.serialize_entry("field_error", "field was no a valid object")?
193 // We have previously recorded fields for this span
194 // should be valid JSON. However, they appear to *not*
195 // be valid JSON. This is almost certainly a bug, so
196 // panic if we're in debug mode
197 Err(e
) if cfg
!(debug_assertions
) => panic
!(
198 "span '{}' had malformed fields! this is a bug.\n error: {}\n fields: {:?}",
199 self.0.metadata().name(),
203 // If we *aren't* in debug mode, it's probably best not
204 // crash the program, but let's at least make sure it's clear
205 // that the fields are not supposed to be missing.
206 Err(e
) => serializer
.serialize_entry("field_error", &format
!("{}", e
))?
,
208 serializer
.serialize_entry("name", self.0.metadata().name())?
;
213 impl<S
, N
, T
> FormatEvent
<S
, N
> for Format
<Json
, T
>
215 S
: Subscriber
+ for<'lookup
> LookupSpan
<'lookup
>,
216 N
: for<'writer
> FormatFields
<'writer
> + '
static,
221 ctx
: &FmtContext
<'_
, S
, N
>,
222 mut writer
: Writer
<'_
>,
226 S
: Subscriber
+ for<'a
> LookupSpan
<'a
>,
228 let mut timestamp
= String
::new();
229 self.timer
.format_time(&mut Writer
::new(&mut timestamp
))?
;
231 #[cfg(feature = "tracing-log")]
232 let normalized_meta
= event
.normalized_metadata();
233 #[cfg(feature = "tracing-log")]
234 let meta
= normalized_meta
.as_ref().unwrap_or_else(|| event
.metadata());
235 #[cfg(not(feature = "tracing-log"))]
236 let meta
= event
.metadata();
239 let mut serializer
= Serializer
::new(WriteAdaptor
::new(&mut writer
));
241 let mut serializer
= serializer
.serialize_map(None
)?
;
243 if self.display_timestamp
{
244 serializer
.serialize_entry("timestamp", ×tamp
)?
;
247 if self.display_level
{
248 serializer
.serialize_entry("level", &meta
.level().as_serde())?
;
251 let format_field_marker
: std
::marker
::PhantomData
<N
> = std
::marker
::PhantomData
;
253 let current_span
= if self.format
.display_current_span
|| self.format
.display_span_list
257 .and_then(|id
| ctx
.span(id
))
258 .or_else(|| ctx
.lookup_current())
263 if self.format
.flatten_event
{
264 let mut visitor
= tracing_serde
::SerdeMapVisitor
::new(serializer
);
265 event
.record(&mut visitor
);
267 serializer
= visitor
.take_serializer()?
;
269 use tracing_serde
::fields
::AsMap
;
270 serializer
.serialize_entry("fields", &event
.field_map())?
;
273 if self.display_target
{
274 serializer
.serialize_entry("target", meta
.target())?
;
277 if self.display_filename
{
278 if let Some(filename
) = meta
.file() {
279 serializer
.serialize_entry("filename", filename
)?
;
283 if self.display_line_number
{
284 if let Some(line_number
) = meta
.line() {
285 serializer
.serialize_entry("line_number", &line_number
)?
;
289 if self.format
.display_current_span
{
290 if let Some(ref span
) = current_span
{
292 .serialize_entry("span", &SerializableSpan(span
, format_field_marker
))
297 if self.format
.display_span_list
&& current_span
.is_some() {
298 serializer
.serialize_entry(
300 &SerializableContext(&ctx
.ctx
, format_field_marker
),
304 if self.display_thread_name
{
305 let current_thread
= std
::thread
::current();
306 match current_thread
.name() {
308 serializer
.serialize_entry("threadName", name
)?
;
310 // fall-back to thread id when name is absent and ids are not enabled
311 None
if !self.display_thread_id
=> {
313 .serialize_entry("threadName", &format
!("{:?}", current_thread
.id()))?
;
319 if self.display_thread_id
{
321 .serialize_entry("threadId", &format
!("{:?}", std
::thread
::current().id()))?
;
327 visit().map_err(|_
| fmt
::Error
)?
;
332 impl Default
for Json
{
333 fn default() -> Json
{
335 flatten_event
: false,
336 display_current_span
: true,
337 display_span_list
: true,
342 /// The JSON [`FormatFields`] implementation.
344 /// [`FormatFields`]: trait.FormatFields.html
346 pub struct JsonFields
{
347 // reserve the ability to add fields to this without causing a breaking
348 // change in the future.
353 /// Returns a new JSON [`FormatFields`] implementation.
355 /// [`FormatFields`]: trait.FormatFields.html
356 pub fn new() -> Self {
357 Self { _private: () }
361 impl Default
for JsonFields
{
362 fn default() -> Self {
367 impl<'a
> FormatFields
<'a
> for JsonFields
{
368 /// Format the provided `fields` to the provided `writer`, returning a result.
369 fn format_fields
<R
: RecordFields
>(&self, mut writer
: Writer
<'_
>, fields
: R
) -> fmt
::Result
{
370 let mut v
= JsonVisitor
::new(&mut writer
);
371 fields
.record(&mut v
);
375 /// Record additional field(s) on an existing span.
377 /// By default, this appends a space to the current set of fields if it is
378 /// non-empty, and then calls `self.format_fields`. If different behavior is
379 /// required, the default implementation of this method can be overridden.
382 current
: &'a
mut FormattedFields
<Self>,
385 if current
.is_empty() {
386 // If there are no previously recorded fields, we can just reuse the
388 let mut writer
= current
.as_writer();
389 let mut v
= JsonVisitor
::new(&mut writer
);
390 fields
.record(&mut v
);
395 // If fields were previously recorded on this span, we need to parse
396 // the current set of fields as JSON, add the new fields, and
397 // re-serialize them. Otherwise, if we just appended the new fields
398 // to a previously serialized JSON object, we would end up with
401 // XXX(eliza): this is far from efficient, but unfortunately, it is
402 // necessary as long as the JSON formatter is implemented on top of
403 // an interface that stores all formatted fields as strings.
405 // We should consider reimplementing the JSON formatter as a
406 // separate layer, rather than a formatter for the `fmt` layer —
407 // then, we could store fields as JSON values, and add to them
408 // without having to parse and re-serialize.
409 let mut new
= String
::new();
410 let map
: BTreeMap
<&'_
str, serde_json
::Value
> =
411 serde_json
::from_str(current
).map_err(|_
| fmt
::Error
)?
;
412 let mut v
= JsonVisitor
::new(&mut new
);
414 fields
.record(&mut v
);
416 current
.fields
= new
;
422 /// The [visitor] produced by [`JsonFields`]'s [`MakeVisitor`] implementation.
424 /// [visitor]: ../../field/trait.Visit.html
425 /// [`JsonFields`]: struct.JsonFields.html
426 /// [`MakeVisitor`]: ../../field/trait.MakeVisitor.html
427 pub struct JsonVisitor
<'a
> {
428 values
: BTreeMap
<&'a
str, serde_json
::Value
>,
429 writer
: &'a
mut dyn Write
,
432 impl<'a
> fmt
::Debug
for JsonVisitor
<'a
> {
433 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
434 f
.write_fmt(format_args
!("JsonVisitor {{ values: {:?} }}", self.values
))
438 impl<'a
> JsonVisitor
<'a
> {
439 /// Returns a new default visitor that formats to the provided `writer`.
442 /// - `writer`: the writer to format to.
443 /// - `is_empty`: whether or not any fields have been previously written to
445 pub fn new(writer
: &'a
mut dyn Write
) -> Self {
447 values
: BTreeMap
::new(),
453 impl<'a
> crate::field
::VisitFmt
for JsonVisitor
<'a
> {
454 fn writer(&mut self) -> &mut dyn fmt
::Write
{
459 impl<'a
> crate::field
::VisitOutput
<fmt
::Result
> for JsonVisitor
<'a
> {
460 fn finish(self) -> fmt
::Result
{
462 let mut serializer
= Serializer
::new(WriteAdaptor
::new(self.writer
));
463 let mut ser_map
= serializer
.serialize_map(None
)?
;
465 for (k
, v
) in self.values
{
466 ser_map
.serialize_entry(k
, &v
)?
;
472 if inner().is_err() {
480 impl<'a
> field
::Visit
for JsonVisitor
<'a
> {
481 #[cfg(all(tracing_unstable, feature = "valuable"))]
482 fn record_value(&mut self, field
: &Field
, value
: valuable_crate
::Value
<'_
>) {
483 let value
= match serde_json
::to_value(valuable_serde
::Serializable
::new(value
)) {
486 #[cfg(debug_assertions)]
488 "`valuable::Valuable` implementations should always serialize \
489 successfully, but an error occurred: {}",
493 #[cfg(not(debug_assertions))]
498 self.values
.insert(field
.name(), value
);
501 /// Visit a double precision floating point value.
502 fn record_f64(&mut self, field
: &Field
, value
: f64) {
504 .insert(field
.name(), serde_json
::Value
::from(value
));
507 /// Visit a signed 64-bit integer value.
508 fn record_i64(&mut self, field
: &Field
, value
: i64) {
510 .insert(field
.name(), serde_json
::Value
::from(value
));
513 /// Visit an unsigned 64-bit integer value.
514 fn record_u64(&mut self, field
: &Field
, value
: u64) {
516 .insert(field
.name(), serde_json
::Value
::from(value
));
519 /// Visit a boolean value.
520 fn record_bool(&mut self, field
: &Field
, value
: bool
) {
522 .insert(field
.name(), serde_json
::Value
::from(value
));
525 /// Visit a string value.
526 fn record_str(&mut self, field
: &Field
, value
: &str) {
528 .insert(field
.name(), serde_json
::Value
::from(value
));
531 fn record_debug(&mut self, field
: &Field
, value
: &dyn fmt
::Debug
) {
533 // Skip fields that are actually log metadata that have already been handled
534 #[cfg(feature = "tracing-log")]
535 name
if name
.starts_with("log.") => (),
536 name
if name
.starts_with("r#") => {
538 .insert(&name
[2..], serde_json
::Value
::from(format
!("{:?}", value
)));
542 .insert(name
, serde_json
::Value
::from(format
!("{:?}", value
)));
550 use crate::fmt
::{format::FmtSpan, test::MockMakeWriter, time::FormatTime, SubscriberBuilder}
;
551 use tracing
::{self, subscriber::with_default}
;
557 impl FormatTime
for MockTime
{
558 fn format_time(&self, w
: &mut Writer
<'_
>) -> fmt
::Result
{
559 write
!(w
, "fake time")
563 fn subscriber() -> SubscriberBuilder
<JsonFields
, Format
<Json
>> {
564 SubscriberBuilder
::default().json()
570 "{\"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";
571 let subscriber
= subscriber()
572 .flatten_event(false)
573 .with_current_span(true)
574 .with_span_list(true);
575 test_json(expected
, subscriber
, || {
576 let span
= tracing
::span
!(tracing
::Level
::INFO
, "json_span", answer
= 42, number
= 3);
577 let _guard
= span
.enter();
578 tracing
::info
!("some json test");
584 let current_path
= Path
::new("tracing-subscriber")
590 .expect("path must be valid unicode")
591 // escape windows backslashes
592 .replace('
\\'
, "\\\\");
595 "{\"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\",\"filename\":\"",
597 "\",\"fields\":{\"message\":\"some json test\"}}\n");
598 let subscriber
= subscriber()
599 .flatten_event(false)
600 .with_current_span(true)
602 .with_span_list(true);
603 test_json(expected
, subscriber
, || {
604 let span
= tracing
::span
!(tracing
::Level
::INFO
, "json_span", answer
= 42, number
= 3);
605 let _guard
= span
.enter();
606 tracing
::info
!("some json test");
611 fn json_line_number() {
613 "{\"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\",\"line_number\":42,\"fields\":{\"message\":\"some json test\"}}\n";
614 let subscriber
= subscriber()
615 .flatten_event(false)
616 .with_current_span(true)
617 .with_line_number(true)
618 .with_span_list(true);
619 test_json_with_line_number(expected
, subscriber
, || {
620 let span
= tracing
::span
!(tracing
::Level
::INFO
, "json_span", answer
= 42, number
= 3);
621 let _guard
= span
.enter();
622 tracing
::info
!("some json test");
627 fn json_flattened_event() {
629 "{\"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";
631 let subscriber
= subscriber()
633 .with_current_span(true)
634 .with_span_list(true);
635 test_json(expected
, subscriber
, || {
636 let span
= tracing
::span
!(tracing
::Level
::INFO
, "json_span", answer
= 42, number
= 3);
637 let _guard
= span
.enter();
638 tracing
::info
!("some json test");
643 fn json_disabled_current_span_event() {
645 "{\"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";
646 let subscriber
= subscriber()
647 .flatten_event(false)
648 .with_current_span(false)
649 .with_span_list(true);
650 test_json(expected
, subscriber
, || {
651 let span
= tracing
::span
!(tracing
::Level
::INFO
, "json_span", answer
= 42, number
= 3);
652 let _guard
= span
.enter();
653 tracing
::info
!("some json test");
658 fn json_disabled_span_list_event() {
660 "{\"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";
661 let subscriber
= subscriber()
662 .flatten_event(false)
663 .with_current_span(true)
664 .with_span_list(false);
665 test_json(expected
, subscriber
, || {
666 let span
= tracing
::span
!(tracing
::Level
::INFO
, "json_span", answer
= 42, number
= 3);
667 let _guard
= span
.enter();
668 tracing
::info
!("some json test");
673 fn json_nested_span() {
675 "{\"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";
676 let subscriber
= subscriber()
677 .flatten_event(false)
678 .with_current_span(true)
679 .with_span_list(true);
680 test_json(expected
, subscriber
, || {
681 let span
= tracing
::span
!(tracing
::Level
::INFO
, "json_span", answer
= 42, number
= 3);
682 let _guard
= span
.enter();
683 let span
= tracing
::span
!(
684 tracing
::Level
::INFO
,
689 let _guard
= span
.enter();
690 tracing
::info
!("some json test");
697 "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"target\":\"tracing_subscriber::fmt::format::json::test\",\"fields\":{\"message\":\"some json test\"}}\n";
698 let subscriber
= subscriber()
699 .flatten_event(false)
700 .with_current_span(true)
701 .with_span_list(true);
702 test_json(expected
, subscriber
, || {
703 tracing
::info
!("some json test");
709 // This test reproduces issue #707, where using `Span::record` causes
710 // any events inside the span to be ignored.
712 let make_writer
= MockMakeWriter
::default();
713 let subscriber
= crate::fmt()
715 .with_writer(make_writer
.clone())
718 with_default(subscriber
, || {
719 tracing
::info
!("an event outside the root span");
721 parse_as_json(&make_writer
)["fields"]["message"],
722 "an event outside the root span"
725 let span
= tracing
::info_span
!("the span", na
= tracing
::field
::Empty
);
726 span
.record("na", &"value");
727 let _enter
= span
.enter();
729 tracing
::info
!("an event inside the root span");
731 parse_as_json(&make_writer
)["fields"]["message"],
732 "an event inside the root span"
738 fn json_span_event_show_correct_context() {
739 let buffer
= MockMakeWriter
::default();
740 let subscriber
= subscriber()
741 .with_writer(buffer
.clone())
742 .flatten_event(false)
743 .with_current_span(true)
744 .with_span_list(false)
745 .with_span_events(FmtSpan
::FULL
)
748 with_default(subscriber
, || {
749 let context
= "parent";
750 let parent_span
= tracing
::info_span
!("parent_span", context
);
752 let event
= parse_as_json(&buffer
);
753 assert_eq
!(event
["fields"]["message"], "new");
754 assert_eq
!(event
["span"]["context"], "parent");
756 let _parent_enter
= parent_span
.enter();
757 let event
= parse_as_json(&buffer
);
758 assert_eq
!(event
["fields"]["message"], "enter");
759 assert_eq
!(event
["span"]["context"], "parent");
761 let context
= "child";
762 let child_span
= tracing
::info_span
!("child_span", context
);
763 let event
= parse_as_json(&buffer
);
764 assert_eq
!(event
["fields"]["message"], "new");
765 assert_eq
!(event
["span"]["context"], "child");
767 let _child_enter
= child_span
.enter();
768 let event
= parse_as_json(&buffer
);
769 assert_eq
!(event
["fields"]["message"], "enter");
770 assert_eq
!(event
["span"]["context"], "child");
773 let event
= parse_as_json(&buffer
);
774 assert_eq
!(event
["fields"]["message"], "exit");
775 assert_eq
!(event
["span"]["context"], "child");
778 let event
= parse_as_json(&buffer
);
779 assert_eq
!(event
["fields"]["message"], "close");
780 assert_eq
!(event
["span"]["context"], "child");
783 let event
= parse_as_json(&buffer
);
784 assert_eq
!(event
["fields"]["message"], "exit");
785 assert_eq
!(event
["span"]["context"], "parent");
788 let event
= parse_as_json(&buffer
);
789 assert_eq
!(event
["fields"]["message"], "close");
790 assert_eq
!(event
["span"]["context"], "parent");
795 fn json_span_event_with_no_fields() {
796 // Check span events serialize correctly.
797 // Discussion: https://github.com/tokio-rs/tracing/issues/829#issuecomment-661984255
798 let buffer
= MockMakeWriter
::default();
799 let subscriber
= subscriber()
800 .with_writer(buffer
.clone())
801 .flatten_event(false)
802 .with_current_span(false)
803 .with_span_list(false)
804 .with_span_events(FmtSpan
::FULL
)
807 with_default(subscriber
, || {
808 let span
= tracing
::info_span
!("valid_json");
809 assert_eq
!(parse_as_json(&buffer
)["fields"]["message"], "new");
811 let _enter
= span
.enter();
812 assert_eq
!(parse_as_json(&buffer
)["fields"]["message"], "enter");
815 assert_eq
!(parse_as_json(&buffer
)["fields"]["message"], "exit");
818 assert_eq
!(parse_as_json(&buffer
)["fields"]["message"], "close");
822 fn parse_as_json(buffer
: &MockMakeWriter
) -> serde_json
::Value
{
823 let buf
= String
::from_utf8(buffer
.buf().to_vec()).unwrap();
827 .expect("expected at least one line to be written!");
828 match serde_json
::from_str(json
) {
831 "assertion failed: JSON shouldn't be malformed\n error: {}\n json: {}",
839 builder
: crate::fmt
::SubscriberBuilder
<JsonFields
, Format
<Json
>>,
840 producer
: impl FnOnce() -> T
,
842 let make_writer
= MockMakeWriter
::default();
843 let subscriber
= builder
844 .with_writer(make_writer
.clone())
845 .with_timer(MockTime
)
848 with_default(subscriber
, producer
);
850 let buf
= make_writer
.buf();
851 let actual
= std
::str::from_utf8(&buf
[..]).unwrap();
853 serde_json
::from_str
::<std
::collections
::HashMap
<&str, serde_json
::Value
>>(expected
)
855 serde_json
::from_str(actual
).unwrap()
859 fn test_json_with_line_number
<T
>(
861 builder
: crate::fmt
::SubscriberBuilder
<JsonFields
, Format
<Json
>>,
862 producer
: impl FnOnce() -> T
,
864 let make_writer
= MockMakeWriter
::default();
865 let subscriber
= builder
866 .with_writer(make_writer
.clone())
867 .with_timer(MockTime
)
870 with_default(subscriber
, producer
);
872 let buf
= make_writer
.buf();
873 let actual
= std
::str::from_utf8(&buf
[..]).unwrap();
875 serde_json
::from_str
::<std
::collections
::HashMap
<&str, serde_json
::Value
>>(expected
)
877 let expect_line_number
= expected
.remove("line_number").is_some();
878 let mut actual
: std
::collections
::HashMap
<&str, serde_json
::Value
> =
879 serde_json
::from_str(actual
).unwrap();
880 let line_number
= actual
.remove("line_number");
881 if expect_line_number
{
882 assert_eq
!(line_number
.map(|x
| x
.is_number()), Some(true));
884 assert
!(line_number
.is_none());
886 assert_eq
!(actual
, expected
);