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