From 5bff40e9b47e8dff378fcdbb0e2e2ad8f5170c87 Mon Sep 17 00:00:00 2001 From: Developer Date: Mon, 6 Apr 2026 17:40:16 -0700 Subject: [PATCH] Add debug logging to file and fix blank startup screen - Added write_log Tauri command that writes to frontend.log in app data dir - App.svelte now logs each startup step (Tauri import, sidecar check, launch) - Startup overlays use inline styles as fallback so they're visible even if CSS variables fail to load - Debug status shown on the checking/connecting screens - Rust side logs startup info to app.log (resource dir, data dir) Log files location: %APPDATA%/net.anhonesthost.local-transcription/ (Windows) or ~/Library/Application Support/net.anhonesthost.local-transcription/ (macOS) Co-Authored-By: Claude Opus 4.6 (1M context) --- src-tauri/Cargo.lock | 5 ++++- src-tauri/Cargo.toml | 1 + src-tauri/src/lib.rs | 36 ++++++++++++++++++++++++++++++++- src/App.svelte | 48 +++++++++++++++++++++++++++++++++----------- 4 files changed, 76 insertions(+), 14 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 2452a3b..307ea11 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -316,8 +316,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "iana-time-zone", + "js-sys", "num-traits", "serde", + "wasm-bindgen", "windows-link 0.2.1", ] @@ -1879,9 +1881,10 @@ checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "local-transcription" -version = "1.4.3" +version = "1.4.5" dependencies = [ "bytes", + "chrono", "futures-util", "reqwest 0.12.28", "serde", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 9a0bd17..ddd8bf5 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -24,3 +24,4 @@ futures-util = "0.3" zip = { version = "2", default-features = false, features = ["deflate"] } bytes = "1" tokio = { version = "1", features = ["full"] } +chrono = "0.4" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index a5e677e..28b01f4 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -3,6 +3,26 @@ mod sidecar; use std::sync::Mutex; use tauri::Manager; +/// App log directory, set during setup. +static LOG_DIR: std::sync::OnceLock = std::sync::OnceLock::new(); + +/// Write a log message to the app's log file (for debugging). +#[tauri::command] +fn write_log(message: String) { + if let Some(log_dir) = LOG_DIR.get() { + let log_path = log_dir.join("frontend.log"); + use std::io::Write; + if let Ok(mut f) = std::fs::OpenOptions::new() + .create(true) + .append(true) + .open(&log_path) + { + let _ = writeln!(f, "[{}] {}", chrono::Local::now().format("%H:%M:%S%.3f"), message); + } + } + eprintln!("[frontend] {}", message); +} + #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() @@ -22,9 +42,22 @@ pub fn run() { .app_data_dir() .expect("failed to resolve app data dir"); - // Ensure the data directory exists std::fs::create_dir_all(&data_dir).expect("failed to create app data dir"); + // Set up logging + LOG_DIR.set(data_dir.clone()).ok(); + let log_path = data_dir.join("app.log"); + if let Ok(mut f) = std::fs::OpenOptions::new() + .create(true) + .append(true) + .open(&log_path) + { + use std::io::Write; + let _ = writeln!(f, "\n=== App started at {} ===", chrono::Local::now()); + let _ = writeln!(f, "Resource dir: {}", resource_dir.display()); + let _ = writeln!(f, "Data dir: {}", data_dir.display()); + } + sidecar::init_dirs(resource_dir, data_dir); Ok(()) }) @@ -35,6 +68,7 @@ pub fn run() { sidecar::get_sidecar_port, sidecar::start_sidecar, sidecar::stop_sidecar, + write_log, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src/App.svelte b/src/App.svelte index 1d6b642..df8b878 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -13,6 +13,7 @@ let showSettings = $state(false); let sidecarState = $state("checking"); + let debugLog = $state(""); let obsDisplayUrl = $derived(backendStore.obsUrl); let syncDisplayUrl = $derived(backendStore.syncUrl); @@ -27,13 +28,25 @@ showSettings = false; } + let tauriInvoke: ((cmd: string, args?: Record) => Promise) | null = null; + + function log(msg: string) { + console.log(`[App] ${msg}`); + debugLog = msg; + // Also write to file via Tauri if available + tauriInvoke?.("write_log", { message: msg }); + } + async function checkAndLaunchSidecar() { try { + log("Importing Tauri API..."); const { invoke } = await import("@tauri-apps/api/core"); + tauriInvoke = invoke; - // Check if sidecar is installed + log("Checking if sidecar is installed..."); sidecarState = "checking"; const installed = await invoke("check_sidecar"); + log(`Sidecar installed: ${installed}`); if (!installed) { sidecarState = "needs_setup"; @@ -41,9 +54,10 @@ } await launchSidecar(); - } catch { + } catch (err) { // Not running in Tauri (browser dev mode) - skip sidecar check // and connect directly to localhost:8081 + log(`Tauri not available (${err}), using dev mode`); sidecarState = "starting"; backendStore.setPort(8081); backendStore.connect(); @@ -55,15 +69,19 @@ try { const { invoke } = await import("@tauri-apps/api/core"); + log("Starting sidecar..."); sidecarState = "starting"; await invoke("start_sidecar"); + log("Getting sidecar port..."); const port = await invoke("get_sidecar_port"); + log(`Sidecar ready on port ${port}`); backendStore.setPort(port); backendStore.connect(); configStore.loadConfig(); - } catch { + } catch (err) { // If sidecar launch fails, still try connecting to default port + log(`Sidecar launch failed: ${err}, trying default port`); sidecarState = "starting"; backendStore.connect(); configStore.loadConfig(); @@ -84,13 +102,16 @@ {#if sidecarState === "checking"} -
-
+
+
-

Local Transcription

-

Checking setup...

+

Local Transcription

+

Checking setup...

+ {#if debugLog} +

{debugLog}

+ {/if}
@@ -98,8 +119,8 @@ {:else if !isConnected} -
-
+
+
{#if connectionState === "error"} @@ -111,13 +132,16 @@
{/if}
-

Local Transcription

+

Local Transcription

{#if connectionState === "error"} -

Cannot connect to backend

+

Cannot connect to backend

Make sure the Python backend is running:
uv run python -m backend.main_headless

{:else} -

Connecting to backend...

+

Connecting to backend...

+ {/if} + {#if debugLog} +

{debugLog}

{/if}