提交 73b7f479 编写于 作者: A Andre Weinand

debt: clean up DA error handling; fixes #57810

上级 a1ac197b
...@@ -167,7 +167,7 @@ export interface ISession extends ITreeElement, IDisposable { ...@@ -167,7 +167,7 @@ export interface ISession extends ITreeElement, IDisposable {
/** /**
* Allows to register on DA events. * Allows to register on DA events.
*/ */
onDidExitAdapter: Event<void>; onDidExitAdapter: Event<Error>;
} }
export interface IThread extends ITreeElement { export interface IThread extends ITreeElement {
......
...@@ -400,6 +400,10 @@ export class DebugService implements IDebugService { ...@@ -400,6 +400,10 @@ export class DebugService implements IDebugService {
}); });
} }
private isExtensionHostDebugging(config: IConfig) {
return equalsIgnoreCase(config.type, 'extensionhost');
}
private attachExtensionHost(session: Session, port: number): TPromise<void> { private attachExtensionHost(session: Session, port: number): TPromise<void> {
session.configuration.request = 'attach'; session.configuration.request = 'attach';
...@@ -418,18 +422,25 @@ export class DebugService implements IDebugService { ...@@ -418,18 +422,25 @@ export class DebugService implements IDebugService {
const session = this.instantiationService.createInstance(Session, configuration, root, this.model); const session = this.instantiationService.createInstance(Session, configuration, root, this.model);
this.allSessions.set(session.getId(), session); this.allSessions.set(session.getId(), session);
// register listeners as the very first thing!
this.registerSessionListeners(session);
// since the Session is now properly registered under its ID and hooked, we can announce it
// this event doesn't go to extensions
this._onWillNewSession.fire(session); this._onWillNewSession.fire(session);
const resolved = configuration.resolved; const resolved = configuration.resolved;
resolved.__sessionId = session.getId();
const dbgr = this.configurationManager.getDebugger(resolved.type); const dbgr = this.configurationManager.getDebugger(resolved.type);
return session.initialize(dbgr).then(() => { return session.initialize(dbgr).then(() => {
this.registerSessionListeners(session);
const raw = <RawDebugSession>session.raw; const raw = <RawDebugSession>session.raw;
// pass the sessionID for EH debugging
if (this.isExtensionHostDebugging(resolved)) {
resolved.__sessionId = session.getId();
}
return (resolved.request === 'attach' ? raw.attach(resolved) : raw.launch(resolved)).then(result => { return (resolved.request === 'attach' ? raw.attach(resolved) : raw.launch(resolved)).then(result => {
if (raw.disconnected) { if (raw.disconnected) {
...@@ -438,6 +449,7 @@ export class DebugService implements IDebugService { ...@@ -438,6 +449,7 @@ export class DebugService implements IDebugService {
this.focusStackFrame(undefined, undefined, session); this.focusStackFrame(undefined, undefined, session);
// since the initialized response has arrived announce the new Session (including extensions)
this._onDidNewSession.fire(session); this._onDidNewSession.fire(session);
const internalConsoleOptions = resolved.internalConsoleOptions || this.configurationService.getValue<IDebugConfiguration>('debug').internalConsoleOptions; const internalConsoleOptions = resolved.internalConsoleOptions || this.configurationService.getValue<IDebugConfiguration>('debug').internalConsoleOptions;
...@@ -460,6 +472,7 @@ export class DebugService implements IDebugService { ...@@ -460,6 +472,7 @@ export class DebugService implements IDebugService {
return this.telemetryDebugSessionStart(root, resolved.type, dbgr.extensionDescription); return this.telemetryDebugSessionStart(root, resolved.type, dbgr.extensionDescription);
}).then(() => session, (error: Error | string) => { }).then(() => session, (error: Error | string) => {
if (session) { if (session) {
session.dispose(); session.dispose();
} }
...@@ -483,13 +496,18 @@ export class DebugService implements IDebugService { ...@@ -483,13 +496,18 @@ export class DebugService implements IDebugService {
} }
return undefined; return undefined;
}); });
}).then(undefined, err => {
}).then(undefined, error => {
if (session) { if (session) {
session.dispose(); session.dispose();
} }
return TPromise.wrapError(err); if (errors.isPromiseCanceledError(error)) {
// Do not show 'canceled' error messages to the user #7906
return TPromise.as(null);
}
return TPromise.wrapError(error);
}); });
} }
...@@ -502,10 +520,14 @@ export class DebugService implements IDebugService { ...@@ -502,10 +520,14 @@ export class DebugService implements IDebugService {
this.onStateChange(); this.onStateChange();
})); }));
this.toDispose.push(session.onDidExitAdapter(() => { this.toDispose.push(session.onDidExitAdapter(err => {
if (err) {
this.notificationService.error(nls.localize('debugAdapterCrash', "Debug adapter process has terminated unexpectedly ({0})", err.message || err.toString()));
}
// 'Run without debugging' mode VSCode must terminate the extension host. More details: #3905 // 'Run without debugging' mode VSCode must terminate the extension host. More details: #3905
if (equalsIgnoreCase(session.configuration.type, 'extensionhost') && session.state === State.Running && session.configuration.noDebug) { if (this.isExtensionHostDebugging(session.configuration) && session.state === State.Running && session.configuration.noDebug) {
this.broadcastService.broadcast({ this.broadcastService.broadcast({
channel: EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL, channel: EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL,
payload: [session.root.uri.toString()] payload: [session.root.uri.toString()]
...@@ -553,7 +575,7 @@ export class DebugService implements IDebugService { ...@@ -553,7 +575,7 @@ export class DebugService implements IDebugService {
// Do not run preLaunch and postDebug tasks for automatic restarts // Do not run preLaunch and postDebug tasks for automatic restarts
this.skipRunningTask = !!restartData; this.skipRunningTask = !!restartData;
if (equalsIgnoreCase(session.configuration.type, 'extensionHost') && session.root) { if (this.isExtensionHostDebugging(session.configuration) && session.root) {
return this.broadcastService.broadcast({ return this.broadcastService.broadcast({
channel: EXTENSION_RELOAD_BROADCAST_CHANNEL, channel: EXTENSION_RELOAD_BROADCAST_CHANNEL,
payload: [session.root.uri.toString()] payload: [session.root.uri.toString()]
......
...@@ -41,7 +41,7 @@ export class Session implements ISession { ...@@ -41,7 +41,7 @@ export class Session implements ISession {
private readonly _onDidLoadedSource = new Emitter<LoadedSourceEvent>(); private readonly _onDidLoadedSource = new Emitter<LoadedSourceEvent>();
private readonly _onDidCustomEvent = new Emitter<DebugProtocol.Event>(); private readonly _onDidCustomEvent = new Emitter<DebugProtocol.Event>();
private readonly _onDidChangeState = new Emitter<State>(); private readonly _onDidChangeState = new Emitter<State>();
private readonly _onDidExitAdapter = new Emitter<void>(); private readonly _onDidExitAdapter = new Emitter<Error>();
constructor( constructor(
private _configuration: { resolved: IConfig, unresolved: IConfig }, private _configuration: { resolved: IConfig, unresolved: IConfig },
...@@ -93,149 +93,25 @@ export class Session implements ISession { ...@@ -93,149 +93,25 @@ export class Session implements ISession {
return this._onDidChangeState.event; return this._onDidChangeState.event;
} }
getSourceForUri(modelUri: uri): Source {
return this.sources.get(modelUri.toString());
}
getSource(raw: DebugProtocol.Source): Source {
let source = new Source(raw, this.getId());
if (this.sources.has(source.uri.toString())) {
source = this.sources.get(source.uri.toString());
source.raw = mixin(source.raw, raw);
if (source.raw && raw) {
// Always take the latest presentation hint from adapter #42139
source.raw.presentationHint = raw.presentationHint;
}
} else {
this.sources.set(source.uri.toString(), source);
}
return source;
}
getThread(threadId: number): Thread {
return this.threads.get(threadId);
}
getAllThreads(): IThread[] {
const result: IThread[] = [];
this.threads.forEach(t => result.push(t));
return result;
}
getLoadedSources(): TPromise<Source[]> {
return this._raw.loadedSources({}).then(response => {
return response.body.sources.map(src => this.getSource(src));
}, () => {
return [];
});
}
get onDidLoadedSource(): Event<LoadedSourceEvent> {
return this._onDidLoadedSource.event;
}
get onDidCustomEvent(): Event<DebugProtocol.Event> { get onDidCustomEvent(): Event<DebugProtocol.Event> {
return this._onDidCustomEvent.event; return this._onDidCustomEvent.event;
} }
get onDidExitAdapter(): Event<void> { get onDidExitAdapter(): Event<Error> {
return this._onDidExitAdapter.event; return this._onDidExitAdapter.event;
} }
rawUpdate(data: IRawModelUpdate): void {
if (data.thread && !this.threads.has(data.threadId)) {
// A new thread came in, initialize it.
this.threads.set(data.threadId, new Thread(this, data.thread.name, data.thread.id));
} else if (data.thread && data.thread.name) {
// Just the thread name got updated #18244
this.threads.get(data.threadId).name = data.thread.name;
}
if (data.stoppedDetails) {
// Set the availability of the threads' callstacks depending on
// whether the thread is stopped or not
if (data.stoppedDetails.allThreadsStopped) {
this.threads.forEach(thread => {
thread.stoppedDetails = thread.threadId === data.threadId ? data.stoppedDetails : { reason: undefined };
thread.stopped = true;
thread.clearCallStack();
});
} else if (this.threads.has(data.threadId)) {
// One thread is stopped, only update that thread.
const thread = this.threads.get(data.threadId);
thread.stoppedDetails = data.stoppedDetails;
thread.clearCallStack();
thread.stopped = true;
}
}
}
clearThreads(removeThreads: boolean, reference: number = undefined): void {
if (reference !== undefined && reference !== null) {
if (this.threads.has(reference)) {
const thread = this.threads.get(reference);
thread.clearCallStack();
thread.stoppedDetails = undefined;
thread.stopped = false;
if (removeThreads) {
this.threads.delete(reference);
}
}
} else {
this.threads.forEach(thread => {
thread.clearCallStack();
thread.stoppedDetails = undefined;
thread.stopped = false;
});
if (removeThreads) {
this.threads.clear();
ExpressionContainer.allValues.clear();
}
}
}
completions(frameId: number, text: string, position: Position, overwriteBefore: number): TPromise<ISuggestion[]> {
if (!this._raw.capabilities.supportsCompletionsRequest) {
return TPromise.as([]);
}
return this._raw.completions({
frameId,
text,
column: position.column,
line: position.lineNumber
}).then(response => {
const result: ISuggestion[] = [];
if (response && response.body && response.body.targets) {
response.body.targets.forEach(item => {
if (item && item.label) {
result.push({
label: item.label,
insertText: item.text || item.label,
type: item.type,
filterText: item.start && item.length && text.substr(item.start, item.length).concat(item.label),
overwriteBefore: item.length || overwriteBefore
});
}
});
}
return result;
}, () => []);
}
initialize(dbgr: Debugger): TPromise<void> { initialize(dbgr: Debugger): TPromise<void> {
if (this._raw) { if (this._raw) {
// If there was already a connection make sure to remove old listeners // if there was already a connection make sure to remove old listeners
this.dispose(); this.dispose(); // TODO: do not use dispose for this!
} }
return dbgr.getCustomTelemetryService().then(customTelemetryService => { return dbgr.getCustomTelemetryService().then(customTelemetryService => {
this._raw = this.instantiationService.createInstance(RawDebugSession, this._configuration.resolved.debugServer, dbgr, customTelemetryService, this.root); this._raw = this.instantiationService.createInstance(RawDebugSession, this._configuration.resolved.debugServer, dbgr, customTelemetryService, this.root);
this.registerListeners(); this.registerListeners();
return this._raw.initialize({ return this._raw.initialize({
...@@ -249,7 +125,7 @@ export class Session implements ISession { ...@@ -249,7 +125,7 @@ export class Session implements ISession {
supportsVariablePaging: true, // #9537 supportsVariablePaging: true, // #9537
supportsRunInTerminalRequest: true, // #10574 supportsRunInTerminalRequest: true, // #10574
locale: platform.locale locale: platform.locale
}).then(() => { }).then(response => {
this.model.addSession(this); this.model.addSession(this);
this.state = State.Running; this.state = State.Running;
this.model.setExceptionBreakpoints(this._raw.capabilities.exceptionBreakpointFilters); this.model.setExceptionBreakpoints(this._raw.capabilities.exceptionBreakpointFilters);
...@@ -258,6 +134,7 @@ export class Session implements ISession { ...@@ -258,6 +134,7 @@ export class Session implements ISession {
} }
private registerListeners(): void { private registerListeners(): void {
this.rawListeners.push(this._raw.onDidInitialize(() => { this.rawListeners.push(this._raw.onDidInitialize(() => {
aria.status(nls.localize('debuggingStarted', "Debugging started.")); aria.status(nls.localize('debuggingStarted', "Debugging started."));
const sendConfigurationDone = () => { const sendConfigurationDone = () => {
...@@ -415,7 +292,152 @@ export class Session implements ISession { ...@@ -415,7 +292,152 @@ export class Session implements ISession {
this._onDidCustomEvent.fire(event); this._onDidCustomEvent.fire(event);
})); }));
this.rawListeners.push(this._raw.onDidExitAdapter(() => this._onDidExitAdapter.fire())); this.rawListeners.push(this._raw.onDidExitAdapter(error => {
this._onDidExitAdapter.fire(error);
}));
}
dispose(): void {
dispose(this.rawListeners);
this.model.clearThreads(this.getId(), true);
this.model.removeSession(this.getId());
this.fetchThreadsScheduler = undefined;
if (this._raw && !this._raw.disconnected) {
this._raw.disconnect();
}
this._raw = undefined;
}
//---- sources
getSourceForUri(modelUri: uri): Source {
return this.sources.get(modelUri.toString());
}
getSource(raw: DebugProtocol.Source): Source {
let source = new Source(raw, this.getId());
if (this.sources.has(source.uri.toString())) {
source = this.sources.get(source.uri.toString());
source.raw = mixin(source.raw, raw);
if (source.raw && raw) {
// Always take the latest presentation hint from adapter #42139
source.raw.presentationHint = raw.presentationHint;
}
} else {
this.sources.set(source.uri.toString(), source);
}
return source;
}
getLoadedSources(): TPromise<Source[]> {
return this._raw.loadedSources({}).then(response => {
return response.body.sources.map(src => this.getSource(src));
}, () => {
return [];
});
}
get onDidLoadedSource(): Event<LoadedSourceEvent> {
return this._onDidLoadedSource.event;
}
//---- completions
completions(frameId: number, text: string, position: Position, overwriteBefore: number): TPromise<ISuggestion[]> {
if (!this._raw.capabilities.supportsCompletionsRequest) {
return TPromise.as([]);
}
return this._raw.completions({
frameId,
text,
column: position.column,
line: position.lineNumber
}).then(response => {
const result: ISuggestion[] = [];
if (response && response.body && response.body.targets) {
response.body.targets.forEach(item => {
if (item && item.label) {
result.push({
label: item.label,
insertText: item.text || item.label,
type: item.type,
filterText: item.start && item.length && text.substr(item.start, item.length).concat(item.label),
overwriteBefore: item.length || overwriteBefore
});
}
});
}
return result;
}, () => []);
}
//---- threads
getThread(threadId: number): Thread {
return this.threads.get(threadId);
}
getAllThreads(): IThread[] {
const result: IThread[] = [];
this.threads.forEach(t => result.push(t));
return result;
}
clearThreads(removeThreads: boolean, reference: number = undefined): void {
if (reference !== undefined && reference !== null) {
if (this.threads.has(reference)) {
const thread = this.threads.get(reference);
thread.clearCallStack();
thread.stoppedDetails = undefined;
thread.stopped = false;
if (removeThreads) {
this.threads.delete(reference);
}
}
} else {
this.threads.forEach(thread => {
thread.clearCallStack();
thread.stoppedDetails = undefined;
thread.stopped = false;
});
if (removeThreads) {
this.threads.clear();
ExpressionContainer.allValues.clear();
}
}
}
rawUpdate(data: IRawModelUpdate): void {
if (data.thread && !this.threads.has(data.threadId)) {
// A new thread came in, initialize it.
this.threads.set(data.threadId, new Thread(this, data.thread.name, data.thread.id));
} else if (data.thread && data.thread.name) {
// Just the thread name got updated #18244
this.threads.get(data.threadId).name = data.thread.name;
}
if (data.stoppedDetails) {
// Set the availability of the threads' callstacks depending on
// whether the thread is stopped or not
if (data.stoppedDetails.allThreadsStopped) {
this.threads.forEach(thread => {
thread.stoppedDetails = thread.threadId === data.threadId ? data.stoppedDetails : { reason: undefined };
thread.stopped = true;
thread.clearCallStack();
});
} else if (this.threads.has(data.threadId)) {
// One thread is stopped, only update that thread.
const thread = this.threads.get(data.threadId);
thread.stoppedDetails = data.stoppedDetails;
thread.clearCallStack();
thread.stopped = true;
}
}
} }
private fetchThreads(stoppedDetails?: IRawStoppedDetails): TPromise<any> { private fetchThreads(stoppedDetails?: IRawStoppedDetails): TPromise<any> {
...@@ -432,15 +454,4 @@ export class Session implements ISession { ...@@ -432,15 +454,4 @@ export class Session implements ISession {
} }
}); });
} }
dispose(): void {
dispose(this.rawListeners);
this.model.clearThreads(this.getId(), true);
this.model.removeSession(this.getId());
this.fetchThreadsScheduler = undefined;
if (!this._raw.disconnected) {
this._raw.disconnect();
}
this._raw = undefined;
}
} }
...@@ -13,7 +13,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; ...@@ -13,7 +13,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { Debugger } from 'vs/workbench/parts/debug/node/debugger'; import { Debugger } from 'vs/workbench/parts/debug/node/debugger';
import { IOutputService } from 'vs/workbench/parts/output/common/output'; import { IOutputService } from 'vs/workbench/parts/output/common/output';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { formatPII } from 'vs/workbench/parts/debug/common/debugUtils'; import { formatPII } from 'vs/workbench/parts/debug/common/debugUtils';
import { SocketDebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter'; import { SocketDebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter';
import { IRawSession, IDebugAdapter } from 'vs/workbench/parts/debug/common/debug'; import { IRawSession, IDebugAdapter } from 'vs/workbench/parts/debug/common/debug';
...@@ -26,7 +25,7 @@ export class RawDebugSession implements IRawSession { ...@@ -26,7 +25,7 @@ export class RawDebugSession implements IRawSession {
public disconnected: boolean; public disconnected: boolean;
private debugAdapter: IDebugAdapter; private debugAdapter: IDebugAdapter;
private cachedInitServerP: TPromise<void>; private cachedInitDebugAdapterP: TPromise<void>;
private startTime: number; private startTime: number;
private terminated: boolean; private terminated: boolean;
private cancellationTokens: CancellationTokenSource[]; private cancellationTokens: CancellationTokenSource[];
...@@ -48,14 +47,13 @@ export class RawDebugSession implements IRawSession { ...@@ -48,14 +47,13 @@ export class RawDebugSession implements IRawSession {
private readonly _onDidEvent: Emitter<DebugProtocol.Event>; private readonly _onDidEvent: Emitter<DebugProtocol.Event>;
// DA events // DA events
private readonly _onDidExitAdapter: Emitter<void>; private readonly _onDidExitAdapter: Emitter<Error>;
constructor( constructor(
private debugServerPort: number, private debugServerPort: number,
private _debugger: Debugger, private _debugger: Debugger,
public customTelemetryService: ITelemetryService, public customTelemetryService: ITelemetryService,
private root: IWorkspaceFolder, private root: IWorkspaceFolder,
@INotificationService private notificationService: INotificationService,
@ITelemetryService private telemetryService: ITelemetryService, @ITelemetryService private telemetryService: ITelemetryService,
@IOutputService private outputService: IOutputService @IOutputService private outputService: IOutputService
) { ) {
...@@ -76,7 +74,7 @@ export class RawDebugSession implements IRawSession { ...@@ -76,7 +74,7 @@ export class RawDebugSession implements IRawSession {
this._onDidCustomEvent = new Emitter<DebugProtocol.Event>(); this._onDidCustomEvent = new Emitter<DebugProtocol.Event>();
this._onDidEvent = new Emitter<DebugProtocol.Event>(); this._onDidEvent = new Emitter<DebugProtocol.Event>();
this._onDidExitAdapter = new Emitter<void>(); this._onDidExitAdapter = new Emitter<Error>();
} }
// DAP events // DAP events
...@@ -126,83 +124,81 @@ export class RawDebugSession implements IRawSession { ...@@ -126,83 +124,81 @@ export class RawDebugSession implements IRawSession {
} }
// DA event // DA event
public get onDidExitAdapter(): Event<void> { public get onDidExitAdapter(): Event<Error> {
return this._onDidExitAdapter.event; return this._onDidExitAdapter.event;
} }
private initServer(): TPromise<void> { private startAdapter(): TPromise<void> {
if (this.cachedInitServerP) { if (!this.cachedInitDebugAdapterP) {
return this.cachedInitServerP;
}
const startSessionP = this.startSession();
this.cachedInitServerP = startSessionP.then(() => {
this.startTime = new Date().getTime();
}, err => {
this.cachedInitServerP = null;
return TPromise.wrapError(err);
});
return this.cachedInitServerP; const startSessionP = this._debugger.createDebugAdapter(this.root, this.outputService, this.debugServerPort).then(debugAdapter => {
}
private startSession(): TPromise<void> {
return this._debugger.createDebugAdapter(this.root, this.outputService, this.debugServerPort).then(debugAdapter => { this.debugAdapter = debugAdapter;
this.debugAdapter = debugAdapter; this.debugAdapter.onError(err => this.onDebugAdapterError(err));
this.debugAdapter.onEvent(event => this.onDapEvent(event));
this.debugAdapter.onRequest(request => this.dispatchRequest(request));
this.debugAdapter.onExit(code => this.onDebugAdapterExit(code));
this.debugAdapter.onError(err => this.onDebugAdapterError(err)); return this.debugAdapter.startSession();
this.debugAdapter.onEvent(event => this.onDapEvent(event)); });
this.debugAdapter.onRequest(request => this.dispatchRequest(request));
this.debugAdapter.onExit(code => this.onDebugAdapterExit());
return this.debugAdapter.startSession(); this.cachedInitDebugAdapterP = startSessionP.then(() => {
}); this.startTime = new Date().getTime();
} }, err => {
this.cachedInitDebugAdapterP = null;
return TPromise.wrapError(err);
});
}
public custom(request: string, args: any): TPromise<DebugProtocol.Response> { return this.cachedInitDebugAdapterP;
return this.send(request, args);
} }
private send<R extends DebugProtocol.Response>(command: string, args: any, cancelOnDisconnect = true): TPromise<R> { private send<R extends DebugProtocol.Response>(command: string, args: any, cancelOnDisconnect = true): TPromise<R> {
return this.initServer().then(() => { return this.startAdapter().then(() => {
const cancellationSource = new CancellationTokenSource(); const cancellationSource = new CancellationTokenSource();
const promise = this.internalSend<R>(command, args, cancellationSource.token).then(response => response, (errorResponse: DebugProtocol.ErrorResponse) => {
const error = errorResponse && errorResponse.body ? errorResponse.body.error : null; const promise = this.internalSend<R>(command, args, cancellationSource.token).then(response => {
const errorMessage = errorResponse ? errorResponse.message : ''; return response;
const telemetryMessage = error ? formatPII(error.format, true, error.variables) : errorMessage; },
if (error && error.sendTelemetry) { (errorResponse: DebugProtocol.ErrorResponse) => {
/* __GDPR__ const error = errorResponse && errorResponse.body ? errorResponse.body.error : null;
"debugProtocolErrorResponse" : { const errorMessage = errorResponse ? errorResponse.message : '';
"error" : { "classification": "CallstackOrException", "purpose": "FeatureInsight" } const telemetryMessage = error ? formatPII(error.format, true, error.variables) : errorMessage;
} if (error && error.sendTelemetry) {
*/ /* __GDPR__
this.telemetryService.publicLog('debugProtocolErrorResponse', { error: telemetryMessage }); "debugProtocolErrorResponse" : {
if (this.customTelemetryService) { "error" : { "classification": "CallstackOrException", "purpose": "FeatureInsight" }
/* __GDPR__TODO__ }
The message is sent in the name of the adapter but the adapter doesn't know about it.
However, since adapters are an open-ended set, we can not declared the events statically either.
*/ */
this.customTelemetryService.publicLog('debugProtocolErrorResponse', { error: telemetryMessage }); this.telemetryService.publicLog('debugProtocolErrorResponse', { error: telemetryMessage });
if (this.customTelemetryService) {
/* __GDPR__TODO__
The message is sent in the name of the adapter but the adapter doesn't know about it.
However, since adapters are an open-ended set, we can not declared the events statically either.
*/
this.customTelemetryService.publicLog('debugProtocolErrorResponse', { error: telemetryMessage });
}
} }
}
const userMessage = error ? formatPII(error.format, false, error.variables) : errorMessage; const userMessage = error ? formatPII(error.format, false, error.variables) : errorMessage;
if (error && error.url) { if (error && error.url) {
const label = error.urlLabel ? error.urlLabel : nls.localize('moreInfo', "More Info"); const label = error.urlLabel ? error.urlLabel : nls.localize('moreInfo', "More Info");
return TPromise.wrapError<R>(errors.create(userMessage, { return TPromise.wrapError<R>(errors.create(userMessage, {
actions: [new Action('debug.moreInfo', label, null, true, () => { actions: [new Action('debug.moreInfo', label, null, true, () => {
window.open(error.url); window.open(error.url);
return TPromise.as(null); return TPromise.as(null);
})] })]
})); }));
} }
return errors.isPromiseCanceledError(errorResponse) ? undefined : TPromise.wrapError<R>(new Error(userMessage)); if (errors.isPromiseCanceledError(errorResponse)) {
}); return TPromise.wrapError<R>(<any>errorResponse);
}
return TPromise.wrapError<R>(new Error(userMessage));
});
if (cancelOnDisconnect) { if (cancelOnDisconnect) {
this.cancellationTokens.push(cancellationSource); this.cancellationTokens.push(cancellationSource);
...@@ -397,7 +393,6 @@ export class RawDebugSession implements IRawSession { ...@@ -397,7 +393,6 @@ export class RawDebugSession implements IRawSession {
return this.send<DebugProtocol.LoadedSourcesResponse>('loadedSources', args); return this.send<DebugProtocol.LoadedSourcesResponse>('loadedSources', args);
} }
public threads(): TPromise<DebugProtocol.ThreadsResponse> { public threads(): TPromise<DebugProtocol.ThreadsResponse> {
return this.send<DebugProtocol.ThreadsResponse>('threads', null); return this.send<DebugProtocol.ThreadsResponse>('threads', null);
} }
...@@ -424,6 +419,10 @@ export class RawDebugSession implements IRawSession { ...@@ -424,6 +419,10 @@ export class RawDebugSession implements IRawSession {
}); });
} }
public custom(request: string, args: any): TPromise<DebugProtocol.Response> {
return this.send(request, args);
}
public getLengthInSeconds(): number { public getLengthInSeconds(): number {
return (new Date().getTime() - this.startTime) / 1000; return (new Date().getTime() - this.startTime) / 1000;
} }
...@@ -503,14 +502,14 @@ export class RawDebugSession implements IRawSession { ...@@ -503,14 +502,14 @@ export class RawDebugSession implements IRawSession {
return TPromise.as(null); return TPromise.as(null);
} }
private stopServer(): TPromise<any> { private stopServer(error?: Error): TPromise<any> {
if (/* this.socket !== null */ this.debugAdapter instanceof SocketDebugAdapter) { if (/* this.socket !== null */ this.debugAdapter instanceof SocketDebugAdapter) {
this.debugAdapter.stopSession(); this.debugAdapter.stopSession();
this.cachedInitServerP = null; this.cachedInitDebugAdapterP = null;
} }
this._onDidExitAdapter.fire(); this._onDidExitAdapter.fire(error);
this.disconnected = true; this.disconnected = true;
if (!this.debugAdapter || this.debugAdapter instanceof SocketDebugAdapter) { if (!this.debugAdapter || this.debugAdapter instanceof SocketDebugAdapter) {
return TPromise.as(null); return TPromise.as(null);
...@@ -518,18 +517,18 @@ export class RawDebugSession implements IRawSession { ...@@ -518,18 +517,18 @@ export class RawDebugSession implements IRawSession {
return this.debugAdapter.stopSession(); return this.debugAdapter.stopSession();
} }
private onDebugAdapterError(err: Error): void { private onDebugAdapterError(err: Error): void {
this.notificationService.error(err.message || err.toString()); this.stopServer(err);
this.stopServer();
} }
private onDebugAdapterExit(): void { private onDebugAdapterExit(code: number): void {
this.debugAdapter = null; this.debugAdapter = null;
this.cachedInitServerP = null; this.cachedInitDebugAdapterP = null;
if (!this.disconnected) { if (!this.disconnected && code !== 0) {
this.notificationService.error(nls.localize('debugAdapterCrash', "Debug adapter process has terminated unexpectedly")); this._onDidExitAdapter.fire(new Error(`exit code: ${code}`));
} else {
// normal exit
this._onDidExitAdapter.fire();
} }
this._onDidExitAdapter.fire();
} }
} }
...@@ -157,7 +157,7 @@ export class MockSession implements ISession { ...@@ -157,7 +157,7 @@ export class MockSession implements ISession {
return null; return null;
} }
get onDidExitAdapter(): Event<void> { get onDidExitAdapter(): Event<Error> {
return null; return null;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册