use super ::*;
use tracing_core::subscriber::NoSubscriber;
#[ derive(Debug)]
pub (crate ) struct NopLayer;
impl <S: Subscriber> Layer<S> for NopLayer {}
#[ allow(dead_code)]
struct NopLayer2;
impl <S: Subscriber> Layer<S> for NopLayer2 {}
/// A layer that holds a string.
///
/// Used to test that pointers returned by downcasting are actually valid.
struct StringLayer(&'static str);
impl <S: Subscriber> Layer<S> for StringLayer {}
struct StringLayer2(&'static str);
impl <S: Subscriber> Layer<S> for StringLayer2 {}
struct StringLayer3(&'static str);
impl <S: Subscriber> Layer<S> for StringLayer3 {}
pub (crate ) struct StringSubscriber(&'static str);
impl Subscriber for StringSubscriber {
fn register_callsite(&self , _: &'static Metadata<' static >) -> Interest {
Interest::never()
}
fn enabled(&self , _: &Metadata<'_>) -> bool {
false
}
fn new_span(&self , _: &span::Attributes<'_>) -> span::Id {
span::Id::from_u64(1 )
}
fn record(&self , _: &span::Id, _: &span::Record<'_>) {}
fn record_follows_from(&self , _: &span::Id, _: &span::Id) {}
fn event(&self , _: &Event<'_>) {}
fn enter(&self , _: &span::Id) {}
fn exit(&self , _: &span::Id) {}
}
fn assert_subscriber(_s: impl Subscriber) {}
fn assert_layer<S: Subscriber>(_l: &impl Layer<S>) {}
#[ test]
fn layer_is_subscriber() {
let s = NopLayer.with_subscriber(NoSubscriber::default());
assert_subscriber(s)
}
#[ test]
fn two_layers_are_subscriber() {
let s = NopLayer
.and_then(NopLayer)
.with_subscriber(NoSubscriber::default());
assert_subscriber(s)
}
#[ test]
fn three_layers_are_subscriber() {
let s = NopLayer
.and_then(NopLayer)
.and_then(NopLayer)
.with_subscriber(NoSubscriber::default());
assert_subscriber(s)
}
#[ test]
fn three_layers_are_layer() {
let layers = NopLayer.and_then(NopLayer).and_then(NopLayer);
assert_layer(&layers);
let _ = layers.with_subscriber(NoSubscriber::default());
}
#[ test]
#[ cfg(feature = "alloc" )]
fn box_layer_is_layer() {
use alloc::boxed::Box ;
let l: Box <dyn Layer<NoSubscriber> + Send + Sync> = Box ::new(NopLayer);
assert_layer(&l);
l.with_subscriber(NoSubscriber::default());
}
#[ test]
fn downcasts_to_subscriber() {
let s = NopLayer
.and_then(NopLayer)
.and_then(NopLayer)
.with_subscriber(StringSubscriber("subscriber" ));
let subscriber =
<dyn Subscriber>::downcast_ref::<StringSubscriber>(&s).expect("subscriber should downcast" );
assert_eq!(subscriber.0 , "subscriber" );
}
#[ test]
fn downcasts_to_layer() {
let s = StringLayer("layer_1" )
.and_then(StringLayer2("layer_2" ))
.and_then(StringLayer3("layer_3" ))
.with_subscriber(NoSubscriber::default());
let layer = <dyn Subscriber>::downcast_ref::<StringLayer>(&s).expect("layer 1 should downcast" );
assert_eq!(layer.0 , "layer_1" );
let layer =
<dyn Subscriber>::downcast_ref::<StringLayer2>(&s).expect("layer 2 should downcast" );
assert_eq!(layer.0 , "layer_2" );
let layer =
<dyn Subscriber>::downcast_ref::<StringLayer3>(&s).expect("layer 3 should downcast" );
assert_eq!(layer.0 , "layer_3" );
}
#[ cfg(all(feature = "registry" , feature = "std" ))]
mod registry_tests {
use super ::*;
use crate ::registry::LookupSpan;
#[ test]
fn context_event_span() {
use std::sync::{Arc, Mutex};
let last_event_span = Arc::new(Mutex::new(None));
struct RecordingLayer {
last_event_span: Arc<Mutex<Option<&'static str>>>,
}
impl <S> Layer<S> for RecordingLayer
where
S: Subscriber + for <'lookup> LookupSpan<' lookup>,
{
fn on_event(&self , event: &Event<'_>, ctx: Context<' _, S>) {
let span = ctx.event_span(event);
*self .last_event_span.lock().unwrap() = span.map(|s| s.name());
}
}
tracing::subscriber::with_default(
crate ::registry().with(RecordingLayer {
last_event_span: last_event_span.clone(),
}),
|| {
tracing::info!("no span" );
assert_eq!(*last_event_span.lock().unwrap(), None);
let parent = tracing::info_span!("explicit" );
tracing::info!(parent: &parent, "explicit span" );
assert_eq!(*last_event_span.lock().unwrap(), Some("explicit" ));
let _guard = tracing::info_span!("contextual" ).entered();
tracing::info!("contextual span" );
assert_eq!(*last_event_span.lock().unwrap(), Some("contextual" ));
},
);
}
/// Tests for how max-level hints are calculated when combining layers
/// with and without per-layer filtering.
mod max_level_hints {
use super ::*;
use crate ::filter::*;
#[ test]
fn mixed_with_unfiltered() {
let subscriber = crate ::registry()
.with(NopLayer)
.with(NopLayer.with_filter(LevelFilter::INFO));
assert_eq!(subscriber.max_level_hint(), None);
}
#[ test]
fn mixed_with_unfiltered_layered() {
let subscriber = crate ::registry().with(NopLayer).with(
NopLayer
.with_filter(LevelFilter::INFO)
.and_then(NopLayer.with_filter(LevelFilter::TRACE)),
);
assert_eq!(dbg!(subscriber).max_level_hint(), None);
}
#[ test]
fn mixed_interleaved() {
let subscriber = crate ::registry()
.with(NopLayer)
.with(NopLayer.with_filter(LevelFilter::INFO))
.with(NopLayer)
.with(NopLayer.with_filter(LevelFilter::INFO));
assert_eq!(dbg!(subscriber).max_level_hint(), None);
}
#[ test]
fn mixed_layered() {
let subscriber = crate ::registry()
.with(NopLayer.with_filter(LevelFilter::INFO).and_then(NopLayer))
.with(NopLayer.and_then(NopLayer.with_filter(LevelFilter::INFO)));
assert_eq!(dbg!(subscriber).max_level_hint(), None);
}
#[ test]
fn plf_only_unhinted() {
let subscriber = crate ::registry()
.with(NopLayer.with_filter(LevelFilter::INFO))
.with(NopLayer.with_filter(filter_fn(|_| true )));
assert_eq!(dbg!(subscriber).max_level_hint(), None);
}
#[ test]
fn plf_only_unhinted_nested_outer() {
// if a nested tree of per-layer filters has an _outer_ filter with
// no max level hint, it should return `None`.
let subscriber = crate ::registry()
.with(
NopLayer
.with_filter(LevelFilter::INFO)
.and_then(NopLayer.with_filter(LevelFilter::WARN)),
)
.with(
NopLayer
.with_filter(filter_fn(|_| true ))
.and_then(NopLayer.with_filter(LevelFilter::DEBUG)),
);
assert_eq!(dbg!(subscriber).max_level_hint(), None);
}
#[ test]
fn plf_only_unhinted_nested_inner() {
// If a nested tree of per-layer filters has an _inner_ filter with
// no max-level hint, but the _outer_ filter has a max level hint,
// it should pick the outer hint. This is because the outer filter
// will disable the spans/events before they make it to the inner
// filter.
let subscriber = dbg!(crate ::registry().with(
NopLayer
.with_filter(filter_fn(|_| true ))
.and_then(NopLayer.with_filter(filter_fn(|_| true )))
.with_filter(LevelFilter::INFO),
));
assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::INFO));
}
#[ test]
fn unhinted_nested_inner() {
let subscriber = dbg!(crate ::registry()
.with(NopLayer.and_then(NopLayer).with_filter(LevelFilter::INFO))
.with(
NopLayer
.with_filter(filter_fn(|_| true ))
.and_then(NopLayer.with_filter(filter_fn(|_| true )))
.with_filter(LevelFilter::WARN),
));
assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::INFO));
}
#[ test]
fn unhinted_nested_inner_mixed() {
let subscriber = dbg!(crate ::registry()
.with(
NopLayer
.and_then(NopLayer.with_filter(filter_fn(|_| true )))
.with_filter(LevelFilter::INFO)
)
.with(
NopLayer
.with_filter(filter_fn(|_| true ))
.and_then(NopLayer.with_filter(filter_fn(|_| true )))
.with_filter(LevelFilter::WARN),
));
assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::INFO));
}
#[ test]
fn plf_only_picks_max() {
let subscriber = crate ::registry()
.with(NopLayer.with_filter(LevelFilter::WARN))
.with(NopLayer.with_filter(LevelFilter::DEBUG));
assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::DEBUG));
}
#[ test]
fn many_plf_only_picks_max() {
let subscriber = crate ::registry()
.with(NopLayer.with_filter(LevelFilter::WARN))
.with(NopLayer.with_filter(LevelFilter::DEBUG))
.with(NopLayer.with_filter(LevelFilter::INFO))
.with(NopLayer.with_filter(LevelFilter::ERROR));
assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::DEBUG));
}
#[ test]
fn nested_plf_only_picks_max() {
let subscriber = crate ::registry()
.with(
NopLayer.with_filter(LevelFilter::INFO).and_then(
NopLayer
.with_filter(LevelFilter::WARN)
.and_then(NopLayer.with_filter(LevelFilter::DEBUG)),
),
)
.with(
NopLayer
.with_filter(LevelFilter::INFO)
.and_then(NopLayer.with_filter(LevelFilter::ERROR)),
);
assert_eq!(dbg!(subscriber).max_level_hint(), Some(LevelFilter::DEBUG));
}
}
}
Messung V0.5 in Prozent C=79 H=97 G=88
¤ Dauer der Verarbeitung: 0.20 Sekunden
(vorverarbeitet am 2026-08-25)
¤
*© Formatika GbR, Deutschland