1use super::*;
2use tracing_core::subscriber::NoSubscriber;
3
4#[derive(Debug)]
5pub(crate) struct NopLayer;
6impl<S: Subscriber> Layer<S> for NopLayer {}
7
8#[allow(dead_code)]
9struct NopLayer2;
10impl<S: Subscriber> Layer<S> for NopLayer2 {}
11
12/// A layer that holds a string.
13///
14/// Used to test that pointers returned by downcasting are actually valid.
15struct StringLayer(&'static str);
16impl<S: Subscriber> Layer<S> for StringLayer {}
17struct StringLayer2(&'static str);
18impl<S: Subscriber> Layer<S> for StringLayer2 {}
19
20struct StringLayer3(&'static str);
21impl<S: Subscriber> Layer<S> for StringLayer3 {}
22
23pub(crate) struct StringSubscriber(&'static str);
24
25impl Subscriber for StringSubscriber {
26 fn register_callsite(&self, _: &'static Metadata<'static>) -> Interest {
27 Interest::never()
28 }
29
30 fn enabled(&self, _: &Metadata<'_>) -> bool {
31 false
32 }
33
34 fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
35 span::Id::from_u64(1)
36 }
37
38 fn record(&self, _: &span::Id, _: &span::Record<'_>) {}
39 fn record_follows_from(&self, _: &span::Id, _: &span::Id) {}
40 fn event(&self, _: &Event<'_>) {}
41 fn enter(&self, _: &span::Id) {}
42 fn exit(&self, _: &span::Id) {}
43}
44
45fn assert_subscriber(_s: impl Subscriber) {}
46fn assert_layer<S: Subscriber>(_l: &impl Layer<S>) {}
47
48#[test]
49fn layer_is_subscriber() {
50 let s = NopLayer.with_subscriber(NoSubscriber::default());
51 assert_subscriber(s)
52}
53
54#[test]
55fn two_layers_are_subscriber() {
56 let s = NopLayer
57 .and_then(NopLayer)
58 .with_subscriber(NoSubscriber::default());
59 assert_subscriber(s)
60}
61
62#[test]
63fn three_layers_are_subscriber() {
64 let s = NopLayer
65 .and_then(NopLayer)
66 .and_then(NopLayer)
67 .with_subscriber(NoSubscriber::default());
68 assert_subscriber(s)
69}
70
71#[test]
72fn three_layers_are_layer() {
73 let layers = NopLayer.and_then(NopLayer).and_then(NopLayer);
74 assert_layer(&layers);
75 let _ = layers.with_subscriber(NoSubscriber::default());
76}
77
78#[test]
79#[cfg(feature = "alloc")]
80fn box_layer_is_layer() {
81 use alloc::boxed::Box;
82 let l: Box<dyn Layer<NoSubscriber> + Send + Sync> = Box::new(NopLayer);
83 assert_layer(&l);
84 l.with_subscriber(NoSubscriber::default());
85}
86
87#[test]
88fn downcasts_to_subscriber() {
89 let s = NopLayer
90 .and_then(NopLayer)
91 .and_then(NopLayer)
92 .with_subscriber(StringSubscriber("subscriber"));
93 let subscriber =
94 <dyn Subscriber>::downcast_ref::<StringSubscriber>(&s).expect("subscriber should downcast");
95 assert_eq!(subscriber.0, "subscriber");
96}
97
98#[test]
99fn downcasts_to_layer() {
100 let s = StringLayer("layer_1")
101 .and_then(StringLayer2("layer_2"))
102 .and_then(StringLayer3("layer_3"))
103 .with_subscriber(NoSubscriber::default());
104 let layer = <dyn Subscriber>::downcast_ref::<StringLayer>(&s).expect("layer 1 should downcast");
105 assert_eq!(layer.0, "layer_1");
106 let layer =
107 <dyn Subscriber>::downcast_ref::<StringLayer2>(&s).expect("layer 2 should downcast");
108 assert_eq!(layer.0, "layer_2");
109 let layer =
110 <dyn Subscriber>::downcast_ref::<StringLayer3>(&s).expect("layer 3 should downcast");
111 assert_eq!(layer.0, "layer_3");
112}
113
114#[cfg(all(feature = "registry", feature = "std"))]
115mod registry_tests {
116 use super::*;
117 use crate::registry::LookupSpan;
118
119 #[test]
120 fn context_event_span() {
121 use std::sync::{Arc, Mutex};
122 let last_event_span = Arc::new(Mutex::new(None));
123
124 struct RecordingLayer {
125 last_event_span: Arc<Mutex<Option<&'static str>>>,
126 }
127
128 impl<S> Layer<S> for RecordingLayer
129 where
130 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
131 {
132 fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
133 let span = ctx.event_span(event);
134 *self.last_event_span.lock().unwrap() = span.map(|s| s.name());
135 }
136 }
137
138 tracing::subscriber::with_default(
139 crate::registry().with(RecordingLayer {
140 last_event_span: last_event_span.clone(),
141 }),
142 || {
143 tracing::info!("no span");
144 assert_eq!(*last_event_span.lock().unwrap(), None);
145
146 let parent = tracing::info_span!("explicit");
147 tracing::info!(parent: &parent, "explicit span");
148 assert_eq!(*last_event_span.lock().unwrap(), Some("explicit"));
149
150 let _guard = tracing::info_span!("contextual").entered();
151 tracing::info!("contextual span");
152 assert_eq!(*last_event_span.lock().unwrap(), Some("contextual"));
153 },
154 );
155 }
156
157 /// Tests for how max-level hints are calculated when combining layers
158 /// with and without per-layer filtering.
159 mod max_level_hints {
160
161 use super::*;
162 use crate::filter::*;
163
164 #[test]
165 fn mixed_with_unfiltered() {
166 let subscriber = crate::registry()
167 .with(NopLayer)
168 .with(NopLayer.with_filter(LevelFilter::INFO));
169 assert_eq!(subscriber.max_level_hint(), None);
170 }
171
172 #[test]
173 fn mixed_with_unfiltered_layered() {
174 let subscriber = crate::registry().with(NopLayer).with(
175 NopLayer
176 .with_filter(LevelFilter::INFO)
177 .and_then(NopLayer.with_filter(LevelFilter::TRACE)),
178 );
179 assert_eq!(dbg!(subscriber).max_level_hint(), None);
180 }
181
182 #[test]
183 fn mixed_interleaved() {
184 let subscriber = crate::registry()
185 .with(NopLayer)
186 .with(NopLayer.with_filter(LevelFilter::INFO))
187 .with(NopLayer)
188 .with(NopLayer.with_filter(LevelFilter::INFO));
189 assert_eq!(dbg!(subscriber).max_level_hint(), None);
190 }
191
192 #[test]
193 fn mixed_layered() {
194 let subscriber = crate::registry()
195 .with(NopLayer.with_filter(LevelFilter::INFO).and_then(NopLayer))
196 .with(NopLayer.and_then(NopLayer.with_filter(LevelFilter::INFO)));
197 assert_eq!(dbg!(subscriber).max_level_hint(), None);
198 }
199
200 #[test]
201 fn plf_only_unhinted() {
202 let subscriber = crate::registry()
203 .with(NopLayer.with_filter(LevelFilter::INFO))
204 .with(NopLayer.with_filter(filter_fn(|_| true)));
205 assert_eq!(dbg!(subscriber).max_level_hint(), None);
206 }
207
208 #[test]
209 fn plf_only_unhinted_nested_outer() {
210 // if a nested tree of per-layer filters has an _outer_ filter with
211 // no max level hint, it should return `None`.
212 let subscriber = crate::registry()
213 .with(
214 NopLayer
215 .with_filter(LevelFilter::INFO)
216 .and_then(NopLayer.with_filter(LevelFilter::WARN)),
217 )
218 .with(
219 NopLayer
220 .with_filter(filter_fn(|_| true))
221 .and_then(NopLayer.with_filter(LevelFilter::DEBUG)),
222 );
223 assert_eq!(dbg!(subscriber).max_level_hint(), None);
224 }
225
226 #[test]
227 fn plf_only_unhinted_nested_inner() {
228 // If a nested tree of per-layer filters has an _inner_ filter with
229 // no max-level hint, but the _outer_ filter has a max level hint,
230 // it should pick the outer hint. This is because the outer filter
231 // will disable the spans/events before they make it to the inner
232 // filter.
233 let subscriber = dbg!(crate::registry().with(
234 NopLayer
235 .with_filter(filter_fn(|_| true))
236 .and_then(NopLayer.with_filter(filter_fn(|_| true)))
237 .with_filter(LevelFilter::INFO),
238 ));
239 assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::INFO));
240 }
241
242 #[test]
243 fn unhinted_nested_inner() {
244 let subscriber = dbg!(crate::registry()
245 .with(NopLayer.and_then(NopLayer).with_filter(LevelFilter::INFO))
246 .with(
247 NopLayer
248 .with_filter(filter_fn(|_| true))
249 .and_then(NopLayer.with_filter(filter_fn(|_| true)))
250 .with_filter(LevelFilter::WARN),
251 ));
252 assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::INFO));
253 }
254
255 #[test]
256 fn unhinted_nested_inner_mixed() {
257 let subscriber = dbg!(crate::registry()
258 .with(
259 NopLayer
260 .and_then(NopLayer.with_filter(filter_fn(|_| true)))
261 .with_filter(LevelFilter::INFO)
262 )
263 .with(
264 NopLayer
265 .with_filter(filter_fn(|_| true))
266 .and_then(NopLayer.with_filter(filter_fn(|_| true)))
267 .with_filter(LevelFilter::WARN),
268 ));
269 assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::INFO));
270 }
271
272 #[test]
273 fn plf_only_picks_max() {
274 let subscriber = crate::registry()
275 .with(NopLayer.with_filter(LevelFilter::WARN))
276 .with(NopLayer.with_filter(LevelFilter::DEBUG));
277 assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::DEBUG));
278 }
279
280 #[test]
281 fn many_plf_only_picks_max() {
282 let subscriber = crate::registry()
283 .with(NopLayer.with_filter(LevelFilter::WARN))
284 .with(NopLayer.with_filter(LevelFilter::DEBUG))
285 .with(NopLayer.with_filter(LevelFilter::INFO))
286 .with(NopLayer.with_filter(LevelFilter::ERROR));
287 assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::DEBUG));
288 }
289
290 #[test]
291 fn nested_plf_only_picks_max() {
292 let subscriber = crate::registry()
293 .with(
294 NopLayer.with_filter(LevelFilter::INFO).and_then(
295 NopLayer
296 .with_filter(LevelFilter::WARN)
297 .and_then(NopLayer.with_filter(LevelFilter::DEBUG)),
298 ),
299 )
300 .with(
301 NopLayer
302 .with_filter(LevelFilter::INFO)
303 .and_then(NopLayer.with_filter(LevelFilter::ERROR)),
304 );
305 assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::DEBUG));
306 }
307 }
308}
309