gila/src/kernel/log.rs
2025-10-09 13:12:54 -04:00

157 lines
3.9 KiB
Rust

// Copyright (c) 2025 shibedrill
// SPDX-License-Identifier: MIT
use crate::constants::LOG_DEFAULT_LEVEL;
use crate::format;
use crate::memory::alloc::boxed::Box;
use crate::memory::alloc::string::String;
use crate::memory::alloc::vec::Vec;
use lazy_static::lazy_static;
use spin::Mutex;
pub type LogDevice = dyn Fn(&str) + Send + Sync;
pub struct Logger {
pub level: LogLevel,
devices: Vec<Box<LogDevice>>,
}
lazy_static! {
pub static ref LOGGER: Mutex<Logger> = Mutex::new(Logger::new());
}
#[macro_export]
macro_rules! log_info {
($($arg:tt)*) => {
LOGGER.lock().log(LogLevel::Info, &format!($($arg)*), file!(), line!(), column!())
};
}
#[macro_export]
macro_rules! log_trace {
($($arg:tt)*) => {
LOGGER.lock().log(LogLevel::Trace, &format!($($arg)*), file!(), line!(), column!())
};
}
#[macro_export]
macro_rules! log_warning {
($($arg:tt)*) => {
LOGGER.lock().log(LogLevel::Warning, &format!($($arg)*), file!(), line!(), column!())
};
}
#[macro_export]
macro_rules! log_error {
($($arg:tt)*) => {
LOGGER.lock().log(LogLevel::Error, &format!($($arg)*), file!(), line!(), column!())
};
}
#[macro_export]
macro_rules! log_critical {
($($arg:tt)*) => {
LOGGER.lock().log(LogLevel::Critical, &format!($($arg)*), file!(), line!(), column!())
};
}
impl Logger {
pub fn new() -> Self {
Logger {
level: LOG_DEFAULT_LEVEL,
devices: Vec::new(),
}
}
pub fn log(
&mut self,
level: LogLevel,
message: &str,
file: &'static str,
line: u32,
column: u32,
) {
for dev in &self.devices {
let message = format!(
"{} {}:{},{}- {}",
level.normalized_string(),
file,
line,
column,
message
);
dev(&message)
}
}
pub fn add_device(&mut self, device: Box<dyn Fn(&str) + Send + Sync>) {
self.devices.push(device);
}
}
pub struct EnumParseError {}
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub enum LogLevel {
Disabled = 0,
Critical = 1,
Error = 2,
Warning = 3,
Info = 4,
Trace = 5,
}
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 {}),
}
}
}
impl From<LogLevel> for String {
fn from(from: LogLevel) -> String {
match from {
LogLevel::Disabled => "Disabled",
LogLevel::Critical => "CRIT ",
LogLevel::Error => "ERROR",
LogLevel::Warning => "WARN ",
LogLevel::Info => "INFO ",
LogLevel::Trace => "TRACE",
}
.into()
}
}
impl LogLevel {
fn normalized_string(&self) -> &str {
match self {
LogLevel::Critical => "[CRIT ]",
LogLevel::Error => "[ERROR]",
LogLevel::Info => "[INFO ]",
LogLevel::Trace => "[TRACE]",
LogLevel::Warning => "[WARN ]",
LogLevel::Disabled => "[DSBLD]",
}
}
}