use crate::config::AppConfig;
use std::fs::OpenOptions;
use std::path::PathBuf;
use tracing_subscriber::prelude::*;
use tracing_subscriber::{filter::Directive, EnvFilter};
fn get_log_file_path(working_dir: &PathBuf) -> Result<PathBuf, Box<dyn std::error::Error>> {
let logs_dir = working_dir.join(".robit").join("logs");
std::fs::create_dir_all(&logs_dir)?;
let date = chrono::Local::now().format("%Y-%m-%d");
let log_file = logs_dir.join(format!("robit-{}.log", date));
Ok(log_file)
}
fn build_filter(
app_config: Option<&AppConfig>,
target_crate: &str,
additional_directives: &[&str],
) -> EnvFilter {
let mut filter = EnvFilter::from_default_env();
if std::env::var("RUST_LOG").is_err() {
let global_level = app_config
.and_then(|c| c.log_level.as_deref())
.unwrap_or("info");
if let Ok(dir) = format!("{}={}", target_crate, global_level).parse() {
filter = filter.add_directive(dir);
}
for robit_crate in &["robit_agent", "robit_chatbot", "robit_ai"] {
if robit_crate != &target_crate {
if let Ok(dir) = format!("{}={}", robit_crate, global_level).parse() {
filter = filter.add_directive(dir);
}
}
}
for dir_str in additional_directives {
if let Ok(dir) = dir_str.parse::<Directive>() {
filter = filter.add_directive(dir);
}
}
for dep_crate in &[
"reqwest",
"hyper",
"hyper_util",
"tungstenite",
"tokio_tungstenite",
"tokio",
"tauri",
] {
if let Ok(dir) = format!("{}=warn", dep_crate).parse() {
filter = filter.add_directive(dir);
}
}
}
filter
}
pub fn init_logging(
app_config: Option<&AppConfig>,
target_crate: &str,
working_dir: &PathBuf,
additional_directives: &[&str],
) {
let filter = build_filter(app_config, target_crate, additional_directives);
let log_file_enabled = app_config.and_then(|c| c.log_file).unwrap_or(false);
if log_file_enabled {
match get_log_file_path(working_dir) {
Ok(log_path) => {
match OpenOptions::new()
.create(true)
.append(true)
.open(&log_path)
{
Ok(file) => {
let file_writer = tracing_subscriber::fmt::writer::MakeWriterExt::with_max_level(file, tracing::Level::TRACE);
let console_layer = tracing_subscriber::fmt::layer()
.with_writer(std::io::stdout)
.with_filter(filter.clone());
let file_layer = tracing_subscriber::fmt::layer()
.with_writer(file_writer)
.with_ansi(false)
.with_filter(filter);
let registry = tracing_subscriber::registry()
.with(console_layer)
.with(file_layer);
registry.init();
tracing::info!("Logging to file: {}", log_path.display());
}
Err(e) => {
eprintln!("Failed to open log file: {}. Falling back to console-only logging.", e);
tracing_subscriber::fmt().with_env_filter(filter).init();
}
}
}
Err(e) => {
eprintln!("Failed to prepare log path: {}. Falling back to console-only logging.", e);
tracing_subscriber::fmt().with_env_filter(filter).init();
}
}
} else {
tracing_subscriber::fmt().with_env_filter(filter).init();
}
}
pub fn init_logging_silent(
app_config: Option<&AppConfig>,
target_crate: &str,
_working_dir: &PathBuf,
additional_directives: &[&str],
) {
let filter = build_filter(app_config, target_crate, additional_directives);
tracing_subscriber::fmt()
.with_env_filter(filter)
.with_writer(std::io::sink)
.init();
}