elfo_logger/
scope_filter.rs1use std::sync::Arc;
2#[cfg(feature = "tracing-log")]
3use std::sync::OnceLock;
4
5use arc_swap::ArcSwap;
6use fxhash::FxHashMap;
7use tracing::{metadata::LevelFilter, subscriber::Interest, Metadata, Subscriber};
8use tracing_subscriber::{filter::Targets, layer};
9
10use elfo_core::{logging::CheckResult, scope};
11
12use crate::{config::LoggingTargetConfig, stats};
13
14#[derive(PartialEq)]
15struct ScopeFilterConfig {
16 targets: Targets,
17}
18
19impl Default for ScopeFilterConfig {
20 fn default() -> Self {
21 Self {
22 targets: Targets::new().with_default(LevelFilter::TRACE),
23 }
24 }
25}
26
27struct Inner {
28 config: ArcSwap<ScopeFilterConfig>,
29 #[cfg(feature = "tracing-log")]
30 log_metadata_name: OnceLock<&'static str>,
31}
32
33pub struct ScopeFilter {
46 inner: Arc<Inner>,
47}
48
49impl ScopeFilter {
50 pub(crate) fn new() -> Self {
51 Self {
52 inner: Arc::new(Inner {
53 config: ArcSwap::new(Arc::new(ScopeFilterConfig::default())),
54 #[cfg(feature = "tracing-log")]
55 log_metadata_name: OnceLock::new(),
56 }),
57 }
58 }
59
60 pub(crate) fn clone(&self) -> Self {
62 Self {
63 inner: Arc::clone(&self.inner),
64 }
65 }
66
67 pub(crate) fn configure(&self, targets: &FxHashMap<String, LoggingTargetConfig>) {
68 let targets = Targets::new()
69 .with_default(LevelFilter::TRACE)
70 .with_targets(
71 targets
72 .iter()
73 .map(|(target, target_config)| (target, target_config.max_level)),
74 );
75
76 let config = Arc::new(ScopeFilterConfig { targets });
77 let old_config = self.inner.config.swap(Arc::clone(&config));
78 if config != old_config {
79 tracing::callsite::rebuild_interest_cache();
80 }
81 }
82
83 fn interested(&self, meta: &Metadata<'_>) -> Interest {
84 let config = self.inner.config.load();
85 if config.targets.would_enable(meta.target(), meta.level()) {
86 Interest::sometimes()
88 } else {
89 Interest::never()
91 }
92 }
93
94 fn enabled(&self, meta: &Metadata<'_>) -> bool {
95 let level = *meta.level();
98
99 #[cfg(feature = "tracing-log")]
100 {
101 let name = meta.name();
104 if let Some(&log_name) = self.inner.log_metadata_name.get() {
105 if std::ptr::eq(log_name, name) {
108 let config = self.inner.config.load();
109 if !config.targets.would_enable(meta.target(), meta.level()) {
110 return false;
111 }
112 }
113 } else if name == "log record" {
114 let config = self.inner.config.load();
115 if !config.targets.would_enable(meta.target(), meta.level()) {
116 return false;
117 }
118 if meta.target() == "elfo_logger" {
121 self.inner.log_metadata_name.set(name).ok();
122 return false;
123 }
124 }
125 }
126
127 scope::try_with(|scope| {
128 if !scope.permissions().is_logging_enabled(level) {
129 return false;
130 }
131
132 match scope.logging().check(meta) {
133 CheckResult::Passed => true,
134 CheckResult::NotInterested => false,
135 CheckResult::Limited => {
136 stats::counter_per_level("elfo_limited_events_total", level);
137 false
138 }
139 }
140 })
141 .unwrap_or(level <= LevelFilter::INFO)
143 }
144}
145
146impl<S: Subscriber> layer::Layer<S> for ScopeFilter {
147 fn register_callsite(&self, meta: &'static Metadata<'static>) -> Interest {
148 self.interested(meta)
149 }
150
151 fn enabled(&self, meta: &Metadata<'_>, _cx: layer::Context<'_, S>) -> bool {
152 self.enabled(meta)
153 }
154
155 }
157
158impl<S> layer::Filter<S> for ScopeFilter {
160 fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest {
161 self.interested(meta)
162 }
163
164 fn enabled(&self, meta: &Metadata<'_>, _cx: &layer::Context<'_, S>) -> bool {
165 !self.interested(meta).is_never() && self.enabled(meta)
171 }
172
173 }