use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::{EnvFilter, fmt};
pub fn get_log_dir(root: &Path, explicit_db: Option<&Path>) -> PathBuf {
if crate::mcp::server::accepts_root(root, explicit_db) {
code_kb_core::workspace::log_dir(root)
} else {
code_kb_core::get_global_telemetry_dir().join("logs")
}
}
pub fn init_logging(log_dir: &Path, is_serve: bool, verbose: bool) -> Option<WorkerGuard> {
if let Err(e) = fs::create_dir_all(log_dir) {
eprintln!(
"Warning: Failed to create log directory '{}': {e}",
log_dir.display()
);
return None;
}
if let Some(code_kb_dir) = log_dir.parent().filter(|dir| dir.ends_with(".code-kb")) {
let gitignore = code_kb_dir.join(".gitignore");
if let Err(e) = fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(&gitignore)
.and_then(|mut file| file.write_all(b"*\n"))
&& e.kind() != std::io::ErrorKind::AlreadyExists
{
eprintln!(
"Warning: Failed to create ignore file '{}': {e}",
gitignore.display()
);
}
}
let file_appender = match tracing_appender::rolling::RollingFileAppender::builder()
.rotation(tracing_appender::rolling::Rotation::DAILY)
.filename_prefix("code-kb.log")
.max_log_files(7)
.build(log_dir)
{
Ok(appender) => appender,
Err(e) => {
eprintln!("Warning: Failed to initialize rolling file appender: {e}");
return None;
}
};
let (non_blocking_file, guard) = tracing_appender::non_blocking(file_appender);
let default_filter = if verbose {
"code_kb_core=debug,code_kb_cli=debug,code_kb=debug,info"
} else {
"code_kb_core=info,code_kb_cli=info,code_kb=info,warn"
};
let env_filter =
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(default_filter));
let file_layer = fmt::layer()
.with_writer(non_blocking_file)
.with_ansi(false)
.with_target(true)
.with_thread_ids(true)
.with_file(true)
.with_line_number(true);
let stderr_layer = if !is_serve && (verbose || std::env::var_os("RUST_LOG").is_some()) {
Some(
fmt::layer()
.with_writer(std::io::stderr)
.with_ansi(true)
.with_target(false),
)
} else {
None
};
let subscriber = tracing_subscriber::registry()
.with(env_filter)
.with(file_layer)
.with(stderr_layer);
let _ = subscriber.try_init();
Some(guard)
}