Add debug logging to file and fix blank startup screen
All checks were successful
Release / Bump version and tag (push) Successful in 5s
All checks were successful
Release / Bump version and tag (push) Successful in 5s
- 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) <noreply@anthropic.com>
This commit is contained in:
5
src-tauri/Cargo.lock
generated
5
src-tauri/Cargo.lock
generated
@@ -316,8 +316,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"serde",
|
"serde",
|
||||||
|
"wasm-bindgen",
|
||||||
"windows-link 0.2.1",
|
"windows-link 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1879,9 +1881,10 @@ checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "local-transcription"
|
name = "local-transcription"
|
||||||
version = "1.4.3"
|
version = "1.4.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"chrono",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"reqwest 0.12.28",
|
"reqwest 0.12.28",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
@@ -24,3 +24,4 @@ futures-util = "0.3"
|
|||||||
zip = { version = "2", default-features = false, features = ["deflate"] }
|
zip = { version = "2", default-features = false, features = ["deflate"] }
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
chrono = "0.4"
|
||||||
|
|||||||
@@ -3,6 +3,26 @@ mod sidecar;
|
|||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
|
|
||||||
|
/// App log directory, set during setup.
|
||||||
|
static LOG_DIR: std::sync::OnceLock<std::path::PathBuf> = 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)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
@@ -22,9 +42,22 @@ pub fn run() {
|
|||||||
.app_data_dir()
|
.app_data_dir()
|
||||||
.expect("failed to resolve 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");
|
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);
|
sidecar::init_dirs(resource_dir, data_dir);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
@@ -35,6 +68,7 @@ pub fn run() {
|
|||||||
sidecar::get_sidecar_port,
|
sidecar::get_sidecar_port,
|
||||||
sidecar::start_sidecar,
|
sidecar::start_sidecar,
|
||||||
sidecar::stop_sidecar,
|
sidecar::stop_sidecar,
|
||||||
|
write_log,
|
||||||
])
|
])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
let showSettings = $state(false);
|
let showSettings = $state(false);
|
||||||
let sidecarState = $state<SidecarState>("checking");
|
let sidecarState = $state<SidecarState>("checking");
|
||||||
|
let debugLog = $state("");
|
||||||
|
|
||||||
let obsDisplayUrl = $derived(backendStore.obsUrl);
|
let obsDisplayUrl = $derived(backendStore.obsUrl);
|
||||||
let syncDisplayUrl = $derived(backendStore.syncUrl);
|
let syncDisplayUrl = $derived(backendStore.syncUrl);
|
||||||
@@ -27,13 +28,25 @@
|
|||||||
showSettings = false;
|
showSettings = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let tauriInvoke: ((cmd: string, args?: Record<string, unknown>) => Promise<unknown>) | 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() {
|
async function checkAndLaunchSidecar() {
|
||||||
try {
|
try {
|
||||||
|
log("Importing Tauri API...");
|
||||||
const { invoke } = await import("@tauri-apps/api/core");
|
const { invoke } = await import("@tauri-apps/api/core");
|
||||||
|
tauriInvoke = invoke;
|
||||||
|
|
||||||
// Check if sidecar is installed
|
log("Checking if sidecar is installed...");
|
||||||
sidecarState = "checking";
|
sidecarState = "checking";
|
||||||
const installed = await invoke<boolean>("check_sidecar");
|
const installed = await invoke<boolean>("check_sidecar");
|
||||||
|
log(`Sidecar installed: ${installed}`);
|
||||||
|
|
||||||
if (!installed) {
|
if (!installed) {
|
||||||
sidecarState = "needs_setup";
|
sidecarState = "needs_setup";
|
||||||
@@ -41,9 +54,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
await launchSidecar();
|
await launchSidecar();
|
||||||
} catch {
|
} catch (err) {
|
||||||
// Not running in Tauri (browser dev mode) - skip sidecar check
|
// Not running in Tauri (browser dev mode) - skip sidecar check
|
||||||
// and connect directly to localhost:8081
|
// and connect directly to localhost:8081
|
||||||
|
log(`Tauri not available (${err}), using dev mode`);
|
||||||
sidecarState = "starting";
|
sidecarState = "starting";
|
||||||
backendStore.setPort(8081);
|
backendStore.setPort(8081);
|
||||||
backendStore.connect();
|
backendStore.connect();
|
||||||
@@ -55,15 +69,19 @@
|
|||||||
try {
|
try {
|
||||||
const { invoke } = await import("@tauri-apps/api/core");
|
const { invoke } = await import("@tauri-apps/api/core");
|
||||||
|
|
||||||
|
log("Starting sidecar...");
|
||||||
sidecarState = "starting";
|
sidecarState = "starting";
|
||||||
await invoke("start_sidecar");
|
await invoke("start_sidecar");
|
||||||
|
|
||||||
|
log("Getting sidecar port...");
|
||||||
const port = await invoke<number>("get_sidecar_port");
|
const port = await invoke<number>("get_sidecar_port");
|
||||||
|
log(`Sidecar ready on port ${port}`);
|
||||||
backendStore.setPort(port);
|
backendStore.setPort(port);
|
||||||
backendStore.connect();
|
backendStore.connect();
|
||||||
configStore.loadConfig();
|
configStore.loadConfig();
|
||||||
} catch {
|
} catch (err) {
|
||||||
// If sidecar launch fails, still try connecting to default port
|
// If sidecar launch fails, still try connecting to default port
|
||||||
|
log(`Sidecar launch failed: ${err}, trying default port`);
|
||||||
sidecarState = "starting";
|
sidecarState = "starting";
|
||||||
backendStore.connect();
|
backendStore.connect();
|
||||||
configStore.loadConfig();
|
configStore.loadConfig();
|
||||||
@@ -84,13 +102,16 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if sidecarState === "checking"}
|
{#if sidecarState === "checking"}
|
||||||
<div class="connecting-overlay">
|
<div class="connecting-overlay" style="background:#1e1e1e;color:#e0e0e0;display:flex;align-items:center;justify-content:center;height:100%;width:100%;">
|
||||||
<div class="connecting-content">
|
<div class="connecting-content" style="text-align:center;">
|
||||||
<div class="connecting-icon">
|
<div class="connecting-icon">
|
||||||
<div class="spinner"></div>
|
<div class="spinner"></div>
|
||||||
</div>
|
</div>
|
||||||
<h2>Local Transcription</h2>
|
<h2 style="font-size:20px;margin:16px 0 8px;">Local Transcription</h2>
|
||||||
<p>Checking setup...</p>
|
<p style="color:#a0a0a0;font-size:14px;">Checking setup...</p>
|
||||||
|
{#if debugLog}
|
||||||
|
<p style="color:#707070;font-size:11px;margin-top:12px;">{debugLog}</p>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -98,8 +119,8 @@
|
|||||||
<SidecarSetup onComplete={onSidecarReady} />
|
<SidecarSetup onComplete={onSidecarReady} />
|
||||||
|
|
||||||
{:else if !isConnected}
|
{:else if !isConnected}
|
||||||
<div class="connecting-overlay">
|
<div class="connecting-overlay" style="background:#1e1e1e;color:#e0e0e0;display:flex;align-items:center;justify-content:center;height:100%;width:100%;">
|
||||||
<div class="connecting-content">
|
<div class="connecting-content" style="text-align:center;">
|
||||||
<div class="connecting-icon">
|
<div class="connecting-icon">
|
||||||
{#if connectionState === "error"}
|
{#if connectionState === "error"}
|
||||||
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#e74c3c" stroke-width="2">
|
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#e74c3c" stroke-width="2">
|
||||||
@@ -111,13 +132,16 @@
|
|||||||
<div class="spinner"></div>
|
<div class="spinner"></div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<h2>Local Transcription</h2>
|
<h2 style="font-size:20px;margin:16px 0 8px;">Local Transcription</h2>
|
||||||
{#if connectionState === "error"}
|
{#if connectionState === "error"}
|
||||||
<p>Cannot connect to backend</p>
|
<p style="color:#a0a0a0;">Cannot connect to backend</p>
|
||||||
<p class="hint">Make sure the Python backend is running:<br>
|
<p class="hint">Make sure the Python backend is running:<br>
|
||||||
<code>uv run python -m backend.main_headless</code></p>
|
<code>uv run python -m backend.main_headless</code></p>
|
||||||
{:else}
|
{:else}
|
||||||
<p>Connecting to backend...</p>
|
<p style="color:#a0a0a0;">Connecting to backend...</p>
|
||||||
|
{/if}
|
||||||
|
{#if debugLog}
|
||||||
|
<p style="color:#707070;font-size:11px;margin-top:12px;">{debugLog}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user