json_subscriber/layer/
mod.rs

1use std::{
2    borrow::Cow,
3    cell::RefCell,
4    collections::{BTreeMap, HashMap},
5    fmt,
6    io,
7    sync::Arc,
8};
9
10use serde::Serialize;
11use tracing_core::{
12    span::{Attributes, Id, Record},
13    Event,
14    Subscriber,
15};
16use tracing_serde::fields::AsMap;
17use tracing_subscriber::{
18    fmt::{format::Writer, time::FormatTime, MakeWriter, TestWriter},
19    layer::Context,
20    registry::{LookupSpan, SpanRef},
21    Layer,
22    Registry,
23};
24
25mod event;
26
27use event::EventRef;
28use uuid::Uuid;
29
30use crate::{
31    cached::Cached,
32    fields::{JsonFields, JsonFieldsInner},
33    visitor::JsonVisitor,
34};
35
36/// Layer that implements logging JSON to a configured output. This is a lower-level API that may
37/// change a bit in next versions.
38///
39/// See [`fmt::Layer`](crate::fmt::Layer) for an alternative especially if you're migrating from
40/// `tracing_subscriber`.
41pub struct JsonLayer<S: for<'lookup> LookupSpan<'lookup> = Registry, W = fn() -> io::Stdout> {
42    make_writer: W,
43    log_internal_errors: bool,
44    keyed_values: BTreeMap<SchemaKey, JsonValue<S>>,
45    flattened_values: BTreeMap<FlatSchemaKey, JsonValue<S>>,
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
49pub(crate) enum SchemaKey {
50    Static(Cow<'static, str>),
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
54pub(crate) enum FlatSchemaKey {
55    Uuid(Uuid),
56    FlattenedEvent,
57    FlattenedCurrentSpan,
58    FlattenedSpanList,
59}
60
61impl FlatSchemaKey {
62    fn new_uuid() -> Self {
63        Self::Uuid(uuid::Uuid::new_v4())
64    }
65}
66
67impl From<Cow<'static, str>> for SchemaKey {
68    fn from(value: Cow<'static, str>) -> Self {
69        Self::Static(value)
70    }
71}
72
73impl From<&'static str> for SchemaKey {
74    fn from(value: &'static str) -> Self {
75        Self::Static(value.into())
76    }
77}
78
79impl From<String> for SchemaKey {
80    fn from(value: String) -> Self {
81        Self::Static(value.into())
82    }
83}
84
85#[allow(clippy::type_complexity)]
86pub(crate) enum JsonValue<S: for<'lookup> LookupSpan<'lookup>> {
87    Serde(serde_json::Value),
88    DynamicFromEvent(
89        Box<dyn Fn(&EventRef<'_, '_, '_, S>) -> Option<serde_json::Value> + Send + Sync>,
90    ),
91    DynamicFromSpan(Box<dyn Fn(&SpanRef<'_, S>) -> Option<serde_json::Value> + Send + Sync>),
92    DynamicCachedFromSpan(Box<dyn Fn(&SpanRef<'_, S>) -> Option<Cached> + Send + Sync>),
93    DynamicRawFromEvent(
94        Box<dyn Fn(&EventRef<'_, '_, '_, S>, &mut dyn fmt::Write) -> fmt::Result + Send + Sync>,
95    ),
96}
97
98impl<S, W> Layer<S> for JsonLayer<S, W>
99where
100    S: Subscriber + for<'lookup> LookupSpan<'lookup>,
101    W: for<'writer> MakeWriter<'writer> + 'static,
102{
103    fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
104        let Some(span) = ctx.span(id) else {
105            if self.log_internal_errors {
106                eprintln!("[json-subscriber] Span not found, this is a bug.");
107            }
108            return;
109        };
110
111        let mut extensions = span.extensions_mut();
112
113        if extensions.get_mut::<JsonFields>().is_none() {
114            let mut fields = JsonFieldsInner::default();
115            let mut visitor = JsonVisitor::new(&mut fields);
116            attrs.record(&mut visitor);
117            fields
118                .fields
119                .insert("name", serde_json::Value::from(attrs.metadata().name()));
120            let fields = fields.finish();
121            extensions.insert(fields);
122        } else if self.log_internal_errors {
123            eprintln!(
124                "[json-subscriber] Unable to format the following event, ignoring: {attrs:?}",
125            );
126        }
127    }
128
129    fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {
130        let Some(span) = ctx.span(id) else {
131            if self.log_internal_errors {
132                eprintln!("[json-subscriber] Span not found, this is a bug.");
133            }
134            return;
135        };
136
137        let mut extensions = span.extensions_mut();
138        let Some(fields) = extensions.get_mut::<JsonFields>() else {
139            if self.log_internal_errors {
140                eprintln!(
141                    "[json-subscriber] Span was created but does not contain formatted fields, \
142                     this is a bug and some fields may have been lost."
143                );
144            }
145            return;
146        };
147
148        values.record(&mut JsonVisitor::new(&mut fields.inner));
149        let serialized = serde_json::to_string(&fields).unwrap();
150        fields.serialized = Arc::from(serialized.as_str());
151    }
152
153    fn on_enter(&self, _id: &Id, _ctx: Context<'_, S>) {}
154
155    fn on_exit(&self, _id: &Id, _ctx: Context<'_, S>) {}
156
157    fn on_close(&self, _id: Id, _ctx: Context<'_, S>) {}
158
159    fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
160        thread_local! {
161            static BUF: RefCell<String> = const { RefCell::new(String::new()) };
162        }
163
164        BUF.with(|buf| {
165            let borrow = buf.try_borrow_mut();
166            let mut a;
167            let mut b;
168            let buf = if let Ok(buf) = borrow {
169                a = buf;
170                &mut *a
171            } else {
172                b = String::new();
173                &mut b
174            };
175
176            if self.format_event(&ctx, buf, event).is_ok() {
177                let mut writer = self.make_writer.make_writer_for(event.metadata());
178                let res = io::Write::write_all(&mut writer, buf.as_bytes());
179                if self.log_internal_errors {
180                    if let Err(e) = res {
181                        eprintln!(
182                            "[tracing-json] Unable to write an event to the Writer for this \
183                             Subscriber! Error: {e}\n",
184                        );
185                    }
186                }
187            } else if self.log_internal_errors {
188                eprintln!(
189                    "[tracing-json] Unable to format the following event. Name: {}; Fields: {:?}",
190                    event.metadata().name(),
191                    event.fields()
192                );
193            }
194
195            buf.clear();
196        });
197    }
198}
199
200impl<S> JsonLayer<S>
201where
202    S: Subscriber + for<'lookup> LookupSpan<'lookup>,
203{
204    /// Creates an empty [`JsonLayer`] which will output logs to stdout.
205    pub fn stdout() -> JsonLayer<S, fn() -> io::Stdout> {
206        JsonLayer::new(io::stdout)
207    }
208
209    /// Creates an empty [`JsonLayer`] which will output logs to stderr.
210    pub fn stderr() -> JsonLayer<S, fn() -> io::Stderr> {
211        JsonLayer::new(io::stderr)
212    }
213
214    /// Creates an empty [`JsonLayer`] which will output logs to the configured
215    /// [`Writer`](io::Write).
216    pub fn new<W>(make_writer: W) -> JsonLayer<S, W>
217    where
218        W: for<'writer> MakeWriter<'writer> + 'static,
219    {
220        JsonLayer::<S, W> {
221            make_writer,
222            log_internal_errors: false,
223            keyed_values: BTreeMap::new(),
224            flattened_values: BTreeMap::new(),
225        }
226    }
227}
228
229impl<S, W> JsonLayer<S, W>
230where
231    S: Subscriber + for<'lookup> LookupSpan<'lookup>,
232{
233    /// Sets the [`MakeWriter`] that the [`JsonLayer`] being built will use to write events.
234    ///
235    /// # Examples
236    ///
237    /// Using `stderr` rather than `stdout`:
238    ///
239    /// ```rust
240    /// # use tracing_subscriber::prelude::*;
241    /// let layer = json_subscriber::JsonLayer::stdout()
242    ///     .with_writer(std::io::stderr);
243    /// # tracing_subscriber::registry().with(layer);
244    /// ```
245    ///
246    /// [`MakeWriter`]: MakeWriter
247    /// [`JsonLayer`]: super::JsonLayer
248    pub fn with_writer<W2>(self, make_writer: W2) -> JsonLayer<S, W2>
249    where
250        W2: for<'writer> MakeWriter<'writer> + 'static,
251    {
252        JsonLayer {
253            make_writer,
254            log_internal_errors: self.log_internal_errors,
255            keyed_values: self.keyed_values,
256            flattened_values: self.flattened_values,
257        }
258    }
259
260    /// Borrows the [writer] for this subscriber.
261    ///
262    /// [writer]: MakeWriter
263    pub fn writer(&self) -> &W {
264        &self.make_writer
265    }
266
267    /// Mutably borrows the [writer] for this subscriber.
268    ///
269    /// This method is primarily expected to be used with the
270    /// [`reload::Handle::modify`](tracing_subscriber::reload::Handle::modify) method.
271    ///
272    /// # Examples
273    ///
274    /// ```
275    /// # use tracing::info;
276    /// # use tracing_subscriber::{fmt,reload,Registry,prelude::*};
277    /// # fn non_blocking<T: std::io::Write>(writer: T) -> (fn() -> std::io::Stdout) {
278    /// #   std::io::stdout
279    /// # }
280    /// # fn main() {
281    /// let layer = json_subscriber::JsonLayer::stdout().with_writer(non_blocking(std::io::stderr()));
282    /// let (layer, reload_handle) = reload::Layer::new(layer);
283    ///
284    /// tracing_subscriber::registry().with(layer).init();
285    ///
286    /// info!("This will be logged to stderr");
287    /// reload_handle.modify(|subscriber| *subscriber.writer_mut() = non_blocking(std::io::stdout()));
288    /// info!("This will be logged to stdout");
289    /// # }
290    /// ```
291    ///
292    /// [writer]: MakeWriter
293    pub fn writer_mut(&mut self) -> &mut W {
294        &mut self.make_writer
295    }
296
297    /// Configures the subscriber to support [`libtest`'s output capturing][capturing] when used in
298    /// unit tests.
299    ///
300    /// See [`TestWriter`] for additional details.
301    ///
302    /// # Examples
303    ///
304    /// Using [`TestWriter`] to let `cargo test` capture test output:
305    ///
306    /// ```rust
307    /// # use tracing_subscriber::prelude::*;
308    /// let layer = json_subscriber::JsonLayer::stdout()
309    ///     .with_test_writer();
310    /// # tracing_subscriber::registry().with(layer);
311    /// ```
312    /// [capturing]:
313    /// https://doc.rust-lang.org/book/ch11-02-running-tests.html#showing-function-output
314    pub fn with_test_writer(self) -> JsonLayer<S, TestWriter> {
315        JsonLayer {
316            make_writer: TestWriter::default(),
317            log_internal_errors: self.log_internal_errors,
318            keyed_values: self.keyed_values,
319            flattened_values: self.flattened_values,
320        }
321    }
322
323    /// Sets whether to write errors from [`FormatEvent`] to the writer.
324    /// Defaults to true.
325    ///
326    /// By default, `fmt::JsonLayer` will write any `FormatEvent`-internal errors to
327    /// the writer. These errors are unlikely and will only occur if there is a
328    /// bug in the `FormatEvent` implementation or its dependencies.
329    ///
330    /// If writing to the writer fails, the error message is printed to stderr
331    /// as a fallback.
332    ///
333    /// [`FormatEvent`]: tracing_subscriber::fmt::FormatEvent
334    pub fn log_internal_errors(&mut self, log_internal_errors: bool) -> &mut Self {
335        self.log_internal_errors = log_internal_errors;
336        self
337    }
338
339    /// Updates the [`MakeWriter`] by applying a function to the existing [`MakeWriter`].
340    ///
341    /// This sets the [`MakeWriter`] that the subscriber being built will use to write events.
342    ///
343    /// # Examples
344    ///
345    /// Redirect output to stderr if level is <= WARN:
346    ///
347    /// ```rust
348    /// # use tracing_subscriber::prelude::*;
349    /// use tracing_subscriber::fmt::writer::MakeWriterExt;
350    ///
351    /// let stderr = std::io::stderr.with_max_level(tracing::Level::WARN);
352    /// let layer = json_subscriber::JsonLayer::stdout()
353    ///     .map_writer(move |w| stderr.or_else(w));
354    /// # tracing_subscriber::registry().with(layer);
355    /// ```
356    pub fn map_writer<W2>(self, f: impl FnOnce(W) -> W2) -> JsonLayer<S, W2>
357    where
358        W2: for<'writer> MakeWriter<'writer> + 'static,
359    {
360        JsonLayer {
361            make_writer: f(self.make_writer),
362            log_internal_errors: self.log_internal_errors,
363            keyed_values: self.keyed_values,
364            flattened_values: self.flattened_values,
365        }
366    }
367
368    /// Adds a new static field with a given key to the output.
369    ///
370    /// # Examples
371    ///
372    /// Print hostname in each log:
373    ///
374    /// ```rust
375    /// # use tracing_subscriber::prelude::*;
376    /// let mut layer = json_subscriber::JsonLayer::stdout();
377    /// layer.add_static_field(
378    ///     "hostname",
379    ///     serde_json::Value::String(get_hostname().to_owned()),
380    /// );
381    /// # tracing_subscriber::registry().with(layer);
382    /// # fn get_hostname() -> &'static str { "localhost" }
383    /// ```
384    pub fn add_static_field(&mut self, key: impl Into<String>, value: serde_json::Value) {
385        self.keyed_values
386            .insert(SchemaKey::from(key.into()), JsonValue::Serde(value));
387    }
388
389    /// Removes a field that was inserted to the output. This can only remove fields that have a
390    /// static key, not keys added with
391    /// [`add_multiple_dynamic_fields`](Self::add_multiple_dynamic_fields).
392    ///
393    /// # Examples
394    ///
395    /// Add a field and then remove it:
396    ///
397    /// ```rust
398    /// # use tracing_subscriber::prelude::*;
399    /// let mut layer = json_subscriber::JsonLayer::stdout();
400    /// layer.add_static_field(
401    ///     "deleteMe",
402    ///     serde_json::json!("accident"),
403    /// );
404    /// layer.remove_field("deleteMe");
405    ///
406    /// # tracing_subscriber::registry().with(layer);
407    /// ```
408    pub fn remove_field(&mut self, key: impl Into<String>) {
409        self.keyed_values.remove(&SchemaKey::from(key.into()));
410    }
411
412    pub(crate) fn remove_flattened_field(&mut self, key: &FlatSchemaKey) {
413        self.flattened_values.remove(key);
414    }
415
416    /// Adds a new dynamic field with a given key to the output. This method is more general than
417    /// [`add_static_field`](Self::add_static_field) but also more expensive.
418    ///
419    /// This method takes a closure argument that will be called with the event and tracing context.
420    /// Through these, the parent span can be accessed among other things. This closure returns an
421    /// `Option` where nothing will be added to the output if `None` is returned.
422    ///
423    /// # Examples
424    ///
425    /// Print an atomic counter.
426    ///
427    /// ```rust
428    /// # use tracing_subscriber::prelude::*;
429    /// # use std::sync::atomic::{AtomicU32, Ordering};
430    /// static COUNTER: AtomicU32 = AtomicU32::new(42);
431    ///
432    /// let mut layer = json_subscriber::JsonLayer::stdout();
433    /// layer.add_dynamic_field(
434    ///     "counter",
435    ///     |_event, _context| {
436    ///         Some(serde_json::Value::Number(COUNTER.load(Ordering::Relaxed).into()))
437    /// });
438    /// # tracing_subscriber::registry().with(layer);
439    /// ```
440    pub fn add_dynamic_field<Fun, Res>(&mut self, key: impl Into<String>, mapper: Fun)
441    where
442        for<'a> Fun: Fn(&'a Event<'_>, &Context<'_, S>) -> Option<Res> + Send + Sync + 'a,
443        Res: serde::Serialize,
444    {
445        self.keyed_values.insert(
446            SchemaKey::from(key.into()),
447            JsonValue::DynamicFromEvent(Box::new(move |event| {
448                serde_json::to_value(mapper(event.event(), event.context())?).ok()
449            })),
450        );
451    }
452
453    /// Adds multiple new dynamic field where the keys may not be known when calling this method.
454    ///
455    /// This method takes a closure argument that will be called with the event and tracing context.
456    /// Through these, the parent span can be accessed among other things. This closure returns a
457    /// value which can be iterated over to return a tuple of a `String` which will be used as a
458    /// JSON key and a `serde_json::Value` which will be used as a value. In most cases returning
459    /// `HashMap<String, serde_json::Value>` should be sufficient.
460    ///
461    /// It is the user's responsibility to make sure that no two keys clash as that would create an
462    /// invalid JSON. It's generally better to use [`add_dynamic_field`](Self::add_dynamic_field)
463    /// instead if the field names are known.
464    ///
465    /// # Examples
466    ///
467    /// Print either a question or an answer:
468    ///
469    /// ```rust
470    /// # use tracing_subscriber::prelude::*;
471    ///
472    /// let mut layer = json_subscriber::JsonLayer::stdout();
473    /// layer.add_multiple_dynamic_fields(
474    ///     |_event, _context| {
475    /// #       let condition = true;
476    ///         if condition {
477    ///             [("question".to_owned(), serde_json::Value::String("What?".to_owned()))]
478    ///         } else {
479    ///             [("answer".to_owned(), serde_json::Value::Number(42.into()))]
480    ///         }
481    /// });
482    /// # tracing_subscriber::registry().with(layer);
483    /// # fn get_hostname() -> &'static str { "localhost" }
484    /// ```
485    pub fn add_multiple_dynamic_fields<Fun, Res>(&mut self, mapper: Fun)
486    where
487        for<'a> Fun: Fn(&'a Event<'_>, &Context<'_, S>) -> Res + Send + Sync + 'a,
488        Res: IntoIterator<Item = (String, serde_json::Value)>,
489    {
490        self.flattened_values.insert(
491            FlatSchemaKey::new_uuid(),
492            JsonValue::DynamicFromEvent(Box::new(move |event| {
493                serde_json::to_value(
494                    mapper(event.event(), event.context())
495                        .into_iter()
496                        .collect::<HashMap<_, _>>(),
497                )
498                .ok()
499            })),
500        );
501    }
502
503    /// Adds a new dynamic field with a given key to the output. This method is a specialized
504    /// version of [`add_dynamic_field`](Self::add_dynamic_field) where just a reference to the
505    /// parent span is needed.
506    ///
507    /// This method takes a closure argument that will be called with the parent span context. This
508    /// closure returns an `Option` where nothing will be added to the output if `None` is returned.
509    ///
510    /// # Examples
511    ///
512    /// Print uppercase target:
513    ///
514    /// ```rust
515    /// # use tracing_subscriber::prelude::*;
516    ///
517    /// let mut layer = json_subscriber::JsonLayer::stdout();
518    /// layer.add_from_span(
519    ///     "TARGET",
520    ///     |span| Some(span.metadata().target().to_uppercase())
521    /// );
522    /// # tracing_subscriber::registry().with(layer);
523    /// ```
524    pub fn add_from_span<Fun, Res>(&mut self, key: impl Into<String>, mapper: Fun)
525    where
526        for<'a> Fun: Fn(&'a SpanRef<'_, S>) -> Option<Res> + Send + Sync + 'a,
527        Res: serde::Serialize,
528    {
529        self.keyed_values.insert(
530            SchemaKey::from(key.into()),
531            JsonValue::DynamicFromSpan(Box::new(move |span| {
532                serde_json::to_value(mapper(span)?).ok()
533            })),
534        );
535    }
536
537    /// Adds a field with a given key to the output. The value will be serialized JSON of the
538    /// provided extension. Other [`Layer`]s may add these extensions to the span.
539    ///
540    /// The serialization happens every time a log line is emitted so if the extension changes, the
541    /// latest version will be emitted.
542    ///
543    /// If the extension is not found, nothing is added to the output.
544    ///
545    /// # Examples
546    ///
547    /// ```rust
548    /// # use tracing::span::Attributes;
549    /// # use tracing::Id;
550    /// # use tracing::Subscriber;
551    /// # use tracing_subscriber::registry;
552    /// # use tracing_subscriber::registry::LookupSpan;
553    /// # use tracing_subscriber::Layer;
554    /// # use tracing_subscriber::layer::Context;
555    /// # use tracing_subscriber::prelude::*;
556    /// # use serde::Serialize;
557    /// struct FooLayer;
558    ///
559    /// #[derive(Serialize)]
560    /// struct Foo(String);
561    ///
562    /// impl<S: Subscriber + for<'lookup> LookupSpan<'lookup>> Layer<S> for FooLayer {
563    ///     fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
564    ///         let span = ctx.span(id).unwrap();
565    ///         let mut extensions = span.extensions_mut();
566    ///         let foo = Foo("hello".to_owned());
567    ///         extensions.insert(foo);
568    ///     }
569    /// }
570    ///
571    /// # fn main() {
572    /// let foo_layer = FooLayer;
573    ///
574    /// let mut layer = json_subscriber::JsonLayer::stdout();
575    /// layer.serialize_extension::<Foo>("foo");
576    ///
577    /// registry().with(foo_layer).with(layer);
578    /// # }
579    /// ```
580    pub fn serialize_extension<Ext: Serialize + 'static>(&mut self, key: impl Into<String>) {
581        self.add_from_extension_ref(key, |extension: &Ext| Some(extension));
582    }
583
584    /// Adds a field with a given key to the output. The user-provided closure can transform the
585    /// extension and return reference to any serializable structure.
586    ///
587    /// The mapping and serialization happens every time a log line is emitted so if the extension
588    /// changes, the latest version will be emitted.
589    ///
590    /// If the extension is not found, or the mapping returns `None`, nothing is added to the
591    /// output.
592    ///
593    /// Use [`Self::add_from_extension`] if you cannot return a reference.
594    ///
595    /// # Examples
596    ///
597    /// ```rust
598    /// # use tracing::span::Attributes;
599    /// # use tracing::Id;
600    /// # use tracing::Subscriber;
601    /// # use tracing_subscriber::registry;
602    /// # use tracing_subscriber::registry::LookupSpan;
603    /// # use tracing_subscriber::Layer;
604    /// # use tracing_subscriber::layer::Context;
605    /// # use tracing_subscriber::prelude::*;
606    /// # use serde::Serialize;
607    /// struct FooLayer;
608    ///
609    /// #[derive(Serialize)]
610    /// struct Foo(String);
611    ///
612    /// impl<S: Subscriber + for<'lookup> LookupSpan<'lookup>> Layer<S> for FooLayer {
613    ///     fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
614    ///         let span = ctx.span(id).unwrap();
615    ///         let mut extensions = span.extensions_mut();
616    ///         let foo = Foo("hello".to_owned());
617    ///         extensions.insert(foo);
618    ///     }
619    /// }
620    ///
621    /// # fn main() {
622    /// let foo_layer = FooLayer;
623    ///
624    /// let mut layer = json_subscriber::JsonLayer::stdout();
625    /// layer.add_from_extension_ref::<Foo, _, _>("foo", |foo| Some(&foo.0));
626    ///
627    /// registry().with(foo_layer).with(layer);
628    /// # }
629    /// ```
630    pub fn add_from_extension_ref<Ext, Fun, Res>(&mut self, key: impl Into<String>, mapper: Fun)
631    where
632        Ext: 'static,
633        for<'a> Fun: Fn(&'a Ext) -> Option<&'a Res> + Send + Sync + 'a,
634        Res: serde::Serialize,
635    {
636        self.keyed_values.insert(
637            SchemaKey::from(key.into()),
638            JsonValue::DynamicFromSpan(Box::new(move |span| {
639                let extensions = span.extensions();
640                let extension = extensions.get::<Ext>()?;
641                serde_json::to_value(mapper(extension)).ok()
642            })),
643        );
644    }
645
646    /// Adds a field with a given key to the output. The user-provided closure can transform the
647    /// extension and return any serializable structure.
648    ///
649    /// The mapping and serialization happens every time a log line is emitted so if the extension
650    /// changes, the latest version will be emitted.
651    ///
652    /// If the extension is not found, or the mapping returns `None`, nothing is added to the
653    /// output.
654    ///
655    /// Use [`Self::add_from_extension_ref`] if you want to return a reference to data in the
656    /// extension.
657    ///
658    /// # Examples
659    ///
660    /// ```rust
661    /// # use tracing::span::Attributes;
662    /// # use tracing::Id;
663    /// # use tracing::Subscriber;
664    /// # use tracing_subscriber::registry;
665    /// # use tracing_subscriber::registry::LookupSpan;
666    /// # use tracing_subscriber::Layer;
667    /// # use tracing_subscriber::layer::Context;
668    /// # use tracing_subscriber::prelude::*;
669    /// # use serde::Serialize;
670    /// struct FooLayer;
671    ///
672    /// #[derive(Serialize)]
673    /// struct Foo(String);
674    ///
675    /// impl<S: Subscriber + for<'lookup> LookupSpan<'lookup>> Layer<S> for FooLayer {
676    ///     fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
677    ///         let span = ctx.span(id).unwrap();
678    ///         let mut extensions = span.extensions_mut();
679    ///         let foo = Foo("hello".to_owned());
680    ///         extensions.insert(foo);
681    ///     }
682    /// }
683    ///
684    /// # fn main() {
685    /// let foo_layer = FooLayer;
686    ///
687    /// let mut layer = json_subscriber::JsonLayer::stdout();
688    /// layer.add_from_extension::<Foo, _, _>("foo", |foo| foo.0.parse::<u64>().ok());
689    ///
690    /// registry().with(foo_layer).with(layer);
691    /// # }
692    /// ```
693    pub fn add_from_extension<Ext, Fun, Res>(&mut self, key: impl Into<String>, mapper: Fun)
694    where
695        Ext: 'static,
696        for<'a> Fun: Fn(&'a Ext) -> Option<Res> + Send + Sync + 'a,
697        Res: serde::Serialize,
698    {
699        self.keyed_values.insert(
700            SchemaKey::from(key.into()),
701            JsonValue::DynamicFromSpan(Box::new(move |span| {
702                let extensions = span.extensions();
703                let extension = extensions.get::<Ext>()?;
704                serde_json::to_value(mapper(extension)).ok()
705            })),
706        );
707    }
708
709    /// Print all event fields in an object with the key as specified.
710    pub fn with_event(&mut self, key: impl Into<String>) -> &mut Self {
711        self.keyed_values.insert(
712            SchemaKey::from(key.into()),
713            JsonValue::DynamicFromEvent(Box::new(move |event| {
714                serde_json::to_value(event.field_map()).ok()
715            })),
716        );
717        self
718    }
719
720    /// Print all current span fields, each as its own top level member of the JSON.
721    ///
722    /// It is the user's responsibility to make sure that the field names will not clash with other
723    /// defined members of the output JSON. If they clash, invalid JSON with multiple fields with
724    /// the same key may be generated.
725    ///
726    /// It's therefore preferable to use [`with_current_span`](Self::with_current_span) instead.
727    pub fn with_top_level_flattened_current_span(&mut self) -> &mut Self {
728        self.flattened_values.insert(
729            FlatSchemaKey::FlattenedCurrentSpan,
730            JsonValue::DynamicCachedFromSpan(Box::new(move |span| {
731                span.extensions()
732                    .get::<JsonFields>()
733                    .map(|fields| Cached::Raw(fields.serialized.clone()))
734            })),
735        );
736        self
737    }
738
739    /// Print all parent spans' fields, each as its own top level member of the JSON.
740    ///
741    /// If multiple spans define the same field, the one furthest from the root span will be kept.
742    ///
743    /// It is the user's responsibility to make sure that the field names will not clash with other
744    /// defined members of the output JSON. If they clash, invalid JSON with multiple fields with
745    /// the same key may be generated.
746    ///
747    /// It's therefore preferable to use [`with_span_list`](Self::with_span_list) instead.
748    pub fn with_top_level_flattened_span_list(&mut self) -> &mut Self {
749        self.flattened_values.insert(
750            FlatSchemaKey::FlattenedSpanList,
751            JsonValue::DynamicFromSpan(Box::new(|span| {
752                let fields =
753                    span.scope()
754                        .from_root()
755                        .fold(BTreeMap::new(), |mut accumulator, span| {
756                            let extensions = span.extensions();
757                            let Some(fields) = extensions.get::<JsonFields>() else {
758                                return accumulator;
759                            };
760                            accumulator.extend(
761                                fields
762                                    .inner
763                                    .fields
764                                    .iter()
765                                    .map(|(key, value)| (*key, value.clone())),
766                            );
767                            accumulator
768                        });
769
770                serde_json::to_value(fields).ok()
771            })),
772        );
773        self
774    }
775
776    /// Print all event fields, each as its own top level member of the JSON.
777    ///
778    /// It is the user's responsibility to make sure that the field names will not clash with other
779    /// defined members of the output JSON. If they clash, invalid JSON with multiple fields with
780    /// the same key may be generated.
781    ///
782    /// It's therefore preferable to use [`with_event`](Self::with_event) instead.
783    pub fn with_flattened_event(&mut self) -> &mut Self {
784        self.flattened_values.insert(
785            FlatSchemaKey::FlattenedEvent,
786            JsonValue::DynamicFromEvent(Box::new(move |event| {
787                serde_json::to_value(event.field_map()).ok()
788            })),
789        );
790        self
791    }
792
793    /// Sets whether or not the log line will include the current span in formatted events.
794    pub fn with_current_span(&mut self, key: impl Into<String>) -> &mut Self {
795        self.keyed_values.insert(
796            SchemaKey::from(key.into()),
797            JsonValue::DynamicCachedFromSpan(Box::new(move |span| {
798                span.extensions()
799                    .get::<JsonFields>()
800                    .map(|fields| Cached::Raw(fields.serialized.clone()))
801            })),
802        );
803        self
804    }
805
806    /// Sets whether or not the formatter will include a list (from root to leaf) of all currently
807    /// entered spans in formatted events.
808    pub fn with_span_list(&mut self, key: impl Into<String>) -> &mut Self {
809        self.keyed_values.insert(
810            SchemaKey::from(key.into()),
811            JsonValue::DynamicCachedFromSpan(Box::new(|span| {
812                Some(Cached::Array(
813                    span.scope()
814                        .from_root()
815                        .filter_map(|span| {
816                            span.extensions()
817                                .get::<JsonFields>()
818                                .map(|fields| fields.serialized.clone())
819                        })
820                        .collect::<Vec<_>>(),
821                ))
822            })),
823        );
824        self
825    }
826
827    /// Sets the formatter to include an object containing all parent spans' fields. If multiple
828    /// ancestor spans recorded the same field, the span closer to the leaf span overrides the
829    /// values of spans that are closer to the root spans.
830    pub fn with_flattened_span_fields(&mut self, key: impl Into<String>) -> &mut Self {
831        self.keyed_values.insert(
832            SchemaKey::from(key.into()),
833            JsonValue::DynamicFromSpan(Box::new(|span| {
834                let fields =
835                    span.scope()
836                        .from_root()
837                        .fold(BTreeMap::new(), |mut accumulator, span| {
838                            let extensions = span.extensions();
839                            let Some(fields) = extensions.get::<JsonFields>() else {
840                                return accumulator;
841                            };
842                            accumulator.extend(
843                                fields
844                                    .inner
845                                    .fields
846                                    .iter()
847                                    .map(|(key, value)| (*key, value.clone())),
848                            );
849                            accumulator
850                        });
851
852                serde_json::to_value(fields).ok()
853            })),
854        );
855        self
856    }
857
858    /// Use the given [`timer`] for log message timestamps with the `timestamp` key.
859    ///
860    /// See the [`time` module] for the provided timer implementations.
861    ///
862    /// [`timer`]: tracing_subscriber::fmt::time::FormatTime
863    /// [`time` module]: mod@tracing_subscriber::fmt::time
864    pub fn with_timer<T: FormatTime + Send + Sync + 'static>(
865        &mut self,
866        key: impl Into<String>,
867        timer: T,
868    ) -> &mut Self {
869        self.keyed_values.insert(
870            SchemaKey::from(key.into()),
871            JsonValue::DynamicFromEvent(Box::new(move |_| {
872                let mut timestamp = String::with_capacity(32);
873                timer.format_time(&mut Writer::new(&mut timestamp)).ok()?;
874                Some(timestamp.into())
875            })),
876        );
877        self
878    }
879
880    /// Sets whether or not an event's target is displayed. It will use the `target` key if so.
881    pub fn with_target(&mut self, key: impl Into<String>) -> &mut Self {
882        self.keyed_values.insert(
883            SchemaKey::from(key.into()),
884            JsonValue::DynamicRawFromEvent(Box::new(|event, writer| {
885                write_escaped(writer, event.metadata().target())
886            })),
887        );
888
889        self
890    }
891
892    /// Sets whether or not an event's [source code file path][file] is displayed. It will use the
893    /// `file` key if so.
894    ///
895    /// [file]: tracing_core::Metadata::file
896    pub fn with_file(&mut self, key: impl Into<String>) -> &mut Self {
897        self.keyed_values.insert(
898            SchemaKey::from(key.into()),
899            JsonValue::DynamicRawFromEvent(Box::new(|event, writer| {
900                match event.metadata().file() {
901                    Some(file) => write_escaped(writer, file),
902                    None => write!(writer, "null"),
903                }
904            })),
905        );
906        self
907    }
908
909    /// Sets whether or not an event's [source code line number][line] is displayed. It will use the
910    /// `line_number` key if so.
911    ///
912    /// [line]: tracing_core::Metadata::line
913    pub fn with_line_number(&mut self, key: impl Into<String>) -> &mut Self {
914        self.keyed_values.insert(
915            SchemaKey::from(key.into()),
916            JsonValue::DynamicRawFromEvent(Box::new(|event, writer| {
917                match event.metadata().line() {
918                    Some(line) => write!(writer, "{line}"),
919                    None => write!(writer, "null"),
920                }
921            })),
922        );
923        self
924    }
925
926    /// Sets whether or not an event's level is displayed. It will use the `level` key if so.
927    pub fn with_level(&mut self, key: impl Into<String>) -> &mut Self {
928        self.keyed_values.insert(
929            SchemaKey::from(key.into()),
930            JsonValue::DynamicRawFromEvent(Box::new(|event, writer| {
931                write_escaped(writer, event.metadata().level().as_str())
932            })),
933        );
934        self
935    }
936
937    /// Sets whether or not the [name] of the current thread is displayed when formatting events. It
938    /// will use the `threadName` key if so.
939    ///
940    /// [name]: std::thread#naming-threads
941    pub fn with_thread_names(&mut self, key: impl Into<String>) -> &mut Self {
942        self.keyed_values.insert(
943            SchemaKey::from(key.into()),
944            JsonValue::DynamicRawFromEvent(Box::new(|_event, writer| {
945                match std::thread::current().name() {
946                    Some(name) => write_escaped(writer, name),
947                    None => write!(writer, "null"),
948                }
949            })),
950        );
951        self
952    }
953
954    /// Sets whether or not the [thread ID] of the current thread is displayed when formatting
955    /// events. It will use the `threadId` key if so.
956    ///
957    /// [thread ID]: std::thread::ThreadId
958    pub fn with_thread_ids(&mut self, key: impl Into<String>) -> &mut Self {
959        self.keyed_values.insert(
960            SchemaKey::from(key.into()),
961            JsonValue::DynamicRawFromEvent(Box::new(|_event, writer| {
962                use std::fmt::Write;
963                let mut value = String::with_capacity(12);
964                write!(&mut value, "{:?}", std::thread::current().id())?;
965                write_escaped(writer, &value)
966            })),
967        );
968
969        self
970    }
971
972    /// Sets whether or not [OpenTelemetry] trace ID and span ID is displayed when formatting
973    /// events. It will use the `openTelemetry` key if so and the value will be an object with
974    /// `traceId` and `spanId` fields, each being a string.
975    ///
976    /// This works only if your `tracing-opentelemetry` version and this crate's features match. If
977    /// you update that dependency, you need to change the feature here or this call will do
978    /// nothing.
979    ///
980    /// [OpenTelemetry]: https://opentelemetry.io
981    #[cfg(any(
982        feature = "opentelemetry",
983        feature = "tracing-opentelemetry-0-28",
984        feature = "tracing-opentelemetry-0-29",
985        feature = "tracing-opentelemetry-0-30",
986        feature = "tracing-opentelemetry-0-31"
987    ))]
988    #[cfg_attr(
989        docsrs,
990        doc(any(
991            feature = "opentelemetry",
992            feature = "tracing-opentelemetry-0-28",
993            feature = "tracing-opentelemetry-0-29",
994            feature = "tracing-opentelemetry-0-30",
995            feature = "tracing-opentelemetry-0-31"
996        ))
997    )]
998    pub fn with_opentelemetry_ids(&mut self, display_opentelemetry_ids: bool) -> &mut Self {
999        if display_opentelemetry_ids {
1000            self.keyed_values.insert(
1001                SchemaKey::from("openTelemetry"),
1002                JsonValue::DynamicFromSpan(Box::new(|span| {
1003                    let mut ids: Option<serde_json::Value> = None;
1004                    #[cfg(feature = "tracing-opentelemetry-0-31")]
1005                    {
1006                        use opentelemetry_0_30::trace::{TraceContextExt, TraceId};
1007
1008                        ids = ids.or_else(|| {
1009                            span.extensions()
1010                                .get::<tracing_opentelemetry_0_31::OtelData>()
1011                                .and_then(|otel_data| {
1012                                    // We should use the parent first if available because we can
1013                                    // create a new trace and then change the parent. In that case
1014                                    // the value in the builder is not updated.
1015                                    let mut trace_id =
1016                                        otel_data.parent_cx.span().span_context().trace_id();
1017                                    if trace_id == TraceId::INVALID {
1018                                        trace_id = otel_data.builder.trace_id?;
1019                                    }
1020                                    let span_id = otel_data.builder.span_id?;
1021
1022                                    Some(serde_json::json!({
1023                                        "traceId": trace_id.to_string(),
1024                                        "spanId": span_id.to_string(),
1025                                    }))
1026                                })
1027                        });
1028                    }
1029                    #[cfg(feature = "tracing-opentelemetry-0-30")]
1030                    {
1031                        use opentelemetry_0_29::trace::{TraceContextExt, TraceId};
1032
1033                        ids = ids.or_else(|| {
1034                            span.extensions()
1035                                .get::<tracing_opentelemetry_0_30::OtelData>()
1036                                .and_then(|otel_data| {
1037                                    // We should use the parent first if available because we can
1038                                    // create a new trace and then change the parent. In that case
1039                                    // the value in the builder is not updated.
1040                                    let mut trace_id =
1041                                        otel_data.parent_cx.span().span_context().trace_id();
1042                                    if trace_id == TraceId::INVALID {
1043                                        trace_id = otel_data.builder.trace_id?;
1044                                    }
1045                                    let span_id = otel_data.builder.span_id?;
1046
1047                                    Some(serde_json::json!({
1048                                        "traceId": trace_id.to_string(),
1049                                        "spanId": span_id.to_string(),
1050                                    }))
1051                                })
1052                        });
1053                    }
1054                    #[cfg(feature = "tracing-opentelemetry-0-29")]
1055                    {
1056                        use opentelemetry_0_28::trace::{TraceContextExt, TraceId};
1057
1058                        ids = ids.or_else(|| {
1059                            span.extensions()
1060                                .get::<tracing_opentelemetry_0_29::OtelData>()
1061                                .and_then(|otel_data| {
1062                                    // We should use the parent first if available because we can
1063                                    // create a new trace and then change the parent. In that case
1064                                    // the value in the builder is not updated.
1065                                    let mut trace_id =
1066                                        otel_data.parent_cx.span().span_context().trace_id();
1067                                    if trace_id == TraceId::INVALID {
1068                                        trace_id = otel_data.builder.trace_id?;
1069                                    }
1070                                    let span_id = otel_data.builder.span_id?;
1071
1072                                    Some(serde_json::json!({
1073                                        "traceId": trace_id.to_string(),
1074                                        "spanId": span_id.to_string(),
1075                                    }))
1076                                })
1077                        });
1078                    }
1079                    #[cfg(feature = "tracing-opentelemetry-0-28")]
1080                    {
1081                        use opentelemetry_0_27::trace::{TraceContextExt, TraceId};
1082
1083                        ids = ids.or_else(|| {
1084                            span.extensions()
1085                                .get::<tracing_opentelemetry_0_28::OtelData>()
1086                                .and_then(|otel_data| {
1087                                    // We should use the parent first if available because we can
1088                                    // create a new trace and then change the parent. In that case
1089                                    // the value in the builder is not updated.
1090                                    let mut trace_id =
1091                                        otel_data.parent_cx.span().span_context().trace_id();
1092                                    if trace_id == TraceId::INVALID {
1093                                        trace_id = otel_data.builder.trace_id?;
1094                                    }
1095                                    let span_id = otel_data.builder.span_id?;
1096
1097                                    Some(serde_json::json!({
1098                                        "traceId": trace_id.to_string(),
1099                                        "spanId": span_id.to_string(),
1100                                    }))
1101                                })
1102                        });
1103                    }
1104                    #[cfg(feature = "opentelemetry")]
1105                    {
1106                        use opentelemetry_0_24::trace::{TraceContextExt, TraceId};
1107
1108                        ids = ids.or_else(|| {
1109                            span.extensions()
1110                                .get::<tracing_opentelemetry_0_25::OtelData>()
1111                                .and_then(|otel_data| {
1112                                    // We should use the parent first if available because we can
1113                                    // create a new trace and then change the parent. In that case
1114                                    // the value in the builder is not updated.
1115                                    let mut trace_id =
1116                                        otel_data.parent_cx.span().span_context().trace_id();
1117                                    if trace_id == TraceId::INVALID {
1118                                        trace_id = otel_data.builder.trace_id?;
1119                                    }
1120                                    let span_id = otel_data.builder.span_id?;
1121
1122                                    Some(serde_json::json!({
1123                                        "traceId": trace_id.to_string(),
1124                                        "spanId": span_id.to_string(),
1125                                    }))
1126                                })
1127                        });
1128                    }
1129
1130                    ids
1131                })),
1132            );
1133        } else {
1134            self.keyed_values.remove(&SchemaKey::from("openTelemetry"));
1135        }
1136
1137        self
1138    }
1139}
1140
1141fn write_escaped(writer: &mut dyn fmt::Write, value: &str) -> Result<(), fmt::Error> {
1142    let mut rest = value;
1143    writer.write_str("\"")?;
1144    let mut shift = 0;
1145    while let Some(position) = rest
1146        .get(shift..)
1147        .and_then(|haystack| haystack.find(['\"', '\\']))
1148    {
1149        let (before, after) = rest.split_at(position + shift);
1150        writer.write_str(before)?;
1151        writer.write_char('\\')?;
1152        rest = after;
1153        shift = 1;
1154    }
1155    writer.write_str(rest)?;
1156    writer.write_str("\"")
1157}
1158
1159#[cfg(test)]
1160mod tests {
1161    use serde_json::json;
1162    use tracing::subscriber::with_default;
1163    use tracing_subscriber::{registry, Layer, Registry};
1164
1165    use super::JsonLayer;
1166    use crate::tests::MockMakeWriter;
1167
1168    fn test_json<W, T>(
1169        expected: &serde_json::Value,
1170        layer: JsonLayer<Registry, W>,
1171        producer: impl FnOnce() -> T,
1172    ) {
1173        let actual = produce_log_line(layer, producer);
1174        assert_eq!(
1175            expected,
1176            &serde_json::from_str::<serde_json::Value>(&actual).unwrap(),
1177        );
1178    }
1179
1180    fn produce_log_line<W, T>(
1181        layer: JsonLayer<Registry, W>,
1182        producer: impl FnOnce() -> T,
1183    ) -> String {
1184        let make_writer = MockMakeWriter::default();
1185        let collector = layer
1186            .with_writer(make_writer.clone())
1187            .with_subscriber(registry());
1188
1189        with_default(collector, producer);
1190
1191        let buf = make_writer.buf();
1192        dbg!(std::str::from_utf8(&buf[..]).unwrap()).to_owned()
1193    }
1194
1195    #[test]
1196    fn add_and_remove_static() {
1197        let mut layer = JsonLayer::stdout();
1198        layer.add_static_field("static", json!({"lorem": "ipsum", "answer": 42}));
1199        layer.add_static_field(String::from("zero"), json!(0));
1200        layer.add_static_field(String::from("one").as_str(), json!(1));
1201        layer.add_static_field("nonExistent", json!(1));
1202        layer.remove_field("nonExistent");
1203
1204        let expected = json!({
1205            "static": {
1206                "lorem": "ipsum",
1207                "answer": 42,
1208            },
1209            "zero": 0,
1210            "one": 1,
1211        });
1212
1213        test_json(&expected, layer, || {
1214            tracing::info!(does = "not matter", "whatever");
1215        });
1216    }
1217}