#![doc = include_str!("../README.md")]
mod ui;
use std::collections::HashMap;
use std::sync::LazyLock;
use std::sync::Mutex;
pub use ui::logger_ui;
pub use ui::LoggerUi;
use log::SetLoggerError;
const LEVELS: [log::Level; log::Level::Trace as usize] = [
log::Level::Error,
log::Level::Warn,
log::Level::Info,
log::Level::Debug,
log::Level::Trace,
];
pub struct EguiLogger {
max_level: log::LevelFilter,
show_all_categories: bool,
}
impl EguiLogger {
fn new(max_level: log::LevelFilter, show_all_categories: bool) -> Self {
Self {
max_level,
show_all_categories,
}
}
}
pub struct Builder {
max_level: log::LevelFilter,
show_all_categories: bool,
}
impl Default for Builder {
fn default() -> Self {
Self {
max_level: log::LevelFilter::Debug,
show_all_categories: true,
}
}
}
impl Builder {
pub fn build(self) -> EguiLogger {
EguiLogger::new(self.max_level, self.show_all_categories)
}
pub fn max_level(mut self, max_level: log::LevelFilter) -> Self {
self.max_level = max_level;
self
}
pub fn show_all_categories(mut self, show_all_categories: bool) -> Self {
self.show_all_categories = show_all_categories;
self
}
pub fn init(self) -> Result<(), SetLoggerError> {
log::set_max_level(self.max_level);
log::set_logger(Box::leak(Box::new(self.build())))
}
}
impl log::Log for EguiLogger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
metadata.level() <= self.max_level
}
fn log(&self, record: &log::Record) {
if self.enabled(record.metadata()) {
if let Ok(ref mut logger) = LOGGER.lock() {
logger.logs.push(Record {
level: record.level(),
message: record.args().to_string(),
target: record.target().to_string(),
time: chrono::Local::now(),
});
if !logger.categories.contains_key(record.target()) {
logger
.categories
.insert(record.target().to_string(), self.show_all_categories);
logger.max_category_length =
logger.max_category_length.max(record.target().len());
}
}
}
}
fn flush(&self) {}
}
struct Record {
level: log::Level,
message: String,
target: String,
time: chrono::DateTime<chrono::Local>,
}
struct Logger {
logs: Vec<Record>,
categories: HashMap<String, bool>,
max_category_length: usize,
start_time: chrono::DateTime<chrono::Local>,
}
static LOGGER: LazyLock<Mutex<Logger>> = LazyLock::new(|| {
Mutex::new(Logger {
logs: Vec::new(),
categories: HashMap::new(),
max_category_length: 0,
start_time: chrono::Local::now(),
})
});
pub fn clear_logs() {
LOGGER
.lock()
.expect("could not get access to logger")
.logs
.clear();
}
pub fn builder() -> Builder {
Builder::default()
}