mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-15 04:40:40 -07:00
Enhance server startup logging and error handling
- Implemented detailed logging for server startup in server.py, including Python version, executable path, and parsed arguments. - Added error handling for module imports and server initialization to improve robustness. - Introduced an Entitlements.plist file for macOS to manage security settings. - Updated tauri.conf.json to reference the new Entitlements.plist. - Enhanced error reporting in main.rs for better debugging during server process management.
This commit is contained in:
+71
-36
@@ -5,45 +5,80 @@ This module provides an entry point that works with PyInstaller by using
|
||||
absolute imports instead of relative imports.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import uvicorn
|
||||
import sys
|
||||
import logging
|
||||
|
||||
# Import the FastAPI app from the backend package
|
||||
from backend.main import app
|
||||
from backend import config, database
|
||||
# Set up logging FIRST, before any imports that might fail
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
stream=sys.stderr, # Log to stderr so it's captured by Tauri
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Log startup immediately to confirm binary execution
|
||||
logger.info("=" * 60)
|
||||
logger.info("voicebox-server starting up...")
|
||||
logger.info(f"Python version: {sys.version}")
|
||||
logger.info(f"Executable: {sys.executable}")
|
||||
logger.info(f"Arguments: {sys.argv}")
|
||||
logger.info("=" * 60)
|
||||
|
||||
try:
|
||||
import argparse
|
||||
import uvicorn
|
||||
logger.info("Standard library imports successful")
|
||||
|
||||
# Import the FastAPI app from the backend package
|
||||
logger.info("Importing backend modules...")
|
||||
from backend.main import app
|
||||
from backend import config, database
|
||||
logger.info("Backend imports successful")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to import required modules: {e}", exc_info=True)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="voicebox backend server")
|
||||
parser.add_argument(
|
||||
"--host",
|
||||
type=str,
|
||||
default="127.0.0.1",
|
||||
help="Host to bind to (use 0.0.0.0 for remote access)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--port",
|
||||
type=int,
|
||||
default=8000,
|
||||
help="Port to bind to",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--data-dir",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Data directory for database, profiles, and generated audio",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
parser = argparse.ArgumentParser(description="voicebox backend server")
|
||||
parser.add_argument(
|
||||
"--host",
|
||||
type=str,
|
||||
default="127.0.0.1",
|
||||
help="Host to bind to (use 0.0.0.0 for remote access)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--port",
|
||||
type=int,
|
||||
default=8000,
|
||||
help="Port to bind to",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--data-dir",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Data directory for database, profiles, and generated audio",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
logger.info(f"Parsed arguments: host={args.host}, port={args.port}, data_dir={args.data_dir}")
|
||||
|
||||
# Set data directory if provided
|
||||
if args.data_dir:
|
||||
config.set_data_dir(args.data_dir)
|
||||
# Set data directory if provided
|
||||
if args.data_dir:
|
||||
logger.info(f"Setting data directory to: {args.data_dir}")
|
||||
config.set_data_dir(args.data_dir)
|
||||
|
||||
# Initialize database after data directory is set
|
||||
database.init_db()
|
||||
# Initialize database after data directory is set
|
||||
logger.info("Initializing database...")
|
||||
database.init_db()
|
||||
logger.info("Database initialized successfully")
|
||||
|
||||
uvicorn.run(
|
||||
app,
|
||||
host=args.host,
|
||||
port=args.port,
|
||||
log_level="info",
|
||||
)
|
||||
logger.info(f"Starting uvicorn server on {args.host}:{args.port}...")
|
||||
uvicorn.run(
|
||||
app,
|
||||
host=args.host,
|
||||
port=args.port,
|
||||
log_level="info",
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Server startup failed: {e}", exc_info=True)
|
||||
sys.exit(1)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
Binary file not shown.
@@ -31,10 +31,21 @@ async fn start_server(
|
||||
std::fs::create_dir_all(&data_dir)
|
||||
.map_err(|e| format!("Failed to create data dir: {}", e))?;
|
||||
|
||||
println!("=================================================================");
|
||||
println!("Starting voicebox-server sidecar");
|
||||
println!("Data directory: {:?}", data_dir);
|
||||
println!("Remote mode: {}", remote.unwrap_or(false));
|
||||
|
||||
let mut sidecar = app
|
||||
.shell()
|
||||
.sidecar("voicebox-server")
|
||||
.map_err(|e| format!("Failed to get sidecar: {}", e))?;
|
||||
.map_err(|e| {
|
||||
eprintln!("Failed to get sidecar: {}", e);
|
||||
eprintln!("This usually means the binary is not bundled correctly or doesn't have execute permissions");
|
||||
format!("Failed to get sidecar: {}", e)
|
||||
})?;
|
||||
|
||||
println!("Sidecar command created successfully");
|
||||
|
||||
// Pass data directory to Python server
|
||||
sidecar = sidecar.args([
|
||||
@@ -48,9 +59,21 @@ async fn start_server(
|
||||
sidecar = sidecar.args(["--host", "0.0.0.0"]);
|
||||
}
|
||||
|
||||
println!("Spawning server process...");
|
||||
let (mut rx, child) = sidecar
|
||||
.spawn()
|
||||
.map_err(|e| format!("Failed to spawn: {}", e))?;
|
||||
.map_err(|e| {
|
||||
eprintln!("Failed to spawn server process: {}", e);
|
||||
eprintln!("This could be due to:");
|
||||
eprintln!(" - Missing or corrupted binary");
|
||||
eprintln!(" - Missing execute permissions");
|
||||
eprintln!(" - Code signing issues on macOS");
|
||||
eprintln!(" - Missing dependencies");
|
||||
format!("Failed to spawn: {}", e)
|
||||
})?;
|
||||
|
||||
println!("Server process spawned, waiting for ready signal...");
|
||||
println!("=================================================================");
|
||||
|
||||
// Store child process
|
||||
*state.child.lock().unwrap() = Some(child);
|
||||
@@ -58,10 +81,18 @@ async fn start_server(
|
||||
// Wait for server to be ready by listening for startup log
|
||||
let timeout = tokio::time::Duration::from_secs(30);
|
||||
let start_time = tokio::time::Instant::now();
|
||||
let mut error_output = Vec::new();
|
||||
|
||||
loop {
|
||||
if start_time.elapsed() > timeout {
|
||||
return Err("Server startup timeout".to_string());
|
||||
eprintln!("Server startup timeout after 30 seconds");
|
||||
if !error_output.is_empty() {
|
||||
eprintln!("Collected error output:");
|
||||
for line in &error_output {
|
||||
eprintln!(" {}", line);
|
||||
}
|
||||
}
|
||||
return Err("Server startup timeout - check Console.app for detailed logs".to_string());
|
||||
}
|
||||
|
||||
match tokio::time::timeout(tokio::time::Duration::from_millis(100), rx.recv()).await {
|
||||
@@ -77,9 +108,14 @@ async fn start_server(
|
||||
}
|
||||
}
|
||||
tauri_plugin_shell::process::CommandEvent::Stderr(line) => {
|
||||
let line_str = String::from_utf8_lossy(&line);
|
||||
let line_str = String::from_utf8_lossy(&line).to_string();
|
||||
eprintln!("Server: {}", line_str);
|
||||
|
||||
// Collect error lines for debugging
|
||||
if line_str.contains("ERROR") || line_str.contains("Error") || line_str.contains("Failed") {
|
||||
error_output.push(line_str.clone());
|
||||
}
|
||||
|
||||
// Uvicorn logs to stderr, so check there too
|
||||
if line_str.contains("Uvicorn running") || line_str.contains("Application startup complete") {
|
||||
println!("Server is ready!");
|
||||
@@ -90,6 +126,9 @@ async fn start_server(
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
eprintln!("Server process ended unexpectedly during startup!");
|
||||
eprintln!("The server binary may have crashed or exited with an error.");
|
||||
eprintln!("Check Console.app logs for more details (search for 'voicebox')");
|
||||
return Err("Server process ended unexpectedly".to_string());
|
||||
}
|
||||
Err(_) => {
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
"macOS": {
|
||||
"frameworks": [],
|
||||
"minimumSystemVersion": "11.0",
|
||||
"infoPlist": "Info.plist"
|
||||
"infoPlist": "Info.plist",
|
||||
"entitlements": "Entitlements.plist"
|
||||
},
|
||||
"resources": {
|
||||
"gen/Assets.car": "./",
|
||||
|
||||
Reference in New Issue
Block a user