diff --git a/packages/cli/src/commands/daemon/local-daemon.ts b/packages/cli/src/commands/daemon/local-daemon.ts index 86e06fa47..f2c92ad1d 100644 --- a/packages/cli/src/commands/daemon/local-daemon.ts +++ b/packages/cli/src/commands/daemon/local-daemon.ts @@ -1,5 +1,5 @@ import { spawn, spawnSync } from "node:child_process"; -import { appendFileSync, existsSync, readFileSync } from "node:fs"; +import { existsSync, readFileSync } from "node:fs"; import { createRequire } from "node:module"; import path from "node:path"; import { loadConfig, resolvePaseoHome } from "@getpaseo/server"; @@ -64,7 +64,6 @@ const DETACHED_STARTUP_GRACE_MS = 1200; const PID_POLL_INTERVAL_MS = 100; const KILL_TIMEOUT_MS = 3000; const DAEMON_LOG_FILENAME = "daemon.log"; -const DAEMON_LAUNCH_LOG_FILENAME = "daemon-launch.log"; const DAEMON_PID_FILENAME = "paseo.pid"; export const DEFAULT_STOP_TIMEOUT_MS = 15_000; @@ -115,24 +114,6 @@ function buildChildEnv(options: DaemonStartOptions): NodeJS.ProcessEnv { return childEnv; } -function appendLaunchLog(home: string, message: string, details?: Record): void { - const line = [ - new Date().toISOString(), - "[CLI daemon]", - `pid=${process.pid}`, - message, - details ? JSON.stringify(details) : "", - ] - .filter((part) => part.length > 0) - .join(" "); - - try { - appendFileSync(path.join(home, DAEMON_LAUNCH_LOG_FILENAME), `${line}\n`, "utf-8"); - } catch { - // Keep launch debugging best-effort so daemon startup behavior is unchanged. - } -} - function resolveDaemonRunnerEntry(): string { const serverExportPath = require.resolve("@getpaseo/server"); let currentDir = path.dirname(serverExportPath); @@ -373,14 +354,6 @@ export async function startLocalDaemonDetached( const paseoHome = resolvePaseoHome(childEnv); const logPath = path.join(paseoHome, DAEMON_LOG_FILENAME); const daemonRunnerEntry = resolveDaemonRunnerEntry(); - appendLaunchLog(paseoHome, "starting detached daemon", { - execPath: process.execPath, - execArgv: process.execArgv, - daemonRunnerEntry, - runnerArgs: buildRunnerArgs(options), - listen: childEnv.PASEO_LISTEN ?? null, - allowedHosts: childEnv.PASEO_ALLOWED_HOSTS ?? null, - }); const child = spawn( process.execPath, [...process.execArgv, daemonRunnerEntry, ...buildRunnerArgs(options)], @@ -391,12 +364,6 @@ export async function startLocalDaemonDetached( }, ); - appendLaunchLog(paseoHome, "detached spawn returned", { - childPid: child.pid ?? null, - spawnfile: child.spawnfile, - spawnargs: child.spawnargs, - }); - child.unref(); const startup = await new Promise((resolve) => { @@ -411,33 +378,16 @@ export async function startLocalDaemonDetached( const timer = setTimeout(() => finish(startupReady()), DETACHED_STARTUP_GRACE_MS); child.once("error", (error) => { - appendLaunchLog(paseoHome, "detached child emitted error during grace period", { - childPid: child.pid ?? null, - message: error.message, - }); clearTimeout(timer); finish(startupExited({ code: null, signal: null, error })); }); child.once("exit", (code, signal) => { - appendLaunchLog(paseoHome, "detached child emitted exit during grace period", { - childPid: child.pid ?? null, - code, - signal, - }); clearTimeout(timer); finish(startupExited({ code, signal })); }); }); - appendLaunchLog(paseoHome, "detached startup grace period completed", { - childPid: child.pid ?? null, - exitedEarly: startup.exitedEarly, - code: startup.exitedEarly ? startup.code : null, - signal: startup.exitedEarly ? startup.signal : null, - error: startup.exitedEarly ? startup.error?.message ?? null : null, - }); - if (startup.exitedEarly) { const reason = startup.error ? startup.error.message diff --git a/packages/desktop/src/daemon/daemon-manager.ts b/packages/desktop/src/daemon/daemon-manager.ts index b70656115..4df565e19 100644 --- a/packages/desktop/src/daemon/daemon-manager.ts +++ b/packages/desktop/src/daemon/daemon-manager.ts @@ -1,7 +1,8 @@ import { spawn, type ChildProcess } from "node:child_process"; -import { appendFileSync, existsSync, readFileSync } from "node:fs"; +import { existsSync, readFileSync } from "node:fs"; import path from "node:path"; import { app, ipcMain } from "electron"; +import log from "electron-log/main"; import { loadConfig, resolvePaseoHome, getOrCreateServerId } from "@getpaseo/server"; import { copyAttachmentFileToManagedStorage, @@ -27,7 +28,6 @@ const STOP_TIMEOUT_MS = 15_000; const KILL_TIMEOUT_MS = 3_000; const DETACHED_STARTUP_GRACE_MS = 1200; const DEFAULT_ELECTRON_DEV_SERVER_URL = "http://localhost:8081"; -const DAEMON_LAUNCH_LOG_FILENAME = "daemon-launch.log"; type DesktopDaemonState = "starting" | "running" | "stopped" | "errored"; @@ -76,10 +76,6 @@ function logFilePath(): string { return path.join(getPaseoHome(), DAEMON_LOG_FILENAME); } -function launchLogFilePath(): string { - return path.join(getPaseoHome(), DAEMON_LAUNCH_LOG_FILENAME); -} - function isProcessRunning(pid: number): boolean { try { process.kill(pid, 0); @@ -145,22 +141,11 @@ function tailFile(filePath: string, lines = 50): string { } } -function appendLaunchLog(message: string, details?: Record): void { - const line = [ - new Date().toISOString(), - "[desktop daemon]", - `pid=${process.pid}`, - message, - details ? JSON.stringify(details) : "", - ] - .filter((part) => part.length > 0) - .join(" "); - - try { - appendFileSync(launchLogFilePath(), `${line}\n`, "utf-8"); - } catch { - // Keep launch debugging best-effort so desktop startup behavior is unchanged. - } +function logDesktopDaemonLifecycle(message: string, details?: Record): void { + log.info("[desktop daemon]", message, { + pid: process.pid, + ...(details ?? {}), + }); } function buildDesktopDaemonCorsOriginsEnv(): string | undefined { @@ -326,7 +311,7 @@ async function startDaemon(): Promise { }, }); - appendLaunchLog("starting detached daemon", { + logDesktopDaemonLifecycle("starting detached daemon", { appIsPackaged: app.isPackaged, daemonRunnerEntry: daemonRunner.entryPath, daemonRunnerExecArgv: daemonRunner.execArgv, @@ -346,7 +331,7 @@ async function startDaemon(): Promise { }, ); - appendLaunchLog("detached spawn returned", { + logDesktopDaemonLifecycle("detached spawn returned", { childPid: child.pid ?? null, spawnfile: child.spawnfile, spawnargs: child.spawnargs, @@ -366,14 +351,14 @@ async function startDaemon(): Promise { const timer = setTimeout(() => finish(false), DETACHED_STARTUP_GRACE_MS); child.once("error", () => { - appendLaunchLog("detached child emitted error during grace period", { + logDesktopDaemonLifecycle("detached child emitted error during grace period", { childPid: child.pid ?? null, }); clearTimeout(timer); finish(true); }); child.once("exit", () => { - appendLaunchLog("detached child emitted exit during grace period", { + logDesktopDaemonLifecycle("detached child emitted exit during grace period", { childPid: child.pid ?? null, }); clearTimeout(timer); @@ -381,7 +366,7 @@ async function startDaemon(): Promise { }); }); - appendLaunchLog("detached startup grace period completed", { + logDesktopDaemonLifecycle("detached startup grace period completed", { childPid: child.pid ?? null, exitedEarly, }); @@ -395,7 +380,7 @@ async function startDaemon(): Promise { for (let attempt = 0; attempt < STARTUP_POLL_MAX_ATTEMPTS; attempt++) { const status = resolveStatus(); if (attempt === 0 || attempt === STARTUP_POLL_MAX_ATTEMPTS - 1 || attempt % 10 === 9) { - appendLaunchLog("polling daemon status after detached start", { + logDesktopDaemonLifecycle("polling daemon status after detached start", { attempt: attempt + 1, status: status.status, pid: status.pid, diff --git a/packages/server/scripts/daemon-runner.ts b/packages/server/scripts/daemon-runner.ts index fc02ceaac..db6d660e2 100644 --- a/packages/server/scripts/daemon-runner.ts +++ b/packages/server/scripts/daemon-runner.ts @@ -1,5 +1,5 @@ import { fileURLToPath } from "url"; -import { appendFileSync, existsSync } from "node:fs"; +import { existsSync } from "node:fs"; import path from "node:path"; import { loadConfig } from "../src/server/config.js"; import { acquirePidLock, PidLockError, releasePidLock } from "../src/server/pid-lock.js"; @@ -68,28 +68,6 @@ function resolvePackagedNodeEntrypointRunnerPath(currentScriptPath: string): str return existsSync(runnerPath) ? runnerPath : null; } -function appendLaunchLog( - launchLogPath: string, - message: string, - details?: Record, -): void { - const line = [ - new Date().toISOString(), - "[DaemonRunner]", - `pid=${process.pid}`, - message, - details ? JSON.stringify(details) : "", - ] - .filter((part) => part.length > 0) - .join(" "); - - try { - appendFileSync(launchLogPath, `${line}\n`, "utf-8"); - } catch { - // Keep launch debugging best-effort so daemon startup behavior is unchanged. - } -} - async function main(): Promise { const config = parseConfig(process.argv.slice(2)); const workerEntry = config.devMode ? resolveDevWorkerEntry() : resolveWorkerEntry(); @@ -106,34 +84,14 @@ async function main(): Promise { applySherpaLoaderEnv(workerEnv); const paseoHome = resolvePaseoHome(workerEnv); - const launchLogPath = path.join(paseoHome, "daemon-launch.log"); const daemonConfig = loadConfig(paseoHome, { env: workerEnv }); - appendLaunchLog(launchLogPath, "daemon runner starting", { - argv: process.argv.slice(2), - execPath: process.execPath, - execArgv: process.execArgv, - workerEntry, - workerExecArgv, - devMode: config.devMode, - listen: daemonConfig.listen, - packagedNodeEntrypointRunner, - }); - try { await acquirePidLock(paseoHome, daemonConfig.listen, { ownerPid: process.pid, }); - appendLaunchLog(launchLogPath, "pid lock acquired", { - ownerPid: process.pid, - listen: daemonConfig.listen, - }); } catch (error) { if (error instanceof PidLockError) { - appendLaunchLog(launchLogPath, "pid lock acquisition failed", { - message: error.message, - existingLock: error.existingLock, - }); process.stderr.write(`${error.message}\n`); process.exit(1); return; @@ -147,9 +105,6 @@ async function main(): Promise { return; } lockReleased = true; - appendLaunchLog(launchLogPath, "releasing pid lock", { - ownerPid: process.pid, - }); await releasePidLock(paseoHome, { ownerPid: process.pid, }); @@ -157,7 +112,6 @@ async function main(): Promise { runSupervisor({ name: "DaemonRunner", - launchLogPath, startupMessage: config.devMode ? "Starting daemon worker (dev mode, crash restarts enabled)" : "Starting daemon worker (IPC restart enabled)", diff --git a/packages/server/scripts/supervisor.ts b/packages/server/scripts/supervisor.ts index bc863f75b..b661371ab 100644 --- a/packages/server/scripts/supervisor.ts +++ b/packages/server/scripts/supervisor.ts @@ -1,5 +1,4 @@ import { fork, spawn, type ChildProcess } from "child_process"; -import { appendFileSync } from "node:fs"; type WorkerLifecycleMessage = | { @@ -13,7 +12,6 @@ type WorkerLifecycleMessage = type SupervisorOptions = { name: string; startupMessage: string; - launchLogPath?: string; resolveWorkerEntry: () => string; workerArgs?: string[]; workerEnv?: NodeJS.ProcessEnv; @@ -65,28 +63,6 @@ export function runSupervisor(options: SupervisorOptions): void { process.stderr.write(`[${options.name}] ${message}\n`); }; - const logLaunch = (message: string, details?: Record): void => { - if (!options.launchLogPath) { - return; - } - - const line = [ - new Date().toISOString(), - `[${options.name}]`, - `pid=${process.pid}`, - message, - details ? JSON.stringify(details) : "", - ] - .filter((part) => part.length > 0) - .join(" "); - - try { - appendFileSync(options.launchLogPath, `${line}\n`, "utf-8"); - } catch { - // Keep launch debugging best-effort so daemon startup behavior is unchanged. - } - }; - const exitSupervisor = (code: number): void => { if (exiting) { return; @@ -116,22 +92,11 @@ export function runSupervisor(options: SupervisorOptions): void { const spawnSpec = resolveWorkerSpawnSpec?.(workerEntry) ?? null; if (spawnSpec) { - logLaunch("spawning worker via explicit spawn spec", { - workerEntry, - command: spawnSpec.command, - args: spawnSpec.args, - workerArgs, - }); child = spawn(spawnSpec.command, spawnSpec.args, { stdio: ["inherit", "inherit", "inherit", "ipc"], env: spawnSpec.env ?? workerEnv, }); } else { - logLaunch("spawning worker via fork", { - workerEntry, - workerArgs, - workerExecArgv, - }); child = fork(workerEntry, workerArgs, { stdio: "inherit", env: workerEnv, @@ -139,35 +104,8 @@ export function runSupervisor(options: SupervisorOptions): void { }); } - logLaunch("worker spawn returned", { - childPid: child.pid ?? null, - connected: child.connected, - spawnfile: child.spawnfile, - spawnargs: child.spawnargs, - }); - - child.on("spawn", () => { - logLaunch("worker emitted spawn", { - childPid: child?.pid ?? null, - }); - }); - - child.on("error", (error) => { - logLaunch("worker emitted error", { - childPid: child?.pid ?? null, - message: error.message, - }); - }); - child.on("message", (msg: unknown) => { const lifecycleMessage = parseLifecycleMessage(msg); - logLaunch("worker emitted ipc message", { - childPid: child?.pid ?? null, - rawType: - typeof msg === "object" && msg !== null && "type" in msg - ? (msg as { type?: unknown }).type - : typeof msg, - }); if (!lifecycleMessage) { return; } @@ -181,13 +119,6 @@ export function runSupervisor(options: SupervisorOptions): void { }); child.on("exit", (code, signal) => { - logLaunch("worker emitted exit", { - childPid: child?.pid ?? null, - code, - signal, - restarting, - shuttingDown, - }); const exitDescriptor = describeExit(code, signal); if (shuttingDown) { @@ -206,20 +137,6 @@ export function runSupervisor(options: SupervisorOptions): void { log(`Worker exited (${exitDescriptor}). Supervisor exiting.`); exitSupervisor(typeof code === "number" ? code : 0); }); - - child.on("close", (code, signal) => { - logLaunch("worker emitted close", { - childPid: child?.pid ?? null, - code, - signal, - }); - }); - - child.on("disconnect", () => { - logLaunch("worker emitted disconnect", { - childPid: child?.pid ?? null, - }); - }); }; const requestRestart = (reason: string) => { @@ -252,12 +169,6 @@ export function runSupervisor(options: SupervisorOptions): void { process.on("SIGINT", () => forwardSignal("SIGINT")); process.on("SIGTERM", () => forwardSignal("SIGTERM")); - logLaunch("supervisor starting", { - startupMessage: options.startupMessage, - restartOnCrash, - workerArgs, - workerExecArgv, - }); process.stdout.write(`[${options.name}] ${options.startupMessage}\n`); spawnWorker(); }