1use std::{error::Error, io};
2
3use tracing::{Dispatch, Subscriber};
4use tracing_core::LevelFilter;
5use tracing_subscriber::{
6 fmt::{
7 time::{FormatTime, SystemTime},
8 MakeWriter,
9 TestWriter,
10 },
11 layer::{Layered, SubscriberExt},
12 registry::LookupSpan,
13 reload,
14 Layer,
15 Registry,
16};
17
18use super::names::{
19 CURRENT_SPAN,
20 FIELDS,
21 FILENAME,
22 LEVEL,
23 LINE_NUMBER,
24 SPAN_LIST,
25 TARGET,
26 THREAD_ID,
27 THREAD_NAME,
28 TIMESTAMP,
29};
30use crate::layer::JsonLayer;
31
32pub struct SubscriberBuilder<W = fn() -> io::Stdout, T = SystemTime, F = LevelFilter> {
97 make_writer: W,
98 timer: T,
99 filter: F,
100
101 log_internal_errors: bool,
102
103 display_timestamp: bool,
104 display_target: bool,
105 display_level: bool,
106 display_thread_id: bool,
107 display_thread_name: bool,
108 display_filename: bool,
109 display_line_number: bool,
110 flatten_event: bool,
111 display_current_span: bool,
112 display_span_list: bool,
113 #[cfg(feature = "opentelemetry")]
114 display_opentelemetry_ids: bool,
115}
116
117impl Default for SubscriberBuilder {
118 fn default() -> Self {
119 Self {
120 make_writer: io::stdout,
121 filter: LevelFilter::INFO,
122 timer: SystemTime,
123 log_internal_errors: false,
124
125 display_timestamp: true,
126 display_target: true,
127 display_level: true,
128 display_thread_id: false,
129 display_thread_name: false,
130 display_filename: false,
131 display_line_number: false,
132 flatten_event: false,
133 display_current_span: true,
134 display_span_list: true,
135 #[cfg(feature = "opentelemetry")]
136 display_opentelemetry_ids: false,
137 }
138 }
139}
140
141impl<W, T, F> SubscriberBuilder<W, T, F>
142where
143 W: for<'writer> MakeWriter<'writer> + Send + Sync + 'static,
144 T: FormatTime + Send + Sync + 'static,
145 F: Layer<Layered<JsonLayer<Registry, W>, Registry>> + 'static,
146 Layered<F, Layered<JsonLayer<Registry, W>, Registry>>:
147 tracing_core::Subscriber + Into<Dispatch>,
148{
149 pub(crate) fn layers<S>(self) -> (JsonLayer<S, W>, F)
150 where
151 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
152 {
153 let mut layer = JsonLayer::<S>::new(self.make_writer);
154
155 if self.display_timestamp {
156 layer.with_timer(TIMESTAMP, self.timer);
157 }
158
159 if self.display_level {
160 layer.with_level(LEVEL);
161 }
162
163 if self.display_target {
164 layer.with_target(TARGET);
165 }
166
167 if self.display_filename {
168 layer.with_file(FILENAME);
169 }
170
171 if self.display_line_number {
172 layer.with_line_number(LINE_NUMBER);
173 }
174
175 if self.display_thread_name {
176 layer.with_thread_names(THREAD_NAME);
177 }
178
179 if self.display_thread_id {
180 layer.with_thread_ids(THREAD_ID);
181 }
182
183 if self.flatten_event {
184 layer.with_flattened_event();
185 } else {
186 layer.with_event(FIELDS);
187 }
188
189 if self.display_current_span {
190 layer.with_current_span(CURRENT_SPAN);
191 }
192
193 if self.display_span_list {
194 layer.with_span_list(SPAN_LIST);
195 }
196
197 (layer, self.filter)
198 }
199
200 pub fn finish(self) -> Layered<F, Layered<JsonLayer<Registry, W>, Registry>> {
204 let (json_layer, filter_layer) = self.layers();
205 tracing_subscriber::registry()
206 .with(json_layer)
207 .with(filter_layer)
208 }
209
210 pub fn try_init(self) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
221 use tracing_subscriber::util::SubscriberInitExt;
222 self.finish().try_init()?;
223
224 Ok(())
225 }
226
227 pub fn init(self) {
236 self.try_init()
237 .expect("Unable to install global subscriber");
238 }
239}
240
241impl<W, T, F> SubscriberBuilder<W, T, F> {
242 #[deprecated(note = "Calling `json()` does nothing.")]
244 #[must_use]
245 pub fn json(self) -> Self {
246 self
247 }
248
249 #[deprecated(note = "Calling `with_ansi()` does nothing.")]
251 #[must_use]
252 pub fn with_ansi(self, _ansi: bool) -> Self {
253 self
254 }
255
256 pub fn with_writer<W2>(self, make_writer: W2) -> SubscriberBuilder<W2, T, F>
269 where
270 W2: for<'writer> MakeWriter<'writer> + 'static,
271 {
272 SubscriberBuilder {
273 make_writer,
274 timer: self.timer,
275 filter: self.filter,
276 log_internal_errors: self.log_internal_errors,
277 display_timestamp: self.display_timestamp,
278 display_target: self.display_target,
279 display_level: self.display_level,
280 display_thread_id: self.display_thread_id,
281 display_thread_name: self.display_thread_name,
282 display_filename: self.display_filename,
283 display_line_number: self.display_line_number,
284 flatten_event: self.flatten_event,
285 display_current_span: self.display_current_span,
286 display_span_list: self.display_span_list,
287 #[cfg(feature = "opentelemetry")]
288 display_opentelemetry_ids: self.display_opentelemetry_ids,
289 }
290 }
291
292 pub fn writer(&self) -> &W {
296 &self.make_writer
297 }
298
299 pub fn writer_mut(&mut self) -> &mut W {
322 &mut self.make_writer
323 }
324
325 pub fn with_test_writer(self) -> SubscriberBuilder<TestWriter, T, F> {
342 SubscriberBuilder {
343 make_writer: TestWriter::default(),
344 timer: self.timer,
345 filter: self.filter,
346 log_internal_errors: self.log_internal_errors,
347 display_timestamp: self.display_timestamp,
348 display_target: self.display_target,
349 display_level: self.display_level,
350 display_thread_id: self.display_thread_id,
351 display_thread_name: self.display_thread_name,
352 display_filename: self.display_filename,
353 display_line_number: self.display_line_number,
354 flatten_event: self.flatten_event,
355 display_current_span: self.display_current_span,
356 display_span_list: self.display_span_list,
357 #[cfg(feature = "opentelemetry")]
358 display_opentelemetry_ids: self.display_opentelemetry_ids,
359 }
360 }
361
362 #[must_use]
367 pub fn log_internal_errors(self, log_internal_errors: bool) -> Self {
368 Self {
369 log_internal_errors,
370 ..self
371 }
372 }
373
374 pub fn map_writer<W2>(self, f: impl FnOnce(W) -> W2) -> SubscriberBuilder<W2, T, F>
391 where
392 W2: for<'writer> MakeWriter<'writer> + 'static,
393 {
394 SubscriberBuilder {
395 make_writer: f(self.make_writer),
396 timer: self.timer,
397 filter: self.filter,
398 log_internal_errors: self.log_internal_errors,
399 display_timestamp: self.display_timestamp,
400 display_target: self.display_target,
401 display_level: self.display_level,
402 display_thread_id: self.display_thread_id,
403 display_thread_name: self.display_thread_name,
404 display_filename: self.display_filename,
405 display_line_number: self.display_line_number,
406 flatten_event: self.flatten_event,
407 display_current_span: self.display_current_span,
408 display_span_list: self.display_span_list,
409 #[cfg(feature = "opentelemetry")]
410 display_opentelemetry_ids: self.display_opentelemetry_ids,
411 }
412 }
413
414 #[must_use]
416 pub fn flatten_event(self, flatten_event: bool) -> SubscriberBuilder<W, T, F> {
417 SubscriberBuilder {
418 flatten_event,
419 ..self
420 }
421 }
422
423 #[must_use]
426 pub fn with_current_span(self, display_current_span: bool) -> SubscriberBuilder<W, T, F> {
427 SubscriberBuilder {
428 display_current_span,
429 ..self
430 }
431 }
432
433 #[must_use]
436 pub fn with_span_list(self, display_span_list: bool) -> SubscriberBuilder<W, T, F> {
437 SubscriberBuilder {
438 display_span_list,
439 ..self
440 }
441 }
442
443 pub fn with_timer<T2>(self, timer: T2) -> SubscriberBuilder<W, T2, F> {
459 SubscriberBuilder {
460 make_writer: self.make_writer,
461 timer,
462 filter: self.filter,
463 log_internal_errors: self.log_internal_errors,
464 display_timestamp: self.display_timestamp,
465 display_target: self.display_target,
466 display_level: self.display_level,
467 display_thread_id: self.display_thread_id,
468 display_thread_name: self.display_thread_name,
469 display_filename: self.display_filename,
470 display_line_number: self.display_line_number,
471 flatten_event: self.flatten_event,
472 display_current_span: self.display_current_span,
473 display_span_list: self.display_span_list,
474 #[cfg(feature = "opentelemetry")]
475 display_opentelemetry_ids: self.display_opentelemetry_ids,
476 }
477 }
478
479 pub fn without_time(self) -> SubscriberBuilder<W, (), F> {
481 SubscriberBuilder {
482 make_writer: self.make_writer,
483 timer: (),
484 filter: self.filter,
485 log_internal_errors: self.log_internal_errors,
486 display_timestamp: self.display_timestamp,
487 display_target: self.display_target,
488 display_level: self.display_level,
489 display_thread_id: self.display_thread_id,
490 display_thread_name: self.display_thread_name,
491 display_filename: self.display_filename,
492 display_line_number: self.display_line_number,
493 flatten_event: self.flatten_event,
494 display_current_span: self.display_current_span,
495 display_span_list: self.display_span_list,
496 #[cfg(feature = "opentelemetry")]
497 display_opentelemetry_ids: self.display_opentelemetry_ids,
498 }
499 }
500
501 #[must_use]
551 pub fn with_target(self, display_target: bool) -> SubscriberBuilder<W, T, F> {
552 SubscriberBuilder {
553 display_target,
554 ..self
555 }
556 }
557
558 #[must_use]
563 pub fn with_file(self, display_filename: bool) -> SubscriberBuilder<W, T, F> {
564 SubscriberBuilder {
565 display_filename,
566 ..self
567 }
568 }
569
570 #[must_use]
575 pub fn with_line_number(self, display_line_number: bool) -> SubscriberBuilder<W, T, F> {
576 SubscriberBuilder {
577 display_line_number,
578 ..self
579 }
580 }
581
582 #[must_use]
584 pub fn with_level(self, display_level: bool) -> SubscriberBuilder<W, T, F> {
585 SubscriberBuilder {
586 display_level,
587 ..self
588 }
589 }
590
591 #[must_use]
596 pub fn with_thread_names(self, display_thread_name: bool) -> SubscriberBuilder<W, T, F> {
597 SubscriberBuilder {
598 display_thread_name,
599 ..self
600 }
601 }
602
603 #[must_use]
608 pub fn with_thread_ids(self, display_thread_id: bool) -> SubscriberBuilder<W, T, F> {
609 SubscriberBuilder {
610 display_thread_id,
611 ..self
612 }
613 }
614
615 #[cfg(feature = "opentelemetry")]
620 #[cfg_attr(docsrs, doc(cfg(feature = "opentelemetry")))]
621 #[must_use]
622 pub fn with_opentelemetry_ids(self, display_opentelemetry_ids: bool) -> Self {
623 SubscriberBuilder {
624 display_opentelemetry_ids,
625 ..self
626 }
627 }
628
629 #[cfg(feature = "env-filter")]
676 #[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))]
677 pub fn with_env_filter(
678 self,
679 filter: impl Into<tracing_subscriber::EnvFilter>,
680 ) -> SubscriberBuilder<W, T, tracing_subscriber::EnvFilter> {
681 SubscriberBuilder {
682 make_writer: self.make_writer,
683 timer: self.timer,
684 filter: filter.into(),
685 log_internal_errors: self.log_internal_errors,
686 display_timestamp: self.display_timestamp,
687 display_target: self.display_target,
688 display_level: self.display_level,
689 display_thread_id: self.display_thread_id,
690 display_thread_name: self.display_thread_name,
691 display_filename: self.display_filename,
692 display_line_number: self.display_line_number,
693 flatten_event: self.flatten_event,
694 display_current_span: self.display_current_span,
695 display_span_list: self.display_span_list,
696 #[cfg(feature = "opentelemetry")]
697 display_opentelemetry_ids: self.display_opentelemetry_ids,
698 }
699 }
700
701 pub fn with_max_level(
731 self,
732 filter: impl Into<LevelFilter>,
733 ) -> SubscriberBuilder<W, T, LevelFilter> {
734 SubscriberBuilder {
735 make_writer: self.make_writer,
736 timer: self.timer,
737 filter: filter.into(),
738 log_internal_errors: self.log_internal_errors,
739 display_timestamp: self.display_timestamp,
740 display_target: self.display_target,
741 display_level: self.display_level,
742 display_thread_id: self.display_thread_id,
743 display_thread_name: self.display_thread_name,
744 display_filename: self.display_filename,
745 display_line_number: self.display_line_number,
746 flatten_event: self.flatten_event,
747 display_current_span: self.display_current_span,
748 display_span_list: self.display_span_list,
749 #[cfg(feature = "opentelemetry")]
750 display_opentelemetry_ids: self.display_opentelemetry_ids,
751 }
752 }
753
754 #[cfg(feature = "env-filter")]
791 #[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))]
792 pub fn with_filter_reloading<S>(self) -> SubscriberBuilder<W, T, reload::Layer<F, S>> {
793 let (filter, _) = reload::Layer::new(self.filter);
794 SubscriberBuilder {
795 make_writer: self.make_writer,
796 timer: self.timer,
797 filter,
798 log_internal_errors: self.log_internal_errors,
799 display_timestamp: self.display_timestamp,
800 display_target: self.display_target,
801 display_level: self.display_level,
802 display_thread_id: self.display_thread_id,
803 display_thread_name: self.display_thread_name,
804 display_filename: self.display_filename,
805 display_line_number: self.display_line_number,
806 flatten_event: self.flatten_event,
807 display_current_span: self.display_current_span,
808 display_span_list: self.display_span_list,
809 #[cfg(feature = "opentelemetry")]
810 display_opentelemetry_ids: self.display_opentelemetry_ids,
811 }
812 }
813}
814
815impl<W, T, F, S> SubscriberBuilder<W, T, reload::Layer<F, S>> {
816 pub fn reload_handle(&self) -> reload::Handle<F, S> {
819 self.filter.handle()
820 }
821}
822
823#[cfg(test)]
824mod tests {
825 use std::path::Path;
828
829 use tracing::subscriber::with_default;
830 use tracing_core::Dispatch;
831 use tracing_subscriber::{filter::LevelFilter, registry::LookupSpan, Registry};
832
833 use super::SubscriberBuilder;
834 use crate::{
835 layer::JsonLayer,
836 tests::{MockMakeWriter, MockTime},
837 };
838
839 fn subscriber() -> SubscriberBuilder {
840 SubscriberBuilder::default()
841 }
842
843 #[rustfmt::skip]
844 #[test]
867 fn json_filename() {
868 let current_path = Path::new("src")
869 .join("fmt")
870 .join("builder.rs")
871 .to_str()
872 .expect("path must be valid unicode")
873 .replace('\\', "\\\\");
875 #[rustfmt::skip]
876 let expected = &format!("{}{}{}",
877 "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"json_subscriber::fmt::builder::tests\",\"filename\":\"",
878 current_path,
879 "\",\"fields\":{\"message\":\"some json test\"}}\n"
880 );
881 let collector = subscriber()
882 .flatten_event(false)
883 .with_current_span(true)
884 .with_file(true)
885 .with_span_list(true);
886 test_json(expected, collector, || {
887 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
888 let _guard = span.enter();
889 tracing::info!("some json test");
890 });
891 }
892
893 #[test]
894 fn json_line_number() {
895 #[rustfmt::skip]
896 let expected = "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"json_subscriber::fmt::builder::tests\",\"line_number\":42,\"fields\":{\"message\":\"some json test\"}}\n";
897 let collector = subscriber()
898 .flatten_event(false)
899 .with_current_span(true)
900 .with_line_number(true)
901 .with_span_list(true);
902 test_json_with_line_number(expected, collector, || {
903 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
904 let _guard = span.enter();
905 tracing::info!("some json test");
906 });
907 }
908
909 #[test]
910 fn json_flattened_event() {
911 #[rustfmt::skip]
912 let expected = "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"json_subscriber::fmt::builder::tests\",\"message\":\"some json test\"}\n";
913
914 let collector = subscriber()
915 .flatten_event(true)
916 .with_current_span(true)
917 .with_span_list(true);
918 test_json(expected, collector, || {
919 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
920 let _guard = span.enter();
921 tracing::info!("some json test");
922 });
923 }
924
925 #[test]
926 fn json_disabled_current_span_event() {
927 #[rustfmt::skip]
928 let expected = "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3}],\"target\":\"json_subscriber::fmt::builder::tests\",\"fields\":{\"message\":\"some json test\"}}\n";
929 let collector = subscriber()
930 .flatten_event(false)
931 .with_current_span(false)
932 .with_span_list(true);
933 test_json(expected, collector, || {
934 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
935 let _guard = span.enter();
936 tracing::info!("some json test");
937 });
938 }
939
940 #[test]
941 fn json_disabled_span_list_event() {
942 #[rustfmt::skip]
943 let expected = "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":42,\"name\":\"json_span\",\"number\":3},\"target\":\"json_subscriber::fmt::builder::tests\",\"fields\":{\"message\":\"some json test\"}}\n";
944 let collector = subscriber()
945 .flatten_event(false)
946 .with_current_span(true)
947 .with_span_list(false);
948 test_json(expected, collector, || {
949 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
950 let _guard = span.enter();
951 tracing::info!("some json test");
952 });
953 }
954
955 #[test]
956 fn json_nested_span() {
957 #[rustfmt::skip]
958 let expected = "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":43,\"name\":\"nested_json_span\",\"number\":4},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3},{\"answer\":43,\"name\":\"nested_json_span\",\"number\":4}],\"target\":\"json_subscriber::fmt::builder::tests\",\"fields\":{\"message\":\"some json test\"}}\n";
959 let collector = subscriber()
960 .flatten_event(false)
961 .with_current_span(true)
962 .with_span_list(true);
963 test_json(expected, collector, || {
964 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
965 let _guard = span.enter();
966 let span = tracing::span!(
967 tracing::Level::INFO,
968 "nested_json_span",
969 answer = 43,
970 number = 4
971 );
972 let _guard = span.enter();
973 tracing::info!("some json test");
974 });
975 }
976
977 #[test]
978 fn json_explicit_span() {
979 #[rustfmt::skip]
980 let expected = "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"span\":{\"answer\":43,\"name\":\"nested_json_span\",\"number\":4},\"spans\":[{\"answer\":42,\"name\":\"json_span\",\"number\":3},{\"answer\":43,\"name\":\"nested_json_span\",\"number\":4}],\"target\":\"json_subscriber::fmt::builder::tests\",\"fields\":{\"message\":\"some json test\"}}\n";
981 let collector = subscriber()
982 .flatten_event(false)
983 .with_current_span(true)
984 .with_span_list(true);
985 test_json(expected, collector, || {
986 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
987 let span = tracing::span!(
988 parent: &span,
989 tracing::Level::INFO,
990 "nested_json_span",
991 answer = 43,
992 number = 4
993 );
994 tracing::info!(parent: &span, "some json test");
996 });
997 }
998
999 #[test]
1000 fn json_explicit_no_span() {
1001 #[rustfmt::skip]
1002 let expected = "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"target\":\"json_subscriber::fmt::builder::tests\",\"fields\":{\"message\":\"some json test\"}}\n";
1003 let collector = subscriber()
1004 .flatten_event(false)
1005 .with_current_span(true)
1006 .with_span_list(true);
1007 test_json(expected, collector, || {
1008 let span = tracing::span!(tracing::Level::INFO, "json_span", answer = 42, number = 3);
1009 let _guard = span.enter();
1010 let span = tracing::span!(
1011 tracing::Level::INFO,
1012 "nested_json_span",
1013 answer = 43,
1014 number = 4
1015 );
1016 let _guard = span.enter();
1017 tracing::info!(parent: None, "some json test");
1018 });
1019 }
1020
1021 #[test]
1022 fn json_no_span() {
1023 #[rustfmt::skip]
1024 let expected = "{\"timestamp\":\"fake time\",\"level\":\"INFO\",\"target\":\"json_subscriber::fmt::builder::tests\",\"fields\":{\"message\":\"some json test\"}}\n";
1025 let collector = subscriber()
1026 .flatten_event(false)
1027 .with_current_span(true)
1028 .with_span_list(true);
1029 test_json(expected, collector, || {
1030 tracing::info!("some json test");
1031 });
1032 }
1033
1034 #[test]
1035 fn record_works() {
1036 let buffer = MockMakeWriter::default();
1040 let subscriber = SubscriberBuilder::default()
1041 .with_writer(buffer.clone())
1042 .finish();
1043
1044 with_default(subscriber, || {
1045 tracing::info!("an event outside the root span");
1046 assert_eq!(
1047 parse_as_json(&buffer)["fields"]["message"],
1048 "an event outside the root span"
1049 );
1050
1051 let span = tracing::info_span!("the span", na = tracing::field::Empty);
1052 span.record("na", "value");
1053 let _enter = span.enter();
1054
1055 tracing::info!("an event inside the root span");
1056 assert_eq!(
1057 parse_as_json(&buffer)["fields"]["message"],
1058 "an event inside the root span"
1059 );
1060 });
1061 }
1062
1063 fn parse_as_json(buffer: &MockMakeWriter) -> serde_json::Value {
1064 let buf = String::from_utf8(buffer.buf().to_vec()).unwrap();
1065 let json = buf
1066 .lines()
1067 .last()
1068 .expect("expected at least one line to be written!");
1069 match serde_json::from_str(json) {
1070 Ok(v) => v,
1071 Err(e) => {
1072 panic!(
1073 "assertion failed: JSON shouldn't be malformed\n error: {e}\n json: {json}"
1074 )
1075 },
1076 }
1077 }
1078
1079 fn test_json<T>(expected: &str, builder: SubscriberBuilder, producer: impl FnOnce() -> T) {
1080 let make_writer = MockMakeWriter::default();
1081 let collector = builder
1082 .with_writer(make_writer.clone())
1083 .with_timer(MockTime)
1084 .finish();
1085
1086 with_default(collector, producer);
1087
1088 let buf = make_writer.buf();
1089 let actual = dbg!(std::str::from_utf8(&buf[..]).unwrap());
1090 assert_eq!(
1091 serde_json::from_str::<std::collections::HashMap<&str, serde_json::Value>>(expected)
1092 .unwrap(),
1093 serde_json::from_str(actual).unwrap()
1094 );
1095 }
1096
1097 fn test_json_with_line_number<T>(
1098 expected: &str,
1099 builder: SubscriberBuilder,
1100 producer: impl FnOnce() -> T,
1101 ) {
1102 let make_writer = MockMakeWriter::default();
1103 let collector = builder
1104 .with_writer(make_writer.clone())
1105 .with_timer(MockTime)
1106 .finish();
1107
1108 with_default(collector, producer);
1109
1110 let buf = make_writer.buf();
1111 let actual = std::str::from_utf8(&buf[..]).unwrap();
1112 let mut expected =
1113 serde_json::from_str::<std::collections::HashMap<&str, serde_json::Value>>(expected)
1114 .unwrap();
1115 let expect_line_number = expected.remove("line_number").is_some();
1116 let mut actual: std::collections::HashMap<&str, serde_json::Value> =
1117 serde_json::from_str(actual).unwrap();
1118 let line_number = actual.remove("line_number");
1119 if expect_line_number {
1120 assert_eq!(line_number.map(|x| x.is_number()), Some(true));
1121 } else {
1122 assert!(line_number.is_none());
1123 }
1124 assert_eq!(actual, expected);
1125 }
1126
1127 #[test]
1128 fn subscriber_downcasts() {
1129 let subscriber = SubscriberBuilder::default().finish();
1130 let dispatch = Dispatch::new(subscriber);
1131 assert!(dispatch.downcast_ref::<Registry>().is_some());
1132 }
1133
1134 #[test]
1135 fn subscriber_downcasts_to_parts() {
1136 let subscriber = SubscriberBuilder::default().finish();
1137 let dispatch = Dispatch::new(subscriber);
1138 assert!(dispatch.downcast_ref::<JsonLayer>().is_some());
1139 assert!(dispatch.downcast_ref::<LevelFilter>().is_some());
1140 }
1141
1142 #[test]
1143 fn is_lookup_span() {
1144 fn assert_lookup_span<T: for<'a> LookupSpan<'a>>(_: T) {}
1145 let subscriber = SubscriberBuilder::default().finish();
1146 assert_lookup_span(subscriber);
1147 }
1148
1149 #[test]
1150 #[cfg(feature = "env-filter")]
1151 fn reload_filter_works() {
1152 use tracing::Level;
1153 use tracing_subscriber::util::SubscriberInitExt;
1154
1155 let builder = SubscriberBuilder::default()
1156 .with_max_level(Level::INFO)
1158 .with_filter_reloading();
1159
1160 let handle = builder.reload_handle();
1162
1163 builder.finish().init();
1165
1166 tracing::debug!("this is not recorded!");
1168
1169 handle
1173 .reload(Level::DEBUG)
1174 .expect("the collector should still exist");
1175
1176 tracing::debug!("this is recorded!");
1178 }
1179}