tracing_filter/legacy/
mod.rs1use {
7 self::matcher::SpanMatcher,
8 crate::{Diagnostics, DEFAULT_ENV},
9 std::{cell::RefCell, collections::HashMap, env, ffi::OsStr, fmt, sync::RwLock},
10 thread_local::ThreadLocal,
11 tracing_core::{callsite, span, Interest, LevelFilter, Metadata, Subscriber},
12 tracing_subscriber::{
13 layer::Context,
14 registry::{LookupSpan, SpanRef},
15 },
16};
17
18mod directive;
19mod matcher;
20mod parse;
21#[cfg(test)]
22mod tests;
23
24#[derive(Debug)]
54pub struct Filter {
55 scope: ThreadLocal<RefCell<Vec<LevelFilter>>>,
56 statics: directive::Statics,
57 dynamics: directive::Dynamics,
58 by_cs: RwLock<HashMap<callsite::Identifier, matcher::CallsiteMatcher>>,
59}
60
61impl Filter {
62 pub fn new(spec: &str) -> Self {
66 Self::parse(spec).0
67 }
68
69 pub fn empty() -> Self {
71 Self::parse("").0
72 }
73
74 pub fn from_default_env() -> Option<(Self, Option<Diagnostics<'static>>)> {
76 Self::from_env(DEFAULT_ENV)
77 }
78
79 pub fn from_env(key: impl AsRef<OsStr>) -> Option<(Self, Option<Diagnostics<'static>>)> {
83 let s = env::var(key).ok()?;
84 let (filter, err) = Self::parse(&s);
85 Some((
86 filter,
87 match err {
88 None => None,
89 Some(x) => Some({
90 Diagnostics {
91 error: x.error,
92 ignored: x.ignored,
93 disabled: x.disabled,
94 source: s.into(),
95 }
96 }),
97 },
98 ))
99 }
100
101 pub fn layer(self) -> crate::FilterLayer<Self> {
103 crate::FilterLayer::new(self)
104 }
105}
106
107impl Filter {
108 fn has_dynamics(&self) -> bool {
109 !self.dynamics.directives.is_empty()
110 }
111
112 fn cares_about_span<R: for<'a> LookupSpan<'a>>(&self, span: SpanRef<'_, R>) -> bool {
113 let ext = span.extensions();
114 ext.get::<SpanMatcher>().is_some()
115 }
116
117 fn base_interest(&self) -> Interest {
118 if self.has_dynamics() {
119 Interest::sometimes()
120 } else {
121 Interest::never()
122 }
123 }
124}
125
126impl<S: Subscriber + for<'a> LookupSpan<'a>> crate::Filter<S> for Filter {
127 fn enabled(&self, metadata: &Metadata<'_>, _ctx: &Context<'_, S>) -> bool {
128 let level = metadata.level();
129
130 if self.has_dynamics() && self.dynamics.level >= *level {
135 if metadata.is_span() {
136 let enabled = self
138 .by_cs
139 .read()
140 .map(|cs| cs.contains_key(&metadata.callsite()))
141 .unwrap_or_default();
142 if enabled {
143 return true;
144 }
145 }
146
147 let enabled = self
148 .scope
149 .get_or_default()
150 .borrow()
151 .iter()
152 .any(|filter| filter >= level);
153 if enabled {
154 return true;
155 }
156 }
157
158 self.statics.enabled(metadata)
160 }
161
162 fn callsite_enabled(&self, metadata: &Metadata<'_>) -> tracing_core::Interest {
163 if self.has_dynamics() && metadata.is_span() {
164 if let Some(matcher) = self.dynamics.matcher(metadata) {
168 let mut by_cs = try_lock!(self.by_cs.write(), else return self.base_interest());
169 by_cs.insert(metadata.callsite(), matcher);
170 return Interest::always();
171 }
172 }
173
174 if self.statics.enabled(metadata) {
175 Interest::always()
176 } else {
177 self.base_interest()
178 }
179 }
180
181 fn max_level_hint(&self) -> Option<LevelFilter> {
182 if self.dynamics.has_value_filters() {
183 return Some(LevelFilter::TRACE);
187 }
188 std::cmp::max(self.statics.level.into(), self.dynamics.level.into())
189 }
190
191 fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) {
192 let by_cs = try_lock!(self.by_cs.read());
193 if let Some(cs) = by_cs.get(&attrs.metadata().callsite()) {
194 let span = ctx.span(id).expect("span should be registered");
195 let matcher = cs.to_span_matcher(attrs);
196 span.extensions_mut().insert(matcher);
197 }
198 }
199
200 fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) {
201 let span = ctx.span(id).expect("span should be registered");
202 let ext = span.extensions();
203 if let Some(matcher) = ext.get::<SpanMatcher>() {
204 matcher.record_update(values);
205 }
206 }
207
208 fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
209 let span = ctx.span(id).expect("span should be registered");
213 let ext = span.extensions();
214 if let Some(matcher) = ext.get::<SpanMatcher>() {
215 self.scope
216 .get_or_default()
217 .borrow_mut()
218 .push(matcher.level());
219 }
220 }
221
222 fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
223 let span = ctx.span(id).expect("span should be registered");
224 if self.cares_about_span(span) {
225 self.scope.get_or_default().borrow_mut().pop();
226 }
227 }
228
229 fn on_close(&self, id: span::Id, ctx: Context<'_, S>) {
230 let span = ctx.span(&id).expect("span should be registered");
231 span.extensions_mut().remove::<SpanMatcher>();
232 }
233}
234
235impl fmt::Display for Filter {
236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237 let mut wrote_any = false;
238
239 for directive in self.statics.directives.iter() {
240 if wrote_any {
241 write!(f, ",")?;
242 }
243 write!(f, "{}", directive)?;
244 wrote_any = true;
245 }
246
247 for directive in self.dynamics.directives.iter() {
248 if wrote_any {
249 write!(f, ",")?;
250 }
251 write!(f, "{}", directive)?;
252 wrote_any = true;
253 }
254
255 Ok(())
256 }
257}