use log::{Level, LevelFilter};
use std::str::FromStr;
pub fn init_logger(level: &str) -> Result<(), String> {
let level_filter =
LevelFilter::from_str(level).map_err(|e| format!("Invalid log level '{level}': {e}"))?;
env_logger::Builder::from_default_env()
.filter_level(level_filter)
.try_init()
.ok();
Ok(())
}
pub fn log_info(message: &str) -> Result<(), String> {
log::info!("{message}");
Ok(())
}
pub fn log_warn(message: &str) -> Result<(), String> {
log::warn!("{message}");
Ok(())
}
pub fn log_error(message: &str) -> Result<(), String> {
log::error!("{message}");
Ok(())
}
pub fn log_debug(message: &str) -> Result<(), String> {
log::debug!("{message}");
Ok(())
}
pub fn log_trace(message: &str) -> Result<(), String> {
log::trace!("{message}");
Ok(())
}
pub fn get_level() -> Result<String, String> {
let max_level = log::max_level();
Ok(max_level.to_string().to_lowercase())
}
pub fn is_level_enabled(level: &str) -> Result<bool, String> {
let log_level =
Level::from_str(level).map_err(|e| format!("Invalid log level '{level}': {e}"))?;
Ok(log::log_enabled!(log_level))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_init_logger_valid_levels() {
assert!(init_logger("trace").is_ok());
assert!(init_logger("debug").is_ok());
assert!(init_logger("info").is_ok());
assert!(init_logger("warn").is_ok());
assert!(init_logger("error").is_ok());
assert!(init_logger("off").is_ok());
}
#[test]
fn test_init_logger_invalid_level() {
assert!(init_logger("invalid").is_err());
assert!(init_logger("unknown").is_err());
}
#[test]
fn test_init_logger_case_insensitive() {
assert!(init_logger("INFO").is_ok());
assert!(init_logger("Debug").is_ok());
assert!(init_logger("WARN").is_ok());
}
#[test]
fn test_log_info_basic() {
let _ = init_logger("info");
assert!(log_info("Test info message").is_ok());
assert!(log_info("").is_ok()); }
#[test]
fn test_log_warn_basic() {
let _ = init_logger("warn");
assert!(log_warn("Test warning").is_ok());
assert!(log_warn("").is_ok());
}
#[test]
fn test_log_error_basic() {
let _ = init_logger("error");
assert!(log_error("Test error").is_ok());
assert!(log_error("").is_ok());
}
#[test]
fn test_log_debug_basic() {
let _ = init_logger("debug");
assert!(log_debug("Test debug").is_ok());
assert!(log_debug("").is_ok());
}
#[test]
fn test_log_trace_basic() {
let _ = init_logger("trace");
assert!(log_trace("Test trace").is_ok());
assert!(log_trace("").is_ok());
}
#[test]
fn test_get_level() {
let _ = init_logger("info");
let level = get_level().unwrap();
assert!(["trace", "debug", "info", "warn", "error", "off"].contains(&level.as_str()));
}
#[test]
fn test_is_level_enabled_valid() {
let _ = init_logger("info");
assert!(is_level_enabled("info").is_ok());
assert!(is_level_enabled("warn").is_ok());
assert!(is_level_enabled("error").is_ok());
assert!(is_level_enabled("debug").is_ok());
assert!(is_level_enabled("trace").is_ok());
}
#[test]
fn test_is_level_enabled_invalid() {
assert!(is_level_enabled("invalid").is_err());
assert!(is_level_enabled("unknown").is_err());
}
#[test]
fn test_multiple_init_calls() {
assert!(init_logger("info").is_ok());
assert!(init_logger("debug").is_ok());
assert!(init_logger("warn").is_ok());
}
#[test]
fn test_log_all_levels_workflow() {
let _ = init_logger("trace");
assert!(log_trace("Trace message").is_ok());
assert!(log_debug("Debug message").is_ok());
assert!(log_info("Info message").is_ok());
assert!(log_warn("Warn message").is_ok());
assert!(log_error("Error message").is_ok());
}
#[test]
fn test_log_special_characters() {
let _ = init_logger("info");
assert!(log_info("Message with \"quotes\"").is_ok());
assert!(log_info("Message with\nnewlines").is_ok());
assert!(log_info("Message with\ttabs").is_ok());
assert!(log_info("Message with émojis 😀").is_ok());
}
#[test]
fn test_log_long_message() {
let _ = init_logger("info");
let long_msg = "x".repeat(10000);
assert!(log_info(&long_msg).is_ok());
}
#[test]
fn test_level_hierarchy() {
let _ = init_logger("warn");
let level = get_level().unwrap();
assert!(["warn", "error", "off", "info", "debug", "trace"].contains(&level.as_str()));
}
#[test]
fn test_init_logger_with_whitespace() {
assert!(init_logger(" info ").is_err()); assert!(init_logger("info").is_ok()); }
#[test]
fn test_is_level_enabled_case_variations() {
let _ = init_logger("info");
assert!(is_level_enabled("INFO").is_ok());
assert!(is_level_enabled("Info").is_ok());
}
#[test]
fn test_log_info_unicode() {
let _ = init_logger("info");
assert!(log_info("Tëst wîth ünïcödé").is_ok());
assert!(log_info("日本語テスト").is_ok());
assert!(log_info("🚀 Rocket launch").is_ok());
}
#[test]
fn test_log_warn_unicode() {
let _ = init_logger("warn");
assert!(log_warn("警告:このメッセージ").is_ok());
}
#[test]
fn test_log_error_unicode() {
let _ = init_logger("error");
assert!(log_error("Ошибка: русский текст").is_ok());
}
#[test]
fn test_log_debug_unicode() {
let _ = init_logger("debug");
assert!(log_debug("调试:中文消息").is_ok());
}
#[test]
fn test_log_trace_unicode() {
let _ = init_logger("trace");
assert!(log_trace("Traçando: português").is_ok());
}
#[test]
fn test_log_multiline_messages() {
let _ = init_logger("info");
let multiline = "Line 1\nLine 2\nLine 3\n\nLine 5";
assert!(log_info(multiline).is_ok());
}
#[test]
fn test_log_with_format_specifiers() {
let _ = init_logger("info");
assert!(log_info("Test %s %d {name} {{escaped}}").is_ok());
}
#[test]
fn test_get_level_returns_lowercase() {
let _ = init_logger("INFO");
let level = get_level().unwrap();
assert_eq!(level, level.to_lowercase());
}
#[test]
fn test_is_level_enabled_all_levels() {
let _ = init_logger("trace");
assert!(is_level_enabled("trace").is_ok());
assert!(is_level_enabled("debug").is_ok());
assert!(is_level_enabled("info").is_ok());
assert!(is_level_enabled("warn").is_ok());
assert!(is_level_enabled("error").is_ok());
}
}