diff --git a/news/3 Code Health/7332.md b/news/3 Code Health/7332.md new file mode 100644 index 000000000000..2724b77181e7 --- /dev/null +++ b/news/3 Code Health/7332.md @@ -0,0 +1 @@ +Add telemetry to measure debugger start up performance. diff --git a/src/client/datascience/debugLocationTracker.ts b/src/client/datascience/debugLocationTracker.ts index 187a54bffd8c..387475245836 100644 --- a/src/client/datascience/debugLocationTracker.ts +++ b/src/client/datascience/debugLocationTracker.ts @@ -5,6 +5,10 @@ import { injectable } from 'inversify'; import { DebugSession, Event, EventEmitter } from 'vscode'; import { DebugProtocol } from 'vscode-debugprotocol'; +import { StopWatch } from '../common/utils/stopWatch'; +import { AttachRequestArguments, ConsoleType, LaunchRequestArguments, TriggerType } from '../debugger/types'; +import { sendTelemetryEvent } from '../telemetry'; +import { EventName } from '../telemetry/constants'; import { IDebugLocation, IDebugLocationTracker } from './types'; // When a python debugging session is active keep track of the current debug location @@ -13,10 +17,16 @@ export class DebugLocationTracker implements IDebugLocationTracker { private waitingForStackTrace: boolean = false; private _debugLocation: IDebugLocation | undefined; private debugLocationUpdatedEvent: EventEmitter = new EventEmitter(); + private trigger: TriggerType = 'launch'; + private console: ConsoleType | undefined; + private timer = new StopWatch(); - public setDebugSession(_targetSession: DebugSession) { + public setDebugSession(targetSession: DebugSession) { this.DebugLocation = undefined; this.waitingForStackTrace = false; + this.trigger = targetSession.configuration.type as TriggerType; + const debugConfiguration = targetSession.configuration as Partial; + this.console = debugConfiguration.console; } public get debugLocationUpdated(): Event { @@ -27,8 +37,20 @@ export class DebugLocationTracker implements IDebugLocationTracker { return this._debugLocation; } + public onWillStartSession() { + this.sendTelemetry(EventName.DEBUG_SESSION_START); + } + // tslint:disable-next-line:no-any public onDidSendMessage(message: DebugProtocol.ProtocolMessage) { + if (message.type === 'response') { + const response = message as DebugProtocol.Response; + if (response.command === 'configurationDone') { + // "configurationDone" response is sent immediately after user code starts running. + this.sendTelemetry(EventName.DEBUG_SESSION_USER_CODE_RUNNING); + } + } + if (this.isStopEvent(message)) { // Some type of stop, wait to see our next stack trace to find our location this.waitingForStackTrace = true; @@ -51,6 +73,14 @@ export class DebugLocationTracker implements IDebugLocationTracker { } + public onWillStopSession() { + this.sendTelemetry(EventName.DEBUG_SESSION_STOP); + } + + public onError?(_error: Error) { + this.sendTelemetry(EventName.DEBUG_SESSION_ERROR); + } + // Set our new location and fire our debug event private set DebugLocation(newLocation: IDebugLocation | undefined) { const oldLocation = this._debugLocation; @@ -116,4 +146,15 @@ export class DebugLocationTracker implements IDebugLocationTracker { return false; } + + private sendTelemetry(eventName: EventName) { + if (eventName === EventName.DEBUG_SESSION_START) { + this.timer.reset(); + } + const telemetryProps = { + trigger: this.trigger, + console: this.console + }; + sendTelemetryEvent(eventName, this.timer.elapsedTime, telemetryProps); + } } diff --git a/src/client/debugger/types.ts b/src/client/debugger/types.ts index 1241988c1f61..b2675f9082d6 100644 --- a/src/client/debugger/types.ts +++ b/src/client/debugger/types.ts @@ -82,3 +82,5 @@ export interface AttachRequestArguments extends DebugProtocol.AttachRequestArgum export interface DebugConfigurationArguments extends LaunchRequestArguments, AttachRequestArguments { } export type ConsoleType = 'internalConsole' | 'integratedTerminal' | 'externalTerminal'; + +export type TriggerType = 'launch' | 'attach' | 'test'; diff --git a/src/client/telemetry/constants.ts b/src/client/telemetry/constants.ts index 8b97329d0b32..51e8d25c02f1 100644 --- a/src/client/telemetry/constants.ts +++ b/src/client/telemetry/constants.ts @@ -38,6 +38,10 @@ export enum EventName { WORKSPACE_SYMBOLS_GO_TO = 'WORKSPACE_SYMBOLS.GO_TO', EXECUTION_CODE = 'EXECUTION_CODE', EXECUTION_DJANGO = 'EXECUTION_DJANGO', + DEBUG_SESSION_ERROR = 'DEBUG_SESSION.ERROR', + DEBUG_SESSION_START = 'DEBUG_SESSION.START', + DEBUG_SESSION_STOP = 'DEBUG_SESSION.STOP', + DEBUG_SESSION_USER_CODE_RUNNING = 'DEBUG_SESSION.USER_CODE_RUNNING', DEBUGGER = 'DEBUGGER', DEBUGGER_ATTACH_TO_CHILD_PROCESS = 'DEBUGGER.ATTACH_TO_CHILD_PROCESS', DEBUGGER_CONFIGURATION_PROMPTS = 'DEBUGGER.CONFIGURATION.PROMPTS', diff --git a/src/client/telemetry/index.ts b/src/client/telemetry/index.ts index 0e07984ecb69..d185c264c67c 100644 --- a/src/client/telemetry/index.ts +++ b/src/client/telemetry/index.ts @@ -15,7 +15,7 @@ import { TerminalShellType } from '../common/terminal/types'; import { StopWatch } from '../common/utils/stopWatch'; import { Telemetry } from '../datascience/constants'; import { DebugConfigurationType } from '../debugger/extension/types'; -import { ConsoleType } from '../debugger/types'; +import { ConsoleType, TriggerType } from '../debugger/types'; import { AutoSelectionRule } from '../interpreter/autoSelection/types'; import { InterpreterType } from '../interpreter/contracts'; import { LinterId } from '../linters/types'; @@ -267,6 +267,98 @@ export interface IEventNamePropertyMapping { */ enabled: boolean; }; + /** + * Telemetry captured before starting debug session. + */ + [EventName.DEBUG_SESSION_START]: { + /** + * Trigger for starting the debugger. + * - `launch`: Launch/start new code and debug it. + * - `attach`: Attach to an exiting python process (remote debugging). + * - `test`: Debugging python tests. + * + * @type {TriggerType} + */ + trigger: TriggerType; + /** + * Type of console used. + * -`internalConsole`: Use VS Code debug console (no shells/terminals). + * - `integratedTerminal`: Use VS Code terminal. + * - `externalTerminal`: Use an External terminal. + * + * @type {ConsoleType} + */ + console?: ConsoleType; + }; + /** + * Telemetry captured when debug session runs into an error. + */ + [EventName.DEBUG_SESSION_ERROR]: { + /** + * Trigger for starting the debugger. + * - `launch`: Launch/start new code and debug it. + * - `attach`: Attach to an exiting python process (remote debugging). + * - `test`: Debugging python tests. + * + * @type {TriggerType} + */ + trigger: TriggerType; + /** + * Type of console used. + * -`internalConsole`: Use VS Code debug console (no shells/terminals). + * - `integratedTerminal`: Use VS Code terminal. + * - `externalTerminal`: Use an External terminal. + * + * @type {ConsoleType} + */ + console?: ConsoleType; + }; + /** + * Telemetry captured after stopping debug session. + */ + [EventName.DEBUG_SESSION_STOP]: { + /** + * Trigger for starting the debugger. + * - `launch`: Launch/start new code and debug it. + * - `attach`: Attach to an exiting python process (remote debugging). + * - `test`: Debugging python tests. + * + * @type {TriggerType} + */ + trigger: TriggerType; + /** + * Type of console used. + * -`internalConsole`: Use VS Code debug console (no shells/terminals). + * - `integratedTerminal`: Use VS Code terminal. + * - `externalTerminal`: Use an External terminal. + * + * @type {ConsoleType} + */ + console?: ConsoleType; + }; + /** + * Telemetry captured when user code starts running after loading the debugger. + */ + [EventName.DEBUG_SESSION_USER_CODE_RUNNING]: { + /** + * Trigger for starting the debugger. + * - `launch`: Launch/start new code and debug it. + * - `attach`: Attach to an exiting python process (remote debugging). + * - `test`: Debugging python tests. + * + * @type {TriggerType} + */ + trigger: TriggerType; + /** + * Type of console used. + * -`internalConsole`: Use VS Code debug console (no shells/terminals). + * - `integratedTerminal`: Use VS Code terminal. + * - `externalTerminal`: Use an External terminal. + * + * @type {ConsoleType} + */ + console?: ConsoleType; + }; /** * Telemetry captured when starting the debugger. */ @@ -277,9 +369,9 @@ export interface IEventNamePropertyMapping { * - `attach`: Attach to an exiting python process (remote debugging). * - `test`: Debugging python tests. * - * @type {('launch' | 'attach' | 'test')} + * @type {TriggerType} */ - trigger: 'launch' | 'attach' | 'test'; + trigger: TriggerType; /** * Type of console used. * -`internalConsole`: Use VS Code debug console (no shells/terminals).