// TODO: Add a logger api with logger levels and various outputs pub static TERMINAL_LOGGER: Lazy> = Lazy::new(|| Mutex::new(TermLogger::new())); use { limine::{TerminalRequest, TerminalResponse}, log::{Level, SetLoggerError}, spin::{lazy::Lazy, mutex::Mutex}, }; pub fn init() -> Result<(), SetLoggerError> { log::set_logger(&crate::logger::Logger)?; if cfg!(debug_assertions) { log::set_max_level(log::LevelFilter::Debug); } else { log::set_max_level(log::LevelFilter::Info); } Lazy::force(&TERMINAL_LOGGER); Ok(()) } struct Logger; impl log::Log for Logger { fn enabled(&self, _metadata: &log::Metadata) -> bool { true } fn log(&self, record: &log::Record) { let lvl = record.level(); let lvl_color = match lvl { Level::Error => "160", Level::Warn => "172", Level::Info => "47", Level::Debug => "25", Level::Trace => "103", }; let module = record.module_path().unwrap_or_default(); let line = record.line().unwrap_or_default(); crate::arch::log(format_args!( "\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n", record.args(), )) .expect("write to serial console"); } fn flush(&self) {} } pub struct TermLogger(&'static TerminalResponse); unsafe impl Send for TermLogger {} impl TermLogger { pub fn new() -> Self { static TERM_REQ: TerminalRequest = TerminalRequest::new(0); Self( TERM_REQ .get_response() .get() .expect("failed to get terminal response"), ) } } impl core::fmt::Write for TermLogger { fn write_str(&mut self, s: &str) -> core::fmt::Result { if let (Some(w), ts) = (self.0.write(), self.0.terminals()) { for term in ts { w(term, s); } } Ok(()) } }