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 #[test]
reload_handle()36 fn reload_handle() {
37     static FILTER1_CALLS: AtomicUsize = AtomicUsize::new(0);
38     static FILTER2_CALLS: AtomicUsize = AtomicUsize::new(0);
39 
40     enum Filter {
41         One,
42         Two,
43     }
44 
45     impl<S: Subscriber> tracing_subscriber::Layer<S> for Filter {
46         fn register_callsite(&self, m: &Metadata<'_>) -> Interest {
47             println!("REGISTER: {:?}", m);
48             Interest::sometimes()
49         }
50 
51         fn enabled(&self, m: &Metadata<'_>, _: layer::Context<'_, S>) -> bool {
52             println!("ENABLED: {:?}", m);
53             match self {
54                 Filter::One => FILTER1_CALLS.fetch_add(1, Ordering::SeqCst),
55                 Filter::Two => FILTER2_CALLS.fetch_add(1, Ordering::SeqCst),
56             };
57             true
58         }
59 
60         fn max_level_hint(&self) -> Option<LevelFilter> {
61             match self {
62                 Filter::One => Some(LevelFilter::INFO),
63                 Filter::Two => Some(LevelFilter::DEBUG),
64             }
65         }
66     }
67 
68     let (layer, handle) = Layer::new(Filter::One);
69 
70     let subscriber = tracing_core::dispatcher::Dispatch::new(layer.with_subscriber(NopSubscriber));
71 
72     tracing_core::dispatcher::with_default(&subscriber, || {
73         assert_eq!(FILTER1_CALLS.load(Ordering::SeqCst), 0);
74         assert_eq!(FILTER2_CALLS.load(Ordering::SeqCst), 0);
75 
76         event();
77 
78         assert_eq!(FILTER1_CALLS.load(Ordering::SeqCst), 1);
79         assert_eq!(FILTER2_CALLS.load(Ordering::SeqCst), 0);
80 
81         assert_eq!(LevelFilter::current(), LevelFilter::INFO);
82         handle.reload(Filter::Two).expect("should reload");
83         assert_eq!(LevelFilter::current(), LevelFilter::DEBUG);
84 
85         event();
86 
87         assert_eq!(FILTER1_CALLS.load(Ordering::SeqCst), 1);
88         assert_eq!(FILTER2_CALLS.load(Ordering::SeqCst), 1);
89     })
90 }
91 
92 #[test]
reload_filter()93 fn reload_filter() {
94     struct NopLayer;
95     impl<S: Subscriber> tracing_subscriber::Layer<S> for NopLayer {
96         fn register_callsite(&self, _m: &Metadata<'_>) -> Interest {
97             Interest::sometimes()
98         }
99 
100         fn enabled(&self, _m: &Metadata<'_>, _: layer::Context<'_, S>) -> bool {
101             true
102         }
103     }
104 
105     static FILTER1_CALLS: AtomicUsize = AtomicUsize::new(0);
106     static FILTER2_CALLS: AtomicUsize = AtomicUsize::new(0);
107 
108     enum Filter {
109         One,
110         Two,
111     }
112 
113     impl<S: Subscriber> tracing_subscriber::layer::Filter<S> for Filter {
114         fn enabled(&self, m: &Metadata<'_>, _: &layer::Context<'_, S>) -> bool {
115             println!("ENABLED: {:?}", m);
116             match self {
117                 Filter::One => FILTER1_CALLS.fetch_add(1, Ordering::SeqCst),
118                 Filter::Two => FILTER2_CALLS.fetch_add(1, Ordering::SeqCst),
119             };
120             true
121         }
122 
123         fn max_level_hint(&self) -> Option<LevelFilter> {
124             match self {
125                 Filter::One => Some(LevelFilter::INFO),
126                 Filter::Two => Some(LevelFilter::DEBUG),
127             }
128         }
129     }
130 
131     let (filter, handle) = Layer::new(Filter::One);
132 
133     let dispatcher = tracing_core::Dispatch::new(
134         tracing_subscriber::registry().with(NopLayer.with_filter(filter)),
135     );
136 
137     tracing_core::dispatcher::with_default(&dispatcher, || {
138         assert_eq!(FILTER1_CALLS.load(Ordering::SeqCst), 0);
139         assert_eq!(FILTER2_CALLS.load(Ordering::SeqCst), 0);
140 
141         event();
142 
143         assert_eq!(FILTER1_CALLS.load(Ordering::SeqCst), 1);
144         assert_eq!(FILTER2_CALLS.load(Ordering::SeqCst), 0);
145 
146         assert_eq!(LevelFilter::current(), LevelFilter::INFO);
147         handle.reload(Filter::Two).expect("should reload");
148         assert_eq!(LevelFilter::current(), LevelFilter::DEBUG);
149 
150         event();
151 
152         assert_eq!(FILTER1_CALLS.load(Ordering::SeqCst), 1);
153         assert_eq!(FILTER2_CALLS.load(Ordering::SeqCst), 1);
154     })
155 }
156