diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index aa99b93a911..8cc9907cbbd 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -43,6 +43,7 @@ export interface IMessage { export interface IExtensionsStatus { messages: IMessage[]; activationTimes: ActivationTimes; + runtimeErrors: Error[]; } /** diff --git a/src/vs/workbench/api/electron-browser/mainThreadErrors.ts b/src/vs/workbench/api/electron-browser/mainThreadErrors.ts index a737587e706..a1ff2a2dd6c 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadErrors.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadErrors.ts @@ -15,11 +15,11 @@ export class MainThreadErrors implements MainThreadErrorsShape { // } - $onUnexpectedError(err: any | SerializedError, extensionId: string | undefined): void { + $onUnexpectedError(err: any | SerializedError): void { if (err.$isError) { const { name, message, stack } = err; err = new Error(); - err.message = extensionId ? `[${extensionId}] ${message}` : message; + err.message = message; err.name = name; err.stack = stack; } diff --git a/src/vs/workbench/api/electron-browser/mainThreadExtensionService.ts b/src/vs/workbench/api/electron-browser/mainThreadExtensionService.ts index 5627ee185df..f1ab5b7d02c 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadExtensionService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadExtensionService.ts @@ -9,6 +9,7 @@ import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { MainThreadExtensionServiceShape, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { ExtensionService } from 'vs/workbench/services/extensions/electron-browser/extensionService'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +import { SerializedError } from 'vs/base/common/errors'; @extHostNamedCustomer(MainContext.MainThreadExtensionService) export class MainThreadExtensionService implements MainThreadExtensionServiceShape { @@ -33,6 +34,13 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha $onExtensionActivated(extensionId: string, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string): void { this._extensionService._onExtensionActivated(extensionId, startup, codeLoadingTime, activateCallTime, activateResolvedTime, activationEvent); } + $onExtensionRuntimeError(extensionId: string, data: SerializedError): void { + const error = new Error(); + error.name = data.name; + error.message = data.message; + error.stack = data.stack; + this._extensionService._onExtensionRuntimeError(extensionId, error); + } $onExtensionActivationFailed(extensionId: string): void { } $addMessage(extensionId: string, severity: Severity, message: string): void { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 7472f9e7f90..81db78184f5 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -239,7 +239,7 @@ export interface MainThreadTreeViewsShape extends IDisposable { } export interface MainThreadErrorsShape extends IDisposable { - $onUnexpectedError(err: any | SerializedError, extensionId: string | undefined): void; + $onUnexpectedError(err: any | SerializedError): void; } export interface MainThreadLanguageFeaturesShape extends IDisposable { @@ -352,6 +352,7 @@ export interface MainThreadExtensionServiceShape extends IDisposable { $localShowMessage(severity: Severity, msg: string): void; $onExtensionActivated(extensionId: string, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string): void; $onExtensionActivationFailed(extensionId: string): void; + $onExtensionRuntimeError(extensionId: string, error: SerializedError): void; $addMessage(extensionId: string, severity: Severity, message: string): void; } diff --git a/src/vs/workbench/node/extensionHostMain.ts b/src/vs/workbench/node/extensionHostMain.ts index ff5733534e8..551e81121ed 100644 --- a/src/vs/workbench/node/extensionHostMain.ts +++ b/src/vs/workbench/node/extensionHostMain.ts @@ -101,11 +101,16 @@ export class ExtensionHostMain { return `${error.name || 'Error'}: ${error.message || ''}${stackTraceMessage}`; }; }); + const mainThreadExtensions = threadService.get(MainContext.MainThreadExtensionService); const mainThreadErrors = threadService.get(MainContext.MainThreadErrors); errors.setUnexpectedErrorHandler(err => { const data = errors.transformErrorForSerialization(err); const extension = extensionErrors.get(err); - mainThreadErrors.$onUnexpectedError(data, extension && extension.id); + if (extension) { + mainThreadExtensions.$onExtensionRuntimeError(extension.id, data); + } else { + mainThreadErrors.$onUnexpectedError(data); + } }); // Configure the watchdog to kill our process if the JS event loop is unresponsive for more than 10s diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 1d3d3678e5e..e7a9841e051 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -73,6 +73,7 @@ export class ExtensionService extends Disposable implements IExtensionService { */ private _extensionHostProcessFinishedActivateEvents: { [activationEvent: string]: boolean; }; private _extensionHostProcessActivationTimes: { [id: string]: ActivationTimes; }; + private _extensionHostExtensionRuntimeErrors: { [id: string]: Error[]; }; private _extensionHostProcessWorker: ExtensionHostProcessWorker; private _extensionHostProcessThreadService: MainThreadService; private _extensionHostProcessCustomers: IDisposable[]; @@ -102,6 +103,7 @@ export class ExtensionService extends Disposable implements IExtensionService { this._extensionHostProcessFinishedActivateEvents = Object.create(null); this._extensionHostProcessActivationTimes = Object.create(null); + this._extensionHostExtensionRuntimeErrors = Object.create(null); this._extensionHostProcessWorker = null; this._extensionHostProcessThreadService = null; this._extensionHostProcessCustomers = []; @@ -150,6 +152,7 @@ export class ExtensionService extends Disposable implements IExtensionService { this._extensionHostProcessFinishedActivateEvents = Object.create(null); this._extensionHostProcessActivationTimes = Object.create(null); + this._extensionHostExtensionRuntimeErrors = Object.create(null); if (this._extensionHostProcessWorker) { this._extensionHostProcessWorker.dispose(); this._extensionHostProcessWorker = null; @@ -320,7 +323,8 @@ export class ExtensionService extends Disposable implements IExtensionService { const id = extension.id; result[id] = { messages: this._extensionsMessages[id], - activationTimes: this._extensionHostProcessActivationTimes[id] + activationTimes: this._extensionHostProcessActivationTimes[id], + runtimeErrors: this._extensionHostExtensionRuntimeErrors[id], }; } } @@ -524,6 +528,14 @@ export class ExtensionService extends Disposable implements IExtensionService { this._onDidChangeExtensionsStatus.fire([extensionId]); } + public _onExtensionRuntimeError(extensionId: string, err: Error): void { + if (!this._extensionHostExtensionRuntimeErrors[extensionId]) { + this._extensionHostExtensionRuntimeErrors[extensionId] = []; + } + this._extensionHostExtensionRuntimeErrors[extensionId].push(err); + this._onDidChangeExtensionsStatus.fire([extensionId]); + } + public _addMessage(extensionId: string, severity: Severity, message: string): void { if (!this._extensionsMessages[extensionId]) { this._extensionsMessages[extensionId] = [];