Skip to content

Commit

Permalink
Merge pull request #22 from SARDONYX-sard/feature/implement-rotatatio…
Browse files Browse the repository at this point in the history
…n-gui-logger

feat(tauri): implement rotation gui logger
  • Loading branch information
SARDONYX-sard authored Nov 3, 2023
2 parents ce46a28 + 8ccbc8f commit bc43eb2
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 2 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cspell.jsonc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"words": [
"appender",
"chrono",
"Couprie",
"ebnf",
"fullscreen",
Expand Down
3 changes: 3 additions & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ tauri-build = { version = "1.4.0", features = [] }
[dependencies]
async-trait = "0.1.74"
anyhow = { version = "1.0.75", features = ["backtrace"] }
chrono = "0.4.31"
dar2oar_core = { path = "../dar2oar_core" }
once_cell = "1.18.0"
serde = { version = "1.0", features = ["derive"] } # Implement (De)Serializer
Expand All @@ -34,6 +35,8 @@ tracing-subscriber = "0.3.17"

[dev-dependencies]
pretty_assertions = "1.4.0"
temp-dir = "0.1.11"
tracing-appender = "0.2.2"

[features]
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
Expand Down
98 changes: 96 additions & 2 deletions src-tauri/src/logging.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use anyhow::{bail, Context as _, Result};
use chrono::Local;
use once_cell::sync::OnceCell;
use std::fs::{self, File};
use std::path::Path;
use std::str::FromStr;
use tracing::debug;
use tracing_subscriber::{
filter::{self, LevelFilter},
fmt,
Expand All @@ -14,11 +18,11 @@ pub static INSTANCE: OnceCell<Handle<LevelFilter, Registry>> = OnceCell::new();
pub(crate) fn init_logger(app: &tauri::App) -> Result<Handle<LevelFilter, Registry>> {
let resolver = app.path_resolver();
let log_dir = &resolver.app_log_dir().context("Not found log dir")?;
let log_name = log_dir.join(format!("{}.log", app.package_info().name));
let log_name = format!("{}.log", app.package_info().name);

let fmt_layer = fmt::layer()
.with_ansi(false)
.with_writer(std::fs::File::create(log_dir.join(&log_name))?);
.with_writer(create_log(log_dir, &log_name, 4)?);

let (filter, reload_handle) = reload::Layer::new(filter::LevelFilter::ERROR);
tracing_subscriber::registry()
Expand All @@ -40,3 +44,93 @@ pub(crate) fn change_log_level(log_level: &str) -> Result<()> {
None => bail!("Uninitialized logger."),
}
}

/// Rotation Logger File Creator.
/// - When the maximum count is reached, delete the descending ones first and create a new log file.
fn create_log(log_dir: impl AsRef<Path>, log_name: &str, max_files: usize) -> Result<File> {
fs::create_dir_all(&log_dir)?;

let mut log_files = fs::read_dir(&log_dir)?
.filter_map(|entry| entry.ok())
.filter(|entry| {
entry
.file_name()
.to_str()
.map(|name| name.starts_with(log_name))
.unwrap_or(false)
})
.collect::<Vec<_>>();

debug!("existed log files: {:?}", &log_files);
let log_file = log_dir.as_ref().join(log_name);
if log_files.len() > max_files {
log_files.sort_by(|a, b| {
// NOTE: Error in OS that can't be modified, but not considered here.
a.metadata()
.unwrap()
.modified()
.unwrap()
.cmp(&b.metadata().unwrap().modified().unwrap())
});
if let Some(oldest_file) = log_files.first() {
debug!("Remove old log {:?}", &oldest_file);
fs::remove_file(oldest_file.path())?;
}
} else {
let old_file = log_dir.as_ref().join(format!(
"{}_{}.log",
log_name,
Local::now().format("%F__%H_%M_%S")
));

if log_file.exists() {
debug!("From log_file: {:?}", &log_file);
debug!("To old_file: {:?}", &old_file);
fs::rename(&log_file, old_file)?;
}
};
let f = File::create(log_file)?;
Ok(f)
}

#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;

macro_rules! logger_init {
() => {
let (non_blocking, _guard) = tracing_appender::non_blocking(std::io::stdout());
tracing_subscriber::fmt()
.with_writer(non_blocking)
.with_ansi(false)
.with_max_level(tracing::Level::DEBUG)
.init();
};
}

#[test]
fn test() -> Result<()> {
logger_init!();
let log_dir = temp_dir::TempDir::new()?;
let log_dir = log_dir.path();
for _ in 0..5 {
create_log(log_dir, "g_dar2oar.log", 3)?;
std::thread::sleep(std::time::Duration::from_secs(1));
}

fn get_files_in_dir(dir_path: impl AsRef<Path>) -> Result<Vec<fs::DirEntry>> {
let dir = fs::read_dir(dir_path)?;
let files = dir
.filter_map(|entry| entry.ok())
.filter(|entry| entry.file_type().map(|ft| ft.is_file()).unwrap_or(false))
.collect::<Vec<fs::DirEntry>>();
Ok(files)
}

let files = get_files_in_dir(log_dir)?;
debug!("{:?}", &files);
assert_eq!(files.len(), 3);
Ok(())
}
}

0 comments on commit bc43eb2

Please sign in to comment.