mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-30 18:52:12 +08:00
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:
@@ -329,7 +329,7 @@ impl PathBufExec for PathBuf {
|
||||
async fn remove_if_exists(&self) -> Result<()> {
|
||||
if self.exists() {
|
||||
tokio::fs::remove_file(self).await?;
|
||||
logging!(info, Type::File, "Removed file: {:?}", self);
|
||||
logging!(debug, Type::File, "Removed file: {:?}", self);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ async fn delete_snapshot_logs(log_dir: &Path) -> Result<()> {
|
||||
let path = entry.path();
|
||||
if path.extension().and_then(|s| s.to_str()) == Some("log") {
|
||||
let _ = path.remove_if_exists().await;
|
||||
logging!(info, Type::Setup, "delete snapshot log file: {}", path.display());
|
||||
logging!(debug, Type::Setup, "delete snapshot log file: {}", path.display());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ pub async fn delete_log() -> Result<()> {
|
||||
_ => return Ok(()),
|
||||
};
|
||||
|
||||
logging!(info, Type::Setup, "try to delete log files, day: {}", day);
|
||||
logging!(debug, Type::Setup, "try to delete log files, day: {}", day);
|
||||
|
||||
let parse_time_str = |s: &str| {
|
||||
let sa: Vec<&str> = s.split('-').collect();
|
||||
@@ -102,7 +102,7 @@ pub async fn delete_log() -> Result<()> {
|
||||
let duration = now.signed_duration_since(file_time);
|
||||
if duration.num_days() > day {
|
||||
let _ = file.path().remove_if_exists().await;
|
||||
logging!(info, Type::Setup, "delete log file: {}", file_name);
|
||||
logging!(debug, Type::Setup, "delete log file: {}", file_name);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -284,7 +284,7 @@ async fn migrate_legacy_macos_logs() -> Result<()> {
|
||||
|
||||
if is_logs_dir_writable(&log_dir).await {
|
||||
if let Err(e) = migrate_legacy_macos_service_logs(&log_dir).await {
|
||||
logging!(warn, Type::Setup, "Failed to migrate legacy macOS service logs: {}", e);
|
||||
logging!(warn, Type::Setup, "Failed to migrate legacy macOS service logs: {e:#}");
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
@@ -489,9 +489,9 @@ pub async fn init_config() -> Result<()> {
|
||||
|
||||
AsyncHandler::spawn(|| async {
|
||||
if let Err(e) = delete_log().await {
|
||||
logging!(warn, Type::Setup, "Failed to clean old logs: {}", e);
|
||||
logging!(warn, Type::Setup, "Failed to clean old logs: {e:#}");
|
||||
}
|
||||
logging!(info, Type::Setup, "后台日志清理任务完成");
|
||||
logging!(debug, Type::Setup, "后台日志清理任务完成");
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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}"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ pub struct WindowManager;
|
||||
impl WindowManager {
|
||||
#[cfg(target_os = "macos")]
|
||||
fn set_macos_activation_policy_regular() {
|
||||
logging!(info, Type::Window, "应用 macOS 特定的激活策略");
|
||||
logging!(debug, Type::Window, "应用 macOS 特定的激活策略");
|
||||
handle::Handle::global().set_activation_policy_regular();
|
||||
}
|
||||
|
||||
@@ -86,16 +86,16 @@ impl WindowManager {
|
||||
return WindowOperationResult::NoAction;
|
||||
}
|
||||
|
||||
logging!(info, Type::Window, "开始智能显示主窗口");
|
||||
logging!(debug, Type::Window, "开始智能显示主窗口");
|
||||
logging!(debug, Type::Window, "{}", Self::get_window_status_info());
|
||||
|
||||
let current_state = Self::get_main_window_state();
|
||||
|
||||
match current_state {
|
||||
WindowState::NotExist => {
|
||||
logging!(info, Type::Window, "窗口不存在,创建新窗口");
|
||||
logging!(debug, Type::Window, "窗口不存在,创建新窗口");
|
||||
if Self::create_window(true).await {
|
||||
logging!(info, Type::Window, "窗口创建成功");
|
||||
logging!(debug, Type::Window, "窗口创建成功");
|
||||
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
|
||||
WindowOperationResult::Created
|
||||
} else {
|
||||
@@ -104,13 +104,13 @@ impl WindowManager {
|
||||
}
|
||||
}
|
||||
WindowState::VisibleFocused => {
|
||||
logging!(info, Type::Window, "窗口已经可见且有焦点,无需操作");
|
||||
logging!(debug, Type::Window, "窗口已经可见且有焦点,无需操作");
|
||||
WindowOperationResult::NoAction
|
||||
}
|
||||
WindowState::VisibleUnfocused | WindowState::Minimized | WindowState::Hidden => {
|
||||
let (window, state_after_check) = Self::get_main_window_with_state();
|
||||
if state_after_check == WindowState::VisibleFocused {
|
||||
logging!(info, Type::Window, "窗口在检查期间已变为可见和有焦点状态");
|
||||
logging!(debug, Type::Window, "窗口在检查期间已变为可见和有焦点状态");
|
||||
return WindowOperationResult::NoAction;
|
||||
}
|
||||
if let Some(window) = window {
|
||||
@@ -139,7 +139,7 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
async fn handle_not_exist_toggle() -> WindowOperationResult {
|
||||
logging!(info, Type::Window, "窗口不存在,将创建新窗口");
|
||||
logging!(debug, Type::Window, "窗口不存在,将创建新窗口");
|
||||
if Self::create_window(true).await {
|
||||
WindowOperationResult::Created
|
||||
} else {
|
||||
@@ -148,7 +148,7 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
fn hide_main_window(window: Option<&WebviewWindow<Wry>>) -> WindowOperationResult {
|
||||
logging!(info, Type::Window, "窗口可见,将隐藏窗口");
|
||||
logging!(debug, Type::Window, "窗口可见,将隐藏窗口");
|
||||
if let Some(window) = window {
|
||||
match window.close() {
|
||||
Ok(_) => {
|
||||
@@ -167,7 +167,7 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
fn activate_existing_main_window(window: Option<&WebviewWindow<Wry>>) -> WindowOperationResult {
|
||||
logging!(info, Type::Window, "窗口存在但被隐藏或最小化,将激活窗口");
|
||||
logging!(debug, Type::Window, "窗口存在但被隐藏或最小化,将激活窗口");
|
||||
if let Some(window) = window {
|
||||
Self::activate_window(window)
|
||||
} else {
|
||||
@@ -177,7 +177,7 @@ impl WindowManager {
|
||||
}
|
||||
|
||||
fn activate_window(window: &WebviewWindow<Wry>) -> WindowOperationResult {
|
||||
logging!(info, Type::Window, "开始激活窗口");
|
||||
logging!(debug, Type::Window, "开始激活窗口");
|
||||
#[cfg(target_os = "macos")]
|
||||
Self::set_macos_activation_policy_regular();
|
||||
|
||||
@@ -196,7 +196,7 @@ impl WindowManager {
|
||||
let mut operations_successful = true;
|
||||
|
||||
if window.is_minimized().unwrap_or(false) {
|
||||
logging!(info, Type::Window, "窗口已最小化,正在取消最小化");
|
||||
logging!(debug, Type::Window, "窗口已最小化,正在取消最小化");
|
||||
if let Err(e) = window.unminimize() {
|
||||
logging!(warn, Type::Window, "取消最小化失败: {}", e);
|
||||
operations_successful = false;
|
||||
@@ -248,7 +248,7 @@ impl WindowManager {
|
||||
/// Keep new windows hidden until the frontend overlay renders, avoiding a theme flash.
|
||||
pub fn create_window(should_create: bool) -> Pin<Box<dyn Future<Output = bool> + Send>> {
|
||||
Box::pin(async move {
|
||||
logging!(info, Type::Window, "开始创建主窗口, should_create={}", should_create);
|
||||
logging!(debug, Type::Window, "开始创建主窗口, should_create={}", should_create);
|
||||
|
||||
if !should_create {
|
||||
return false;
|
||||
@@ -277,7 +277,7 @@ impl WindowManager {
|
||||
logging!(info, Type::Window, "窗口已摧毁");
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
logging!(info, Type::Window, "应用 macOS 特定的激活策略");
|
||||
logging!(debug, Type::Window, "应用 macOS 特定的激活策略");
|
||||
handle::Handle::global().set_activation_policy_accessory();
|
||||
}
|
||||
return WindowOperationResult::Destroyed;
|
||||
|
||||
Reference in New Issue
Block a user