use tracing_subscriber::filter::LevelFilter;
use tracing_subscriber::fmt;
use serde::Serialize;
#[derive(clap::ValueEnum, Clone, Default, Debug, Serialize, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub enum LogLevel {
#[default]
Info,
Trace,
Debug,
Warn,
Error,
}
impl std::str::FromStr for LogLevel {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"info" => Ok(LogLevel::Info),
"trace" => Ok(LogLevel::Trace),
"debug" => Ok(LogLevel::Debug),
"warn" => Ok(LogLevel::Warn),
"error" => Ok(LogLevel::Error),
_ => Err(format!("Invalid log level: {}", s)),
}
}
}
impl std::fmt::Display for LogLevel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LogLevel::Info => write!(f, "info"),
LogLevel::Trace => write!(f, "trace"),
LogLevel::Debug => write!(f, "debug"),
LogLevel::Warn => write!(f, "warn"),
LogLevel::Error => write!(f, "error"),
}
}
}
pub fn new_tracer_logger(log_level: LogLevel) {
let log_level_filter = match log_level {
LogLevel::Trace => LevelFilter::TRACE,
LogLevel::Debug => LevelFilter::DEBUG,
LogLevel::Info => LevelFilter::INFO,
LogLevel::Warn => LevelFilter::WARN,
LogLevel::Error => LevelFilter::ERROR,
};
let format = fmt::format()
.with_level(true) .with_target(true) .with_thread_ids(true) .with_thread_names(true) .compact();
tracing_subscriber::fmt()
.event_format(format)
.with_max_level(log_level_filter)
.init();
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use super::*;
#[test]
fn test_from_str_valid_levels() {
assert_eq!(LogLevel::from_str("info").unwrap(), LogLevel::Info);
assert_eq!(LogLevel::from_str("trace").unwrap(), LogLevel::Trace);
assert_eq!(LogLevel::from_str("debug").unwrap(), LogLevel::Debug);
assert_eq!(LogLevel::from_str("warn").unwrap(), LogLevel::Warn);
assert_eq!(LogLevel::from_str("error").unwrap(), LogLevel::Error);
}
#[test]
fn test_display() {
assert_eq!(LogLevel::Info.to_string(), "info");
assert_eq!(LogLevel::Trace.to_string(), "trace");
assert_eq!(LogLevel::Debug.to_string(), "debug");
assert_eq!(LogLevel::Warn.to_string(), "warn");
assert_eq!(LogLevel::Error.to_string(), "error");
}
#[test]
fn test_from_str_invalid_level() {
assert!(LogLevel::from_str("invalid").is_err());
}
}