• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![cfg(feature = "registry")]
2 use std::sync::atomic::{AtomicUsize, Ordering};
3 use tracing_core::{
4     span::{Attributes, Id, Record},
5     subscriber::Interest,
6     Event, LevelFilter, Metadata, Subscriber,
7 };
8 use tracing_subscriber::{layer, prelude::*, reload::*};
9 
10 pub struct NopSubscriber;
event()11 fn event() {
12     tracing::info!("my event");
13 }
14 
15 impl Subscriber for NopSubscriber {
register_callsite(&self, _: &'static Metadata<'static>) -> Interest16     fn register_callsite(&self, _: &'static Metadata<'static>) -> Interest {
17         Interest::never()
18     }
19 
enabled(&self, _: &Metadata<'_>) -> bool20     fn enabled(&self, _: &Metadata<'_>) -> bool {
21         false
22     }
23 
new_span(&self, _: &Attributes<'_>) -> Id24     fn new_span(&self, _: &Attributes<'_>) -> Id {
25         Id::from_u64(1)
26     }
27 
record(&self, _: &Id, _: &Record<'_>)28     fn record(&self, _: &Id, _: &Record<'_>) {}
record_follows_from(&self, _: &Id, _: &Id)29     fn record_follows_from(&self, _: &Id, _: &Id) {}
event(&self, _: &Event<'_>)30     fn event(&self, _: &Event<'_>) {}
enter(&self, _: &Id)31     fn enter(&self, _: &Id) {}
exit(&self, _: &Id)32     fn exit(&self, _: &Id) {}
33 }
34 
35 /// Running these two tests in parallel will cause flaky failures, since they are both modifying the MAX_LEVEL value.
36 /// "cargo test -- --test-threads=1 fixes it, but it runs all tests in serial.
37 /// The only way to run tests in serial in a single file is this way.
38 #[test]
run_all_reload_test()39 fn run_all_reload_test() {
40     reload_handle();
41     reload_filter();
42 }
43 
reload_handle()44 fn reload_handle() {
45     static FILTER1_CALLS: AtomicUsize = AtomicUsize::new(0);
46     static FILTER2_CALLS: AtomicUsize = AtomicUsize::new(0);
47 
48     enum Filter {
49         One,
50         Two,
51     }
52 
53     impl<S: Subscriber> tracing_subscriber::Layer<S> for Filter {
54         fn register_callsite(&self, m: &Metadata<'_>) -> Interest {
55             println!("REGISTER: {:?}", m);
56             Interest::sometimes()
57         }
58 
59         fn enabled(&self, m: &Metadata<'_>, _: layer::Context<'_, S>) -> bool {
60             println!("ENABLED: {:?}", m);
61             match self {
62                 Filter::One => FILTER1_CALLS.fetch_add(1, Ordering::SeqCst),
63                 Filter::Two => FILTER2_CALLS.fetch_add(1, Ordering::SeqCst),
64             };
65             true
66         }
67 
68         fn max_level_hint(&self) -> Option<LevelFilter> {
69             match self {
70                 Filter::One => Some(LevelFilter::INFO),
71                 Filter::Two => Some(LevelFilter::DEBUG),
72             }
73         }
74     }
75 
76     let (layer, handle) = Layer::new(Filter::One);
77 
78     let subscriber = tracing_core::dispatcher::Dispatch::new(layer.with_subscriber(NopSubscriber));
79 
80     tracing_core::dispatcher::with_default(&subscriber, || {
81         assert_eq!(FILTER1_CALLS.load(Ordering::SeqCst), 0);
82         assert_eq!(FILTER2_CALLS.load(Ordering::SeqCst), 0);
83 
84         event();
85 
86         assert_eq!(FILTER1_CALLS.load(Ordering::SeqCst), 1);
87         assert_eq!(FILTER2_CALLS.load(Ordering::SeqCst), 0);
88 
89         assert_eq!(LevelFilter::current(), LevelFilter::INFO);
90         handle.reload(Filter::Two).expect("should reload");
91         assert_eq!(LevelFilter::current(), LevelFilter::DEBUG);
92 
93         event();
94 
95         assert_eq!(FILTER1_CALLS.load(Ordering::SeqCst), 1);
96         assert_eq!(FILTER2_CALLS.load(Ordering::SeqCst), 1);
97     })
98 }
99 
reload_filter()100 fn reload_filter() {
101     struct NopLayer;
102     impl<S: Subscriber> tracing_subscriber::Layer<S> for NopLayer {
103         fn register_callsite(&self, _m: &Metadata<'_>) -> Interest {
104             Interest::sometimes()
105         }
106 
107         fn enabled(&self, _m: &Metadata<'_>, _: layer::Context<'_, S>) -> bool {
108             true
109         }
110     }
111 
112     static FILTER1_CALLS: AtomicUsize = AtomicUsize::new(0);
113     static FILTER2_CALLS: AtomicUsize = AtomicUsize::new(0);
114 
115     enum Filter {
116         One,
117         Two,
118     }
119 
120     impl<S: Subscriber> tracing_subscriber::layer::Filter<S> for Filter {
121         fn enabled(&self, m: &Metadata<'_>, _: &layer::Context<'_, S>) -> bool {
122             println!("ENABLED: {:?}", m);
123             match self {
124                 Filter::One => FILTER1_CALLS.fetch_add(1, Ordering::SeqCst),
125                 Filter::Two => FILTER2_CALLS.fetch_add(1, Ordering::SeqCst),
126             };
127             true
128         }
129 
130         fn max_level_hint(&self) -> Option<LevelFilter> {
131             match self {
132                 Filter::One => Some(LevelFilter::INFO),
133                 Filter::Two => Some(LevelFilter::DEBUG),
134             }
135         }
136     }
137 
138     let (filter, handle) = Layer::new(Filter::One);
139 
140     let dispatcher = tracing_core::Dispatch::new(
141         tracing_subscriber::registry().with(NopLayer.with_filter(filter)),
142     );
143 
144     tracing_core::dispatcher::with_default(&dispatcher, || {
145         assert_eq!(FILTER1_CALLS.load(Ordering::SeqCst), 0);
146         assert_eq!(FILTER2_CALLS.load(Ordering::SeqCst), 0);
147 
148         event();
149 
150         assert_eq!(FILTER1_CALLS.load(Ordering::SeqCst), 1);
151         assert_eq!(FILTER2_CALLS.load(Ordering::SeqCst), 0);
152 
153         assert_eq!(LevelFilter::current(), LevelFilter::INFO);
154         handle.reload(Filter::Two).expect("should reload");
155         assert_eq!(LevelFilter::current(), LevelFilter::DEBUG);
156 
157         event();
158 
159         assert_eq!(FILTER1_CALLS.load(Ordering::SeqCst), 1);
160         assert_eq!(FILTER2_CALLS.load(Ordering::SeqCst), 1);
161     })
162 }
163