mirror of https://github.com/jackwener/wx-cli.git
fix: initialize tracing only in daemon mode, tee to daemon.log
- Move init_logging() into daemon-only branch — CLI path doesn't need tracing and WARN-level output could corrupt JSON/YAML stdout - Add TeeWriter that duplicates tracing output to both stderr and ~/.wx-cli/daemon.log, ensuring direct invocation (WX_DAEMON_MODE=1 without 'wx daemon start') also writes to the log file - Keep run_start() stderr redirect as primary path; file writer is a safety net for edge-case direct launchespull/43/head
parent
3afb88920c
commit
eebc9e97b7
61
src/main.rs
61
src/main.rs
|
|
@ -18,38 +18,61 @@ fn main() {
|
|||
|
||||
fn init_logging() {
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use std::sync::{Arc, Mutex, OnceLock};
|
||||
use std::fs::File;
|
||||
|
||||
// CLI 路径不需要 tracing — 只输出用户可见的 stdout/stderr。
|
||||
// daemon 路径:tracing 直接写入 ~/.wx-cli/daemon.log,
|
||||
// 不依赖父进程的 stderr 重定向(避免重复写入)。
|
||||
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
|
||||
EnvFilter::new("info")
|
||||
});
|
||||
|
||||
// daemon 路径:stderr 已通过 run_start() 重定向到 daemon.log,
|
||||
// 但我们也直接写入日志文件以覆盖直接设置 WX_DAEMON_MODE=1 的情况。
|
||||
static LOG_FILE: OnceLock<Arc<Mutex<Option<File>>>> = OnceLock::new();
|
||||
let file_entry = LOG_FILE.get_or_init(|| {
|
||||
let _ = std::fs::create_dir_all(config::cli_dir());
|
||||
let log_file = std::fs::OpenOptions::new()
|
||||
Arc::new(Mutex::new(
|
||||
std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(config::log_path())
|
||||
.ok();
|
||||
.ok(),
|
||||
))
|
||||
});
|
||||
|
||||
match log_file {
|
||||
Some(file) => {
|
||||
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
|
||||
EnvFilter::new("warn")
|
||||
});
|
||||
tracing_subscriber::fmt()
|
||||
.with_target(false)
|
||||
.with_level(true)
|
||||
.with_env_filter(env_filter)
|
||||
.with_writer(file)
|
||||
.init();
|
||||
.with_writer(move || {
|
||||
let file_entry = Arc::clone(file_entry);
|
||||
let guard = file_entry.lock().unwrap();
|
||||
let b: Box<dyn std::io::Write + Send> = guard
|
||||
.as_ref()
|
||||
.and_then(|f| f.try_clone().ok())
|
||||
.map(|f| Box::new(f) as Box<dyn std::io::Write + Send>)
|
||||
.unwrap_or_else(|| Box::new(std::io::stderr()));
|
||||
TeeWriter {
|
||||
a: Box::new(std::io::stderr()),
|
||||
b,
|
||||
}
|
||||
None => {
|
||||
// 文件打开失败时退回到 stderr,确保日志不会静默丢失
|
||||
tracing_subscriber::fmt()
|
||||
.with_target(false)
|
||||
.with_level(true)
|
||||
.with_env_filter(env_filter)
|
||||
.with_writer(std::io::stderr)
|
||||
})
|
||||
.init();
|
||||
}
|
||||
|
||||
/// 同时写入两个 Write 目标
|
||||
struct TeeWriter {
|
||||
a: Box<dyn std::io::Write + Send>,
|
||||
b: Box<dyn std::io::Write + Send>,
|
||||
}
|
||||
|
||||
impl std::io::Write for TeeWriter {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
let _ = self.b.write_all(buf);
|
||||
self.a.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
let _ = self.b.flush();
|
||||
self.a.flush()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue