1// Tests that depend on a count of the number of times their filter is evaluated
2// cant exist in the same file with other tests that add subscribers to the
3// registry. The registry was changed so that each time a new dispatcher is
4// added all filters are re-evaluated. The tests being run only in separate
5// threads with shared global state lets them interfere with each other
6#[cfg(not(feature = "std"))]
7extern crate std;
8
9use tracing::{span, Level};
10use tracing_mock::*;
11
12use std::sync::{
13 atomic::{AtomicUsize, Ordering},
14 Arc,
15};
16
17#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
18#[test]
19fn filters_are_reevaluated_for_different_call_sites() {
20 // Asserts that the `span!` macro caches the result of calling
21 // `Subscriber::enabled` for each span.
22 let charlie_count = Arc::new(AtomicUsize::new(0));
23 let dave_count = Arc::new(AtomicUsize::new(0));
24 let charlie_count2 = charlie_count.clone();
25 let dave_count2 = dave_count.clone();
26
27 let subscriber = subscriber::mock()
28 .with_filter(move |meta| {
29 println!("Filter: {:?}", meta.name());
30 match meta.name() {
31 "charlie" => {
32 charlie_count2.fetch_add(1, Ordering::Relaxed);
33 false
34 }
35 "dave" => {
36 dave_count2.fetch_add(1, Ordering::Relaxed);
37 true
38 }
39 _ => false,
40 }
41 })
42 .run();
43
44 // Since this test is in its own file anyway, we can do this. Thus, this
45 // test will work even with no-std.
46 tracing::subscriber::set_global_default(subscriber).unwrap();
47
48 // Enter "charlie" and then "dave". The dispatcher expects to see "dave" but
49 // not "charlie."
50 let charlie = span!(Level::TRACE, "charlie");
51 let dave = charlie.in_scope(|| {
52 let dave = span!(Level::TRACE, "dave");
53 dave.in_scope(|| {});
54 dave
55 });
56
57 // The filter should have seen each span a single time.
58 assert_eq!(charlie_count.load(Ordering::Relaxed), 1);
59 assert_eq!(dave_count.load(Ordering::Relaxed), 1);
60
61 charlie.in_scope(|| dave.in_scope(|| {}));
62
63 // The subscriber should see "dave" again, but the filter should not have
64 // been called.
65 assert_eq!(charlie_count.load(Ordering::Relaxed), 1);
66 assert_eq!(dave_count.load(Ordering::Relaxed), 1);
67
68 // A different span with the same name has a different call site, so it
69 // should cause the filter to be reapplied.
70 let charlie2 = span!(Level::TRACE, "charlie");
71 charlie.in_scope(|| {});
72 assert_eq!(charlie_count.load(Ordering::Relaxed), 2);
73 assert_eq!(dave_count.load(Ordering::Relaxed), 1);
74
75 // But, the filter should not be re-evaluated for the new "charlie" span
76 // when it is re-entered.
77 charlie2.in_scope(|| span!(Level::TRACE, "dave").in_scope(|| {}));
78 assert_eq!(charlie_count.load(Ordering::Relaxed), 2);
79 assert_eq!(dave_count.load(Ordering::Relaxed), 2);
80}
81