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}