mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-11 21:12:09 +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:
@@ -69,7 +69,7 @@ async fn finalize_restored_verge_config(
|
||||
}
|
||||
.await;
|
||||
if let Err(err) = result {
|
||||
logging!(error, Type::Backup, "Failed to turn the system proxy off: {err:#?}");
|
||||
logging!(error, Type::Backup, "Failed to turn the system proxy off: {err:#}");
|
||||
if SystemProxyStateUnknown::is_in(&err) {
|
||||
return Err(err);
|
||||
}
|
||||
@@ -79,7 +79,7 @@ async fn finalize_restored_verge_config(
|
||||
|
||||
// Run configuration side effects without rewriting the already-restored file.
|
||||
if let Err(err) = super::patch_verge(&restored, true).await {
|
||||
logging!(error, Type::Backup, "Failed to apply restored verge config: {err:#?}");
|
||||
logging!(error, Type::Backup, "Failed to apply restored verge config: {err:#}");
|
||||
// Propagate unknown proxy state; ordinary side-effect failures stay logged.
|
||||
if SystemProxyStateUnknown::is_in(&err) {
|
||||
return Err(err);
|
||||
@@ -88,9 +88,10 @@ async fn finalize_restored_verge_config(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, level = "info")]
|
||||
pub async fn create_backup_and_upload_webdav() -> Result<()> {
|
||||
let (file_name, temp_file_path) = backup::create_backup().await.map_err(|err| {
|
||||
logging!(error, Type::Backup, "Failed to create backup: {err:#?}");
|
||||
logging!(error, Type::Backup, "Failed to create backup: {err:#}");
|
||||
err
|
||||
})?;
|
||||
|
||||
@@ -98,13 +99,13 @@ pub async fn create_backup_and_upload_webdav() -> Result<()> {
|
||||
.upload(temp_file_path.clone(), file_name)
|
||||
.await
|
||||
{
|
||||
logging!(error, Type::Backup, "Failed to upload to WebDAV: {err:#?}");
|
||||
logging!(error, Type::Backup, "Failed to upload to WebDAV: {err:#}");
|
||||
backup::WebDavClient::global().reset();
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
if let Err(err) = temp_file_path.remove_if_exists().await {
|
||||
logging!(warn, Type::Backup, "Failed to remove temp file: {err:#?}");
|
||||
logging!(warn, Type::Backup, "Failed to remove temp file: {err:#}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -112,18 +113,24 @@ pub async fn create_backup_and_upload_webdav() -> Result<()> {
|
||||
|
||||
pub async fn list_wevdav_backup() -> Result<Vec<ListFile>> {
|
||||
backup::WebDavClient::global().list().await.map_err(|err| {
|
||||
logging!(error, Type::Backup, "Failed to list WebDAV backup files: {err:#?}");
|
||||
logging!(error, Type::Backup, "Failed to list WebDAV backup files: {err:#}");
|
||||
err
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn delete_webdav_backup(filename: String) -> Result<()> {
|
||||
let name = filename.to_string();
|
||||
backup::WebDavClient::global().delete(filename).await.map_err(|err| {
|
||||
logging!(error, Type::Backup, "Failed to delete WebDAV backup file: {err:#?}");
|
||||
logging!(
|
||||
error,
|
||||
Type::Backup,
|
||||
"Failed to delete WebDAV backup file {name}: {err:#}"
|
||||
);
|
||||
err
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, level = "info", fields(filename = %filename))]
|
||||
pub async fn restore_webdav_backup(filename: String) -> Result<()> {
|
||||
let verge = Config::verge().await;
|
||||
let verge_data = verge.latest_arc();
|
||||
@@ -134,11 +141,16 @@ pub async fn restore_webdav_backup(filename: String) -> Result<()> {
|
||||
let backup_storage_path = app_home_dir()
|
||||
.map_err(|e| anyhow::anyhow!("Failed to get app home dir: {e}"))?
|
||||
.join(filename.as_str());
|
||||
let name = filename.to_string();
|
||||
backup::WebDavClient::global()
|
||||
.download(filename, backup_storage_path.clone())
|
||||
.await
|
||||
.map_err(|err| {
|
||||
logging!(error, Type::Backup, "Failed to download WebDAV backup file: {err:#?}");
|
||||
logging!(
|
||||
error,
|
||||
Type::Backup,
|
||||
"Failed to download WebDAV backup file {name}: {err:#}"
|
||||
);
|
||||
err
|
||||
})?;
|
||||
|
||||
@@ -163,7 +175,7 @@ where
|
||||
F: FnOnce(&str) -> String,
|
||||
{
|
||||
let (file_name, temp_file_path) = backup::create_backup().await.map_err(|err| {
|
||||
logging!(error, Type::Backup, "Failed to create local backup: {err:#?}");
|
||||
logging!(error, Type::Backup, "Failed to create local backup: {err:#}");
|
||||
err
|
||||
})?;
|
||||
|
||||
@@ -172,12 +184,17 @@ where
|
||||
let target_path = backup_dir.join(final_name.as_str());
|
||||
|
||||
if let Err(err) = move_file(temp_file_path.clone(), target_path.clone()).await {
|
||||
logging!(error, Type::Backup, "Failed to move local backup file: {err:#?}");
|
||||
logging!(
|
||||
error,
|
||||
Type::Backup,
|
||||
"Failed to move local backup file to {}: {err:#}",
|
||||
target_path.display()
|
||||
);
|
||||
if let Err(clean_err) = temp_file_path.remove_if_exists().await {
|
||||
logging!(
|
||||
warn,
|
||||
Type::Backup,
|
||||
"Failed to remove temp backup file after move error: {clean_err:#?}"
|
||||
"Failed to remove temp backup file after move error: {clean_err:#}"
|
||||
);
|
||||
}
|
||||
return Err(err);
|
||||
@@ -186,6 +203,7 @@ where
|
||||
Ok(final_name)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, level = "info", fields(source = %source))]
|
||||
pub async fn import_local_backup(source: String) -> Result<String> {
|
||||
let source_path = PathBuf::from(source.as_str());
|
||||
if !source_path.exists() {
|
||||
@@ -226,7 +244,7 @@ pub async fn import_local_backup(source: String) -> Result<String> {
|
||||
|
||||
fs::copy(&source_path, &target_path)
|
||||
.await
|
||||
.map_err(|err| anyhow!("Failed to import backup file: {err:#?}"))?;
|
||||
.map_err(|err| anyhow!("Failed to import backup file: {err:#}"))?;
|
||||
|
||||
Ok(file_name.to_string().into())
|
||||
}
|
||||
@@ -243,14 +261,14 @@ async fn move_file(from: PathBuf, to: PathBuf) -> Result<()> {
|
||||
logging!(
|
||||
warn,
|
||||
Type::Backup,
|
||||
"Failed to rename backup file directly, fallback to copy/remove: {rename_err:#?}"
|
||||
"Failed to rename backup file directly, fallback to copy/remove: {rename_err}"
|
||||
);
|
||||
fs::copy(&from, &to)
|
||||
.await
|
||||
.map_err(|err| anyhow!("Failed to copy backup file: {err:#?}"))?;
|
||||
.map_err(|err| anyhow!("Failed to copy backup file: {err:#}"))?;
|
||||
fs::remove_file(&from)
|
||||
.await
|
||||
.map_err(|err| anyhow!("Failed to remove temp backup file: {err:#?}"))?;
|
||||
.map_err(|err| anyhow!("Failed to remove temp backup file: {err:#}"))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -295,13 +313,14 @@ pub async fn delete_local_backup(filename: String) -> Result<()> {
|
||||
let backup_dir = local_backup_dir()?;
|
||||
let target_path = backup_dir.join(filename.as_str());
|
||||
if !target_path.exists() {
|
||||
logging!(warn, Type::Backup, "Local backup file not found: {}", filename);
|
||||
logging!(debug, Type::Backup, "Local backup file not found: {}", filename);
|
||||
return Ok(());
|
||||
}
|
||||
target_path.remove_if_exists().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, level = "info", fields(filename = %filename))]
|
||||
pub async fn restore_local_backup(filename: String) -> Result<()> {
|
||||
let backup_dir = local_backup_dir()?;
|
||||
let target_path = backup_dir.join(filename.as_str());
|
||||
@@ -327,6 +346,7 @@ pub async fn restore_local_backup(filename: String) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, level = "info", fields(filename = %filename, destination = %destination))]
|
||||
pub async fn export_local_backup(filename: String, destination: String) -> Result<()> {
|
||||
let backup_dir = local_backup_dir()?;
|
||||
let source_path = backup_dir.join(filename.as_str());
|
||||
@@ -342,6 +362,6 @@ pub async fn export_local_backup(filename: String, destination: String) -> Resul
|
||||
fs::copy(&source_path, &dest_path)
|
||||
.await
|
||||
.map(|_| ())
|
||||
.map_err(|err| anyhow!("Failed to export backup file: {err:#?}"))?;
|
||||
.map_err(|err| anyhow!("Failed to export backup file: {err:#}"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ pub async fn restart_clash_core() {
|
||||
}
|
||||
Err(err) => {
|
||||
handle::Handle::notice_message("set_config::error", format!("{err:#}"));
|
||||
logging!(error, Type::Core, "{err:#}");
|
||||
logging!(error, Type::Core, "restart core failed: {err:#}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,6 @@ pub async fn restart_app() {
|
||||
|
||||
Config::apply_all_and_save_file().await;
|
||||
|
||||
logging!(info, Type::System, "开始异步清理资源");
|
||||
let cleanup_result = clean_async().await;
|
||||
|
||||
logging!(
|
||||
@@ -85,9 +84,8 @@ pub async fn change_clash_mode(mode: String) -> Result<(), String> {
|
||||
let json_value = serde_json::json!({
|
||||
"mode": mode
|
||||
});
|
||||
logging!(debug, Type::Core, "change clash mode to {mode}");
|
||||
if let Err(err) = handle::Handle::mihomo().patch_base_config(&json_value).await {
|
||||
logging!(error, Type::Core, "{err}");
|
||||
logging!(error, Type::Core, "change clash mode failed: {err}");
|
||||
return Err(err.to_string().into());
|
||||
}
|
||||
|
||||
@@ -111,6 +109,7 @@ pub async fn change_clash_mode(mode: String) -> Result<(), String> {
|
||||
|
||||
/// Test delay to a URL through proxy.
|
||||
/// HTTPS: measures TLS handshake time. HTTP: measures HEAD round-trip time.
|
||||
#[tracing::instrument(skip_all, level = "trace", fields(url = %url))]
|
||||
pub async fn test_delay(url: String) -> anyhow::Result<u32> {
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
config::{Config, IVerge},
|
||||
core::{CoreManager, autostart, handle, hotkey, logger::Logger, proxy_control, tray},
|
||||
core::{CoreManager, autostart, handle, hotkey, logger, proxy_control, tray},
|
||||
module::{auto_backup::AutoBackupManager, lightweight},
|
||||
};
|
||||
use anyhow::Result;
|
||||
@@ -267,12 +267,12 @@ async fn process_terminated_flags(update_flags: UpdateFlags, patch: &IVerge) ->
|
||||
}
|
||||
}
|
||||
if update_flags.contains(UpdateFlags::LOG_LEVEL) {
|
||||
Logger::global().update_log_level(patch.get_log_level())?;
|
||||
logger::Logger::global().update_log_level(patch.get_log_level())?;
|
||||
}
|
||||
if update_flags.contains(UpdateFlags::LOG_FILE) {
|
||||
let log_max_size = patch.app_log_max_size.unwrap_or(128);
|
||||
let log_max_count = patch.app_log_max_count.unwrap_or(8);
|
||||
Logger::global().update_log_config(log_max_size, log_max_count).await?;
|
||||
logger::update_log_config(log_max_size, log_max_count).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -317,7 +317,6 @@ pub(super) async fn apply_verge_patch_locked(
|
||||
if !not_save_file {
|
||||
// 分离数据获取和异步调用
|
||||
let verge_data = verge.data_arc();
|
||||
logging!(debug, Type::Setup, "Saving Verge configuration to file...");
|
||||
verge_data.save_file().await?;
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -45,6 +45,7 @@ pub struct CoreUpgradeReport {
|
||||
pub async fn upgrade_core(force: bool) -> Result<CoreUpgradeReport> {
|
||||
let _serialized = UPGRADE_LOCK.lock().await;
|
||||
let core = Config::verge().await.latest_arc().get_valid_clash_core();
|
||||
tracing::Span::current().record("core", tracing::field::display(&core));
|
||||
let alpha = core.ends_with("-alpha");
|
||||
let target = managed_core_path(&core)?;
|
||||
|
||||
@@ -55,11 +56,10 @@ pub async fn upgrade_core(force: bool) -> Result<CoreUpgradeReport> {
|
||||
});
|
||||
|
||||
let (proxy, latest) = resolve_latest_version(alpha).await?;
|
||||
logging!(
|
||||
info,
|
||||
Type::Core,
|
||||
"core upgrade: {core} installed={installed:?} latest={latest:?} via {proxy:?}"
|
||||
);
|
||||
let span = tracing::Span::current();
|
||||
span.record("from", tracing::field::display(&installed));
|
||||
span.record("to", tracing::field::display(&latest));
|
||||
logging!(debug, Type::Core, "core upgrade: latest version resolved via {proxy:?}");
|
||||
|
||||
if !force && installed == latest {
|
||||
return Ok(CoreUpgradeReport {
|
||||
@@ -111,7 +111,6 @@ pub async fn upgrade_core(force: bool) -> Result<CoreUpgradeReport> {
|
||||
#[cfg(windows)]
|
||||
let _ = std::fs::remove_file(target.with_extension("old"));
|
||||
|
||||
logging!(info, Type::Core, "core upgrade: {core} now at {latest}");
|
||||
Ok(CoreUpgradeReport {
|
||||
upgraded: true,
|
||||
from: installed,
|
||||
@@ -175,6 +174,7 @@ fn asset_base_name(alpha: bool) -> Result<&'static str> {
|
||||
}
|
||||
|
||||
/// Returns the proxy that reached GitHub so the package download reuses it.
|
||||
#[tracing::instrument(skip_all, level = "debug", fields(alpha))]
|
||||
async fn resolve_latest_version(alpha: bool) -> Result<(ProxyType, std::string::String)> {
|
||||
let url = if alpha {
|
||||
format!("{ALPHA_BASE_URL}/version.txt")
|
||||
@@ -193,13 +193,33 @@ async fn resolve_latest_version(alpha: bool) -> Result<(ProxyType, std::string::
|
||||
// An error page answered with 200 must not become a version, nor reach the URL.
|
||||
let version = response.text().trim().to_owned();
|
||||
if !is_usable_version(&version) {
|
||||
logging!(
|
||||
warn,
|
||||
Type::Core,
|
||||
"core upgrade: {url} returned an unusable version: {version:?}"
|
||||
);
|
||||
last_error = Some(anyhow!("{url} returned an unusable version"));
|
||||
continue;
|
||||
}
|
||||
return Ok((proxy, version));
|
||||
}
|
||||
Ok(response) => last_error = Some(anyhow!("{url} returned status {}", response.status())),
|
||||
Err(error) => last_error = Some(error.context(format!("{proxy:?} could not reach {url}"))),
|
||||
Ok(response) => {
|
||||
logging!(
|
||||
debug,
|
||||
Type::Core,
|
||||
"core upgrade: version probe via {proxy:?}: status {}",
|
||||
response.status()
|
||||
);
|
||||
last_error = Some(anyhow!("{url} returned status {}", response.status()));
|
||||
}
|
||||
Err(error) => {
|
||||
logging!(
|
||||
debug,
|
||||
Type::Core,
|
||||
"core upgrade: version probe via {proxy:?} failed: {error:#}"
|
||||
);
|
||||
last_error = Some(error.context(format!("{proxy:?} could not reach {url}")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -157,13 +157,7 @@ pub async fn copy_icon_file(path: String, icon_info: IconInfo) -> CmdResult<Stri
|
||||
previous_ico.remove_if_exists().await.unwrap_or_default();
|
||||
}
|
||||
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"Copying icon file path: {:?} -> file dist: {:?}",
|
||||
path,
|
||||
dest_path
|
||||
);
|
||||
logging!(debug, Type::Cmd, "copying icon file: {path} -> {}", dest_path.display());
|
||||
|
||||
match fs::copy(file_path, &dest_path).await {
|
||||
Ok(_) => Ok(dest_path.to_string_lossy().into()),
|
||||
|
||||
@@ -5,15 +5,18 @@ use crate::{
|
||||
utils::help::{mask_err, mask_url},
|
||||
};
|
||||
use anyhow::{Result, bail};
|
||||
use clash_verge_logging::{Type, logging, logging_error};
|
||||
use clash_verge_logging::{Type, logging};
|
||||
use smartstring::alias::String;
|
||||
|
||||
/// Toggle proxy profile
|
||||
pub async fn toggle_proxy_profile(profile_index: String) {
|
||||
logging_error!(
|
||||
Type::Config,
|
||||
cmd::patch_profiles_config_by_profile_index(profile_index).await
|
||||
);
|
||||
if let Err(err) = cmd::patch_profiles_config_by_profile_index(profile_index.clone()).await {
|
||||
logging!(
|
||||
error,
|
||||
Type::Config,
|
||||
"toggle proxy profile {profile_index} failed: {err}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Tell the profile which node this group is on now.
|
||||
@@ -25,7 +28,7 @@ async fn record_switched_node(group_name: &str, proxy_name: &str) {
|
||||
if let Err(error) = crate::config::profiles::record_selected_node(group_name, proxy_name).await {
|
||||
logging!(
|
||||
warn,
|
||||
Type::Tray,
|
||||
Type::Config,
|
||||
"切换代理成功但未能记录到配置: {} -> {}, 错误: {error:#}",
|
||||
group_name,
|
||||
proxy_name
|
||||
@@ -39,21 +42,13 @@ pub async fn switch_proxy_node(group_name: &str, proxy_name: &str) {
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
logging!(info, Type::Tray, "切换代理成功: {} -> {}", group_name, proxy_name);
|
||||
record_switched_node(group_name, proxy_name).await;
|
||||
handle::Handle::refresh_proxy_config();
|
||||
let _ = tray::Tray::global().update_menu().await;
|
||||
return;
|
||||
}
|
||||
Err(err) => {
|
||||
logging!(
|
||||
error,
|
||||
Type::Tray,
|
||||
"切换代理失败: {} -> {}, 错误: {:?}",
|
||||
group_name,
|
||||
proxy_name,
|
||||
err
|
||||
);
|
||||
logging!(error, Type::Tray, "切换代理失败: {err:?}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,14 +62,7 @@ pub async fn switch_proxy_node(group_name: &str, proxy_name: &str) {
|
||||
let _ = tray::Tray::global().update_menu().await;
|
||||
}
|
||||
Err(err) => {
|
||||
logging!(
|
||||
error,
|
||||
Type::Tray,
|
||||
"代理切换最终失败: {} -> {}, 错误: {:?}",
|
||||
group_name,
|
||||
proxy_name,
|
||||
err
|
||||
);
|
||||
logging!(error, Type::Tray, "代理切换最终失败: {err:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,20 +74,19 @@ async fn should_update_profile(uid: &String, ignore_auto_update: bool) -> Result
|
||||
let is_remote = item.itype.as_ref().is_some_and(|s| s == "remote");
|
||||
|
||||
if !is_remote {
|
||||
logging!(info, Type::Config, "[订阅更新] {uid} 不是远程订阅,跳过更新");
|
||||
logging!(info, Type::Config, "[订阅更新] 不是远程订阅,跳过更新");
|
||||
Ok(None)
|
||||
} else if item.url.is_none() {
|
||||
logging!(warn, Type::Config, "Warning: [订阅更新] {uid} 缺少URL,无法更新");
|
||||
logging!(warn, Type::Config, "[订阅更新] 缺少URL,无法更新");
|
||||
bail!("failed to get the profile item url");
|
||||
} else if !ignore_auto_update && !item.option.as_ref().and_then(|o| o.allow_auto_update).unwrap_or(true) {
|
||||
logging!(info, Type::Config, "[订阅更新] {} 禁止自动更新,跳过更新", uid);
|
||||
logging!(info, Type::Config, "[订阅更新] 禁止自动更新,跳过更新");
|
||||
Ok(None)
|
||||
} else {
|
||||
logging!(
|
||||
info,
|
||||
Type::Config,
|
||||
"[订阅更新] {} 是远程订阅,URL: {}",
|
||||
uid,
|
||||
"[订阅更新] 远程订阅,URL: {}",
|
||||
mask_url(
|
||||
item.url
|
||||
.as_ref()
|
||||
@@ -113,6 +100,7 @@ async fn should_update_profile(uid: &String, ignore_auto_update: bool) -> Result
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, level = "info", fields(uid = %uid, strategy = tracing::field::Empty))]
|
||||
async fn perform_profile_update(
|
||||
uid: &String,
|
||||
url: &String,
|
||||
@@ -120,7 +108,6 @@ async fn perform_profile_update(
|
||||
option: Option<&PrfOption>,
|
||||
is_mannual_trigger: bool,
|
||||
) -> Result<()> {
|
||||
logging!(info, Type::Config, "[订阅更新] 开始下载新的订阅内容");
|
||||
let mut merged_opt = PrfOption::merge(opt, option);
|
||||
let profiles = Config::profiles().await;
|
||||
let profiles_arc = profiles.latest_arc();
|
||||
@@ -140,8 +127,8 @@ async fn perform_profile_update(
|
||||
logging!(
|
||||
warn,
|
||||
Type::Config,
|
||||
"Warning: [订阅更新] 正常更新失败: {},尝试使用Clash代理更新",
|
||||
mask_err(&err.to_string())
|
||||
"[订阅更新] 直接更新失败: {},尝试使用Clash代理更新",
|
||||
mask_err(&format!("{err:#}"))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -160,8 +147,8 @@ async fn perform_profile_update(
|
||||
logging!(
|
||||
warn,
|
||||
Type::Config,
|
||||
"Warning: [订阅更新] Clash代理更新失败: {},尝试使用系统代理更新",
|
||||
mask_err(&err.to_string())
|
||||
"[订阅更新] Clash代理更新失败: {},尝试使用系统代理更新",
|
||||
mask_err(&format!("{err:#}"))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -180,8 +167,8 @@ async fn perform_profile_update(
|
||||
logging!(
|
||||
warn,
|
||||
Type::Config,
|
||||
"Warning: [订阅更新] 系统代理更新失败: {},所有重试均已失败",
|
||||
mask_err(&err.to_string())
|
||||
"[订阅更新] 系统代理更新失败: {},所有重试均已失败",
|
||||
mask_err(&format!("{err:#}"))
|
||||
);
|
||||
err
|
||||
}
|
||||
@@ -194,8 +181,8 @@ async fn perform_profile_update(
|
||||
bail!(last_err)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, level = "info", fields(uid = %uid, manual = is_mannual_trigger))]
|
||||
pub async fn update_profile(uid: &String, option: Option<&PrfOption>, is_mannual_trigger: bool) -> Result<()> {
|
||||
logging!(info, Type::Config, "[订阅更新] 开始更新订阅 {}", uid);
|
||||
let url_opt = should_update_profile(uid, is_mannual_trigger).await?;
|
||||
|
||||
let profile_persisted = match url_opt {
|
||||
@@ -210,10 +197,9 @@ pub async fn update_profile(uid: &String, option: Option<&PrfOption>, is_mannual
|
||||
let should_refresh = is_current || (!profile_persisted && is_mannual_trigger);
|
||||
|
||||
if should_refresh {
|
||||
logging!(info, Type::Config, "[订阅更新] 更新内核配置");
|
||||
logging!(debug, Type::Config, "[订阅更新] 更新内核配置");
|
||||
match CoreManager::global().update_config_with_force(is_mannual_trigger).await {
|
||||
Ok(outcome) if outcome.is_valid() => {
|
||||
logging!(info, Type::Config, "[订阅更新] 更新成功");
|
||||
handle::Handle::refresh_clash();
|
||||
}
|
||||
Ok(outcome @ (ValidationOutcome::Skipped { .. } | ValidationOutcome::Busy)) if !is_mannual_trigger => {
|
||||
|
||||
@@ -23,7 +23,11 @@ pub async fn toggle_system_proxy() -> Option<bool> {
|
||||
&& auto_close_connection
|
||||
&& let Err(err) = handle::Handle::mihomo().close_all_connections().await
|
||||
{
|
||||
logging!(error, Type::ProxyMode, "Failed to close all connections: {err}");
|
||||
logging!(
|
||||
error,
|
||||
Type::ProxyMode,
|
||||
"toggle system proxy: failed to close all connections: {err}"
|
||||
);
|
||||
}
|
||||
|
||||
let requested = !current;
|
||||
@@ -42,7 +46,7 @@ pub async fn toggle_system_proxy() -> Option<bool> {
|
||||
match patch_result {
|
||||
Ok(_) => Some(requested),
|
||||
Err(err) => {
|
||||
logging!(error, Type::ProxyMode, "{err:#}");
|
||||
logging!(error, Type::ProxyMode, "toggle system proxy failed: {err:#}");
|
||||
report_toggle_failure(&err).await;
|
||||
None
|
||||
}
|
||||
@@ -84,7 +88,7 @@ pub async fn toggle_tun_mode(not_save_file: Option<bool>) -> bool {
|
||||
Config::verge().await.latest_arc().enable_tun_mode.unwrap_or(false)
|
||||
}
|
||||
Err(err) => {
|
||||
logging!(error, Type::ProxyMode, "{err:#}");
|
||||
logging!(error, Type::ProxyMode, "toggle tun mode failed: {err:#}");
|
||||
current
|
||||
}
|
||||
}
|
||||
@@ -133,7 +137,7 @@ pub async fn copy_clash_env() {
|
||||
}
|
||||
};
|
||||
|
||||
if clipboard.write_text(&export_text).is_err() {
|
||||
logging!(error, Type::ProxyMode, "Failed to write to clipboard");
|
||||
if let Err(err) = clipboard.write_text(&export_text) {
|
||||
logging!(error, Type::ProxyMode, "Failed to write to clipboard: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,11 +88,11 @@ async fn restore_dns_after_core_stop() -> bool {
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
logging!(info, Type::Window, "DNS设置已恢复");
|
||||
logging!(debug, Type::Window, "DNS设置已恢复");
|
||||
true
|
||||
}
|
||||
Err(_) => {
|
||||
logging!(warn, Type::Window, "Warning: 恢复DNS设置超时");
|
||||
logging!(warn, Type::Window, "恢复DNS设置超时");
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,6 @@ pub async fn quit() -> clash_verge_signal::ShutdownOutcome {
|
||||
|
||||
Config::apply_all_and_save_file().await;
|
||||
|
||||
logging!(info, Type::System, "开始异步清理资源");
|
||||
let cleanup_result = clean_async().await;
|
||||
|
||||
logging!(
|
||||
@@ -143,21 +142,12 @@ pub async fn quit() -> clash_verge_signal::ShutdownOutcome {
|
||||
}
|
||||
|
||||
pub async fn clean_async() -> CleanupResult {
|
||||
logging!(
|
||||
info,
|
||||
Type::System,
|
||||
"Starting interactive cleanup; controlled core stop will be awaited to completion"
|
||||
);
|
||||
|
||||
let stop_error = Mutex::new(None);
|
||||
let mut result = run_interactive_cleanup_transition(
|
||||
|| async {
|
||||
logging!(info, Type::System, "Stopping core for interactive quit or restart");
|
||||
logging!(debug, Type::System, "Stopping core for interactive quit or restart");
|
||||
match CoreManager::global().stop_core().await {
|
||||
Ok(()) => {
|
||||
logging!(info, Type::Window, "Core stopped for interactive quit or restart");
|
||||
true
|
||||
}
|
||||
Ok(()) => true,
|
||||
Err(error) => {
|
||||
logging!(
|
||||
warn,
|
||||
@@ -199,13 +189,10 @@ pub async fn clean_session_ending_best_effort() -> CleanupResult {
|
||||
|
||||
let result = run_session_ending_cleanup_transition(
|
||||
|| async {
|
||||
logging!(info, Type::System, "Clearing all WebSocket connections before stopping core");
|
||||
let _ = handle::Handle::mihomo().clear_all_ws_connections();
|
||||
logging!(info, Type::System, "Stopping core during session-ending best-effort cleanup");
|
||||
match CoreManager::global().stop_core().await {
|
||||
let _ = handle::Handle::mihomo().clear_all_ws_connections();
|
||||
match CoreManager::global().stop_core().await {
|
||||
Ok(()) => {
|
||||
logging!(info, Type::Window, "Core stopped during session-ending best-effort cleanup");
|
||||
true
|
||||
true
|
||||
}
|
||||
Err(error) => {
|
||||
logging!(
|
||||
|
||||
Reference in New Issue
Block a user