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
79
src/main.rs
79
src/main.rs
|
|
@ -18,38 +18,61 @@ fn main() {
|
||||||
|
|
||||||
fn init_logging() {
|
fn init_logging() {
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
use std::sync::{Arc, Mutex, OnceLock};
|
||||||
|
use std::fs::File;
|
||||||
|
|
||||||
// CLI 路径不需要 tracing — 只输出用户可见的 stdout/stderr。
|
// CLI 路径不需要 tracing — 只输出用户可见的 stdout/stderr。
|
||||||
// daemon 路径:tracing 直接写入 ~/.wx-cli/daemon.log,
|
// daemon 路径:stderr 已通过 run_start() 重定向到 daemon.log,
|
||||||
// 不依赖父进程的 stderr 重定向(避免重复写入)。
|
// 但我们也直接写入日志文件以覆盖直接设置 WX_DAEMON_MODE=1 的情况。
|
||||||
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
|
static LOG_FILE: OnceLock<Arc<Mutex<Option<File>>>> = OnceLock::new();
|
||||||
EnvFilter::new("info")
|
let file_entry = LOG_FILE.get_or_init(|| {
|
||||||
|
let _ = std::fs::create_dir_all(config::cli_dir());
|
||||||
|
Arc::new(Mutex::new(
|
||||||
|
std::fs::OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.append(true)
|
||||||
|
.open(config::log_path())
|
||||||
|
.ok(),
|
||||||
|
))
|
||||||
});
|
});
|
||||||
|
|
||||||
let _ = std::fs::create_dir_all(config::cli_dir());
|
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
|
||||||
let log_file = std::fs::OpenOptions::new()
|
EnvFilter::new("warn")
|
||||||
.create(true)
|
});
|
||||||
.append(true)
|
tracing_subscriber::fmt()
|
||||||
.open(config::log_path())
|
.with_target(false)
|
||||||
.ok();
|
.with_level(true)
|
||||||
|
.with_env_filter(env_filter)
|
||||||
|
.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,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.init();
|
||||||
|
}
|
||||||
|
|
||||||
match log_file {
|
/// 同时写入两个 Write 目标
|
||||||
Some(file) => {
|
struct TeeWriter {
|
||||||
tracing_subscriber::fmt()
|
a: Box<dyn std::io::Write + Send>,
|
||||||
.with_target(false)
|
b: Box<dyn std::io::Write + Send>,
|
||||||
.with_level(true)
|
}
|
||||||
.with_env_filter(env_filter)
|
|
||||||
.with_writer(file)
|
impl std::io::Write for TeeWriter {
|
||||||
.init();
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
}
|
let _ = self.b.write_all(buf);
|
||||||
None => {
|
self.a.write(buf)
|
||||||
// 文件打开失败时退回到 stderr,确保日志不会静默丢失
|
}
|
||||||
tracing_subscriber::fmt()
|
|
||||||
.with_target(false)
|
fn flush(&mut self) -> std::io::Result<()> {
|
||||||
.with_level(true)
|
let _ = self.b.flush();
|
||||||
.with_env_filter(env_filter)
|
self.a.flush()
|
||||||
.with_writer(std::io::stderr)
|
|
||||||
.init();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue