use std::env;
use std::sync::OnceLock;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub enum LogLevel {
Error = 0,
Info = 1,
Debug = 2,
}
impl LogLevel {
fn from_str(s: &str) -> Self {
match s.to_lowercase().as_str() {
"error" => LogLevel::Error,
"debug" => LogLevel::Debug,
_ => LogLevel::Info,
}
}
}
static LOG_LEVEL: OnceLock<LogLevel> = OnceLock::new();
pub fn log_level() -> LogLevel {
*LOG_LEVEL.get_or_init(|| {
env::var("LOG_LEVEL")
.map(|s| LogLevel::from_str(&s))
.unwrap_or(LogLevel::Info)
})
}
pub fn is_debug() -> bool {
log_level() >= LogLevel::Debug
}
pub fn is_info() -> bool {
log_level() >= LogLevel::Info
}
pub fn log(action: &str, message: &str) {
if log_level() >= LogLevel::Info {
eprintln!("[{}] {}", action, message);
}
}
pub fn error(action: &str, message: &str) {
eprintln!("[{}] {}", action, message);
}
pub fn warn(name: &str, message: &str) {
eprintln!("[warn] [{}] {}", name, message);
}
pub fn warn_simple(message: &str) {
eprintln!("[warn] {}", message);
}
pub fn status(name: &str, message: &str, ok: bool) {
if ok {
eprintln!("[ok] [{}] {}", name, message);
} else {
eprintln!("[fail] [{}] {}", name, message);
}
}
pub fn header(title: &str) {
eprintln!();
eprintln!("{}", title);
eprintln!("{}", "-".repeat(40));
}
pub fn blank() {
eprintln!();
}
pub fn success(message: &str) {
eprintln!("[ok] {}", message);
}
pub fn fail(message: &str) {
eprintln!("[fail] {}", message);
}
pub fn info(label: &str, value: &str) {
eprintln!(" {:<10} {}", label, value);
}
pub fn hint(message: &str) {
eprintln!(" {}", message);
}
pub fn detail(message: &str) {
eprintln!(" -> {}", message);
}
pub fn next_step(description: &str, command: &str) {
eprintln!(" -> {}: {}", description, command);
}
pub fn diagnostic(component: &str, message: &str) {
eprintln!("[warn] [{}] {}", component, message);
}
pub fn debug(action: &str, message: &str) {
if log_level() >= LogLevel::Debug {
eprintln!("[{}] {}", action, message);
}
}
#[macro_export]
macro_rules! logf {
($action:expr, $($arg:tt)*) => {
if $crate::log_level() >= $crate::LogLevel::Info {
eprintln!(concat!("[", $action, "] {}"), format!($($arg)*));
}
};
}
#[macro_export]
macro_rules! errorf {
($action:expr, $($arg:tt)*) => {
eprintln!(concat!("[", $action, "] {}"), format!($($arg)*));
};
}
#[macro_export]
macro_rules! debugf {
($action:expr, $($arg:tt)*) => {
if $crate::log_level() >= $crate::LogLevel::Debug {
eprintln!(concat!("[", $action, "] {}"), format!($($arg)*));
}
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_log_level_parsing() {
assert_eq!(LogLevel::from_str("error"), LogLevel::Error);
assert_eq!(LogLevel::from_str("info"), LogLevel::Info);
assert_eq!(LogLevel::from_str("debug"), LogLevel::Debug);
assert_eq!(LogLevel::from_str("INFO"), LogLevel::Info);
assert_eq!(LogLevel::from_str("unknown"), LogLevel::Info);
}
#[test]
fn test_log_level_ordering() {
assert!(LogLevel::Error < LogLevel::Info);
assert!(LogLevel::Info < LogLevel::Debug);
}
}