blob: c97bda04bd26cc0409e662edb894f3c14244ce77 [file] [log] [blame]
use std::{cmp::Ordering, fmt, str::FromStr};
use tracing_core::{
subscriber::{Interest, Subscriber},
Level, Metadata,
};
/// A filter which is enabled for a given verbosity level and below.
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct LevelFilter(Inner);
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
enum Inner {
Off,
Level(Level),
}
/// Indicates that a string could not be parsed to a valid level.
#[derive(Clone, Debug)]
pub struct ParseError(());
// === impl LevelFilter ===
impl LevelFilter {
/// The "off" level.
///
/// Designates that trace instrumentation should be completely disabled.
pub const OFF: LevelFilter = LevelFilter(Inner::Off);
/// The "error" level.
///
/// Designates very serious errors.
pub const ERROR: LevelFilter = LevelFilter(Inner::Level(Level::ERROR));
/// The "warn" level.
///
/// Designates hazardous situations.
pub const WARN: LevelFilter = LevelFilter(Inner::Level(Level::WARN));
/// The "info" level.
///
/// Designates useful information.
pub const INFO: LevelFilter = LevelFilter(Inner::Level(Level::INFO));
/// The "debug" level.
///
/// Designates lower priority information.
pub const DEBUG: LevelFilter = LevelFilter(Inner::Level(Level::DEBUG));
/// The "trace" level.
///
/// Designates very low priority, often extremely verbose, information.
pub const TRACE: LevelFilter = LevelFilter(Inner::Level(Level::TRACE));
}
impl<S: Subscriber> crate::Layer<S> for LevelFilter {
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
if self >= metadata.level() {
Interest::always()
} else {
Interest::never()
}
}
fn enabled(&self, metadata: &Metadata<'_>, _: crate::layer::Context<'_, S>) -> bool {
self >= metadata.level()
}
}
impl PartialEq<Level> for LevelFilter {
fn eq(&self, other: &Level) -> bool {
match self.0 {
Inner::Off => false,
Inner::Level(ref level) => level == other,
}
}
}
impl PartialOrd<Level> for LevelFilter {
fn partial_cmp(&self, other: &Level) -> Option<Ordering> {
match self.0 {
Inner::Off => Some(Ordering::Less),
Inner::Level(ref level) => level.partial_cmp(other),
}
}
}
impl fmt::Display for LevelFilter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
Inner::Off => f.pad("off"),
Inner::Level(Level::ERROR) => f.pad("error"),
Inner::Level(Level::WARN) => f.pad("warn"),
Inner::Level(Level::INFO) => f.pad("info"),
Inner::Level(Level::DEBUG) => f.pad("debug"),
Inner::Level(Level::TRACE) => f.pad("trace"),
}
}
}
impl fmt::Debug for LevelFilter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
Inner::Off => f.pad("LevelFilter::OFF"),
Inner::Level(Level::ERROR) => f.pad("LevelFilter::ERROR"),
Inner::Level(Level::WARN) => f.pad("LevelFilter::WARN"),
Inner::Level(Level::INFO) => f.pad("LevelFilter::INFO"),
Inner::Level(Level::DEBUG) => f.pad("LevelFilter::DEBUG"),
Inner::Level(Level::TRACE) => f.pad("LevelFilter::TRACE"),
}
}
}
impl FromStr for LevelFilter {
type Err = ParseError;
fn from_str(from: &str) -> Result<Self, Self::Err> {
from.parse::<usize>()
.ok()
.and_then(|num| match num {
0 => Some(LevelFilter::OFF),
1 => Some(LevelFilter::ERROR),
2 => Some(LevelFilter::WARN),
3 => Some(LevelFilter::INFO),
4 => Some(LevelFilter::DEBUG),
5 => Some(LevelFilter::TRACE),
_ => None,
})
.or_else(|| match from {
"" => Some(LevelFilter::ERROR),
s if s.eq_ignore_ascii_case("error") => Some(LevelFilter::ERROR),
s if s.eq_ignore_ascii_case("warn") => Some(LevelFilter::WARN),
s if s.eq_ignore_ascii_case("info") => Some(LevelFilter::INFO),
s if s.eq_ignore_ascii_case("debug") => Some(LevelFilter::DEBUG),
s if s.eq_ignore_ascii_case("trace") => Some(LevelFilter::TRACE),
s if s.eq_ignore_ascii_case("off") => Some(LevelFilter::OFF),
_ => None,
})
.ok_or_else(|| ParseError(()))
}
}
impl Into<Option<Level>> for LevelFilter {
fn into(self) -> Option<Level> {
match self.0 {
Inner::Off => None,
Inner::Level(l) => Some(l),
}
}
}
impl From<Option<Level>> for LevelFilter {
fn from(level: Option<Level>) -> Self {
match level {
Some(level) => LevelFilter(Inner::Level(level)),
None => LevelFilter(Inner::Off),
}
}
}
impl From<Level> for LevelFilter {
fn from(level: Level) -> Self {
LevelFilter(Inner::Level(level))
}
}
// === impl ParseError ===
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "invalid level`")
}
}
impl std::error::Error for ParseError {}