diff --git a/frontend/src-tauri/src/commands/backend.rs b/frontend/src-tauri/src/commands/backend.rs index 0149ccd78..df0b6a877 100644 --- a/frontend/src-tauri/src/commands/backend.rs +++ b/frontend/src-tauri/src/commands/backend.rs @@ -112,9 +112,18 @@ fn normalize_path(path: &PathBuf) -> PathBuf { // Create, configure and run the Java command to run Stirling-PDF JAR fn run_stirling_pdf_jar(app: &tauri::AppHandle, java_path: &PathBuf, jar_path: &PathBuf) -> Result<(), String> { - // Configure logging to write outside src-tauri to prevent dev server restarts - let temp_dir = std::env::temp_dir(); - let log_dir = temp_dir.join("stirling-pdf-logs"); + // Get platform-specific log directory + let log_dir = if cfg!(target_os = "macos") { + let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string()); + PathBuf::from(home).join("Library").join("Logs").join("Stirling-PDF").join("backend") + } else if cfg!(target_os = "windows") { + let appdata = std::env::var("APPDATA").unwrap_or_else(|_| std::env::temp_dir().to_string_lossy().to_string()); + PathBuf::from(appdata).join("Stirling-PDF").join("backend-logs") + } else { + let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string()); + PathBuf::from(home).join(".config").join("Stirling-PDF").join("backend-logs") + }; + std::fs::create_dir_all(&log_dir).ok(); // Create log directory if it doesn't exist // Define all Java options in an array @@ -132,12 +141,39 @@ fn run_stirling_pdf_jar(app: &tauri::AppHandle, java_path: &PathBuf, jar_path: & // Log the equivalent command for external testing let java_command = format!( - "TAURI_PARENT_PID={} && \"{}\" {}", + "TAURI_PARENT_PID={} \"{}\" {}", std::process::id(), java_path.display(), java_options.join(" ") ); add_log(format!("🔧 Equivalent command: {}", java_command)); + add_log(format!("📁 Backend logs will be in: {}", log_dir.display())); + + // Additional macOS-specific checks + if cfg!(target_os = "macos") { + // Check if java executable has execute permissions + if let Ok(metadata) = std::fs::metadata(java_path) { + let permissions = metadata.permissions(); + add_log(format!("🔍 Java executable permissions: {:?}", permissions)); + + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mode = permissions.mode(); + add_log(format!("🔍 Java executable mode: 0o{:o}", mode)); + if mode & 0o111 == 0 { + add_log("⚠️ Java executable may not have execute permissions".to_string()); + } + } + } + + // Check if we can read the JAR file + if let Ok(metadata) = std::fs::metadata(jar_path) { + add_log(format!("📦 JAR file size: {} bytes", metadata.len())); + } else { + add_log("⚠️ Cannot read JAR file metadata".to_string()); + } + } let sidecar_command = app .shell() diff --git a/frontend/src-tauri/src/utils/logging.rs b/frontend/src-tauri/src/utils/logging.rs index c5c0fccab..7d97bc986 100644 --- a/frontend/src-tauri/src/utils/logging.rs +++ b/frontend/src-tauri/src/utils/logging.rs @@ -1,20 +1,89 @@ use std::sync::Mutex; use std::collections::VecDeque; +use std::fs::OpenOptions; +use std::io::Write; +use std::path::PathBuf; // Store backend logs globally static BACKEND_LOGS: Mutex> = Mutex::new(VecDeque::new()); +// Get platform-specific log directory +fn get_log_directory() -> PathBuf { + if cfg!(target_os = "macos") { + // macOS: ~/Library/Logs/Stirling-PDF + let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string()); + PathBuf::from(home).join("Library").join("Logs").join("Stirling-PDF") + } else if cfg!(target_os = "windows") { + // Windows: %APPDATA%\Stirling-PDF\logs + let appdata = std::env::var("APPDATA").unwrap_or_else(|_| std::env::temp_dir().to_string_lossy().to_string()); + PathBuf::from(appdata).join("Stirling-PDF").join("logs") + } else { + // Linux: ~/.config/Stirling-PDF/logs + let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string()); + PathBuf::from(home).join(".config").join("Stirling-PDF").join("logs") + } +} + // Helper function to add log entry pub fn add_log(message: String) { + let timestamp = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs(); - let mut logs = BACKEND_LOGS.lock().unwrap(); - logs.push_back(format!("{}: {}", std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(), message)); - // Keep only last 100 log entries - if logs.len() > 100 { - logs.pop_front(); + let log_entry = format!("{}: {}", timestamp, message); + + // Add to memory logs + { + let mut logs = BACKEND_LOGS.lock().unwrap(); + logs.push_back(log_entry.clone()); + // Keep only last 100 log entries + if logs.len() > 100 { + logs.pop_front(); + } } + // Write to file + write_to_log_file(&log_entry); + // Remove trailing newline if present let clean_message = message.trim_end_matches('\n').to_string(); println!("{}", clean_message); // Also print to console +} + +// Write log entry to file +fn write_to_log_file(log_entry: &str) { + let log_dir = get_log_directory(); + if let Err(e) = std::fs::create_dir_all(&log_dir) { + eprintln!("Failed to create log directory: {}", e); + return; + } + + let log_file = log_dir.join("tauri-backend.log"); + + match OpenOptions::new() + .create(true) + .append(true) + .open(&log_file) + { + Ok(mut file) => { + if let Err(e) = writeln!(file, "{}", log_entry) { + eprintln!("Failed to write to log file: {}", e); + } + } + Err(e) => { + eprintln!("Failed to open log file {:?}: {}", log_file, e); + } + } +} + +// Get current logs for debugging +pub fn get_logs() -> Vec { + let logs = BACKEND_LOGS.lock().unwrap(); + logs.iter().cloned().collect() +} + +// Get log file path for external access +pub fn get_log_file_path() -> PathBuf { + get_log_directory().join("tauri-backend.log") } \ No newline at end of file