refactor(log): in-place writer lifecycle and span-based core observability (#7889)

* refactor(log): migrate logging to tracing-estuary pipeline

Swap flexi_logger + clash-verge-logger wiring for the tracing-estuary
crate: buffered file sink with explicit panic/exit drains, live level
switching, and tokio-trace/chrome-trace behind crate features.

AsyncLogger moves in-house (VecDeque ring); file format and rotation
stay unchanged.

* fix(log): reset sidecar writer in place and re-pin service-ipc v2.6.7

Rebuilding the sidecar FileLogWriter on config changes leaked flexi's
unstoppable flusher thread plus an fd each time; the writer is now flushed
and reset in place, matching what the service crate does.
get_clash_logs_by_service drops the CompactString conversion layer now that
service-ipc v2.6.7 returns plain Vec<String>, and AsyncLogger is renamed
LogRing to match.

* refactor(log): span-based observability and log noise cleanup

Instrument spans carry the structure flat lines never could: the core-start
spine (mode, readiness/owner generations, pid, config file), proxy apply and
clear routes with guard generations, service IPC sessions with refusal codes
and outcomes, profile-switch terminal outcomes, subscription fetch strategies,
core upgrades with per-proxy version probes, backup flows, timer tasks, config
generation uids, and the startup setup flow; running-mode changes emit one
guarded transition event each.
~90 hand-written noise lines are gone or demoted (entry+success pairs, polled
getter echoes, phase brackets, window sub-steps, platform install chatter);
errors keep their anyhow chain, operation name, and item id, and swallowed
retry results surface per attempt.
This commit is contained in:
Tunglies
2026-09-08 05:51:04 +08:00
committed by GitHub
parent f8b69b5d62
commit 2f370d6490
43 changed files with 807 additions and 797 deletions
+2 -2
View File
@@ -27,7 +27,7 @@ pub async fn set_public_dns(dns_server: String) {
use tauri_plugin_shell::ShellExt as _;
let app_handle = handle::Handle::app_handle();
logging!(info, Type::Config, "try to set system dns");
logging!(debug, Type::Config, "try to set system dns");
let resource_dir = match dirs::app_resources_dir() {
Ok(dir) => dir,
Err(e) => {
@@ -75,7 +75,7 @@ pub async fn restore_public_dns() {
use crate::{core::handle, utils::dirs};
use tauri_plugin_shell::ShellExt as _;
let app_handle = handle::Handle::app_handle();
logging!(info, Type::Config, "try to unset system dns");
logging!(debug, Type::Config, "try to unset system dns");
let resource_dir = match dirs::app_resources_dir() {
Ok(dir) => dir,
Err(e) => {
+45 -42
View File
@@ -8,7 +8,7 @@ use crate::{
CoreManager, Timer,
handle::Handle,
hotkey::Hotkey,
logger::Logger,
logger,
service::{SERVICE_MANAGER, ServiceManager},
tray::Tray,
},
@@ -31,7 +31,7 @@ pub(crate) fn init_work_dir_and_logger() -> anyhow::Result<()> {
AsyncHandler::block_on(async {
init_work_config().await;
logging!(info, Type::Setup, "Initializing logger");
Logger::global().init().await?;
logger::init().await?;
Ok(())
})
}
@@ -46,50 +46,53 @@ pub(crate) fn resolve_setup_sync() {
}
pub(crate) fn resolve_setup_async() {
AsyncHandler::spawn(|| async {
logging!(info, Type::ClashVergeRev, "Version: {}", env!("CARGO_PKG_VERSION"));
AsyncHandler::spawn(resolve_setup);
}
// Migrate before windows or timers can change the loaded config.
logging_error!(Type::Setup, init::migrate_short_update_intervals().await);
#[tracing::instrument(skip_all, level = "info")]
async fn resolve_setup() {
logging!(info, Type::ClashVergeRev, "Version: {}", env!("CARGO_PKG_VERSION"));
#[cfg(target_os = "macos")]
resolve_dock_show().await;
init_startup_script().await;
init_service_manager().await;
let config_initialized = init_verge_config_before_window().await;
init_window().await;
feat::reconcile_startup_tun_availability().await;
init_resources().await;
if let Err(e) = init::init_dns_config().await {
logging!(warn, Type::Setup, "DNS config initialization failed: {}", e);
}
if config_initialized {
init_verge_config().await;
}
Config::verify_config_initialization().await;
// Migrate before windows or timers can change the loaded config.
logging_error!(Type::Setup, init::migrate_short_update_intervals().await);
// Live before the core starts, so a service appearing mid-start is not missed.
#[cfg(target_os = "macos")]
crate::core::network_watch::start();
#[cfg(target_os = "macos")]
resolve_dock_show().await;
init_startup_script().await;
init_service_manager().await;
let config_initialized = init_verge_config_before_window().await;
init_window().await;
feat::reconcile_startup_tun_availability().await;
init_resources().await;
if let Err(e) = init::init_dns_config().await {
logging!(warn, Type::Setup, "DNS config initialization failed: {}", e);
}
if config_initialized {
init_verge_config().await;
}
Config::verify_config_initialization().await;
let core_init = AsyncHandler::spawn(|| async {
init_core_manager().await;
});
// Live before the core starts, so a service appearing mid-start is not missed.
#[cfg(target_os = "macos")]
crate::core::network_watch::start();
let _ = futures::join!(
core_init,
init_tray(),
init_timer(),
init_hotkey(),
init_auto_lightweight_boot(),
init_auto_backup(),
init_silent_updater(),
);
Handle::refresh_clash();
refresh_tray_menu().await;
resolve_done();
let core_init = AsyncHandler::spawn(|| async {
init_core_manager().await;
});
let _ = futures::join!(
core_init,
init_tray(),
init_timer(),
init_hotkey(),
init_auto_lightweight_boot(),
init_auto_backup(),
init_silent_updater(),
);
Handle::refresh_clash();
refresh_tray_menu().await;
resolve_done();
}
pub async fn resolve_reset_async() -> Result<(), anyhow::Error> {
@@ -165,7 +168,7 @@ async fn init_silent_updater() {
use crate::core::SilentUpdater;
use crate::core::handle::Handle;
logging!(info, Type::Setup, "Initializing silent updater...");
logging!(debug, Type::Setup, "Initializing silent updater...");
let app_handle = Handle::app_handle();
@@ -184,7 +187,7 @@ async fn init_silent_updater() {
}
pub(crate) fn init_signal() {
logging!(info, Type::Setup, "Initializing signal handlers...");
logging!(debug, Type::Setup, "Initializing signal handlers...");
clash_verge_signal::register(feat::quit);
}
+2 -2
View File
@@ -98,7 +98,7 @@ async fn import_subscription(url: &str, name: Option<&String>) {
}
if let Err(e) = profiles::profiles_save_file_safe().await {
logging!(error, Type::Config, "failed to save imported subscription: {}", e);
logging!(error, Type::Config, "failed to save imported subscription: {e:#}");
handle::Handle::notice_message("import_sub_url::error", e.to_string());
return;
}
@@ -152,7 +152,7 @@ async fn refresh_core_config() {
handle::Handle::notice_message("config_validate::error", message);
}
Err(err) => {
logging!(error, Type::Config, "Apply config error: {}", err);
logging!(error, Type::Config, "Apply config error: {err:#}");
handle::Handle::notice_message("update_failed", format!("{err}"));
}
}