From 5b3dabf090029401859150e80db1531132aa87cf Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Sat, 17 Feb 2024 18:03:35 +0100 Subject: [PATCH] Fix logfiles growing indefinitely (fixes #750, #689, #1000) --- CHANGELOG.md | 3 ++- crates/eww/src/paths.rs | 24 ++++++++++++++------- crates/eww/src/server.rs | 46 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de2c30cac..a584870b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,8 @@ All notable changes to eww will be listed here, starting at changes since versio - Add `eww shell-completions` command, generating completion scripts for different shells ### Fixes -- Fixed wrong values in `EWW_NET` +- Fix wrong values in `EWW_NET` +- Fix logfiles growing indefinitely ## [0.4.0] (04.09.2022) diff --git a/crates/eww/src/paths.rs b/crates/eww/src/paths.rs index 498bd8e52..9ad437d98 100644 --- a/crates/eww/src/paths.rs +++ b/crates/eww/src/paths.rs @@ -10,6 +10,7 @@ use anyhow::{bail, Result}; #[derive(Debug, Clone)] pub struct EwwPaths { pub log_file: PathBuf, + pub log_dir: PathBuf, pub ipc_socket_file: PathBuf, pub config_dir: PathBuf, } @@ -43,14 +44,17 @@ impl EwwPaths { log::warn!("The IPC socket file's absolute path exceeds 100 bytes, the socket may fail to create."); } - Ok(EwwPaths { - config_dir, - log_file: std::env::var("XDG_CACHE_HOME") - .map(PathBuf::from) - .unwrap_or_else(|_| PathBuf::from(std::env::var("HOME").unwrap()).join(".cache")) - .join(format!("eww_{}.log", daemon_id)), - ipc_socket_file, - }) + let log_dir = std::env::var("XDG_CACHE_HOME") + .map(PathBuf::from) + .unwrap_or_else(|_| PathBuf::from(std::env::var("HOME").unwrap()).join(".cache")) + .join("eww"); + + if !log_dir.exists() { + log::info!("Creating log dir"); + std::fs::create_dir_all(&log_dir)?; + } + + Ok(EwwPaths { config_dir, log_file: log_dir.join(format!("eww_{}.log", daemon_id)), log_dir, ipc_socket_file }) } pub fn default() -> Result { @@ -66,6 +70,10 @@ impl EwwPaths { self.log_file.as_path() } + pub fn get_log_dir(&self) -> &Path { + self.log_dir.as_path() + } + pub fn get_ipc_socket_file(&self) -> &Path { self.ipc_socket_file.as_path() } diff --git a/crates/eww/src/server.rs b/crates/eww/src/server.rs index 66cb4f640..be00db3af 100644 --- a/crates/eww/src/server.rs +++ b/crates/eww/src/server.rs @@ -11,6 +11,7 @@ use anyhow::{Context, Result}; use std::{ cell::RefCell, collections::{HashMap, HashSet}, + io::Write, os::unix::io::AsRawFd, path::Path, rc::Rc, @@ -41,6 +42,8 @@ pub fn initialize_server( } }; + cleanup_log_dir(paths.get_log_dir())?; + if should_daemonize { let fork_result = do_detach(paths.get_log_file())?; @@ -263,3 +266,46 @@ fn do_detach(log_file_path: impl AsRef) -> Result { Ok(ForkResult::Child) } + +/// Ensure the log directory never grows larger than 100MB by deleting files older than 7 days, +/// and truncating all other logfiles to 100MB. +fn cleanup_log_dir(log_dir: impl AsRef) -> Result<()> { + // Find all files named "eww_*.log" in the log directory + let log_files = std::fs::read_dir(&log_dir)? + .filter_map(|entry| { + let entry = entry.ok()?; + let path = entry.path(); + if let Some(file_name) = path.file_name() { + if file_name.to_string_lossy().starts_with("eww_") && file_name.to_string_lossy().ends_with(".log") { + Some(path) + } else { + None + } + } else { + None + } + }) + .collect::>(); + + for log_file in log_files { + // if the file is older than a week, delete it + if let Ok(metadata) = log_file.metadata() { + if metadata.modified()?.elapsed()?.as_secs() > 60 * 60 * 24 * 7 { + log::info!("Deleting old log file: {}", log_file.display()); + std::fs::remove_file(&log_file)?; + } else { + // If the file is larger than 200MB, delete the start of it until it's 100MB or less. + let mut file = std::fs::OpenOptions::new().append(true).open(&log_file)?; + let file_size = file.metadata()?.len(); + if file_size > 200_000_000 { + let mut file_content = std::fs::read(&log_file)?; + let bytes_to_remove = file_content.len().saturating_sub(100_000_000); + file_content.drain(0..bytes_to_remove); + file.set_len(0)?; + file.write_all(&file_content)?; + } + } + } + } + Ok(()) +}