mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-09 20:02:20 +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:
@@ -43,7 +43,11 @@ impl IClashTemp {
|
||||
Self(Self::guard(map))
|
||||
}
|
||||
Err(err) => {
|
||||
logging!(error, Type::Config, "{err}");
|
||||
logging!(
|
||||
error,
|
||||
Type::Config,
|
||||
"failed to load clash config, using template: {err:#}"
|
||||
);
|
||||
Self::template()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,16 +144,16 @@ impl Config {
|
||||
.await?;
|
||||
return Ok(Some(("config_validate::boot_error", error_msg)));
|
||||
}
|
||||
logging!(info, Type::Config, "生成运行时配置成功");
|
||||
logging!(debug, Type::Config, "生成运行时配置成功");
|
||||
|
||||
let config_result = Self::generate_file(ConfigType::Run).await;
|
||||
|
||||
if config_result.is_ok() {
|
||||
logging!(info, Type::Config, "开始验证配置");
|
||||
logging!(debug, Type::Config, "开始验证配置");
|
||||
|
||||
match CoreConfigValidator::global().validate_config_outcome().await {
|
||||
Ok(outcome) if outcome.is_valid() => {
|
||||
logging!(info, Type::Config, "配置验证成功");
|
||||
logging!(debug, Type::Config, "配置验证成功");
|
||||
Ok(None)
|
||||
}
|
||||
Ok(outcome) => {
|
||||
@@ -170,7 +170,7 @@ impl Config {
|
||||
Ok(Some(("config_validate::boot_error", error_msg)))
|
||||
}
|
||||
Err(err) => {
|
||||
logging!(warn, Type::Config, "验证过程执行失败: {}", err);
|
||||
logging!(warn, Type::Config, "验证过程执行失败: {err:#}");
|
||||
CoreManager::global()
|
||||
.use_default_config("config_validate::process_terminated", "")
|
||||
.await?;
|
||||
@@ -178,7 +178,8 @@ impl Config {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logging!(warn, Type::Config, "生成配置文件失败,使用默认配置");
|
||||
let error_msg = config_result.err().map(|err| err.to_string()).unwrap_or_default();
|
||||
logging!(warn, Type::Config, "生成配置文件失败,使用默认配置: {error_msg}");
|
||||
CoreManager::global()
|
||||
.use_default_config("config_validate::error", "")
|
||||
.await?;
|
||||
@@ -250,13 +251,13 @@ impl Config {
|
||||
.retry(backoff)
|
||||
.await
|
||||
{
|
||||
logging!(error, Type::Setup, "Config init verification failed: {}", e);
|
||||
logging!(error, Type::Setup, "Config init verification failed: {e:#}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Commits drafts during exit/restart/shutdown so user changes are not lost.
|
||||
pub async fn apply_all_and_save_file() {
|
||||
logging!(info, Type::Config, "save all draft data");
|
||||
logging!(debug, Type::Config, "save all draft data");
|
||||
let save_clash_task = AsyncHandler::spawn(|| async {
|
||||
let clash = Self::clash().await;
|
||||
clash.apply();
|
||||
|
||||
@@ -262,7 +262,7 @@ async fn owned_service_core_uses_port(port: u16) -> bool {
|
||||
logging!(
|
||||
warn,
|
||||
Type::Service,
|
||||
"Current user's service core is active but its mixed proxy port is unavailable: {error}; \
|
||||
"Current user's service core is active but its mixed proxy port is unavailable: {error:#}; \
|
||||
preserving the selected port until core replacement resolves ownership"
|
||||
);
|
||||
true
|
||||
|
||||
@@ -93,7 +93,7 @@ impl IProfiles {
|
||||
let path = match dirs::profiles_path() {
|
||||
Ok(p) => p,
|
||||
Err(err) => {
|
||||
logging!(error, Type::Config, "{err}");
|
||||
logging!(error, Type::Config, "failed to get profiles path: {err:#}");
|
||||
return Self::default();
|
||||
}
|
||||
};
|
||||
@@ -124,12 +124,12 @@ impl IProfiles {
|
||||
}
|
||||
|
||||
if home_changed && let Err(err) = profiles.save_file().await {
|
||||
logging!(error, Type::Config, "无法保存已清理的 profiles.yaml: {err}");
|
||||
logging!(error, Type::Config, "无法保存已清理的 profiles.yaml: {err:#}");
|
||||
}
|
||||
profiles
|
||||
}
|
||||
Err(err) => {
|
||||
logging!(error, Type::Config, "{err}");
|
||||
logging!(error, Type::Config, "failed to read profiles.yaml: {err:#}");
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
@@ -599,7 +599,7 @@ async fn fetch_proxies_with_timeout() -> Result<Proxies> {
|
||||
match handle::Handle::mihomo().get_proxies().await {
|
||||
Ok(proxies) => return proxies,
|
||||
Err(err) => {
|
||||
logging!(debug, Type::Config, "mihomo proxies are not ready yet: {err}");
|
||||
logging!(debug, Type::Config, "mihomo proxies are not ready yet: {err:#}");
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
}
|
||||
}
|
||||
@@ -999,7 +999,7 @@ pub(crate) async fn restore_selected_nodes() {
|
||||
}
|
||||
|
||||
fn activate_selected_nodes_with(repair: SelectionRepair) -> tokio::sync::oneshot::Receiver<()> {
|
||||
logging!(info, Type::Config, "starting activating selected nodes");
|
||||
logging!(debug, Type::Config, "starting activating selected nodes");
|
||||
let mut active_task = ACTIVATE_SELECTED_TASK.lock();
|
||||
let generation = ACTIVATE_SELECTED_GENERATION.fetch_add(1, Ordering::AcqRel) + 1;
|
||||
let previous_task = active_task.take();
|
||||
@@ -1043,7 +1043,7 @@ fn activate_selected_nodes_with(repair: SelectionRepair) -> tokio::sync::oneshot
|
||||
handle::Handle::refresh_clash();
|
||||
}
|
||||
update_tray_after_activation(generation).await;
|
||||
logging!(info, Type::Config, "activating selected nodes done!");
|
||||
logging!(debug, Type::Config, "activating selected nodes done!");
|
||||
}
|
||||
});
|
||||
*active_task = Some(handle);
|
||||
|
||||
@@ -262,13 +262,13 @@ impl IVerge {
|
||||
}
|
||||
|
||||
if needs_fix {
|
||||
logging!(info, Type::Config, "正在保存修正后的配置文件...");
|
||||
logging!(debug, Type::Config, "正在保存修正后的配置文件...");
|
||||
help::save_yaml(&config_path, &config, Some("# Clash Verge Config")).await?;
|
||||
logging!(info, Type::Config, "配置文件修正完成,需要重新加载配置");
|
||||
|
||||
Self::reload_config_after_fix(config).await;
|
||||
} else {
|
||||
logging!(info, Type::Config, "clash_core配置验证通过: {:?}", config.clash_core);
|
||||
logging!(debug, Type::Config, "clash_core配置验证通过: {:?}", config.clash_core);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -305,12 +305,12 @@ impl IVerge {
|
||||
config
|
||||
}
|
||||
Err(err) => {
|
||||
logging!(error, Type::Config, "{err}");
|
||||
logging!(error, Type::Config, "failed to read verge config: {err:#}");
|
||||
Self::template()
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
logging!(error, Type::Config, "{err}");
|
||||
logging!(error, Type::Config, "failed to get verge config path: {err:#}");
|
||||
Self::template()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user