93 lines
2.4 KiB
Rust
93 lines
2.4 KiB
Rust
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<Logger> = Mutex::new(Logger::new());
|
|
|
|
pub struct EnumParseError {}
|
|
|
|
pub struct Logger {
|
|
pub level: LogLevel,
|
|
pub subscriber: Vec<Mutex<Box<dyn LogSubscriber + Send + Sync>>>,
|
|
}
|
|
|
|
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<u8> for LogLevel {
|
|
type Error = EnumParseError;
|
|
fn try_from(from: u8) -> Result<Self, <crate::log::LogLevel as TryFrom<u8>>::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<Self, <crate::log::LogLevel as TryFrom<u8>>::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 {}),
|
|
}
|
|
}
|
|
}
|