From 7811714f894aaf21784831b6382beb8289e436a0 Mon Sep 17 00:00:00 2001 From: Tunglies Date: Sat, 20 Sep 2025 00:04:46 +0800 Subject: [PATCH] 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 --- CONTRIBUTING.md | 2 + UPDATELOG.md | 3 +- package.json | 7 +- src-tauri/Cargo.lock | 164 +++++------------------------ src-tauri/Cargo.toml | 22 +++- src-tauri/src/lib.rs | 7 +- src-tauri/src/utils/init.rs | 85 +++++++-------- src-tauri/src/utils/logging.rs | 68 +++++++++++- src-tauri/src/utils/resolve/mod.rs | 9 ++ 9 files changed, 170 insertions(+), 197 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 94aa8dc9..3b55dd91 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -74,6 +74,8 @@ To run the development server, use the following command: pnpm dev # If an app instance already exists, use a different command pnpm dev:diff +# To using tauri built-in dev tool +pnpm dev:tauri ``` ### Build the Project diff --git a/UPDATELOG.md b/UPDATELOG.md index 3cf51c55..d8ee0782 100644 --- a/UPDATELOG.md +++ b/UPDATELOG.md @@ -1,9 +1,10 @@ ## v2.4.3 -### 🚀 性能优化 +### 🚀 优化改进 - 重构并简化服务模式启动检测流程,消除重复检测 - 重构并简化窗口创建流程 +- 重构日志系统,单个日志默认最大 10 MB - 优化前端资源占用 ### 🐞 修复问题 diff --git a/package.json b/package.json index 794ab1ee..d2221bd7 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,10 @@ "version": "2.4.3", "license": "GPL-3.0-only", "scripts": { - "dev": "cross-env RUST_BACKTRACE=1 tauri dev -f verge-dev", - "dev:diff": "cross-env RUST_BACKTRACE=1 tauri dev -f verge-dev", - "dev:trace": "cross-env RUST_BACKTRACE=1 RUSTFLAGS=\"--cfg tokio_unstable\" tauri dev -f verge-dev tokio-trace", + "dev": "cross-env RUST_BACKTRACE=full tauri dev -f verge-dev", + "dev:diff": "cross-env RUST_BACKTRACE=full tauri dev -f verge-dev", + "dev:trace": "cross-env RUST_BACKTRACE=full RUSTFLAGS=\"--cfg tokio_unstable\" tauri dev -f verge-dev tokio-trace", + "dev:tauri": "cross-env RUST_BACKTRACE=full tauri dev -f tauri-dev", "build": "cross-env NODE_OPTIONS='--max-old-space-size=4096' tauri build", "build:fast": "cross-env NODE_OPTIONS='--max-old-space-size=4096' tauri build -- --profile fast-release", "tauri": "tauri", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index b61def69..414e3ba4 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -152,12 +152,6 @@ dependencies = [ "x11rb", ] -[[package]] -name = "arc-swap" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" - [[package]] name = "arrayvec" version = "0.7.6" @@ -1103,6 +1097,7 @@ dependencies = [ "backoff", "base64 0.22.1", "boa_engine", + "cfg-if", "chrono", "console-subscriber", "criterion", @@ -1111,6 +1106,7 @@ dependencies = [ "delay_timer", "dirs 6.0.0", "dunce", + "flexi_logger", "futures", "gethostname", "getrandom 0.3.3", @@ -1120,9 +1116,9 @@ dependencies = [ "kode-bridge", "libc", "log", - "log4rs", "nanoid", "network-interface", + "nu-ansi-term 0.50.1", "once_cell", "open", "parking_lot 0.12.4", @@ -1742,33 +1738,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "derive_more" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", - "unicode-xid", -] - -[[package]] -name = "destructure_traitobject" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7" - [[package]] name = "devtools-core" version = "0.3.6" @@ -2224,6 +2193,19 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "flexi_logger" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759bfa52db036a2db54f0b5f0ff164efa249b3014720459c5ea4198380c529bc" +dependencies = [ + "chrono", + "log", + "nu-ansi-term 0.50.1", + "regex", + "thiserror 2.0.16", +] + [[package]] name = "fnv" version = "1.0.7" @@ -3954,44 +3936,6 @@ name = "log" version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" -dependencies = [ - "serde", -] - -[[package]] -name = "log-mdc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" - -[[package]] -name = "log4rs" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e947bb896e702c711fccc2bf02ab2abb6072910693818d1d6b07ee2b9dfd86c" -dependencies = [ - "anyhow", - "arc-swap", - "chrono", - "derive_more 2.0.1", - "fnv", - "humantime", - "libc", - "log", - "log-mdc", - "mock_instant", - "parking_lot 0.12.4", - "rand 0.9.2", - "serde", - "serde-value", - "serde_json", - "serde_yaml", - "thiserror 2.0.16", - "thread-id", - "typemap-ors", - "unicode-segmentation", - "winapi", -] [[package]] name = "lru" @@ -4180,12 +4124,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "mock_instant" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce6dd36094cac388f119d2e9dc82dc730ef91c32a6222170d630e5414b956e6" - [[package]] name = "muda" version = "0.17.1" @@ -4392,6 +4330,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "nu-ansi-term" +version = "0.50.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -6278,7 +6225,7 @@ checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" dependencies = [ "bitflags 1.3.2", "cssparser", - "derive_more 0.99.20", + "derive_more", "fxhash", "log", "phf 0.8.0", @@ -6351,16 +6298,6 @@ dependencies = [ "typeid", ] -[[package]] -name = "serde-value" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" -dependencies = [ - "ordered-float", - "serde", -] - [[package]] name = "serde-xml-rs" version = "0.6.0" @@ -6490,19 +6427,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap 2.11.0", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - [[package]] name = "serde_yaml_ng" version = "0.10.0" @@ -7680,16 +7604,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "thread-id" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99043e46c5a15af379c06add30d9c93a6c0e8849de00d244c4a2c417da128d80" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "thread_local" version = "1.1.9" @@ -8213,7 +8127,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", - "nu-ansi-term", + "nu-ansi-term 0.46.0", "once_cell", "regex", "sharded-slab", @@ -8276,15 +8190,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" -[[package]] -name = "typemap-ors" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68c24b707f02dd18f1e4ccceb9d49f2058c2fb86384ef9972592904d7a28867" -dependencies = [ - "unsafe-any-ors", -] - [[package]] name = "typenum" version = "1.18.0" @@ -8367,12 +8272,6 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "universal-hash" version = "0.5.1" @@ -8383,15 +8282,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "unsafe-any-ors" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a303d30665362d9680d7d91d78b23f5f899504d4f08b3c4cf08d055d87c0ad" -dependencies = [ - "destructure_traitobject", -] - [[package]] name = "unsafe-libyaml" version = "0.2.11" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 3b61ecd8..d4cccfe6 100755 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -22,7 +22,6 @@ dirs = "6.0" open = "5.3.2" log = "0.4.28" dunce = "1.0.5" -log4rs = "1.4.0" nanoid = "0.4" chrono = "0.4.42" sysinfo = { version = "0.37.0", features = ["network", "system"] } @@ -58,7 +57,6 @@ tauri-plugin-fs = "2.4.2" tauri-plugin-process = "2.3.0" tauri-plugin-clipboard-manager = "2.3.0" tauri-plugin-deep-link = "2.4.3" -tauri-plugin-devtools = "2.0.1" tauri-plugin-window-state = "2.4.0" zip = "5.1.1" reqwest_dav = "0.2.2" @@ -76,7 +74,6 @@ scopeguard = "1.2.0" kode-bridge = "0.2.1" dashmap = "6.1.0" tauri-plugin-notification = "2.3.1" -console-subscriber = { version = "0.4.1", optional = true } tokio-stream = "0.1.17" isahc = { version = "1.7.2", default-features = false, features = [ "text-decoding", @@ -84,6 +81,20 @@ isahc = { version = "1.7.2", default-features = false, features = [ ] } backoff = { version = "0.4.0", features = ["tokio"] } tauri-plugin-http = "2" +flexi_logger = "0.31.2" +cfg-if = "1.0.3" + +[dependencies.nu-ansi-term] +version = "0.50.1" +optional = true + +[dependencies.console-subscriber] +version = "0.4.1" +optional = true + +[dependencies.tauri-plugin-devtools] +version = "2.0.1" +optional = true [target.'cfg(windows)'.dependencies] @@ -115,8 +126,9 @@ tauri-plugin-updater = "2.9.0" [features] default = ["custom-protocol"] custom-protocol = ["tauri/custom-protocol"] -verge-dev = [] -tokio-trace = ["console-subscriber"] +verge-dev = ["dep:nu-ansi-term"] +tauri-dev = ["dep:tauri-plugin-devtools"] +tokio-trace = ["dep:console-subscriber"] [profile.release] panic = "abort" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 07c9dec3..44683d27 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -77,7 +77,9 @@ mod app_init { .plugin(tauri_plugin_deep_link::init()) .plugin(tauri_plugin_http::init()); - #[cfg(all(debug_assertions, not(feature = "tokio-trace")))] + // Devtools plugin only in debug mode with feature tauri-dev + // to avoid duplicated registering of logger since the devtools plugin also registers a logger + #[cfg(all(debug_assertions, not(feature = "tokio-trace"), feature = "tauri-dev"))] { builder = builder.plugin(tauri_plugin_devtools::init()); } @@ -271,8 +273,7 @@ pub fn run() { // Setup singleton check app_init::init_singleton_check(); - // We don't need init_portable_flag here anymore due to the init_config will do the things - // let _ = utils::dirs::init_portable_flag(); + let _ = utils::dirs::init_portable_flag(); // Set Linux environment variable #[cfg(target_os = "linux")] diff --git a/src-tauri/src/utils/init.rs b/src-tauri/src/utils/init.rs index 13415147..e9ee216d 100644 --- a/src-tauri/src/utils/init.rs +++ b/src-tauri/src/utils/init.rs @@ -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?; diff --git a/src-tauri/src/utils/logging.rs b/src-tauri/src/utils/logging.rs index 6762ddb9..33341b8b 100644 --- a/src-tauri/src/utils/logging.rs +++ b/src-tauri/src/utils/logging.rs @@ -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(""), + 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(), + ) +} diff --git a/src-tauri/src/utils/resolve/mod.rs b/src-tauri/src/utils/resolve/mod.rs index 0b6770bc..da1c6a35 100644 --- a/src-tauri/src/utils/resolve/mod.rs +++ b/src-tauri/src/utils/resolve/mod.rs @@ -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")]