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 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) { 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 { 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 { 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 {}), } } }