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(any(
547        feature = "opentelemetry",
548        feature = "tracing-opentelemetry-0-28",
549        feature = "tracing-opentelemetry-0-29",
550        feature = "tracing-opentelemetry-0-30",
551        feature = "tracing-opentelemetry-0-31"
552    ))]
553    #[cfg_attr(
554        docsrs,
555        doc(any(
556            feature = "opentelemetry",
557            feature = "tracing-opentelemetry-0-28",
558            feature = "tracing-opentelemetry-0-29",
559            feature = "tracing-opentelemetry-0-30",
560            feature = "tracing-opentelemetry-0-31"
561        ))
562    )]
563    #[must_use]
564    pub fn with_opentelemetry_ids(mut self, display_opentelemetry_ids: bool) -> Self {
565        self.inner.with_opentelemetry_ids(display_opentelemetry_ids);
566        self
567    }
568}
569
570#[cfg(test)]
571mod tests {
572    use serde_json::json;
573    use tracing::subscriber::with_default;
574    use tracing_subscriber::{registry, Layer as _, Registry};
575
576    use super::Layer;
577    use crate::tests::{MockMakeWriter, MockTime};
578
579    fn test_json<W, T>(
580        expected: &serde_json::Value,
581        layer: Layer<Registry, W>,
582        producer: impl FnOnce() -> T,
583    ) {
584        let actual = produce_log_line(layer, producer);
585        assert_eq!(
586            expected,
587            &serde_json::from_str::<serde_json::Value>(&actual).unwrap(),
588            "expected != actual"
589        );
590    }
591
592    fn produce_log_line<W, T>(layer: Layer<Registry, W>, producer: impl FnOnce() -> T) -> String {
593        let make_writer = MockMakeWriter::default();
594        let collector = layer
595            .with_writer(make_writer.clone())
596            .with_timer(MockTime)
597            .with_subscriber(registry());
598
599        with_default(collector, producer);
600
601        let buf = make_writer.buf();
602        dbg!(std::str::from_utf8(&buf[..]).unwrap()).to_owned()
603    }
604
605    #[test]
606    fn default() {
607        let expected = json!(
608            {
609                "timestamp": "fake time",
610                "level": "INFO",
611                "span": {
612                    "answer": 42,
613                    "name": "json_span",
614                    "number": 3,
615                },
616                "spans": [
617                    {
618                        "answer": 42,
619                        "name": "json_span",
620                        "number": 3,
621                    },
622                ],
623                "target": "json_subscriber::fmt::layer::tests",
624                "fields": {
625                    "message": "some json test",
626                },
627            }
628        );
629
630        let layer = Layer::default();
631
632        test_json(&expected, layer, || {
633            let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
634            let _guard = span.enter();
635            tracing::info!("some json test");
636        });
637    }
638
639    #[test]
640    fn flatten() {
641        let expected = json!(
642            {
643                "timestamp": "fake time",
644                "level": "INFO",
645                "span": {
646                    "answer": 42,
647                    "name": "json_span",
648                    "number": 3,
649                },
650                "spans": [
651                    {
652                        "answer": 42,
653                        "name": "json_span",
654                        "number": 3,
655                    },
656                ],
657                "target": "json_subscriber::fmt::layer::tests",
658                "message": "some json test",
659            }
660        );
661
662        let layer = Layer::default()
663            .flatten_event(true)
664            .with_current_span(true)
665            .with_span_list(true);
666        test_json(&expected, layer, || {
667            let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
668            let _guard = span.enter();
669            tracing::info!("some json test");
670        });
671    }
672
673    #[test]
674    fn flatten_conflict() {
675        // This probably should not work like this. But it's an open question how it *should* work.
676
677        // Notice that there is `level` twice so this is not a valid JSON.
678        #[rustfmt::skip]
679        let expected = "{\"level\":\"INFO\",\"timestamp\":\"fake time\",\"level\":\"this is a bug\",\"message\":\"some json test\"}\n";
680
681        let layer = Layer::default()
682            .flatten_event(true)
683            .with_current_span(false)
684            .with_span_list(false)
685            .with_target(false);
686
687        let actual = produce_log_line(layer, || {
688            let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
689            let _guard = span.enter();
690            tracing::info!(level = "this is a bug", "some json test");
691        });
692
693        assert_eq!(expected, actual);
694    }
695
696    #[test]
697    fn flat_span_list() {
698        let expected = json!(
699            {
700                "timestamp": "fake time",
701                "level": "INFO",
702                "spans": {
703                    "answer": 42,
704                    "name": "child_span",
705                    "number": 100,
706                    "text": "text",
707                },
708                "target": "json_subscriber::fmt::layer::tests",
709                "fields": {
710                    "message": "some json test",
711                },
712            }
713        );
714
715        let layer = Layer::default()
716            .with_flat_span_list(true)
717            .with_current_span(false);
718
719        test_json(&expected, layer, || {
720            let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
721            let _guard = span.enter();
722            let child =
723                tracing::info_span!("child_span", number = 100, text = tracing::field::Empty);
724            let _guard = child.clone().entered();
725            child.record("text", "text");
726            tracing::info!("some json test");
727        });
728    }
729
730    #[test]
731    fn top_level_flatten_current_span() {
732        let expected = json!(
733            {
734                "timestamp": "fake time",
735                "level": "INFO",
736                "name": "child_span",
737                "number": 100,
738                "text": "text",
739                "fields": {
740                    "message": "some json test",
741                },
742            }
743        );
744
745        let layer = Layer::default()
746            .with_target(false)
747            .with_span_list(false)
748            .flatten_current_span_on_top_level(true);
749
750        test_json(&expected, layer, || {
751            let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
752            let _guard = span.enter();
753            let child =
754                tracing::info_span!("child_span", number = 100, text = tracing::field::Empty);
755            let _guard = child.clone().entered();
756            child.record("text", "text");
757            tracing::info!("some json test");
758        });
759    }
760
761    #[test]
762    fn top_level_flatten_span_list() {
763        let expected = json!(
764            {
765                "timestamp": "fake time",
766                "level": "INFO",
767                "name": "child_span",
768                "answer": 42,
769                "number": 100,
770                "text": "text",
771                "fields": {
772                    "message": "some json test",
773                },
774            }
775        );
776
777        let layer = Layer::default()
778            .with_target(false)
779            .with_current_span(false)
780            .flatten_span_list_on_top_level(true);
781
782        test_json(&expected, layer, || {
783            let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
784            let _guard = span.enter();
785            let child =
786                tracing::info_span!("child_span", number = 100, text = tracing::field::Empty);
787            let _guard = child.clone().entered();
788            child.record("text", "text");
789            tracing::info!("some json test");
790        });
791    }
792
793    #[test]
794    fn target_quote() {
795        let expected = json!(
796            {
797                "timestamp": "fake time",
798                "target": "\"",
799                "fields": {
800                    "message": "some json test",
801                },
802            }
803        );
804
805        let layer = Layer::default()
806            .with_span_list(false)
807            .with_current_span(false)
808            .with_level(false);
809
810        test_json(&expected, layer, || {
811            tracing::info!(target: "\"", "some json test");
812        });
813    }
814
815    #[test]
816    fn target_backslash() {
817        let expected = json!(
818            {
819                "timestamp": "fake time",
820                "target": "\\hello\\\\world\\",
821                "fields": {
822                    "message": "some json test",
823                },
824            }
825        );
826
827        let layer = Layer::default()
828            .with_span_list(false)
829            .with_current_span(false)
830            .with_level(false);
831
832        test_json(&expected, layer, || {
833            tracing::info!(target: "\\hello\\\\world\\", "some json test");
834        });
835    }
836}