use log::LevelFilter;
use simplelog::*;
use std::fs::File;
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct LogConfig {
pub enabled: bool,
pub log_file: PathBuf,
pub clear_on_startup: bool,
pub features: LogFeatures,
pub level: LevelFilter,
}
#[derive(Debug, Clone)]
pub struct LogFeatures {
pub modal_state: bool,
pub key_events: bool,
pub rendering: bool,
pub api_calls: bool,
pub settings: bool,
pub general: bool,
}
impl Default for LogConfig {
fn default() -> Self {
Self {
enabled: true,
log_file: PathBuf::from("fido_debug.log"),
clear_on_startup: true,
features: LogFeatures::default(),
level: LevelFilter::Debug,
}
}
}
impl Default for LogFeatures {
fn default() -> Self {
Self {
modal_state: true,
key_events: true,
rendering: true,
api_calls: true,
settings: true,
general: true,
}
}
}
impl LogConfig {
pub fn disabled() -> Self {
Self {
enabled: false,
..Default::default()
}
}
pub fn minimal() -> Self {
Self {
enabled: true,
level: LevelFilter::Warn,
features: LogFeatures {
modal_state: false,
key_events: false,
rendering: false,
api_calls: false,
settings: false,
general: false,
},
..Default::default()
}
}
pub fn verbose() -> Self {
Self {
enabled: true,
level: LevelFilter::Trace,
features: LogFeatures {
modal_state: true,
key_events: true,
rendering: true,
api_calls: true,
settings: true,
general: true,
},
..Default::default()
}
}
}
pub fn init_logging(config: &LogConfig) -> anyhow::Result<()> {
if !config.enabled {
let _ = WriteLogger::init(
LevelFilter::Off,
Config::default(),
std::io::sink(),
);
return Ok(());
}
if config.clear_on_startup {
let _ = File::create(&config.log_file)?;
}
let log_file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(&config.log_file)?;
let log_config = ConfigBuilder::new()
.set_time_format_rfc3339()
.set_time_offset_to_local()
.unwrap_or_else(|builder| builder)
.build();
WriteLogger::init(config.level, log_config, log_file)?;
log::info!("Logging initialized: file={}, level={:?}", config.log_file.display(), config.level);
log::debug!("Log features: {:?}", config.features);
Ok(())
}
#[macro_export]
macro_rules! log_modal_state {
($config:expr, $($arg:tt)*) => {
if $config.enabled && $config.features.modal_state {
log::debug!(target: "modal_state", $($arg)*);
}
};
}
#[macro_export]
macro_rules! log_key_event {
($config:expr, $($arg:tt)*) => {
if $config.enabled && $config.features.key_events {
log::debug!(target: "key_events", $($arg)*);
}
};
}
#[macro_export]
macro_rules! log_rendering {
($config:expr, $($arg:tt)*) => {
if $config.enabled && $config.features.rendering {
log::debug!(target: "rendering", $($arg)*);
}
};
}
#[macro_export]
macro_rules! log_api_call {
($config:expr, $($arg:tt)*) => {
if $config.enabled && $config.features.api_calls {
log::debug!(target: "api_calls", $($arg)*);
}
};
}
#[macro_export]
macro_rules! log_settings {
($config:expr, $($arg:tt)*) => {
if $config.enabled && $config.features.settings {
log::debug!(target: "settings", $($arg)*);
}
};
}
#[macro_export]
macro_rules! log_debug {
($config:expr, $($arg:tt)*) => {
if $config.enabled && $config.features.general {
log::debug!(target: "general", $($arg)*);
}
};
}