Add debug log window

This commit is contained in:
Elias Projahn 2023-01-15 13:21:50 +01:00
parent 8b45ec4940
commit 7eb85f094f
8 changed files with 111 additions and 8 deletions

View file

@ -4,6 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
chrono = "0.4"
fragile = "2"
gio = "0.16"
glib = "0.16"

View file

@ -5,6 +5,7 @@ use std::{
cell::{Cell, RefCell},
path::PathBuf,
rc::Rc,
sync::Arc,
};
use tokio::sync::{broadcast, broadcast::Sender};
@ -18,6 +19,7 @@ pub mod library;
pub use library::*;
mod logger;
pub use logger::{LogMessage, Logger};
pub mod player;
pub use player::*;
@ -40,6 +42,9 @@ pub enum BackendState {
/// A collection of all backend state and functionality.
pub struct Backend {
/// Registered instance of [Logger].
logger: Arc<Logger>,
/// A closure that will be called whenever the backend state changes.
state_cb: RefCell<Option<Box<dyn Fn(BackendState)>>>,
@ -72,11 +77,11 @@ impl Backend {
/// and call init() afterwards. There may be only one backend for a process and this method
/// may only be called exactly once. Otherwise it will panic.
pub fn new() -> Self {
logger::register();
let logger = logger::register();
let (library_updated_sender, _) = broadcast::channel(1024);
Backend {
logger,
state_cb: RefCell::new(None),
settings: gio::Settings::new("de.johrpan.musicus"),
music_library_path: RefCell::new(None),
@ -88,6 +93,11 @@ impl Backend {
}
}
/// Get the registered instance of [Logger].
pub fn logger(&self) -> Arc<Logger> {
Arc::clone(&self.logger)
}
/// Set the closure to be called whenever the backend state changes.
pub fn set_state_cb<F: Fn(BackendState) + 'static>(&self, cb: F) {
self.state_cb.replace(Some(Box::new(cb)));

View file

@ -1,20 +1,31 @@
use chrono::{Local, DateTime};
use log::{Level, LevelFilter, Log, Metadata, Record};
use std::{fmt::Display, sync::Mutex};
use std::{fmt::Display, sync::{Arc, Mutex}};
/// Register the custom logger. This will panic if called more than once.
pub fn register() {
log::set_boxed_logger(Box::new(Logger::default()))
pub fn register() -> Arc<Logger> {
let logger = Arc::new(Logger::default());
log::set_boxed_logger(Box::new(Arc::clone(&logger)))
.map(|()| log::set_max_level(LevelFilter::Info))
.unwrap();
logger
}
/// A simple logging handler that prints out all messages and caches them for
/// later access by the user interface.
struct Logger {
pub struct Logger {
/// All messages since the start of the program.
messages: Mutex<Vec<LogMessage>>,
}
impl Logger {
pub fn messages(&self) -> Vec<LogMessage> {
self.messages.lock().unwrap().clone()
}
}
impl Default for Logger {
fn default() -> Self {
Self {
@ -40,7 +51,9 @@ impl Log for Logger {
}
/// A simplified representation of a [`Record`].
struct LogMessage {
#[derive(Clone)]
pub struct LogMessage {
pub time: DateTime<Local>,
pub level: String,
pub module: String,
pub message: String,
@ -49,6 +62,7 @@ struct LogMessage {
impl<'a> From<&Record<'a>> for LogMessage {
fn from(record: &Record<'a>) -> Self {
Self {
time: Local::now(),
level: record.level().to_string(),
module: String::from(record.module_path().unwrap_or_else(|| record.target())),
message: format!("{}", record.args()),
@ -58,6 +72,6 @@ impl<'a> From<&Record<'a>> for LogMessage {
impl Display for LogMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} ({}): {}", self.module, self.level, self.message)
write!(f, "{} {} ({}): {}", self.time, self.module, self.level, self.message)
}
}