use std::path::PathBuf; use tracing_appender::rolling::{RollingFileAppender, Rotation}; use tracing_subscriber::{ fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, }; /// Get the default log directory path: ~/.picobot/logs pub fn get_default_log_dir() -> PathBuf { let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from(".")); home.join(".picobot").join("logs") } /// Get the default config file path: ~/.picobot/config.json pub fn get_default_config_path() -> PathBuf { let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from(".")); home.join(".picobot").join("config.json") } /// Initialize logging with file appender /// Logs are written to ~/.picobot/logs/ with daily rotation pub fn init_logging() { let log_dir = get_default_log_dir(); // Create log directory if it doesn't exist if !log_dir.exists() { if let Err(e) = std::fs::create_dir_all(&log_dir) { eprintln!("Warning: Failed to create log directory {}: {}", log_dir.display(), e); } } // Create file appender with daily rotation let file_appender = RollingFileAppender::new( Rotation::DAILY, &log_dir, "picobot.log", ); // Build subscriber with both console and file output let env_filter = EnvFilter::try_from_default_env() .unwrap_or_else(|_| EnvFilter::new("info")); let file_layer = fmt::layer() .with_writer(file_appender) .with_ansi(false) .with_target(true) .with_level(true) .with_thread_ids(true); let console_layer = fmt::layer() .with_target(true) .with_level(true); tracing_subscriber::registry() .with(env_filter) .with(console_layer) .with(file_layer) .init(); tracing::info!("Logging initialized. Log directory: {}", log_dir.display()); } /// Initialize logging without file output (console only) pub fn init_logging_console_only() { let env_filter = EnvFilter::try_from_default_env() .unwrap_or_else(|_| EnvFilter::new("info")); let console_layer = fmt::layer() .with_target(true) .with_level(true); tracing_subscriber::registry() .with(env_filter) .with(console_layer) .init(); tracing::info!("Logging initialized (console only)"); }