Skip to main content

json_subscriber/layer/
mod.rs

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