From 2d55fc27c1df4ffe340f77f25bf30fff465656c6 Mon Sep 17 00:00:00 2001 From: Istvan Zolyomi Date: Mon, 17 Mar 2025 08:18:25 +0100 Subject: [PATCH 1/4] Fix log level filtering in multilog environments --- Cargo.toml | 2 +- src/lib.rs | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a0e1fc5..f90534b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "egui_logger" -version = "0.6.3" +version = "0.7.0" edition = "2021" authors = ["Jacob "] license = "MIT" diff --git a/src/lib.rs b/src/lib.rs index 8697f8e..9fdfafd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,15 @@ const LEVELS: [log::Level; log::Level::Trace as usize] = [ /// The logger for egui /// You might want to use [`builder()`] instead. /// To get a builder with default values. -pub struct EguiLogger; +pub struct EguiLogger { + max_level: log::LevelFilter, +} + +impl EguiLogger { + fn new(max_level: log::LevelFilter) -> Self { + Self { max_level } + } +} /// The builder for the logger. /// You can use [`builder()`] to get an instance of this. @@ -42,7 +50,7 @@ impl Builder { /// Useful if you want to add it to a multi-logger. /// See [here](https://github.com/RegenJacob/egui_logger/blob/main/examples/multi_log.rs) for an example. pub fn build(self) -> EguiLogger { - EguiLogger + EguiLogger::new(self.max_level) } /// Sets the max level for the logger @@ -59,13 +67,14 @@ impl Builder { /// /// The max level is the [max_level](Self::max_level) field. pub fn init(self) -> Result<(), SetLoggerError> { - log::set_logger(&EguiLogger).map(|()| log::set_max_level(self.max_level)) + log::set_max_level(self.max_level); + log::set_boxed_logger(Box::new(self.build())) } } impl log::Log for EguiLogger { fn enabled(&self, metadata: &log::Metadata) -> bool { - metadata.level() <= log::STATIC_MAX_LEVEL + metadata.level() <= self.max_level } fn log(&self, record: &log::Record) { From 83b065d03b5d32354cef10c1eb96756393ca3fc4 Mon Sep 17 00:00:00 2001 From: Istvan Zolyomi Date: Mon, 24 Mar 2025 09:00:30 +0100 Subject: [PATCH 2/4] Data structure optimization --- Cargo.toml | 1 - src/lib.rs | 8 ++++---- src/ui.rs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f90534b..dbb8b4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,6 @@ include = ["src/*.rs", "Cargo.toml", "LICENSE"] log = "0.4" egui = "0.31" regex = "1.11" -hashbrown = "0.15" [dev-dependencies] eframe = "0.31" diff --git a/src/lib.rs b/src/lib.rs index 9fdfafd..e9c1bdf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,10 @@ #![doc = include_str!("../README.md")] mod ui; +use std::collections::{HashMap, VecDeque}; use std::sync::LazyLock; use std::sync::Mutex; -use hashbrown::HashMap; pub use ui::logger_ui; pub use ui::LoggerUi; @@ -80,7 +80,7 @@ impl log::Log for EguiLogger { fn log(&self, record: &log::Record) { if self.enabled(record.metadata()) { if let Ok(ref mut logger) = LOGGER.lock() { - logger.logs.push(Record { + logger.logs.push_back(Record { level: record.level(), message: record.args().to_string(), target: record.target().to_string(), @@ -132,14 +132,14 @@ struct Record { } struct Logger { - logs: Vec, + logs: VecDeque, categories: HashMap, max_category_length: usize, start_time: chrono::DateTime, } static LOGGER: LazyLock> = LazyLock::new(|| { Mutex::new(Logger { - logs: Vec::new(), + logs: VecDeque::new(), categories: HashMap::new(), max_category_length: 0, start_time: chrono::Local::now(), diff --git a/src/ui.rs b/src/ui.rs index 0a49b21..e858b90 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -246,7 +246,7 @@ impl LoggerUi { let mut logs_displayed: usize = 0; - let time_padding = logger.logs.last().map_or(0, |record| { + let time_padding = logger.logs.back().map_or(0, |record| { format_time(record.time, &self.style, logger.start_time).len() }); From cccfbd2de9498f13e2da5433015adc6446580ae7 Mon Sep 17 00:00:00 2001 From: Istvan Zolyomi Date: Mon, 31 Mar 2025 17:57:17 +0200 Subject: [PATCH 3/4] Guard init() with cfg annotations. Delay using VecDeque. Follow linter suggestions. --- Cargo.toml | 4 ++++ src/lib.rs | 13 ++++++++----- src/ui.rs | 6 +++--- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dbb8b4c..347baa3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,10 @@ log = "0.4" egui = "0.31" regex = "1.11" +[features] +default = ["std"] +std = ["log/std"] + [dev-dependencies] eframe = "0.31" multi_log = "0.1" diff --git a/src/lib.rs b/src/lib.rs index e9c1bdf..ef7ae1d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![doc = include_str!("../README.md")] mod ui; -use std::collections::{HashMap, VecDeque}; +use std::collections::HashMap; use std::sync::LazyLock; use std::sync::Mutex; @@ -54,7 +54,7 @@ impl Builder { } /// Sets the max level for the logger - /// this only has an effect when calling [`init()`]. + /// this only has an effect when calling [init](Self::init). /// /// Defaults to [Debug](`log::LevelFilter::Debug`). pub fn max_level(mut self, max_level: log::LevelFilter) -> Self { @@ -66,6 +66,7 @@ impl Builder { /// This should be called very early in the program. /// /// The max level is the [max_level](Self::max_level) field. + #[cfg(all(feature = "std", target_has_atomic = "ptr"))] pub fn init(self) -> Result<(), SetLoggerError> { log::set_max_level(self.max_level); log::set_boxed_logger(Box::new(self.build())) @@ -80,7 +81,7 @@ impl log::Log for EguiLogger { fn log(&self, record: &log::Record) { if self.enabled(record.metadata()) { if let Ok(ref mut logger) = LOGGER.lock() { - logger.logs.push_back(Record { + logger.logs.push(Record { level: record.level(), message: record.args().to_string(), target: record.target().to_string(), @@ -108,6 +109,7 @@ impl log::Log for EguiLogger { since = "0.5.0", note = "Please use `egui_logger::builder().init()` instead" )] +#[cfg(all(feature = "std", target_has_atomic = "ptr"))] pub fn init() -> Result<(), SetLoggerError> { builder().init() } @@ -120,6 +122,7 @@ pub fn init() -> Result<(), SetLoggerError> { since = "0.5.0", note = "Please use `egui_logger::builder().max_level(max_level).init()` instead" )] +#[cfg(all(feature = "std", target_has_atomic = "ptr"))] pub fn init_with_max_level(max_level: log::LevelFilter) -> Result<(), SetLoggerError> { builder().max_level(max_level).init() } @@ -132,14 +135,14 @@ struct Record { } struct Logger { - logs: VecDeque, + logs: Vec, categories: HashMap, max_category_length: usize, start_time: chrono::DateTime, } static LOGGER: LazyLock> = LazyLock::new(|| { Mutex::new(Logger { - logs: VecDeque::new(), + logs: Vec::new(), categories: HashMap::new(), max_category_length: 0, start_time: chrono::Local::now(), diff --git a/src/ui.rs b/src/ui.rs index e858b90..21f4861 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -246,7 +246,7 @@ impl LoggerUi { let mut logs_displayed: usize = 0; - let time_padding = logger.logs.back().map_or(0, |record| { + let time_padding = logger.logs.last().map_or(0, |record| { format_time(record.time, &self.style, logger.start_time).len() }); @@ -267,7 +267,7 @@ impl LoggerUi { // Filter out log levels that are disabled via regex or log level if (!self.search_term.is_empty() && !self.match_string(&raw_text)) - || !(self.loglevels[record.level as usize - 1]) + || !self.loglevels[record.level as usize - 1] { return; } @@ -300,7 +300,7 @@ impl LoggerUi { ui.horizontal(|ui| { ui.label(format!("Log size: {}", logger.logs.len())); ui.label(format!("Displayed: {}", logs_displayed)); - ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { + ui.with_layout(egui::Layout::right_to_left(Align::Center), |ui| { if ui.button("Copy").clicked() { let mut out_string = String::new(); logger From 718932bd67ce2b33b5f420d8580e32876234d6a5 Mon Sep 17 00:00:00 2001 From: Istvan Zolyomi Date: Mon, 31 Mar 2025 18:19:08 +0200 Subject: [PATCH 4/4] Better logger boxing --- Cargo.toml | 4 ---- src/lib.rs | 5 +---- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 347baa3..dbb8b4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,10 +17,6 @@ log = "0.4" egui = "0.31" regex = "1.11" -[features] -default = ["std"] -std = ["log/std"] - [dev-dependencies] eframe = "0.31" multi_log = "0.1" diff --git a/src/lib.rs b/src/lib.rs index ef7ae1d..44c0391 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,10 +66,9 @@ impl Builder { /// This should be called very early in the program. /// /// The max level is the [max_level](Self::max_level) field. - #[cfg(all(feature = "std", target_has_atomic = "ptr"))] pub fn init(self) -> Result<(), SetLoggerError> { log::set_max_level(self.max_level); - log::set_boxed_logger(Box::new(self.build())) + log::set_logger(Box::leak(Box::new(self.build()))) } } @@ -109,7 +108,6 @@ impl log::Log for EguiLogger { since = "0.5.0", note = "Please use `egui_logger::builder().init()` instead" )] -#[cfg(all(feature = "std", target_has_atomic = "ptr"))] pub fn init() -> Result<(), SetLoggerError> { builder().init() } @@ -122,7 +120,6 @@ pub fn init() -> Result<(), SetLoggerError> { since = "0.5.0", note = "Please use `egui_logger::builder().max_level(max_level).init()` instead" )] -#[cfg(all(feature = "std", target_has_atomic = "ptr"))] pub fn init_with_max_level(max_level: log::LevelFilter) -> Result<(), SetLoggerError> { builder().max_level(max_level).init() }