use core::fmt::Write; use crate::memory::alloc; use alloc::boxed::*; use alloc::string::*; use alloc::vec::*; use spin::Mutex; /// The logger exists for the entire lifetime of the kernel. pub static LOGGER: Mutex = Mutex::new(Logger::new()); pub struct EnumParseError {} pub struct Logger { pub level: LogLevel, pub subscriber: Vec>>, } pub trait LogSubscriber { fn write(&self, msg: &str); } impl Default for Logger { fn default() -> Self { Self::new() } } impl Logger { pub const fn new() -> Self { Logger { level: LogLevel::Warning, subscriber: Vec::new(), } } /// Calling log will sequentially acquire lock on all logging subscribers /// to write to them with a formatted log message. pub fn log(&self, level: LogLevel, msg: &str) { // Nobody is EVER allowed to call log with the Disabled log level. It is a placeholder. if level == LogLevel::Disabled { // Nothing } else if level > self.level { for sub in &self.subscriber { let mut message = String::new(); write!(&mut message, "{:?}: {}", level, msg).unwrap(); sub.lock().write(&message); } } } } #[derive(PartialEq, Eq, PartialOrd, Ord, Debug)] pub enum LogLevel { Disabled, Critical, Error, Warning, Info, Trace, } impl TryFrom for LogLevel { type Error = EnumParseError; fn try_from(from: u8) -> Result>::Error> { match from { 0 => Ok(Self::Disabled), 1 => Ok(Self::Critical), 2 => Ok(Self::Error), 3 => Ok(Self::Warning), 4 => Ok(Self::Info), 5 => Ok(Self::Trace), _ => Err(EnumParseError {}), } } } impl TryFrom<&str> for LogLevel { type Error = EnumParseError; fn try_from(from: &str) -> Result>::Error> { match from.to_ascii_lowercase().as_ref() { "disabled" => Ok(Self::Disabled), "critical" => Ok(Self::Critical), "error" => Ok(Self::Error), "warning" => Ok(Self::Warning), "info" => Ok(Self::Info), "trace" => Ok(Self::Trace), _ => Err(EnumParseError {}), } } }