Files
clash-verge-rev/src-tauri/src/core/logger.rs
T
Tunglies 2f370d6490 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.
2026-09-08 05:51:04 +08:00

62 lines
2.0 KiB
Rust

use anyhow::Result;
use clash_verge_logging::{LoggerConfig, Type, logging};
use crate::{
core::{CoreManager, manager::RunningMode, service},
utils::dirs,
};
pub use clash_verge_logging::Logger;
const fn should_sync_service_writer(running_mode: RunningMode) -> bool {
matches!(running_mode, RunningMode::Service)
}
async fn logger_config() -> Result<LoggerConfig> {
let (level, max_size, max_count) = {
let verge_guard = crate::config::Config::verge().await;
let verge = verge_guard.latest_arc();
(
verge.get_log_level(),
verge.app_log_max_size.unwrap_or(128),
verge.app_log_max_count.unwrap_or(8),
)
};
Ok(LoggerConfig {
level,
max_size_kb: max_size,
max_count,
log_dir: dirs::app_logs_dir()?,
sidecar_log_dir: dirs::sidecar_log_dir()?,
})
}
/// Initializes the logging stack. The devtools plugin installs its own global
/// subscriber; in that mode only the sidecar writer and panic hook are set up.
pub async fn init() -> Result<()> {
let cfg = logger_config().await?;
#[cfg(not(feature = "tauri-dev"))]
Logger::global().init(&cfg)?;
Logger::global().init_sidecar(&cfg)?;
Ok(())
}
pub async fn update_log_config(log_max_size: u64, log_max_count: usize) -> Result<()> {
Logger::global().update_log_config(log_max_size, log_max_count)?;
// The service writer is auxiliary to the local logger. Synchronize it only
// for an active service session and do not roll back local settings on failure.
if should_sync_service_writer(*CoreManager::global().get_running_mode())
&& let Err(error) = service::update_writer_by_service(&clash_verge_service_ipc::WriterConfig {
directory: String::new(),
max_log_size: log_max_size * 1024,
max_log_files: log_max_count,
})
.await
{
logging!(warn, Type::Service, "failed to update service writer config: {error:#}");
}
Ok(())
}