| 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; |
| 11 | fn event() { |
| 12 | tracing::info!("my event" ); |
| 13 | } |
| 14 | |
| 15 | impl Subscriber for NopSubscriber { |
| 16 | fn register_callsite(&self, _: &'static Metadata<'static>) -> Interest { |
| 17 | Interest::never() |
| 18 | } |
| 19 | |
| 20 | fn enabled(&self, _: &Metadata<'_>) -> bool { |
| 21 | false |
| 22 | } |
| 23 | |
| 24 | fn new_span(&self, _: &Attributes<'_>) -> Id { |
| 25 | Id::from_u64(1) |
| 26 | } |
| 27 | |
| 28 | fn record(&self, _: &Id, _: &Record<'_>) {} |
| 29 | fn record_follows_from(&self, _: &Id, _: &Id) {} |
| 30 | fn event(&self, _: &Event<'_>) {} |
| 31 | fn enter(&self, _: &Id) {} |
| 32 | fn exit(&self, _: &Id) {} |
| 33 | } |
| 34 | |
| 35 | #[test] |
| 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] |
| 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 | |