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