Files
RedBear-OS/drivers/common/src/logger.rs
T

109 lines
3.3 KiB
Rust

use std::str::FromStr;
use libredox::{flag, Fd};
use redox_log::{OutputBuilder, RedoxLogger};
/// Get the log verbosity for the output level.
pub fn output_level() -> log::LevelFilter {
log::LevelFilter::Info
}
/// Get the log verbosity for the file level.
pub fn file_level() -> log::LevelFilter {
log::LevelFilter::Info
}
/// Configures logging for a single driver.
#[cfg_attr(not(target_os = "redox"), allow(unused_variables, unused_mut))]
pub fn setup_logging(
category: &str,
subcategory: &str,
logfile_base: &str,
mut output_level: log::LevelFilter,
file_level: log::LevelFilter,
) {
RedoxLogger::init_timezone();
if let Some(log_level) = read_bootloader_log_level_env(category, subcategory) {
output_level = log_level;
}
let mut logger = RedoxLogger::new().with_output(
OutputBuilder::stderr()
.with_filter(output_level) // limit global output to important info
.with_ansi_escape_codes()
.flush_on_newline(true)
.build(),
);
#[cfg(target_os = "redox")]
match OutputBuilder::in_redox_logging_scheme(
category,
subcategory,
format!("{logfile_base}.log"),
) {
Ok(b) => {
logger = logger.with_output(b.with_filter(file_level).flush_on_newline(true).build())
}
Err(error) => eprintln!("Failed to create {logfile_base}.log: {}", error),
}
#[cfg(target_os = "redox")]
match OutputBuilder::in_redox_logging_scheme(
category,
subcategory,
format!("{logfile_base}.ansi.log"),
) {
Ok(b) => {
logger = logger.with_output(
b.with_filter(file_level)
.with_ansi_escape_codes()
.flush_on_newline(true)
.build(),
)
}
Err(error) => eprintln!("Failed to create {logfile_base}.ansi.log: {}", error),
}
logger.enable().expect("failed to set default logger");
}
fn read_bootloader_log_level_env(category: &str, subcategory: &str) -> Option<log::LevelFilter> {
let mut env_bytes = [0_u8; 4096];
// TODO: Have the kernel env can specify prefixed env key instead of having to read all of them
let envs = {
let Ok(fd) = Fd::open("/scheme/sys/env", flag::O_RDONLY | flag::O_CLOEXEC, 0) else {
return None;
};
let Ok(bytes_read) = fd.read(&mut env_bytes) else {
return None;
};
if bytes_read >= env_bytes.len() {
return None;
}
let env_bytes = &mut env_bytes[..bytes_read];
env_bytes
.split(|&c| c == b'\n')
.filter(|var| var.starts_with(b"DRIVER_"))
.collect::<Vec<_>>()
};
let log_env_keys = [
format!("DRIVER_{}_LOG_LEVEL=", subcategory.to_ascii_uppercase()),
format!("DRIVER_{}_LOG_LEVEL=", category.to_ascii_uppercase()),
"DRIVER_LOG_LEVEL=".to_string(),
];
for log_env_key in log_env_keys {
let log_env_key = log_env_key.as_bytes();
if let Some(log_env) = envs.iter().find_map(|var| var.strip_prefix(log_env_key)) {
if let Ok(Ok(log_level)) = str::from_utf8(&log_env).map(log::LevelFilter::from_str) {
return Some(log_level);
}
}
}
None
}