diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index fbe457fd459..3fb0f3a0e78 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -9,7 +9,6 @@ import { validatedIpcMain } from '../../base/parts/ipc/electron-main/ipcMain.js' import { hostname, release } from 'os'; import { VSBuffer } from '../../base/common/buffer.js'; import { toErrorMessage } from '../../base/common/errorMessage.js'; -import { isSigPipeError, onUnexpectedError, setUnexpectedErrorHandler } from '../../base/common/errors.js'; import { Event } from '../../base/common/event.js'; import { parse } from '../../base/common/jsonc.js'; import { getPathLabel } from '../../base/common/labels.js'; @@ -122,6 +121,7 @@ import { INativeMcpDiscoveryHelperService, NativeMcpDiscoveryHelperChannelName } import { NativeMcpDiscoveryHelperService } from '../../platform/mcp/node/nativeMcpDiscoveryHelperService.js'; import { IWebContentExtractorService } from '../../platform/webContentExtractor/common/webContentExtractor.js'; import { NativeWebContentExtractorService } from '../../platform/webContentExtractor/electron-main/webContentExtractorService.js'; +import ErrorTelemetry from '../../platform/telemetry/electron-main/errorTelemetry.js'; /** * The main VS Code application. There will only ever be one instance, @@ -373,15 +373,6 @@ export class CodeApplication extends Disposable { private registerListeners(): void { - // We handle uncaught exceptions here to prevent electron from opening a dialog to the user - setUnexpectedErrorHandler(error => this.onUnexpectedError(error)); - process.on('uncaughtException', error => { - if (!isSigPipeError(error)) { - onUnexpectedError(error); - } - }); - process.on('unhandledRejection', (reason: unknown) => onUnexpectedError(reason)); - // Dispose on shutdown Event.once(this.lifecycleMainService.onWillShutdown)(() => this.dispose()); @@ -528,25 +519,6 @@ export class CodeApplication extends Disposable { //#endregion } - private onUnexpectedError(error: Error): void { - if (error) { - - // take only the message and stack property - const friendlyError = { - message: `[uncaught exception in main]: ${error.message}`, - stack: error.stack - }; - - // handle on client side - this.windowsMainService?.sendToFocused('vscode:reportError', JSON.stringify(friendlyError)); - } - - this.logService.error(`[uncaught exception in main]: ${error}`); - if (error.stack) { - this.logService.error(error.stack); - } - } - async startup(): Promise { this.logService.debug('Starting VS Code'); this.logService.debug(`from: ${this.environmentMainService.appRoot}`); @@ -603,6 +575,9 @@ export class CodeApplication extends Disposable { // Services const appInstantiationService = await this.initServices(machineId, sqmId, devDeviceId, sharedProcessReady); + // Error telemetry + appInstantiationService.invokeFunction(accessor => this._register(new ErrorTelemetry(accessor.get(ILogService), accessor.get(ITelemetryService)))); + // Auth Handler appInstantiationService.invokeFunction(accessor => accessor.get(IProxyAuthService)); diff --git a/src/vs/platform/telemetry/electron-main/errorTelemetry.ts b/src/vs/platform/telemetry/electron-main/errorTelemetry.ts new file mode 100644 index 00000000000..e093fda1474 --- /dev/null +++ b/src/vs/platform/telemetry/electron-main/errorTelemetry.ts @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { isSigPipeError, onUnexpectedError, setUnexpectedErrorHandler } from '../../../base/common/errors.js'; +import BaseErrorTelemetry from '../common/errorTelemetry.js'; +import { ITelemetryService } from '../common/telemetry.js'; +import { ILogService } from '../../../platform/log/common/log.js'; + +export default class ErrorTelemetry extends BaseErrorTelemetry { + constructor( + private readonly logService: ILogService, + @ITelemetryService telemetryService: ITelemetryService + ) { + super(telemetryService); + } + + protected override installErrorListeners(): void { + // We handle uncaught exceptions here to prevent electron from opening a dialog to the user + setUnexpectedErrorHandler(error => this.onUnexpectedError(error)); + + process.on('uncaughtException', error => { + if (!isSigPipeError(error)) { + onUnexpectedError(error); + } + }); + + process.on('unhandledRejection', (reason: unknown) => onUnexpectedError(reason)); + } + + private onUnexpectedError(error: Error): void { + this.logService.error(`[uncaught exception in main]: ${error}`); + if (error.stack) { + this.logService.error(error.stack); + } + } +} diff --git a/src/vs/workbench/electron-sandbox/window.ts b/src/vs/workbench/electron-sandbox/window.ts index 1c187b2948e..d306dbe5bdc 100644 --- a/src/vs/workbench/electron-sandbox/window.ts +++ b/src/vs/workbench/electron-sandbox/window.ts @@ -6,7 +6,6 @@ import './media/window.css'; import { localize } from '../../nls.js'; import { URI } from '../../base/common/uri.js'; -import { onUnexpectedError } from '../../base/common/errors.js'; import { equals } from '../../base/common/objects.js'; import { EventType, EventHelper, addDisposableListener, ModifierKeyEmitter, getActiveElement, hasWindow, getWindowById, getWindows, $ } from '../../base/browser/dom.js'; import { Action, Separator, WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from '../../base/common/actions.js'; @@ -187,13 +186,6 @@ export class NativeWindow extends BaseWindow { } }); - // Error reporting from main - ipcRenderer.on('vscode:reportError', (event: unknown, error: string) => { - if (error) { - onUnexpectedError(JSON.parse(error)); - } - }); - // Shared Process crash reported from main ipcRenderer.on('vscode:reportSharedProcessCrash', (event: unknown, error: string) => { this.notificationService.prompt(