feat: support auto clean log files

This commit is contained in:
GyDi 2023-11-02 20:12:46 +08:00
parent 7e3a85e9da
commit e0d26203dd
6 changed files with 121 additions and 6 deletions

View File

@ -83,6 +83,10 @@ pub struct IVerge {
/// proxy 页面布局 列数 /// proxy 页面布局 列数
pub proxy_layout_column: Option<i32>, pub proxy_layout_column: Option<i32>,
/// 日志清理
/// 0: 不清理; 1: 7天; 2: 30天; 3: 90天
pub auto_log_clean: Option<i32>,
/// window size and position /// window size and position
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub window_size_position: Option<Vec<f64>>, pub window_size_position: Option<Vec<f64>>,
@ -137,6 +141,7 @@ impl IVerge {
auto_close_connection: Some(true), auto_close_connection: Some(true),
enable_builtin_enhanced: Some(true), enable_builtin_enhanced: Some(true),
enable_clash_fields: Some(true), enable_clash_fields: Some(true),
auto_log_clean: Some(3),
..Self::default() ..Self::default()
} }
} }
@ -183,7 +188,7 @@ impl IVerge {
patch!(enable_builtin_enhanced); patch!(enable_builtin_enhanced);
patch!(proxy_layout_column); patch!(proxy_layout_column);
patch!(enable_clash_fields); patch!(enable_clash_fields);
patch!(auto_log_clean);
patch!(window_size_position); patch!(window_size_position);
} }

View File

@ -1,13 +1,14 @@
use crate::config::*; use crate::config::*;
use crate::utils::{dirs, help}; use crate::utils::{dirs, help};
use anyhow::Result; use anyhow::Result;
use chrono::Local; use chrono::{DateTime, Local};
use log::LevelFilter; use log::LevelFilter;
use log4rs::append::console::ConsoleAppender; use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender; use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Logger, Root}; use log4rs::config::{Appender, Logger, Root};
use log4rs::encode::pattern::PatternEncoder; use log4rs::encode::pattern::PatternEncoder;
use std::fs; use std::fs::{self, DirEntry};
use std::str::FromStr;
use tauri::PackageInfo; use tauri::PackageInfo;
/// initialize this instance's log file /// initialize this instance's log file
@ -69,6 +70,72 @@ fn init_log() -> Result<()> {
Ok(()) Ok(())
} }
/// 删除log文件
pub fn delete_log() -> Result<()> {
let log_dir = dirs::app_logs_dir()?;
if !log_dir.exists() {
return Ok(());
}
let auto_log_clean = {
let verge = Config::verge();
let verge = verge.data();
verge.auto_log_clean.clone().unwrap_or(0)
};
let day = match auto_log_clean {
1 => 7,
2 => 30,
3 => 90,
_ => return Ok(()),
};
log::debug!(target: "app", "try to delete log files, day: {day}");
// %Y-%m-%d to NaiveDateTime
let parse_time_str = |s: &str| {
let sa: Vec<&str> = s.split('-').collect();
if sa.len() != 4 {
return Err(anyhow::anyhow!("invalid time str"));
}
let year = i32::from_str(sa[0])?;
let month = u32::from_str(sa[1])?;
let day = u32::from_str(sa[2])?;
let time = chrono::NaiveDate::from_ymd_opt(year, month, day)
.ok_or(anyhow::anyhow!("invalid time str"))?
.and_hms_opt(0, 0, 0)
.ok_or(anyhow::anyhow!("invalid time str"))?;
Ok(time)
};
let process_file = |file: DirEntry| -> Result<()> {
let file_name = file.file_name();
let file_name = file_name.to_str().unwrap_or_default();
if file_name.ends_with(".log") {
let now = Local::now();
let created_time = parse_time_str(&file_name[0..file_name.len() - 4])?;
let file_time = DateTime::<Local>::from_local(created_time, now.offset().clone());
let duration = now.signed_duration_since(file_time);
if duration.num_days() > day {
let file_path = file.path();
let _ = fs::remove_file(file_path);
log::info!(target: "app", "delete log file: {file_name}");
}
}
Ok(())
};
for file in fs::read_dir(&log_dir)? {
if let Ok(file) = file {
let _ = process_file(file);
}
}
Ok(())
}
/// Initialize all the config files /// Initialize all the config files
/// before tauri setup /// before tauri setup
pub fn init_config() -> Result<()> { pub fn init_config() -> Result<()> {
@ -78,6 +145,7 @@ pub fn init_config() -> Result<()> {
} }
let _ = init_log(); let _ = init_log();
let _ = delete_log();
crate::log_err!(dirs::app_home_dir().map(|app_dir| { crate::log_err!(dirs::app_home_dir().map(|app_dir| {
if !app_dir.exists() { if !app_dir.exists() {

View File

@ -25,6 +25,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
enableBuiltinEnhanced: true, enableBuiltinEnhanced: true,
proxyLayoutColumn: 6, proxyLayoutColumn: 6,
defaultLatencyTest: "", defaultLatencyTest: "",
autoLogClean: 0,
}); });
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
@ -37,6 +38,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
enableBuiltinEnhanced: verge?.enable_builtin_enhanced ?? true, enableBuiltinEnhanced: verge?.enable_builtin_enhanced ?? true,
proxyLayoutColumn: verge?.proxy_layout_column || 6, proxyLayoutColumn: verge?.proxy_layout_column || 6,
defaultLatencyTest: verge?.default_latency_test || "", defaultLatencyTest: verge?.default_latency_test || "",
autoLogClean: verge?.auto_log_clean || 0,
}); });
}, },
close: () => setOpen(false), close: () => setOpen(false),
@ -51,6 +53,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
enable_builtin_enhanced: values.enableBuiltinEnhanced, enable_builtin_enhanced: values.enableBuiltinEnhanced,
proxy_layout_column: values.proxyLayoutColumn, proxy_layout_column: values.proxyLayoutColumn,
default_latency_test: values.defaultLatencyTest, default_latency_test: values.defaultLatencyTest,
auto_log_clean: values.autoLogClean as any,
}); });
setOpen(false); setOpen(false);
} catch (err: any) { } catch (err: any) {
@ -128,7 +131,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
<ListItemText primary={t("Proxy Layout Column")} /> <ListItemText primary={t("Proxy Layout Column")} />
<Select <Select
size="small" size="small"
sx={{ width: 100, "> div": { py: "7.5px" } }} sx={{ width: 135, "> div": { py: "7.5px" } }}
value={values.proxyLayoutColumn} value={values.proxyLayoutColumn}
onChange={(e) => { onChange={(e) => {
setValues((v) => ({ setValues((v) => ({
@ -148,6 +151,32 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
</Select> </Select>
</ListItem> </ListItem>
<ListItem sx={{ padding: "5px 2px" }}>
<ListItemText primary={t("Auto Log Clean")} />
<Select
size="small"
sx={{ width: 135, "> div": { py: "7.5px" } }}
value={values.autoLogClean}
onChange={(e) => {
setValues((v) => ({
...v,
autoLogClean: e.target.value as number,
}));
}}
>
{[
{ key: "Never Clean", value: 0 },
{ key: "Retain 7 Days", value: 1 },
{ key: "Retain 30 Days", value: 2 },
{ key: "Retain 90 Days", value: 3 },
].map((i) => (
<MenuItem key={i.value} value={i.value}>
{t(i.key)}
</MenuItem>
))}
</Select>
</ListItem>
<ListItem sx={{ padding: "5px 2px" }}> <ListItem sx={{ padding: "5px 2px" }}>
<ListItemText primary={t("Default Latency Test")} /> <ListItemText primary={t("Default Latency Test")} />
<TextField <TextField

View File

@ -125,5 +125,11 @@
"Enable Clash Fields Filter": "Enable Clash Fields Filter", "Enable Clash Fields Filter": "Enable Clash Fields Filter",
"Enable Builtin Enhanced": "Enable Builtin Enhanced", "Enable Builtin Enhanced": "Enable Builtin Enhanced",
"Proxy Layout Column": "Proxy Layout Column", "Proxy Layout Column": "Proxy Layout Column",
"Default Latency Test": "Default Latency Test" "Default Latency Test": "Default Latency Test",
"Auto Log Clean": "Auto Log Clean",
"Never Clean": "Never Clean",
"Retain 7 Days": "Retain 7 Days",
"Retain 30 Days": "Retain 30 Days",
"Retain 90 Days": "Retain 90 Days"
} }

View File

@ -125,5 +125,11 @@
"Enable Clash Fields Filter": "开启Clash字段过滤", "Enable Clash Fields Filter": "开启Clash字段过滤",
"Enable Builtin Enhanced": "开启内建增强功能", "Enable Builtin Enhanced": "开启内建增强功能",
"Proxy Layout Column": "代理页布局列数", "Proxy Layout Column": "代理页布局列数",
"Default Latency Test": "默认测试链接" "Default Latency Test": "默认测试链接",
"Auto Log Clean": "自动清理日志",
"Never Clean": "不清理",
"Retain 7 Days": "保留7天",
"Retain 30 Days": "保留30天",
"Retain 90 Days": "保留90天"
} }

View File

@ -186,6 +186,7 @@ interface IVergeConfig {
default_latency_test?: string; default_latency_test?: string;
enable_clash_fields?: boolean; enable_clash_fields?: boolean;
enable_builtin_enhanced?: boolean; enable_builtin_enhanced?: boolean;
auto_log_clean?: 0 | 1 | 2 | 3;
proxy_layout_column?: number; proxy_layout_column?: number;
} }