110 lines
3.6 KiB
Rust
110 lines
3.6 KiB
Rust
#![allow(static_mut_refs)]
|
|
|
|
use embassy_sync::blocking_mutex::{raw::CriticalSectionRawMutex, Mutex};
|
|
use esp_hal::time::Instant;
|
|
use esp_println::println;
|
|
use log::{LevelFilter, Metadata, Record};
|
|
|
|
// Provides a threadsafe serial logger
|
|
pub struct RenderbugLogger {
|
|
lock: Mutex<CriticalSectionRawMutex, ()>,
|
|
current_level: LevelFilter,
|
|
default_level: LevelFilter
|
|
}
|
|
|
|
impl Default for RenderbugLogger {
|
|
fn default() -> Self {
|
|
Self {
|
|
lock: Mutex::new(()),
|
|
current_level: LevelFilter::Info,
|
|
default_level: LevelFilter::Info
|
|
}
|
|
}
|
|
}
|
|
|
|
static mut LOGGER: Option<RenderbugLogger> = None;
|
|
|
|
impl RenderbugLogger {
|
|
pub fn init_logger() {
|
|
#[cfg(feature = "rtt")]
|
|
rtt_target::rtt_init_print!(rtt_target::ChannelMode::BlockIfFull);
|
|
|
|
let default_level = match option_env!("LOG_LEVEL").unwrap_or("info").to_lowercase().as_str() {
|
|
"debug" => LevelFilter::Debug,
|
|
"warn" => LevelFilter::Warn,
|
|
"trace" => LevelFilter::Trace,
|
|
"error" => LevelFilter::Error,
|
|
_ => LevelFilter::Info
|
|
};
|
|
|
|
unsafe { LOGGER.replace(RenderbugLogger { default_level, current_level: default_level, ..Default::default() }) };
|
|
let logger = unsafe { LOGGER.as_mut().unwrap() };
|
|
unsafe {
|
|
critical_section::with(|_| {
|
|
log::set_logger_racy(logger).ok();
|
|
log::set_max_level_racy(default_level);
|
|
});
|
|
};
|
|
}
|
|
|
|
pub fn set_level(level: LevelFilter) {
|
|
unsafe {
|
|
critical_section::with(|_| {
|
|
log::set_max_level_racy(level);
|
|
LOGGER.as_mut().unwrap().current_level = level;
|
|
})
|
|
}
|
|
}
|
|
|
|
pub fn reset_level() {
|
|
unsafe {
|
|
critical_section::with(|_| {
|
|
let logger = LOGGER.as_mut().unwrap();
|
|
log::set_max_level_racy(logger.default_level);
|
|
logger.current_level = logger.default_level;
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
impl log::Log for RenderbugLogger {
|
|
fn enabled(&self, metadata: &Metadata) -> bool {
|
|
metadata.level() >= self.default_level
|
|
}
|
|
|
|
fn flush(&self) {}
|
|
|
|
fn log(&self, record: &Record) {
|
|
const RESET: &str = "\u{001B}[0m";
|
|
const RED: &str = "\u{001B}[31m";
|
|
const GREEN: &str = "\u{001B}[32m";
|
|
const YELLOW: &str = "\u{001B}[33m";
|
|
const BLUE: &str = "\u{001B}[34m";
|
|
const CYAN: &str = "\u{001B}[35m";
|
|
const GREY: &str = "\u{001B}[38;5;240m";
|
|
|
|
let color = match record.level() {
|
|
log::Level::Error => RED,
|
|
log::Level::Warn => YELLOW,
|
|
log::Level::Info => GREEN,
|
|
log::Level::Debug => BLUE,
|
|
log::Level::Trace => CYAN,
|
|
};
|
|
|
|
let filename = record.file().map_or("???", |f| {f});
|
|
let crate_name = record.module_path_static().unwrap();
|
|
let timestamp = Instant::now().duration_since_epoch().as_micros();
|
|
for enabled in option_env!("LOG_CRATES").unwrap_or("").split(",") {
|
|
if crate_name.starts_with(enabled) {
|
|
self.lock.lock(|_| {
|
|
#[cfg(feature = "rtt")]
|
|
rtt_target::rprintln!("{}{}\t{}{}:{}{}\t{}{}", color, record.level(), GREY, filename, record.line().map_or(0, |f| {f}), RESET, record.args(), RESET);
|
|
|
|
println!("{color}{}\t{GREY}{timestamp}\t{} {filename}:{}{RESET}\t{}{RESET}", record.level(), record.module_path_static().unwrap(), record.line().map_or(0, |f| {f}), record.args());
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|