Skip to main content

json_subscriber/fmt/
layer.rs

1use std::io;
2
3use tracing::Subscriber;
4use tracing_subscriber::{
5    fmt::{
6        time::{FormatTime, SystemTime},
7        MakeWriter,
8        TestWriter,
9    },
10    registry::LookupSpan,
11    Layer as Subscribe,
12    Registry,
13};
14
15use super::names::{
16    CURRENT_SPAN,
17    FIELDS,
18    FILENAME,
19    LEVEL,
20    LINE_NUMBER,
21    SPAN_LIST,
22    TARGET,
23    THREAD_ID,
24    THREAD_NAME,
25    TIMESTAMP,
26};
27use crate::layer::{FlatSchemaKey, JsonLayer};
28
29/// A [`Layer`] that logs JSON formatted representations of `tracing` events.
30///
31/// This is just a wrapper around [`JsonLayer`] which exists for compatibility with
32/// `tracing_subscriber`.
33///
34/// ## Examples
35///
36/// Constructing a layer with the default configuration:
37///
38/// ```rust
39/// use tracing_subscriber::Registry;
40/// use tracing_subscriber::layer::SubscriberExt as _;
41/// use json_subscriber::fmt;
42///
43/// let subscriber = Registry::default()
44///     .with(fmt::Layer::default());
45///
46/// tracing::subscriber::set_global_default(subscriber).unwrap();
47/// ```
48///
49/// Overriding the layer's behavior:
50///
51/// ```rust
52/// use tracing_subscriber::Registry;
53/// use tracing_subscriber::layer::SubscriberExt as _;
54/// use json_subscriber::fmt;
55///
56/// let fmt_layer = fmt::layer()
57///    .with_target(false) // don't include event targets when logging
58///    .with_level(false); // don't include event levels when logging
59///
60/// let subscriber = Registry::default().with(fmt_layer);
61/// # tracing::subscriber::set_global_default(subscriber).unwrap();
62/// ```
63///
64/// [`Layer`]: tracing_subscriber::Layer
65pub struct Layer<S: for<'lookup> LookupSpan<'lookup> = Registry, W = fn() -> io::Stdout> {
66    inner: JsonLayer<S, W>,
67}
68
69impl<S: Subscriber + for<'lookup> LookupSpan<'lookup>> Default for Layer<S> {
70    fn default() -> Self {
71        let mut inner = JsonLayer::stdout();
72
73        inner
74            // If we do not call this, fields are not printed at all.
75            .with_event(FIELDS)
76            .with_timer(TIMESTAMP, SystemTime)
77            .with_target(TARGET)
78            .with_level(LEVEL)
79            .with_current_span(CURRENT_SPAN)
80            .with_span_list(SPAN_LIST);
81
82        Self { inner }
83    }
84}
85
86impl<S, W> Subscribe<S> for Layer<S, W>
87where
88    JsonLayer<S, W>: Subscribe<S>,
89    S: Subscriber + for<'lookup> LookupSpan<'lookup>,
90{
91    fn on_register_dispatch(&self, subscriber: &tracing::Dispatch) {
92        self.inner.on_register_dispatch(subscriber);
93    }
94
95    fn on_layer(&mut self, subscriber: &mut S) {
96        self.inner.on_layer(subscriber);
97    }
98
99    fn register_callsite(
100        &self,
101        metadata: &'static tracing::Metadata<'static>,
102    ) -> tracing_core::Interest {
103        self.inner.register_callsite(metadata)
104    }
105
106    fn enabled(
107        &self,
108        metadata: &tracing::Metadata<'_>,
109        ctx: tracing_subscriber::layer::Context<'_, S>,
110    ) -> bool {
111        self.inner.enabled(metadata, ctx)
112    }
113
114    fn on_new_span(
115        &self,
116        attrs: &tracing_core::span::Attributes<'_>,
117        id: &tracing_core::span::Id,
118        ctx: tracing_subscriber::layer::Context<'_, S>,
119    ) {
120        self.inner.on_new_span(attrs, id, ctx);
121    }
122
123    fn on_record(
124        &self,
125        span: &tracing_core::span::Id,
126        values: &tracing_core::span::Record<'_>,
127        ctx: tracing_subscriber::layer::Context<'_, S>,
128    ) {
129        self.inner.on_record(span, values, ctx);
130    }
131
132    fn on_follows_from(
133        &self,
134        span: &tracing_core::span::Id,
135        follows: &tracing_core::span::Id,
136        ctx: tracing_subscriber::layer::Context<'_, S>,
137    ) {
138        self.inner.on_follows_from(span, follows, ctx);
139    }
140
141    fn event_enabled(
142        &self,
143        event: &tracing::Event<'_>,
144        ctx: tracing_subscriber::layer::Context<'_, S>,
145    ) -> bool {
146        self.inner.event_enabled(event, ctx)
147    }
148
149    fn on_event(&self, event: &tracing::Event<'_>, ctx: tracing_subscriber::layer::Context<'_, S>) {
150        self.inner.on_event(event, ctx);
151    }
152
153    fn on_enter(
154        &self,
155        id: &tracing_core::span::Id,
156        ctx: tracing_subscriber::layer::Context<'_, S>,
157    ) {
158        self.inner.on_enter(id, ctx);
159    }
160
161    fn on_exit(&self, id: &tracing_core::span::Id, ctx: tracing_subscriber::layer::Context<'_, S>) {
162        self.inner.on_exit(id, ctx);
163    }
164
165    fn on_close(&self, id: tracing_core::span::Id, ctx: tracing_subscriber::layer::Context<'_, S>) {
166        self.inner.on_close(id, ctx);
167    }
168
169    fn on_id_change(
170        &self,
171        old: &tracing_core::span::Id,
172        new: &tracing_core::span::Id,
173        ctx: tracing_subscriber::layer::Context<'_, S>,
174    ) {
175        self.inner.on_id_change(old, new, ctx);
176    }
177}
178
179impl<S, W> Layer<S, W>
180where
181    S: Subscriber + for<'lookup> LookupSpan<'lookup>,
182{
183    /// Sets the [`MakeWriter`] that the [`JsonLayer`] being built will use to write events.
184    ///
185    /// # Examples
186    ///
187    /// Using `stderr` rather than `stdout`:
188    ///
189    /// ```rust
190    /// # use tracing_subscriber::prelude::*;
191    /// let layer = json_subscriber::fmt::layer()
192    ///     .with_writer(std::io::stderr);
193    /// # tracing_subscriber::registry().with(layer);
194    /// ```
195    ///
196    /// [`MakeWriter`]: MakeWriter
197    /// [`JsonLayer`]: JsonLayer
198    pub fn with_writer<W2>(self, make_writer: W2) -> Layer<S, W2>
199    where
200        W2: for<'writer> MakeWriter<'writer> + 'static,
201    {
202        Layer::<S, W2> {
203            inner: self.inner.with_writer(make_writer),
204        }
205    }
206
207    /// Updates the [`MakeWriter`] by applying a function to the existing [`MakeWriter`].
208    ///
209    /// This sets the [`MakeWriter`] that the layer being built will use to write events.
210    ///
211    /// # Examples
212    ///
213    /// Redirect output to stderr if level is <= WARN:
214    ///
215    /// ```rust
216    /// # use tracing_subscriber::prelude::*;
217    /// use tracing_subscriber::fmt::writer::MakeWriterExt;
218    ///
219    /// let stderr = std::io::stderr.with_max_level(tracing::Level::WARN);
220    /// let layer = json_subscriber::fmt::layer()
221    ///     .map_writer(move |w| stderr.or_else(w));
222    /// # tracing_subscriber::registry().with(layer);
223    /// ```
224    pub fn map_writer<W2>(self, f: impl FnOnce(W) -> W2) -> Layer<S, W2>
225    where
226        W2: for<'writer> MakeWriter<'writer> + 'static,
227    {
228        Layer::<S, W2> {
229            inner: self.inner.map_writer(f),
230        }
231    }
232
233    /// Configures the layer to support [`libtest`'s output capturing][capturing] when used in
234    /// unit tests.
235    ///
236    /// See [`TestWriter`] for additional details.
237    ///
238    /// # Examples
239    ///
240    /// Using [`TestWriter`] to let `cargo test` capture test output:
241    ///
242    /// ```rust
243    /// # use tracing_subscriber::prelude::*;
244    /// use tracing_subscriber::fmt::writer::MakeWriterExt;
245    ///
246    /// let layer = json_subscriber::fmt::layer()
247    ///     .with_test_writer();
248    /// # tracing_subscriber::registry().with(layer);
249    /// ```
250    /// [capturing]:
251    /// https://doc.rust-lang.org/book/ch11-02-running-tests.html#showing-function-output
252    /// [`TestWriter`]: TestWriter
253    pub fn with_test_writer(self) -> Layer<S, TestWriter> {
254        Layer::<S, TestWriter> {
255            inner: self.inner.with_test_writer(),
256        }
257    }
258
259    /// Borrows the [writer] for this layer.
260    ///
261    /// [writer]: MakeWriter
262    pub fn writer(&self) -> &W {
263        self.inner.writer()
264    }
265
266    /// Mutably borrows the [writer] for this layer.
267    ///
268    /// This method is primarily expected to be used with the [`reload::Handle::modify`] method.
269    ///
270    /// # Examples
271    ///
272    /// ```
273    /// # use tracing::info;
274    /// # use tracing_subscriber::{fmt,reload,Registry,prelude::*};
275    /// # fn non_blocking<T: std::io::Write>(writer: T) -> (fn() -> std::io::Stdout) {
276    /// #   std::io::stdout
277    /// # }
278    /// # fn main() {
279    /// let layer = json_subscriber::fmt::layer().with_writer(non_blocking(std::io::stderr()));
280    /// let (layer, reload_handle) = reload::Layer::new(layer);
281    ///
282    /// tracing_subscriber::registry().with(layer).init();
283    ///
284    /// info!("This will be logged to stderr");
285    /// reload_handle.modify(|subscriber| *subscriber.writer_mut() = non_blocking(std::io::stdout()));
286    /// info!("This will be logged to stdout");
287    /// # }
288    /// ```
289    ///
290    /// [writer]: MakeWriter
291    /// [`reload::Handle::modify`]: tracing_subscriber::reload::Handle::modify
292    pub fn writer_mut(&mut self) -> &mut W {
293        self.inner.writer_mut()
294    }
295
296    /// Mutably borrows the [`JsonLayer`] inside of this layer. This can be useful to add more
297    /// information to the output or to change the output with the [`reload::Handle::modify`]
298    /// method.
299    ///
300    /// # Examples
301    /// ```rust
302    /// # use tracing_subscriber::prelude::*;
303    /// let mut layer = json_subscriber::layer();
304    /// let mut inner = layer.inner_layer_mut();
305    ///
306    /// inner.add_static_field(
307    ///     "hostname",
308    ///     serde_json::json!({
309    ///         "hostname": get_hostname(),
310    ///     }),
311    /// );
312    /// # tracing_subscriber::registry().with(layer);
313    /// # fn get_hostname() -> &'static str { "localhost" }
314    /// ```
315    ///
316    /// [`reload::Handle::modify`]: tracing_subscriber::reload::Handle::modify
317    pub fn inner_layer_mut(&mut self) -> &mut JsonLayer<S, W> {
318        &mut self.inner
319    }
320
321    /// Sets whether to write errors from [`FormatEvent`] to the writer.
322    /// Defaults to true.
323    ///
324    /// By default, `fmt::JsonLayer` will write any `FormatEvent`-internal errors to the writer.
325    /// These errors are unlikely and will only occur if there is a bug in the `FormatEvent`
326    /// implementation or its dependencies.
327    ///
328    /// If writing to the writer fails, the error message is printed to stderr as a fallback.
329    ///
330    /// [`FormatEvent`]: tracing_subscriber::fmt::FormatEvent
331    #[must_use]
332    pub fn log_internal_errors(mut self, log_internal_errors: bool) -> Self {
333        self.inner.log_internal_errors(log_internal_errors);
334        self
335    }
336
337    /// Sets the JSON subscriber being built to flatten the current span's fields to the top level
338    /// of the output.
339    ///
340    /// It is the user's responsibility to make sure that the span field names do not clash with any
341    /// other fields logged on the span. This should not be used with
342    /// [`Self::flatten_span_list_on_top_level`] as that will log the current span's fields twice
343    /// which would make the resulting JSON invalid.
344    #[must_use]
345    pub fn flatten_current_span_on_top_level(mut self, flatten_span: bool) -> Self {
346        if flatten_span {
347            self.inner.remove_field(CURRENT_SPAN);
348            self.inner.with_top_level_flattened_current_span();
349        } else {
350            self.inner
351                .remove_flattened_field(&FlatSchemaKey::FlattenedCurrentSpan);
352            self.inner.with_current_span(CURRENT_SPAN);
353        }
354        self
355    }
356
357    /// Sets the JSON subscriber being built to flatten all parent spans' fields to the top level of
358    /// the output. Values of fields in spans closer to the event will take precedence over spans
359    /// closer to the root span.
360    ///
361    /// If you're looking to have all parent spans' fields flattened but do not need them at the top
362    /// level, use [`Self::with_flat_span_list`] instead.
363    ///
364    /// It is the user's responsibility to make sure that the span field names do not clash with any
365    /// other fields logged on the span. This should not be used with
366    /// [`Self::flatten_current_span_on_top_level`] as that will log the current span's fields twice
367    /// which would make the resulting JSON invalid.
368    #[must_use]
369    pub fn flatten_span_list_on_top_level(mut self, flatten_span_list: bool) -> Self {
370        if flatten_span_list {
371            self.inner.remove_field(SPAN_LIST);
372            self.inner.with_top_level_flattened_span_list();
373        } else {
374            self.inner
375                .remove_flattened_field(&FlatSchemaKey::FlattenedSpanList);
376            self.inner.with_span_list(SPAN_LIST);
377        }
378        self
379    }
380
381    /// Sets the JSON subscriber being built to flatten event metadata.
382    #[must_use]
383    pub fn flatten_event(mut self, flatten_event: bool) -> Self {
384        if flatten_event {
385            self.inner.remove_field(FIELDS);
386            self.inner.with_flattened_event();
387        } else {
388            self.inner
389                .remove_flattened_field(&FlatSchemaKey::FlattenedEvent);
390            self.inner.with_event(FIELDS);
391        }
392        self
393    }
394
395    /// Sets whether or not the formatter will include the current span in formatted events.
396    #[must_use]
397    pub fn with_current_span(mut self, display_current_span: bool) -> Self {
398        if display_current_span {
399            self.inner.with_current_span(CURRENT_SPAN);
400        } else {
401            self.inner.remove_field(CURRENT_SPAN);
402        }
403        self
404    }
405
406    /// Sets whether or not the formatter will include a list (from root to leaf) of all currently
407    /// entered spans in formatted events.
408    ///
409    /// This overrides any previous calls to [`with_flat_span_list`](Self::with_flat_span_list).
410    #[must_use]
411    pub fn with_span_list(mut self, display_span_list: bool) -> Self {
412        if display_span_list {
413            self.inner.with_span_list(SPAN_LIST);
414        } else {
415            self.inner.remove_field(SPAN_LIST);
416        }
417        self
418    }
419
420    /// Sets whether or not the formatter will include an object containing all parent spans'
421    /// fields. If multiple ancestor spans recorded the same field, the span closer to the leaf span
422    /// overrides the values of spans that are closer to the root spans.
423    ///
424    /// This overrides any previous calls to [`with_span_list`](Self::with_span_list).
425    #[must_use]
426    pub fn with_flat_span_list(mut self, flatten_span_list: bool) -> Self {
427        if flatten_span_list {
428            self.inner.with_flattened_span_fields(SPAN_LIST);
429        } else {
430            self.inner.remove_field(SPAN_LIST);
431        }
432        self
433    }
434
435    /// Use the given [`timer`] for log message timestamps.
436    ///
437    /// See the [`time` module] for the provided timer implementations.
438    ///
439    /// Note that using the `"time`"" feature flag enables the
440    /// additional time formatters [`UtcTime`] and [`LocalTime`], which use the
441    /// [`time` crate] to provide more sophisticated timestamp formatting
442    /// options.
443    ///
444    /// [`timer`]: tracing_subscriber::fmt::time::FormatTime
445    /// [`time` module]: mod@tracing_subscriber::fmt::time
446    /// [`UtcTime`]: tracing_subscriber::fmt::time::UtcTime
447    /// [`LocalTime`]: tracing_subscriber::fmt::time::LocalTime
448    /// [`time` crate]: https://docs.rs/time/0.3
449    #[must_use]
450    pub fn with_timer<T: FormatTime + Send + Sync + 'static>(mut self, timer: T) -> Self {
451        self.inner.with_timer(TIMESTAMP, timer);
452        self
453    }
454
455    /// Do not emit timestamps with log messages.
456    #[must_use]
457    pub fn without_time(mut self) -> Self {
458        self.inner.remove_field(TIMESTAMP);
459        self
460    }
461
462    /// Sets whether or not an event's target is displayed.
463    #[must_use]
464    pub fn with_target(mut self, display_target: bool) -> Self {
465        if display_target {
466            self.inner.with_target(TARGET);
467        } else {
468            self.inner.remove_field(TARGET);
469        }
470
471        self
472    }
473
474    /// Sets whether or not an event's [source code file path][file] is
475    /// displayed.
476    ///
477    /// [file]: tracing_core::Metadata::file
478    #[must_use]
479    pub fn with_file(mut self, display_filename: bool) -> Self {
480        if display_filename {
481            self.inner.with_file(FILENAME);
482        } else {
483            self.inner.remove_field(FILENAME);
484        }
485        self
486    }
487
488    /// Sets whether or not an event's [source code line number][line] is
489    /// displayed.
490    ///
491    /// [line]: tracing_core::Metadata::line
492    #[must_use]
493    pub fn with_line_number(mut self, display_line_number: bool) -> Self {
494        if display_line_number {
495            self.inner.with_line_number(LINE_NUMBER);
496        } else {
497            self.inner.remove_field(LINE_NUMBER);
498        }
499        self
500    }
501
502    /// Sets whether or not an event's level is displayed.
503    #[must_use]
504    pub fn with_level(mut self, display_level: bool) -> Self {
505        if display_level {
506            self.inner.with_level(LEVEL);
507        } else {
508            self.inner.remove_field(LEVEL);
509        }
510        self
511    }
512
513    /// Sets whether or not the [name] of the current thread is displayed
514    /// when formatting events.
515    ///
516    /// [name]: std::thread#naming-threads
517    #[must_use]
518    pub fn with_thread_names(mut self, display_thread_name: bool) -> Self {
519        if display_thread_name {
520            self.inner.with_thread_names(THREAD_NAME);
521        } else {
522            self.inner.remove_field(THREAD_NAME);
523        }
524        self
525    }
526
527    /// Sets whether or not the [thread ID] of the current thread is displayed
528    /// when formatting events.
529    ///
530    /// [thread ID]: std::thread::ThreadId
531    #[must_use]
532    pub fn with_thread_ids(mut self, display_thread_id: bool) -> Self {
533        if display_thread_id {
534            self.inner.with_thread_ids(THREAD_ID);
535        } else {
536            self.inner.remove_field(THREAD_ID);
537        }
538
539        self
540    }
541
542    /// Sets whether or not [OpenTelemetry] trace ID and span ID is displayed when formatting
543    /// events.
544    ///
545    /// [OpenTelemetry]: https://opentelemetry.io
546    #[cfg(feature = "__any-tracing-opentelemetry")]
547    #[cfg_attr(docsrs, doc(feature = "__any-tracing-opentelemetry"))]
548    #[must_use]
549    pub fn with_opentelemetry_ids(mut self, display_opentelemetry_ids: bool) -> Self {
550        self.inner.with_opentelemetry_ids(display_opentelemetry_ids);
551        self
552    }
553}
554
555#[cfg(test)]
556mod tests {
557    use serde_json::json;
558    use tracing::subscriber::with_default;
559    use tracing_subscriber::{registry, Layer as _, Registry};
560
561    use super::Layer;
562    use crate::tests::{MockMakeWriter, MockTime};
563
564    fn test_json<W, T>(
565        expected: &serde_json::Value,
566        layer: Layer<Registry, W>,
567        producer: impl FnOnce() -> T,
568    ) {
569        let actual = produce_log_line(layer, producer);
570        assert_eq!(
571            expected,
572            &serde_json::from_str::<serde_json::Value>(&actual).unwrap(),
573            "expected != actual"
574        );
575    }
576
577    fn produce_log_line<W, T>(layer: Layer<Registry, W>, producer: impl FnOnce() -> T) -> String {
578        let make_writer = MockMakeWriter::default();
579        let collector = layer
580            .with_writer(make_writer.clone())
581            .with_timer(MockTime)
582            .with_subscriber(registry());
583
584        with_default(collector, producer);
585
586        let buf = make_writer.buf();
587        dbg!(std::str::from_utf8(&buf[..]).unwrap()).to_owned()
588    }
589
590    #[test]
591    fn default() {
592        let expected = json!(
593            {
594                "timestamp": "fake time",
595                "level": "INFO",
596                "span": {
597                    "answer": 42,
598                    "name": "json_span",
599                    "number": 3,
600                },
601                "spans": [
602                    {
603                        "answer": 42,
604                        "name": "json_span",
605                        "number": 3,
606                    },
607                ],
608                "target": "json_subscriber::fmt::layer::tests",
609                "fields": {
610                    "message": "some json test",
611                },
612            }
613        );
614
615        let layer = Layer::default();
616
617        test_json(&expected, layer, || {
618            let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
619            let _guard = span.enter();
620            tracing::info!("some json test");
621        });
622    }
623
624    #[test]
625    fn flatten() {
626        let expected = json!(
627            {
628                "timestamp": "fake time",
629                "level": "INFO",
630                "span": {
631                    "answer": 42,
632                    "name": "json_span",
633                    "number": 3,
634                },
635                "spans": [
636                    {
637                        "answer": 42,
638                        "name": "json_span",
639                        "number": 3,
640                    },
641                ],
642                "target": "json_subscriber::fmt::layer::tests",
643                "message": "some json test",
644            }
645        );
646
647        let layer = Layer::default()
648            .flatten_event(true)
649            .with_current_span(true)
650            .with_span_list(true);
651        test_json(&expected, layer, || {
652            let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
653            let _guard = span.enter();
654            tracing::info!("some json test");
655        });
656    }
657
658    #[test]
659    fn flatten_conflict() {
660        // This probably should not work like this. But it's an open question how it *should* work.
661
662        // Notice that there is `level` twice so this is not a valid JSON.
663        #[rustfmt::skip]
664        let expected = "{\"level\":\"INFO\",\"timestamp\":\"fake time\",\"level\":\"this is a bug\",\"message\":\"some json test\"}\n";
665
666        let layer = Layer::default()
667            .flatten_event(true)
668            .with_current_span(false)
669            .with_span_list(false)
670            .with_target(false);
671
672        let actual = produce_log_line(layer, || {
673            let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
674            let _guard = span.enter();
675            tracing::info!(level = "this is a bug", "some json test");
676        });
677
678        assert_eq!(expected, actual);
679    }
680
681    #[test]
682    fn flat_span_list() {
683        let expected = json!(
684            {
685                "timestamp": "fake time",
686                "level": "INFO",
687                "spans": {
688                    "answer": 42,
689                    "name": "child_span",
690                    "number": 100,
691                    "text": "text",
692                },
693                "target": "json_subscriber::fmt::layer::tests",
694                "fields": {
695                    "message": "some json test",
696                },
697            }
698        );
699
700        let layer = Layer::default()
701            .with_flat_span_list(true)
702            .with_current_span(false);
703
704        test_json(&expected, layer, || {
705            let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
706            let _guard = span.enter();
707            let child =
708                tracing::info_span!("child_span", number = 100, text = tracing::field::Empty);
709            let _guard = child.clone().entered();
710            child.record("text", "text");
711            tracing::info!("some json test");
712        });
713    }
714
715    #[test]
716    fn top_level_flatten_current_span() {
717        let expected = json!(
718            {
719                "timestamp": "fake time",
720                "level": "INFO",
721                "name": "child_span",
722                "number": 100,
723                "text": "text",
724                "fields": {
725                    "message": "some json test",
726                },
727            }
728        );
729
730        let layer = Layer::default()
731            .with_target(false)
732            .with_span_list(false)
733            .flatten_current_span_on_top_level(true);
734
735        test_json(&expected, layer, || {
736            let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
737            let _guard = span.enter();
738            let child =
739                tracing::info_span!("child_span", number = 100, text = tracing::field::Empty);
740            let _guard = child.clone().entered();
741            child.record("text", "text");
742            tracing::info!("some json test");
743        });
744    }
745
746    #[test]
747    fn top_level_flatten_span_list() {
748        let expected = json!(
749            {
750                "timestamp": "fake time",
751                "level": "INFO",
752                "name": "child_span",
753                "answer": 42,
754                "number": 100,
755                "text": "text",
756                "fields": {
757                    "message": "some json test",
758                },
759            }
760        );
761
762        let layer = Layer::default()
763            .with_target(false)
764            .with_current_span(false)
765            .flatten_span_list_on_top_level(true);
766
767        test_json(&expected, layer, || {
768            let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
769            let _guard = span.enter();
770            let child =
771                tracing::info_span!("child_span", number = 100, text = tracing::field::Empty);
772            let _guard = child.clone().entered();
773            child.record("text", "text");
774            tracing::info!("some json test");
775        });
776    }
777
778    #[test]
779    fn target_quote() {
780        let expected = json!(
781            {
782                "timestamp": "fake time",
783                "target": "\"",
784                "fields": {
785                    "message": "some json test",
786                },
787            }
788        );
789
790        let layer = Layer::default()
791            .with_span_list(false)
792            .with_current_span(false)
793            .with_level(false);
794
795        test_json(&expected, layer, || {
796            tracing::info!(target: "\"", "some json test");
797        });
798    }
799
800    #[test]
801    fn target_backslash() {
802        let expected = json!(
803            {
804                "timestamp": "fake time",
805                "target": "\\hello\\\\world\\",
806                "fields": {
807                    "message": "some json test",
808                },
809            }
810        );
811
812        let layer = Layer::default()
813            .with_span_list(false)
814            .with_current_span(false)
815            .with_level(false);
816
817        test_json(&expected, layer, || {
818            tracing::info!(target: "\\hello\\\\world\\", "some json test");
819        });
820    }
821}