1use crate::filter::level::{self, LevelFilter};
2#[cfg(not(feature = "smallvec"))]
3use alloc::vec;
4#[cfg(not(feature = "std"))]
5use alloc::{string::String, vec::Vec};
6
7use core::{cmp::Ordering, fmt, iter::FromIterator, slice, str::FromStr};
8use tracing_core::{Level, Metadata};
9/// Indicates that a string could not be parsed as a filtering directive.
10#[derive(Debug)]
11pub struct ParseError {
12 kind: ParseErrorKind,
13}
14
15/// A directive which will statically enable or disable a given callsite.
16///
17/// Unlike a dynamic directive, this can be cached by the callsite.
18#[derive(Debug, PartialEq, Eq, Clone)]
19pub(crate) struct StaticDirective {
20 pub(in crate::filter) target: Option<String>,
21 pub(in crate::filter) field_names: Vec<String>,
22 pub(in crate::filter) level: LevelFilter,
23}
24
25#[cfg(feature = "smallvec")]
26pub(crate) type FilterVec<T> = smallvec::SmallVec<[T; 8]>;
27#[cfg(not(feature = "smallvec"))]
28pub(crate) type FilterVec<T> = Vec<T>;
29
30#[derive(Debug, PartialEq, Clone)]
31pub(in crate::filter) struct DirectiveSet<T> {
32 directives: FilterVec<T>,
33 pub(in crate::filter) max_level: LevelFilter,
34}
35
36pub(in crate::filter) trait Match {
37 fn cares_about(&self, meta: &Metadata<'_>) -> bool;
38 fn level(&self) -> &LevelFilter;
39}
40
41#[derive(Debug)]
42enum ParseErrorKind {
43 #[cfg(feature = "std")]
44 Field(Box<dyn std::error::Error + Send + Sync>),
45 Level(level::ParseError),
46 Other(Option<&'static str>),
47}
48
49// === impl DirectiveSet ===
50
51impl<T> DirectiveSet<T> {
52 #[cfg(feature = "env-filter")]
53 pub(crate) fn is_empty(&self) -> bool {
54 self.directives.is_empty()
55 }
56
57 pub(crate) fn iter(&self) -> slice::Iter<'_, T> {
58 self.directives.iter()
59 }
60}
61
62impl<T: Ord> Default for DirectiveSet<T> {
63 fn default() -> Self {
64 Self {
65 directives: FilterVec::new(),
66 max_level: LevelFilter::OFF,
67 }
68 }
69}
70
71impl<T: Match + Ord> DirectiveSet<T> {
72 pub(crate) fn directives(&self) -> impl Iterator<Item = &T> {
73 self.directives.iter()
74 }
75
76 pub(crate) fn directives_for<'a>(
77 &'a self,
78 metadata: &'a Metadata<'a>,
79 ) -> impl Iterator<Item = &'a T> + 'a {
80 self.directives().filter(move |d| d.cares_about(metadata))
81 }
82
83 pub(crate) fn add(&mut self, directive: T) {
84 // does this directive enable a more verbose level than the current
85 // max? if so, update the max level.
86 let level = *directive.level();
87 if level > self.max_level {
88 self.max_level = level;
89 }
90 // insert the directive into the vec of directives, ordered by
91 // specificity (length of target + number of field filters). this
92 // ensures that, when finding a directive to match a span or event, we
93 // search the directive set in most specific first order.
94 match self.directives.binary_search(&directive) {
95 Ok(i) => self.directives[i] = directive,
96 Err(i) => self.directives.insert(i, directive),
97 }
98 }
99
100 #[cfg(test)]
101 pub(in crate::filter) fn into_vec(self) -> FilterVec<T> {
102 self.directives
103 }
104}
105
106impl<T: Match + Ord> FromIterator<T> for DirectiveSet<T> {
107 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
108 let mut this: DirectiveSet = Self::default();
109 this.extend(iter);
110 this
111 }
112}
113
114impl<T: Match + Ord> Extend<T> for DirectiveSet<T> {
115 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
116 for directive: T in iter.into_iter() {
117 self.add(directive);
118 }
119 }
120}
121
122impl<T> IntoIterator for DirectiveSet<T> {
123 type Item = T;
124
125 #[cfg(feature = "smallvec")]
126 type IntoIter = smallvec::IntoIter<[T; 8]>;
127 #[cfg(not(feature = "smallvec"))]
128 type IntoIter = vec::IntoIter<T>;
129
130 fn into_iter(self) -> Self::IntoIter {
131 self.directives.into_iter()
132 }
133}
134
135// === impl Statics ===
136
137impl DirectiveSet<StaticDirective> {
138 pub(crate) fn enabled(&self, meta: &Metadata<'_>) -> bool {
139 let level = meta.level();
140 match self.directives_for(meta).next() {
141 Some(d) => d.level >= *level,
142 None => false,
143 }
144 }
145
146 /// Same as `enabled` above, but skips `Directive`'s with fields.
147 pub(crate) fn target_enabled(&self, target: &str, level: &Level) -> bool {
148 match self.directives_for_target(target).next() {
149 Some(d) => d.level >= *level,
150 None => false,
151 }
152 }
153
154 pub(crate) fn directives_for_target<'a>(
155 &'a self,
156 target: &'a str,
157 ) -> impl Iterator<Item = &'a StaticDirective> + 'a {
158 self.directives()
159 .filter(move |d| d.cares_about_target(target))
160 }
161}
162
163// === impl StaticDirective ===
164
165impl StaticDirective {
166 pub(in crate::filter) fn new(
167 target: Option<String>,
168 field_names: Vec<String>,
169 level: LevelFilter,
170 ) -> Self {
171 Self {
172 target,
173 field_names,
174 level,
175 }
176 }
177
178 pub(in crate::filter) fn cares_about_target(&self, to_check: &str) -> bool {
179 // Does this directive have a target filter, and does it match the
180 // metadata's target?
181 if let Some(ref target) = self.target {
182 if !to_check.starts_with(&target[..]) {
183 return false;
184 }
185 }
186
187 if !self.field_names.is_empty() {
188 return false;
189 }
190
191 true
192 }
193}
194
195impl Ord for StaticDirective {
196 fn cmp(&self, other: &StaticDirective) -> Ordering {
197 // We attempt to order directives by how "specific" they are. This
198 // ensures that we try the most specific directives first when
199 // attempting to match a piece of metadata.
200
201 // First, we compare based on whether a target is specified, and the
202 // lengths of those targets if both have targets.
203 let ordering = self
204 .target
205 .as_ref()
206 .map(String::len)
207 .cmp(&other.target.as_ref().map(String::len))
208 // Then we compare how many field names are matched by each directive.
209 .then_with(|| self.field_names.len().cmp(&other.field_names.len()))
210 // Finally, we fall back to lexicographical ordering if the directives are
211 // equally specific. Although this is no longer semantically important,
212 // we need to define a total ordering to determine the directive's place
213 // in the BTreeMap.
214 .then_with(|| {
215 self.target
216 .cmp(&other.target)
217 .then_with(|| self.field_names[..].cmp(&other.field_names[..]))
218 })
219 .reverse();
220
221 #[cfg(debug_assertions)]
222 {
223 if ordering == Ordering::Equal {
224 debug_assert_eq!(
225 self.target, other.target,
226 "invariant violated: Ordering::Equal must imply a.target == b.target"
227 );
228 debug_assert_eq!(
229 self.field_names, other.field_names,
230 "invariant violated: Ordering::Equal must imply a.field_names == b.field_names"
231 );
232 }
233 }
234
235 ordering
236 }
237}
238
239impl PartialOrd for StaticDirective {
240 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
241 Some(self.cmp(other))
242 }
243}
244
245impl Match for StaticDirective {
246 fn cares_about(&self, meta: &Metadata<'_>) -> bool {
247 // Does this directive have a target filter, and does it match the
248 // metadata's target?
249 if let Some(ref target) = self.target {
250 if !meta.target().starts_with(&target[..]) {
251 return false;
252 }
253 }
254
255 if meta.is_event() && !self.field_names.is_empty() {
256 let fields = meta.fields();
257 for name in &self.field_names {
258 if fields.field(name).is_none() {
259 return false;
260 }
261 }
262 }
263
264 true
265 }
266
267 fn level(&self) -> &LevelFilter {
268 &self.level
269 }
270}
271
272impl Default for StaticDirective {
273 fn default() -> Self {
274 StaticDirective {
275 target: None,
276 field_names: Vec::new(),
277 level: LevelFilter::ERROR,
278 }
279 }
280}
281
282impl fmt::Display for StaticDirective {
283 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284 let mut wrote_any = false;
285 if let Some(ref target) = self.target {
286 fmt::Display::fmt(target, f)?;
287 wrote_any = true;
288 }
289
290 if !self.field_names.is_empty() {
291 f.write_str("[")?;
292
293 let mut fields = self.field_names.iter();
294 if let Some(field) = fields.next() {
295 write!(f, "{{{}", field)?;
296 for field in fields {
297 write!(f, ",{}", field)?;
298 }
299 f.write_str("}")?;
300 }
301
302 f.write_str("]")?;
303 wrote_any = true;
304 }
305
306 if wrote_any {
307 f.write_str("=")?;
308 }
309
310 fmt::Display::fmt(&self.level, f)
311 }
312}
313
314impl FromStr for StaticDirective {
315 type Err = ParseError;
316
317 fn from_str(s: &str) -> Result<Self, Self::Err> {
318 // This method parses a filtering directive in one of the following
319 // forms:
320 //
321 // * `foo=trace` (TARGET=LEVEL)
322 // * `foo[{bar,baz}]=info` (TARGET[{FIELD,+}]=LEVEL)
323 // * `trace` (bare LEVEL)
324 // * `foo` (bare TARGET)
325 let mut split = s.split('=');
326 let part0 = split
327 .next()
328 .ok_or_else(|| ParseError::msg("string must not be empty"))?;
329
330 // Directive includes an `=`:
331 // * `foo=trace`
332 // * `foo[{bar}]=trace`
333 // * `foo[{bar,baz}]=trace`
334 if let Some(part1) = split.next() {
335 if split.next().is_some() {
336 return Err(ParseError::msg(
337 "too many '=' in filter directive, expected 0 or 1",
338 ));
339 }
340
341 let mut split = part0.split("[{");
342 let target = split.next().map(String::from);
343 let mut field_names = Vec::new();
344 // Directive includes fields:
345 // * `foo[{bar}]=trace`
346 // * `foo[{bar,baz}]=trace`
347 if let Some(maybe_fields) = split.next() {
348 if split.next().is_some() {
349 return Err(ParseError::msg(
350 "too many '[{' in filter directive, expected 0 or 1",
351 ));
352 }
353
354 if !maybe_fields.ends_with("}]") {
355 return Err(ParseError::msg("expected fields list to end with '}]'"));
356 }
357
358 let fields = maybe_fields
359 .trim_end_matches("}]")
360 .split(',')
361 .filter_map(|s| {
362 if s.is_empty() {
363 None
364 } else {
365 Some(String::from(s))
366 }
367 });
368 field_names.extend(fields);
369 };
370 let level = part1.parse()?;
371 return Ok(Self {
372 level,
373 field_names,
374 target,
375 });
376 }
377
378 // Okay, the part after the `=` was empty, the directive is either a
379 // bare level or a bare target.
380 // * `foo`
381 // * `info`
382 Ok(match part0.parse::<LevelFilter>() {
383 Ok(level) => Self {
384 level,
385 target: None,
386 field_names: Vec::new(),
387 },
388 Err(_) => Self {
389 target: Some(String::from(part0)),
390 level: LevelFilter::TRACE,
391 field_names: Vec::new(),
392 },
393 })
394 }
395}
396
397// === impl ParseError ===
398
399impl ParseError {
400 #[cfg(feature = "env-filter")]
401 pub(crate) fn new() -> Self {
402 ParseError {
403 kind: ParseErrorKind::Other(None),
404 }
405 }
406
407 pub(crate) fn msg(s: &'static str) -> Self {
408 ParseError {
409 kind: ParseErrorKind::Other(Some(s)),
410 }
411 }
412}
413
414impl fmt::Display for ParseError {
415 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416 match self.kind {
417 ParseErrorKind::Other(None) => f.pad("invalid filter directive"),
418 ParseErrorKind::Other(Some(msg: &str)) => write!(f, "invalid filter directive: {}", msg),
419 ParseErrorKind::Level(ref l: &ParseLevelFilterError) => l.fmt(f),
420 #[cfg(feature = "std")]
421 ParseErrorKind::Field(ref e: &Box) => write!(f, "invalid field filter: {}", e),
422 }
423 }
424}
425
426#[cfg(feature = "std")]
427impl std::error::Error for ParseError {
428 fn description(&self) -> &str {
429 "invalid filter directive"
430 }
431
432 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
433 match self.kind {
434 ParseErrorKind::Other(_) => None,
435 ParseErrorKind::Level(ref l: &ParseLevelFilterError) => Some(l),
436 ParseErrorKind::Field(ref n: &Box) => Some(n.as_ref()),
437 }
438 }
439}
440
441#[cfg(feature = "std")]
442impl From<Box<dyn std::error::Error + Send + Sync>> for ParseError {
443 fn from(e: Box<dyn std::error::Error + Send + Sync>) -> Self {
444 Self {
445 kind: ParseErrorKind::Field(e),
446 }
447 }
448}
449
450impl From<level::ParseError> for ParseError {
451 fn from(l: level::ParseError) -> Self {
452 Self {
453 kind: ParseErrorKind::Level(l),
454 }
455 }
456}
457