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