mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 08:45:41 +08:00
refactor: enhance logging system and add new development commands (#4803)
* refactor: enhance logging system and add new development commands * refactor: add cfg-if dependency and improve logging configuration
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(not(feature = "tauri-dev"))] {
|
||||
use crate::utils::logging::{console_colored_format, file_format};
|
||||
use flexi_logger::{Cleanup, Criterion, Duplicate, FileSpec, LogSpecification, Logger};
|
||||
use log::LevelFilter;
|
||||
}
|
||||
}
|
||||
|
||||
use crate::{
|
||||
config::*,
|
||||
core::handle,
|
||||
@@ -7,64 +15,47 @@ use crate::{
|
||||
};
|
||||
use anyhow::Result;
|
||||
use chrono::{Local, TimeZone};
|
||||
use log::LevelFilter;
|
||||
use log4rs::{
|
||||
append::{console::ConsoleAppender, file::FileAppender},
|
||||
config::{Appender, Logger, Root},
|
||||
encode::pattern::PatternEncoder,
|
||||
};
|
||||
use std::{path::PathBuf, str::FromStr};
|
||||
use tauri_plugin_shell::ShellExt;
|
||||
use tokio::fs;
|
||||
use tokio::fs::DirEntry;
|
||||
|
||||
/// initialize this instance's log file
|
||||
async fn init_log() -> Result<()> {
|
||||
let log_dir = dirs::app_logs_dir()?;
|
||||
if !log_dir.exists() {
|
||||
let _ = tokio::fs::create_dir_all(&log_dir).await;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "tauri-dev"))]
|
||||
pub async fn init_logger() -> Result<()> {
|
||||
let log_level = Config::verge().await.latest_ref().get_log_level();
|
||||
if log_level == LevelFilter::Off {
|
||||
return Ok(());
|
||||
return Err(anyhow::anyhow!("logging is disabled"));
|
||||
}
|
||||
|
||||
let local_time = Local::now().format("%Y-%m-%d-%H%M").to_string();
|
||||
let log_file = format!("{local_time}.log");
|
||||
let log_file = log_dir.join(log_file);
|
||||
let log_dir = dirs::app_logs_dir()?;
|
||||
let logger = Logger::with(LogSpecification::from(log_level))
|
||||
.log_to_file(FileSpec::default().directory(log_dir).basename(""))
|
||||
.duplicate_to_stdout(Duplicate::Debug)
|
||||
.format(console_colored_format)
|
||||
.format_for_files(file_format)
|
||||
.rotate(
|
||||
// ? 总是保持单个日志最大 10 MB
|
||||
Criterion::Size(10 * 1024 * 1024),
|
||||
flexi_logger::Naming::TimestampsCustomFormat {
|
||||
current_infix: Some("latest"),
|
||||
format: "%Y-%m-%d_%H-%M-%S",
|
||||
},
|
||||
// TODO 提供前端设置最大保留文件数量
|
||||
Cleanup::Never,
|
||||
);
|
||||
|
||||
let log_pattern = match log_level {
|
||||
LevelFilter::Trace => "{d(%Y-%m-%d %H:%M:%S)} {l} [{M}] - {m}{n}",
|
||||
_ => "{d(%Y-%m-%d %H:%M:%S)} {l} - {m}{n}",
|
||||
};
|
||||
let _handle = logger.start()?;
|
||||
|
||||
let encode = Box::new(PatternEncoder::new(log_pattern));
|
||||
|
||||
let stdout = ConsoleAppender::builder().encoder(encode.clone()).build();
|
||||
let tofile = FileAppender::builder().encoder(encode).build(log_file)?;
|
||||
|
||||
let mut logger_builder = Logger::builder();
|
||||
let mut root_builder = Root::builder();
|
||||
|
||||
let log_more = log_level == LevelFilter::Trace || log_level == LevelFilter::Debug;
|
||||
|
||||
logger_builder = logger_builder.appenders(["file"]);
|
||||
if log_more {
|
||||
root_builder = root_builder.appenders(["file"]);
|
||||
}
|
||||
|
||||
let (config, _) = log4rs::config::Config::builder()
|
||||
.appender(Appender::builder().build("stdout", Box::new(stdout)))
|
||||
.appender(Appender::builder().build("file", Box::new(tofile)))
|
||||
.logger(logger_builder.additive(false).build("app", log_level))
|
||||
.build_lossy(root_builder.build(log_level));
|
||||
|
||||
log4rs::init_config(config)?;
|
||||
// TODO 全局 logger handle 控制
|
||||
// GlobalLoggerProxy::global().set_inner(handle);
|
||||
// TODO 提供前端设置等级,热更新等级
|
||||
// logger.parse_new_spec(spec)
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO flexi_logger 提供了最大保留天数,或许我们应该用内置删除log文件
|
||||
/// 删除log文件
|
||||
pub async fn delete_log() -> Result<()> {
|
||||
let log_dir = dirs::app_logs_dir()?;
|
||||
@@ -355,11 +346,13 @@ async fn initialize_config_files() -> Result<()> {
|
||||
/// Initialize all the config files
|
||||
/// before tauri setup
|
||||
pub async fn init_config() -> Result<()> {
|
||||
let _ = dirs::init_portable_flag();
|
||||
// We do not need init_portable_flag here anymore due to lib.rs will to the things
|
||||
// let _ = dirs::init_portable_flag();
|
||||
|
||||
if let Err(e) = init_log().await {
|
||||
eprintln!("Failed to initialize logging: {}", e);
|
||||
}
|
||||
// We do not need init_log here anymore due to resolve will to the things
|
||||
// if let Err(e) = init_log().await {
|
||||
// eprintln!("Failed to initialize logging: {}", e);
|
||||
// }
|
||||
|
||||
ensure_directories().await?;
|
||||
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
use std::fmt;
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "tauri-dev")] {
|
||||
use std::fmt;
|
||||
} else {
|
||||
#[cfg(feature = "verge-dev")]
|
||||
use nu_ansi_term::Color;
|
||||
use std::{fmt, io::Write, thread};
|
||||
use flexi_logger::DeferredNow;
|
||||
use log::{LevelFilter, Record};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Type {
|
||||
@@ -107,7 +117,8 @@ macro_rules! wrap_err {
|
||||
macro_rules! logging {
|
||||
// 带 println 的版本(支持格式化参数)
|
||||
($level:ident, $type:expr, true, $($arg:tt)*) => {
|
||||
println!("{} {}", $type, format_args!($($arg)*));
|
||||
// We dont need println here anymore
|
||||
// println!("{} {}", $type, format_args!($($arg)*));
|
||||
log::$level!(target: "app", "{} {}", $type, format_args!($($arg)*));
|
||||
};
|
||||
|
||||
@@ -157,3 +168,56 @@ macro_rules! logging_error {
|
||||
logging_error!($type, false, $fmt $(, $arg)*);
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "tauri-dev"))]
|
||||
pub fn get_log_level(log_level: &LevelFilter) -> String {
|
||||
#[cfg(feature = "verge-dev")]
|
||||
match log_level {
|
||||
LevelFilter::Off => Color::Fixed(8).paint("OFF").to_string(),
|
||||
LevelFilter::Error => Color::Red.paint("ERROR").to_string(),
|
||||
LevelFilter::Warn => Color::Yellow.paint("WARN ").to_string(),
|
||||
LevelFilter::Info => Color::Green.paint("INFO ").to_string(),
|
||||
LevelFilter::Debug => Color::Blue.paint("DEBUG").to_string(),
|
||||
LevelFilter::Trace => Color::Purple.paint("TRACE").to_string(),
|
||||
}
|
||||
#[cfg(not(feature = "verge-dev"))]
|
||||
log_level.to_string()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "tauri-dev"))]
|
||||
pub fn console_colored_format(
|
||||
w: &mut dyn Write,
|
||||
now: &mut DeferredNow,
|
||||
record: &log::Record,
|
||||
) -> std::io::Result<()> {
|
||||
let current_thread = thread::current();
|
||||
let thread_name = current_thread.name().unwrap_or("unnamed");
|
||||
|
||||
let level = get_log_level(&record.level().to_level_filter());
|
||||
let line = record.line().unwrap_or(0);
|
||||
write!(
|
||||
w,
|
||||
"[{}] {} [{}:{}] T[{}] {}",
|
||||
now.format("%H:%M:%S%.3f"),
|
||||
level,
|
||||
record.module_path().unwrap_or("<unnamed>"),
|
||||
line,
|
||||
thread_name,
|
||||
record.args(),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "tauri-dev"))]
|
||||
pub fn file_format(
|
||||
w: &mut dyn Write,
|
||||
now: &mut DeferredNow,
|
||||
record: &Record,
|
||||
) -> std::io::Result<()> {
|
||||
write!(
|
||||
w,
|
||||
"[{}] {} {}",
|
||||
now.format("%Y-%m-%d %H:%M:%S%.3f"),
|
||||
record.level(),
|
||||
record.args(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ pub fn resolve_setup_async() {
|
||||
);
|
||||
|
||||
AsyncHandler::spawn(|| async {
|
||||
#[cfg(not(feature = "tauri-dev"))]
|
||||
resolve_setup_logger().await;
|
||||
init_service_manager().await;
|
||||
|
||||
futures::join!(
|
||||
@@ -119,6 +121,12 @@ pub(super) fn init_scheme() {
|
||||
logging_error!(Type::Setup, true, init::init_scheme());
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "tauri-dev"))]
|
||||
pub(super) async fn resolve_setup_logger() {
|
||||
logging!(info, Type::Setup, true, "Initializing global logger...");
|
||||
logging_error!(Type::Setup, true, init::init_logger().await);
|
||||
}
|
||||
|
||||
pub async fn resolve_scheme(param: String) -> Result<()> {
|
||||
logging!(
|
||||
info,
|
||||
@@ -243,6 +251,7 @@ pub(super) async fn refresh_tray_menu() {
|
||||
}
|
||||
|
||||
pub(super) async fn init_window() {
|
||||
logging!(info, Type::Setup, true, "Initializing main window...");
|
||||
let is_silent_start =
|
||||
{ Config::verge().await.latest_ref().enable_silent_start }.unwrap_or(false);
|
||||
#[cfg(target_os = "macos")]
|
||||
|
||||
Reference in New Issue
Block a user