From 11528e43c0588973d7912104a40ccd669b7750e1 Mon Sep 17 00:00:00 2001 From: LukeParkerDev <10430890+Hona@users.noreply.github.com> Date: Fri, 17 Apr 2026 15:00:13 +1000 Subject: [PATCH] chore(desktop-wsl): log sidecar start failures and flatten server-health logs The WSL controller previously only stored a failed startup message in its renderer state, so Ubuntu-style silent failures left no trace in main.log. Inject the main-process logger into the controller and emit wsl sidecar ready / wsl sidecar failed to start entries. Also flatten the [server health] renderer logs into a single string argument because Electron's console-message bridge truncates extra args to [object Object]. --- packages/app/src/context/server.tsx | 20 +++++++----------- packages/desktop-electron/src/main/index.ts | 21 +++++++++++++------ .../desktop-electron/src/main/wsl-servers.ts | 19 ++++++++++++----- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/packages/app/src/context/server.tsx b/packages/app/src/context/server.tsx index 372f1dad29..096ef23db9 100644 --- a/packages/app/src/context/server.tsx +++ b/packages/app/src/context/server.tsx @@ -203,14 +203,13 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext( const check = (conn: ServerConnection.Any) => checkServerHealth(conn.http).then((x) => { if (!x.healthy) { - // Loud: makes it trivial to see why a server shows red in the - // status popover / switcher. The dot only goes red when this - // returns false; otherwise undefined (gray) is emitted first. - console.warn("[server health] unhealthy", { - key: ServerConnection.key(conn), - url: conn.http.url, - hasAuth: !!(conn.http.username || conn.http.password), - }) + // Electron's console-message bridge only preserves the first + // console argument, so pre-stringify everything into one string. + console.warn( + `[server health] unhealthy key=${ServerConnection.key(conn)} url=${conn.http.url} hasAuth=${!!( + conn.http.username || conn.http.password + )}`, + ) } return x.healthy }) @@ -224,10 +223,7 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext( return } setState("healthy", undefined) - console.log("[server health] start polling", { - key: ServerConnection.key(current_), - url: current_.http.url, - }) + console.log(`[server health] start polling key=${ServerConnection.key(current_)} url=${current_.http.url}`) onCleanup(startHealthPolling(current_)) }) diff --git a/packages/desktop-electron/src/main/index.ts b/packages/desktop-electron/src/main/index.ts index 4317b731c8..95d688b277 100644 --- a/packages/desktop-electron/src/main/index.ts +++ b/packages/desktop-electron/src/main/index.ts @@ -56,13 +56,22 @@ const pendingDeepLinks: string[] = [] const serverReady = defer() void serverReady.promise.catch(() => undefined) -const wslServers = createWslServersController(app.getVersion(), async (distro) => { +const wslServers = (() => { const logger = initLogging() - logger.log("spawning wsl sidecar", { distro }) - return spawnWslSidecar(distro, { - onLine: (line) => logger.log("wsl sidecar", { distro, stream: line.stream, text: line.text }), - }) -}) + return createWslServersController( + app.getVersion(), + async (distro) => { + logger.log("spawning wsl sidecar", { distro }) + return spawnWslSidecar(distro, { + onLine: (line) => logger.log("wsl sidecar", { distro, stream: line.stream, text: line.text }), + }) + }, + { + log: (message, meta) => logger.log(message, meta), + error: (message, meta) => logger.error(message, meta), + }, + ) +})() const logger = initLogging() logger.log("app starting", { diff --git a/packages/desktop-electron/src/main/wsl-servers.ts b/packages/desktop-electron/src/main/wsl-servers.ts index 5e2438aa09..2757be3a81 100644 --- a/packages/desktop-electron/src/main/wsl-servers.ts +++ b/packages/desktop-electron/src/main/wsl-servers.ts @@ -41,13 +41,19 @@ type RunningSidecar = { type SpawnSidecar = (distro: string) => Promise +type ControllerLogger = { + log: (message: string, meta?: unknown) => void + error: (message: string, meta?: unknown) => void +} + export type WslServersController = ReturnType export function wslServerIdForDistro(distro: string) { return `wsl:${distro}` } -export function createWslServersController(appVersion: string, spawnSidecar: SpawnSidecar) { +export function createWslServersController(appVersion: string, spawnSidecar: SpawnSidecar, logger?: ControllerLogger) { + const mainLogger: ControllerLogger | undefined = logger let state: WslServersState = initialState() const listeners = new Set<(event: WslServersEvent) => void>() const sidecars = new Map() @@ -124,11 +130,14 @@ export function createWslServersController(appVersion: string, spawnSidecar: Spa username: sidecar.username, password: sidecar.password, }) + mainLogger?.log("wsl sidecar ready", { id, distro: item.config.distro, url: sidecar.url }) } catch (error) { - setRuntime(id, { - kind: "failed", - message: error instanceof Error ? error.message : String(error), - }) + const message = error instanceof Error ? error.message : String(error) + setRuntime(id, { kind: "failed", message }) + // Without this, an Ubuntu-style silent failure leaves no trace in + // main.log — the controller captures the message in its state but + // nothing surfaces unless the user opens the WSL servers dialog. + mainLogger?.error("wsl sidecar failed to start", { id, distro: item.config.distro, message }) } }