Capture sidecar stderr to sidecar.log for crash debugging
All checks were successful
All checks were successful
When the sidecar process exits before sending the ready event, the error message now includes the last 10 lines of stderr. Stderr is captured in a background thread and written to sidecar.log in the app data directory. This helps diagnose why the PyInstaller sidecar fails to start (missing DLLs, import errors, permission issues, etc.). Log location: %APPDATA%\net.anhonesthost.local-transcription\sidecar.log Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -463,11 +463,63 @@ impl SidecarManager {
|
||||
.take()
|
||||
.ok_or("Failed to capture sidecar stdout")?;
|
||||
|
||||
let port = Self::wait_for_ready(stdout)?;
|
||||
// Capture stderr in a background thread so we can log it
|
||||
let stderr = child
|
||||
.stderr
|
||||
.take()
|
||||
.ok_or("Failed to capture sidecar stderr")?;
|
||||
|
||||
self.child = Some(child);
|
||||
self.port = Some(port);
|
||||
Ok(port)
|
||||
let log_dir = DIRS.get().map(|d| d.data_dir.clone());
|
||||
std::thread::spawn(move || {
|
||||
use std::io::BufRead;
|
||||
let reader = std::io::BufReader::new(stderr);
|
||||
let mut log_file = log_dir.and_then(|d| {
|
||||
std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(d.join("sidecar.log"))
|
||||
.ok()
|
||||
});
|
||||
for line in reader.lines() {
|
||||
if let Ok(line) = line {
|
||||
eprintln!("[sidecar-stderr] {}", line);
|
||||
if let Some(ref mut f) = log_file {
|
||||
use std::io::Write;
|
||||
let _ = writeln!(f, "{}", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
match Self::wait_for_ready(stdout) {
|
||||
Ok(port) => {
|
||||
self.child = Some(child);
|
||||
self.port = Some(port);
|
||||
Ok(port)
|
||||
}
|
||||
Err(e) => {
|
||||
// Kill the child if ready failed
|
||||
let _ = child.kill();
|
||||
let _ = child.wait();
|
||||
|
||||
// Read the sidecar.log for context
|
||||
let log_hint = DIRS
|
||||
.get()
|
||||
.and_then(|d| std::fs::read_to_string(d.data_dir.join("sidecar.log")).ok())
|
||||
.and_then(|s| {
|
||||
let lines: Vec<&str> = s.lines().collect();
|
||||
let tail: Vec<&str> = lines.iter().rev().take(10).rev().cloned().collect();
|
||||
if tail.is_empty() { None } else { Some(tail.join("\n")) }
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
if log_hint.is_empty() {
|
||||
Err(e)
|
||||
} else {
|
||||
Err(format!("{e}\n\nSidecar stderr (last 10 lines):\n{log_hint}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stop the sidecar process if running.
|
||||
|
||||
Reference in New Issue
Block a user