1use std::io;
2
3use tracing::Subscriber;
4use tracing_subscriber::{
5 fmt::{
6 time::{FormatTime, SystemTime},
7 MakeWriter,
8 TestWriter,
9 },
10 registry::LookupSpan,
11 Layer as Subscribe,
12 Registry,
13};
14
15use super::names::{
16 CURRENT_SPAN,
17 FIELDS,
18 FILENAME,
19 LEVEL,
20 LINE_NUMBER,
21 SPAN_LIST,
22 TARGET,
23 THREAD_ID,
24 THREAD_NAME,
25 TIMESTAMP,
26};
27use crate::layer::{FlatSchemaKey, JsonLayer};
28
29pub struct Layer<S: for<'lookup> LookupSpan<'lookup> = Registry, W = fn() -> io::Stdout> {
66 inner: JsonLayer<S, W>,
67}
68
69impl<S: Subscriber + for<'lookup> LookupSpan<'lookup>> Default for Layer<S> {
70 fn default() -> Self {
71 let mut inner = JsonLayer::stdout();
72
73 inner
74 .with_event(FIELDS)
76 .with_timer(TIMESTAMP, SystemTime)
77 .with_target(TARGET)
78 .with_level(LEVEL)
79 .with_current_span(CURRENT_SPAN)
80 .with_span_list(SPAN_LIST);
81
82 Self { inner }
83 }
84}
85
86impl<S, W> Subscribe<S> for Layer<S, W>
87where
88 JsonLayer<S, W>: Subscribe<S>,
89 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
90{
91 fn on_register_dispatch(&self, subscriber: &tracing::Dispatch) {
92 self.inner.on_register_dispatch(subscriber);
93 }
94
95 fn on_layer(&mut self, subscriber: &mut S) {
96 self.inner.on_layer(subscriber);
97 }
98
99 fn register_callsite(
100 &self,
101 metadata: &'static tracing::Metadata<'static>,
102 ) -> tracing_core::Interest {
103 self.inner.register_callsite(metadata)
104 }
105
106 fn enabled(
107 &self,
108 metadata: &tracing::Metadata<'_>,
109 ctx: tracing_subscriber::layer::Context<'_, S>,
110 ) -> bool {
111 self.inner.enabled(metadata, ctx)
112 }
113
114 fn on_new_span(
115 &self,
116 attrs: &tracing_core::span::Attributes<'_>,
117 id: &tracing_core::span::Id,
118 ctx: tracing_subscriber::layer::Context<'_, S>,
119 ) {
120 self.inner.on_new_span(attrs, id, ctx);
121 }
122
123 fn on_record(
124 &self,
125 span: &tracing_core::span::Id,
126 values: &tracing_core::span::Record<'_>,
127 ctx: tracing_subscriber::layer::Context<'_, S>,
128 ) {
129 self.inner.on_record(span, values, ctx);
130 }
131
132 fn on_follows_from(
133 &self,
134 span: &tracing_core::span::Id,
135 follows: &tracing_core::span::Id,
136 ctx: tracing_subscriber::layer::Context<'_, S>,
137 ) {
138 self.inner.on_follows_from(span, follows, ctx);
139 }
140
141 fn event_enabled(
142 &self,
143 event: &tracing::Event<'_>,
144 ctx: tracing_subscriber::layer::Context<'_, S>,
145 ) -> bool {
146 self.inner.event_enabled(event, ctx)
147 }
148
149 fn on_event(&self, event: &tracing::Event<'_>, ctx: tracing_subscriber::layer::Context<'_, S>) {
150 self.inner.on_event(event, ctx);
151 }
152
153 fn on_enter(
154 &self,
155 id: &tracing_core::span::Id,
156 ctx: tracing_subscriber::layer::Context<'_, S>,
157 ) {
158 self.inner.on_enter(id, ctx);
159 }
160
161 fn on_exit(&self, id: &tracing_core::span::Id, ctx: tracing_subscriber::layer::Context<'_, S>) {
162 self.inner.on_exit(id, ctx);
163 }
164
165 fn on_close(&self, id: tracing_core::span::Id, ctx: tracing_subscriber::layer::Context<'_, S>) {
166 self.inner.on_close(id, ctx);
167 }
168
169 fn on_id_change(
170 &self,
171 old: &tracing_core::span::Id,
172 new: &tracing_core::span::Id,
173 ctx: tracing_subscriber::layer::Context<'_, S>,
174 ) {
175 self.inner.on_id_change(old, new, ctx);
176 }
177}
178
179impl<S, W> Layer<S, W>
180where
181 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
182{
183 pub fn with_writer<W2>(self, make_writer: W2) -> Layer<S, W2>
199 where
200 W2: for<'writer> MakeWriter<'writer> + 'static,
201 {
202 Layer::<S, W2> {
203 inner: self.inner.with_writer(make_writer),
204 }
205 }
206
207 pub fn map_writer<W2>(self, f: impl FnOnce(W) -> W2) -> Layer<S, W2>
225 where
226 W2: for<'writer> MakeWriter<'writer> + 'static,
227 {
228 Layer::<S, W2> {
229 inner: self.inner.map_writer(f),
230 }
231 }
232
233 pub fn with_test_writer(self) -> Layer<S, TestWriter> {
254 Layer::<S, TestWriter> {
255 inner: self.inner.with_test_writer(),
256 }
257 }
258
259 pub fn writer(&self) -> &W {
263 self.inner.writer()
264 }
265
266 pub fn writer_mut(&mut self) -> &mut W {
293 self.inner.writer_mut()
294 }
295
296 pub fn inner_layer_mut(&mut self) -> &mut JsonLayer<S, W> {
318 &mut self.inner
319 }
320
321 #[must_use]
332 pub fn log_internal_errors(mut self, log_internal_errors: bool) -> Self {
333 self.inner.log_internal_errors(log_internal_errors);
334 self
335 }
336
337 #[must_use]
345 pub fn flatten_current_span_on_top_level(mut self, flatten_span: bool) -> Self {
346 if flatten_span {
347 self.inner.remove_field(CURRENT_SPAN);
348 self.inner.with_top_level_flattened_current_span();
349 } else {
350 self.inner
351 .remove_flattened_field(&FlatSchemaKey::FlattenedCurrentSpan);
352 self.inner.with_current_span(CURRENT_SPAN);
353 }
354 self
355 }
356
357 #[must_use]
369 pub fn flatten_span_list_on_top_level(mut self, flatten_span_list: bool) -> Self {
370 if flatten_span_list {
371 self.inner.remove_field(SPAN_LIST);
372 self.inner.with_top_level_flattened_span_list();
373 } else {
374 self.inner
375 .remove_flattened_field(&FlatSchemaKey::FlattenedSpanList);
376 self.inner.with_span_list(SPAN_LIST);
377 }
378 self
379 }
380
381 #[must_use]
383 pub fn flatten_event(mut self, flatten_event: bool) -> Self {
384 if flatten_event {
385 self.inner.remove_field(FIELDS);
386 self.inner.with_flattened_event();
387 } else {
388 self.inner
389 .remove_flattened_field(&FlatSchemaKey::FlattenedEvent);
390 self.inner.with_event(FIELDS);
391 }
392 self
393 }
394
395 #[must_use]
397 pub fn with_current_span(mut self, display_current_span: bool) -> Self {
398 if display_current_span {
399 self.inner.with_current_span(CURRENT_SPAN);
400 } else {
401 self.inner.remove_field(CURRENT_SPAN);
402 }
403 self
404 }
405
406 #[must_use]
411 pub fn with_span_list(mut self, display_span_list: bool) -> Self {
412 if display_span_list {
413 self.inner.with_span_list(SPAN_LIST);
414 } else {
415 self.inner.remove_field(SPAN_LIST);
416 }
417 self
418 }
419
420 #[must_use]
426 pub fn with_flat_span_list(mut self, flatten_span_list: bool) -> Self {
427 if flatten_span_list {
428 self.inner.with_flattened_span_fields(SPAN_LIST);
429 } else {
430 self.inner.remove_field(SPAN_LIST);
431 }
432 self
433 }
434
435 #[must_use]
450 pub fn with_timer<T: FormatTime + Send + Sync + 'static>(mut self, timer: T) -> Self {
451 self.inner.with_timer(TIMESTAMP, timer);
452 self
453 }
454
455 #[must_use]
457 pub fn without_time(mut self) -> Self {
458 self.inner.remove_field(TIMESTAMP);
459 self
460 }
461
462 #[must_use]
464 pub fn with_target(mut self, display_target: bool) -> Self {
465 if display_target {
466 self.inner.with_target(TARGET);
467 } else {
468 self.inner.remove_field(TARGET);
469 }
470
471 self
472 }
473
474 #[must_use]
479 pub fn with_file(mut self, display_filename: bool) -> Self {
480 if display_filename {
481 self.inner.with_file(FILENAME);
482 } else {
483 self.inner.remove_field(FILENAME);
484 }
485 self
486 }
487
488 #[must_use]
493 pub fn with_line_number(mut self, display_line_number: bool) -> Self {
494 if display_line_number {
495 self.inner.with_line_number(LINE_NUMBER);
496 } else {
497 self.inner.remove_field(LINE_NUMBER);
498 }
499 self
500 }
501
502 #[must_use]
504 pub fn with_level(mut self, display_level: bool) -> Self {
505 if display_level {
506 self.inner.with_level(LEVEL);
507 } else {
508 self.inner.remove_field(LEVEL);
509 }
510 self
511 }
512
513 #[must_use]
518 pub fn with_thread_names(mut self, display_thread_name: bool) -> Self {
519 if display_thread_name {
520 self.inner.with_thread_names(THREAD_NAME);
521 } else {
522 self.inner.remove_field(THREAD_NAME);
523 }
524 self
525 }
526
527 #[must_use]
532 pub fn with_thread_ids(mut self, display_thread_id: bool) -> Self {
533 if display_thread_id {
534 self.inner.with_thread_ids(THREAD_ID);
535 } else {
536 self.inner.remove_field(THREAD_ID);
537 }
538
539 self
540 }
541
542 #[cfg(feature = "__any-tracing-opentelemetry")]
547 #[cfg_attr(docsrs, doc(feature = "__any-tracing-opentelemetry"))]
548 #[must_use]
549 pub fn with_opentelemetry_ids(mut self, display_opentelemetry_ids: bool) -> Self {
550 self.inner.with_opentelemetry_ids(display_opentelemetry_ids);
551 self
552 }
553}
554
555#[cfg(test)]
556mod tests {
557 use serde_json::json;
558 use tracing::subscriber::with_default;
559 use tracing_subscriber::{registry, Layer as _, Registry};
560
561 use super::Layer;
562 use crate::tests::{MockMakeWriter, MockTime};
563
564 fn test_json<W, T>(
565 expected: &serde_json::Value,
566 layer: Layer<Registry, W>,
567 producer: impl FnOnce() -> T,
568 ) {
569 let actual = produce_log_line(layer, producer);
570 assert_eq!(
571 expected,
572 &serde_json::from_str::<serde_json::Value>(&actual).unwrap(),
573 "expected != actual"
574 );
575 }
576
577 fn produce_log_line<W, T>(layer: Layer<Registry, W>, producer: impl FnOnce() -> T) -> String {
578 let make_writer = MockMakeWriter::default();
579 let collector = layer
580 .with_writer(make_writer.clone())
581 .with_timer(MockTime)
582 .with_subscriber(registry());
583
584 with_default(collector, producer);
585
586 let buf = make_writer.buf();
587 dbg!(std::str::from_utf8(&buf[..]).unwrap()).to_owned()
588 }
589
590 #[test]
591 fn default() {
592 let expected = json!(
593 {
594 "timestamp": "fake time",
595 "level": "INFO",
596 "span": {
597 "answer": 42,
598 "name": "json_span",
599 "number": 3,
600 },
601 "spans": [
602 {
603 "answer": 42,
604 "name": "json_span",
605 "number": 3,
606 },
607 ],
608 "target": "json_subscriber::fmt::layer::tests",
609 "fields": {
610 "message": "some json test",
611 },
612 }
613 );
614
615 let layer = Layer::default();
616
617 test_json(&expected, layer, || {
618 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
619 let _guard = span.enter();
620 tracing::info!("some json test");
621 });
622 }
623
624 #[test]
625 fn flatten() {
626 let expected = json!(
627 {
628 "timestamp": "fake time",
629 "level": "INFO",
630 "span": {
631 "answer": 42,
632 "name": "json_span",
633 "number": 3,
634 },
635 "spans": [
636 {
637 "answer": 42,
638 "name": "json_span",
639 "number": 3,
640 },
641 ],
642 "target": "json_subscriber::fmt::layer::tests",
643 "message": "some json test",
644 }
645 );
646
647 let layer = Layer::default()
648 .flatten_event(true)
649 .with_current_span(true)
650 .with_span_list(true);
651 test_json(&expected, layer, || {
652 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
653 let _guard = span.enter();
654 tracing::info!("some json test");
655 });
656 }
657
658 #[test]
659 fn flatten_conflict() {
660 #[rustfmt::skip]
664 let expected = "{\"level\":\"INFO\",\"timestamp\":\"fake time\",\"level\":\"this is a bug\",\"message\":\"some json test\"}\n";
665
666 let layer = Layer::default()
667 .flatten_event(true)
668 .with_current_span(false)
669 .with_span_list(false)
670 .with_target(false);
671
672 let actual = produce_log_line(layer, || {
673 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
674 let _guard = span.enter();
675 tracing::info!(level = "this is a bug", "some json test");
676 });
677
678 assert_eq!(expected, actual);
679 }
680
681 #[test]
682 fn flat_span_list() {
683 let expected = json!(
684 {
685 "timestamp": "fake time",
686 "level": "INFO",
687 "spans": {
688 "answer": 42,
689 "name": "child_span",
690 "number": 100,
691 "text": "text",
692 },
693 "target": "json_subscriber::fmt::layer::tests",
694 "fields": {
695 "message": "some json test",
696 },
697 }
698 );
699
700 let layer = Layer::default()
701 .with_flat_span_list(true)
702 .with_current_span(false);
703
704 test_json(&expected, layer, || {
705 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
706 let _guard = span.enter();
707 let child =
708 tracing::info_span!("child_span", number = 100, text = tracing::field::Empty);
709 let _guard = child.clone().entered();
710 child.record("text", "text");
711 tracing::info!("some json test");
712 });
713 }
714
715 #[test]
716 fn top_level_flatten_current_span() {
717 let expected = json!(
718 {
719 "timestamp": "fake time",
720 "level": "INFO",
721 "name": "child_span",
722 "number": 100,
723 "text": "text",
724 "fields": {
725 "message": "some json test",
726 },
727 }
728 );
729
730 let layer = Layer::default()
731 .with_target(false)
732 .with_span_list(false)
733 .flatten_current_span_on_top_level(true);
734
735 test_json(&expected, layer, || {
736 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
737 let _guard = span.enter();
738 let child =
739 tracing::info_span!("child_span", number = 100, text = tracing::field::Empty);
740 let _guard = child.clone().entered();
741 child.record("text", "text");
742 tracing::info!("some json test");
743 });
744 }
745
746 #[test]
747 fn top_level_flatten_span_list() {
748 let expected = json!(
749 {
750 "timestamp": "fake time",
751 "level": "INFO",
752 "name": "child_span",
753 "answer": 42,
754 "number": 100,
755 "text": "text",
756 "fields": {
757 "message": "some json test",
758 },
759 }
760 );
761
762 let layer = Layer::default()
763 .with_target(false)
764 .with_current_span(false)
765 .flatten_span_list_on_top_level(true);
766
767 test_json(&expected, layer, || {
768 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
769 let _guard = span.enter();
770 let child =
771 tracing::info_span!("child_span", number = 100, text = tracing::field::Empty);
772 let _guard = child.clone().entered();
773 child.record("text", "text");
774 tracing::info!("some json test");
775 });
776 }
777
778 #[test]
779 fn target_quote() {
780 let expected = json!(
781 {
782 "timestamp": "fake time",
783 "target": "\"",
784 "fields": {
785 "message": "some json test",
786 },
787 }
788 );
789
790 let layer = Layer::default()
791 .with_span_list(false)
792 .with_current_span(false)
793 .with_level(false);
794
795 test_json(&expected, layer, || {
796 tracing::info!(target: "\"", "some json test");
797 });
798 }
799
800 #[test]
801 fn target_backslash() {
802 let expected = json!(
803 {
804 "timestamp": "fake time",
805 "target": "\\hello\\\\world\\",
806 "fields": {
807 "message": "some json test",
808 },
809 }
810 );
811
812 let layer = Layer::default()
813 .with_span_list(false)
814 .with_current_span(false)
815 .with_level(false);
816
817 test_json(&expected, layer, || {
818 tracing::info!(target: "\\hello\\\\world\\", "some json test");
819 });
820 }
821}