@@ -30,7 +30,10 @@ import type { SuspensionService } from "./services/suspension/service";
3030import type { TaskLinkService } from "./services/task-link/service" ;
3131import type { UpdatesService } from "./services/updates/service" ;
3232import type { WorkspaceService } from "./services/workspace/service" ;
33- import { collectMemorySnapshot } from "./utils/crash-diagnostics" ;
33+ import {
34+ collectMemorySnapshot ,
35+ flattenMemorySnapshot ,
36+ } from "./utils/crash-diagnostics" ;
3437import { ensureClaudeConfigDir } from "./utils/env" ;
3538import {
3639 getChromiumLogFilePath ,
@@ -72,9 +75,18 @@ function isCrashLoop(): boolean {
7275 return recentCrashTimestamps . length >= CRASH_LOOP_THRESHOLD ;
7376}
7477
78+ // Shared diagnostics attached to every crash event: uptime, the native chromium
79+ // log tail, and flattened memory. A hard OOM kills the renderer before it can
80+ // log, so the memory snapshot is often the only signal of what happened.
81+ function crashDiagnostics ( ) {
82+ return {
83+ appUptimeSeconds : Math . round ( process . uptime ( ) ) ,
84+ chromiumLogTail : readChromiumLogTail ( ) ,
85+ ...flattenMemorySnapshot ( collectMemorySnapshot ( ( ) => app . getAppMetrics ( ) ) ) ,
86+ } ;
87+ }
88+
7589app . on ( "render-process-gone" , ( _event , webContents , details ) => {
76- const memory = collectMemorySnapshot ( ( ) => app . getAppMetrics ( ) ) ;
77- const chromiumLogTail = readChromiumLogTail ( ) ;
7890 const props = {
7991 source : "main" ,
8092 type : "render-process-gone" ,
@@ -83,16 +95,11 @@ app.on("render-process-gone", (_event, webContents, details) => {
8395 url : webContents . getURL ( ) ,
8496 title : webContents . getTitle ( ) ,
8597 webContentsId : String ( webContents . id ) ,
86- appUptimeSeconds : Math . round ( process . uptime ( ) ) ,
87- memoryTotalWorkingSetKb : memory ?. totalWorkingSetKb ,
88- memoryPeakWorkingSetKb : memory ?. peakWorkingSetKb ,
89- memoryProcessCount : memory ?. processCount ,
90- memoryByType : memory ? JSON . stringify ( memory . byType ) : undefined ,
98+ ...crashDiagnostics ( ) ,
9199 } ;
92- log . error ( "Renderer process gone" , { ... props , chromiumLogTail } ) ;
100+ log . error ( "Renderer process gone" , props ) ;
93101 captureException ( new Error ( `Renderer process gone: ${ details . reason } ` ) , {
94102 ...props ,
95- chromiumLogTail,
96103 // Stack is always this handler, so default grouping collapses every
97104 // renderer death into one issue. Split by reason instead.
98105 $exception_fingerprint : [ "render-process-gone" , details . reason ] ,
@@ -129,8 +136,6 @@ app.on("render-process-gone", (_event, webContents, details) => {
129136} ) ;
130137
131138app . on ( "child-process-gone" , ( _event , details ) => {
132- const memory = collectMemorySnapshot ( ( ) => app . getAppMetrics ( ) ) ;
133- const chromiumLogTail = readChromiumLogTail ( ) ;
134139 const props = {
135140 source : "main" ,
136141 type : "child-process-gone" ,
@@ -139,18 +144,13 @@ app.on("child-process-gone", (_event, details) => {
139144 exitCode : String ( details . exitCode ) ,
140145 serviceName : details . serviceName ?? "" ,
141146 name : details . name ?? "" ,
142- appUptimeSeconds : Math . round ( process . uptime ( ) ) ,
143- memoryTotalWorkingSetKb : memory ?. totalWorkingSetKb ,
144- memoryPeakWorkingSetKb : memory ?. peakWorkingSetKb ,
145- memoryProcessCount : memory ?. processCount ,
146- memoryByType : memory ? JSON . stringify ( memory . byType ) : undefined ,
147+ ...crashDiagnostics ( ) ,
147148 } ;
148- log . error ( "Child process gone" , { ... props , chromiumLogTail } ) ;
149+ log . error ( "Child process gone" , props ) ;
149150 captureException (
150151 new Error ( `Child process gone (${ details . type } ): ${ details . reason } ` ) ,
151152 {
152153 ...props ,
153- chromiumLogTail,
154154 $exception_fingerprint : [
155155 "child-process-gone" ,
156156 details . type ,
0 commit comments