diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index a08d7a65dff..9e45dd6687e 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -933,19 +933,27 @@ export class CodeApplication extends Disposable { // Observe shared process for errors const telemetryService = accessor.get(ITelemetryService); - this._register(sharedProcess.onDidError(e => { + this._register(sharedProcess.onDidError(({ type, details }) => { // Logging - onUnexpectedError(new Error(e.message)); + let message: string; + if (typeof details === 'string') { + message = details; + } else { + message = `SharedProcess: crashed (detail: ${details.reason})`; + } + onUnexpectedError(new Error(message)); // Telemetry type SharedProcessErrorClassification = { type: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + reason: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; }; type SharedProcessErrorEvent = { type: WindowError; + reason: string | undefined; }; - telemetryService.publicLog2('sharedprocesserror', { type: e.type }); + telemetryService.publicLog2('sharedprocesserror', { type, reason: typeof details !== 'string' ? details.reason : undefined }); })); // Windows: install mutex diff --git a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts index 720b318dda7..e0fcf5fee5c 100644 --- a/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts +++ b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { BrowserWindow, ipcMain, Event as ElectronEvent, MessagePortMain, IpcMainEvent } from 'electron'; +import { BrowserWindow, ipcMain, Event as ElectronEvent, MessagePortMain, IpcMainEvent, RenderProcessGoneDetails } from 'electron'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { Barrier } from 'vs/base/common/async'; import { ILogService } from 'vs/platform/log/common/log'; @@ -26,7 +26,7 @@ export class SharedProcess extends Disposable implements ISharedProcess { private window: BrowserWindow | undefined = undefined; private windowCloseListener: ((event: ElectronEvent) => void) | undefined = undefined; - private readonly _onDidError = this._register(new Emitter<{ type: WindowError, message: string }>()); + private readonly _onDidError = this._register(new Emitter<{ type: WindowError, details: string | RenderProcessGoneDetails }>()); readonly onDidError = Event.buffer(this._onDidError.event); // buffer until we have a listener! constructor( @@ -217,9 +217,9 @@ export class SharedProcess extends Disposable implements ISharedProcess { // Crashes & Unrsponsive & Failed to load // We use `onUnexpectedError` explicitly because the error handler // will send the error to the active window to log in devtools too - this.window.webContents.on('render-process-gone', (event, details) => this._onDidError.fire({ type: WindowError.CRASHED, message: `SharedProcess: crashed (detail: ${details?.reason})` })); - this.window.on('unresponsive', () => this._onDidError.fire({ type: WindowError.UNRESPONSIVE, message: 'SharedProcess: detected unresponsive window' })); - this.window.webContents.on('did-fail-load', (event, errorCode, errorDescription) => this._onDidError.fire({ type: WindowError.LOAD, message: `SharedProcess: failed to load window: ${errorDescription}` })); + this.window.webContents.on('render-process-gone', (event, details) => this._onDidError.fire({ type: WindowError.CRASHED, details })); + this.window.on('unresponsive', () => this._onDidError.fire({ type: WindowError.UNRESPONSIVE, details: 'SharedProcess: detected unresponsive window' })); + this.window.webContents.on('did-fail-load', (event, errorCode, errorDescription) => this._onDidError.fire({ type: WindowError.LOAD, details: `SharedProcess: failed to load: ${errorDescription}` })); } async connect(): Promise { diff --git a/src/vs/platform/windows/electron-main/window.ts b/src/vs/platform/windows/electron-main/window.ts index 943028dff4a..7fe996e17c0 100644 --- a/src/vs/platform/windows/electron-main/window.ts +++ b/src/vs/platform/windows/electron-main/window.ts @@ -9,7 +9,7 @@ import { localize } from 'vs/nls'; import { getMarks, mark } from 'vs/base/common/performance'; import { Emitter } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; -import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display, TouchBarSegmentedControl, NativeImage, BrowserWindowConstructorOptions, SegmentedControlSegment, nativeTheme, Event } from 'electron'; +import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display, TouchBarSegmentedControl, NativeImage, BrowserWindowConstructorOptions, SegmentedControlSegment, nativeTheme, Event, RenderProcessGoneDetails } from 'electron'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -399,7 +399,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Crashes & Unrsponsive & Failed to load this._win.on('unresponsive', () => this.onWindowError(WindowError.UNRESPONSIVE)); - this._win.webContents.on('render-process-gone', (event, details) => this.onWindowError(WindowError.CRASHED, details.reason)); + this._win.webContents.on('render-process-gone', (event, details) => this.onWindowError(WindowError.CRASHED, details)); this._win.webContents.on('did-fail-load', (event, errorCode, errorDescription) => this.onWindowError(WindowError.LOAD, errorDescription)); // Window close @@ -545,19 +545,19 @@ export class CodeWindow extends Disposable implements ICodeWindow { } private async onWindowError(error: WindowError.UNRESPONSIVE): Promise; - private async onWindowError(error: WindowError.CRASHED, details: string): Promise; + private async onWindowError(error: WindowError.CRASHED, details: RenderProcessGoneDetails): Promise; private async onWindowError(error: WindowError.LOAD, details: string): Promise; - private async onWindowError(type: WindowError, details?: string): Promise { + private async onWindowError(type: WindowError, details?: string | RenderProcessGoneDetails): Promise { switch (type) { case WindowError.CRASHED: - this.logService.error(`CodeWindow: renderer process crashed (detail: ${details})`); + this.logService.error(`CodeWindow: renderer process crashed (detail: ${typeof details === 'string' ? details : details?.reason})`); break; case WindowError.UNRESPONSIVE: this.logService.error('CodeWindow: detected unresponsive'); break; case WindowError.LOAD: - this.logService.error(`CodeWindow: failed to load workbench window: ${details}`); + this.logService.error(`CodeWindow: failed to load workbench window: ${typeof details === 'string' ? details : details?.reason}`); break; } @@ -572,11 +572,13 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Telemetry type WindowErrorClassification = { type: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + reason: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; }; type WindowErrorEvent = { type: WindowError; + reason: string | undefined; }; - this.telemetryService.publicLog2('windowerror', { type }); + this.telemetryService.publicLog2('windowerror', { type, reason: (details && typeof details !== 'string') ? details.reason : undefined }); // Unresponsive if (type === WindowError.UNRESPONSIVE) { @@ -615,10 +617,10 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Crashed else if (type === WindowError.CRASHED) { let message: string; - if (details && details !== 'crashed') { - message = localize('appCrashedDetails', "The window has crashed (reason: '{0}')", details); + if (typeof details === 'string' || !details) { + message = localize('appCrashed', "The window has crashed"); } else { - message = localize('appCrashed', "The window has crashed", details); + message = localize('appCrashedDetails', "The window has crashed (reason: '{0}')", details.reason); } const result = await this.dialogMainService.showMessageBox({