From c13bb07894455d27ed4fb94b12262e9be006176e Mon Sep 17 00:00:00 2001 From: Anthony Kim <62267334+anthonykim1@users.noreply.github.com> Date: Tue, 13 Aug 2024 13:40:31 -0700 Subject: [PATCH] REPL Telemetry for Terminal REPL and Native REPL (#23941) Resolves: https://github.com/microsoft/vscode-python/issues/23740 Also organize Telemetry for Terminal REPL vs. Native REPL. Now we can sort them out with new attribute 'replType' on the REPL Event. With this PR: - (EventName.REPL, { replType: 'Terminal' }) for when people launch Terminal REPL via Command Palette, Manually type Python in terminal (tried to account for all Python cases that will trigger REPL). - (EventName.REPL, { replType: 'Native' }) for when people launch Native REPL via Command Palette. --------- Co-authored-by: Karthik Nadig --- src/client/extensionActivation.ts | 2 ++ src/client/providers/replProvider.ts | 2 +- src/client/repl/replCommands.ts | 4 +++- src/client/telemetry/index.ts | 9 +++++++-- .../codeExecution/terminalReplWatcher.ts | 19 +++++++++++++++++++ 5 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 src/client/terminals/codeExecution/terminalReplWatcher.ts diff --git a/src/client/extensionActivation.ts b/src/client/extensionActivation.ts index 77ed2edf6716..fe5d18a8b83f 100644 --- a/src/client/extensionActivation.ts +++ b/src/client/extensionActivation.ts @@ -53,6 +53,7 @@ import { logAndNotifyOnLegacySettings } from './logging/settingLogs'; import { DebuggerTypeName } from './debugger/constants'; import { StopWatch } from './common/utils/stopWatch'; import { registerReplCommands, registerReplExecuteOnEnter, registerStartNativeReplCommand } from './repl/replCommands'; +import { registerTriggerForTerminalREPL } from './terminals/codeExecution/terminalReplWatcher'; export async function activateComponents( // `ext` is passed to any extra activation funcs. @@ -108,6 +109,7 @@ export function activateFeatures(ext: ExtensionState, _components: Components): ); const executionHelper = ext.legacyIOC.serviceContainer.get(ICodeExecutionHelper); const commandManager = ext.legacyIOC.serviceContainer.get(ICommandManager); + registerTriggerForTerminalREPL(ext.disposables); registerStartNativeReplCommand(ext.disposables, interpreterService); registerReplCommands(ext.disposables, interpreterService, executionHelper, commandManager); registerReplExecuteOnEnter(ext.disposables, interpreterService, commandManager); diff --git a/src/client/providers/replProvider.ts b/src/client/providers/replProvider.ts index ba01dea3390d..810e24b78f42 100644 --- a/src/client/providers/replProvider.ts +++ b/src/client/providers/replProvider.ts @@ -28,7 +28,7 @@ export class ReplProvider implements Disposable { this.disposables.push(disposable); } - @captureTelemetry(EventName.REPL) + @captureTelemetry(EventName.REPL, { replType: 'Terminal' }) private async commandHandler() { const resource = this.activeResourceService.getActiveResource(); const interpreterService = this.serviceContainer.get(IInterpreterService); diff --git a/src/client/repl/replCommands.ts b/src/client/repl/replCommands.ts index 5570fa8384f4..120ddf13effc 100644 --- a/src/client/repl/replCommands.ts +++ b/src/client/repl/replCommands.ts @@ -15,6 +15,8 @@ import { isMultiLineText, } from './replUtils'; import { registerCommand } from '../common/vscodeApis/commandApis'; +import { sendTelemetryEvent } from '../telemetry'; +import { EventName } from '../telemetry/constants'; /** * Register Start Native REPL command in the command palette @@ -30,6 +32,7 @@ export async function registerStartNativeReplCommand( ): Promise { disposables.push( registerCommand(Commands.Start_Native_REPL, async (uri: Uri) => { + sendTelemetryEvent(EventName.REPL, undefined, { replType: 'Native' }); const interpreter = await getActiveInterpreter(uri, interpreterService); if (interpreter) { if (interpreter) { @@ -61,7 +64,6 @@ export async function registerReplCommands( await executeInTerminal(); return; } - const interpreter = await getActiveInterpreter(uri, interpreterService); if (interpreter) { diff --git a/src/client/telemetry/index.ts b/src/client/telemetry/index.ts index e995ec6d53eb..4904b330c75b 100644 --- a/src/client/telemetry/index.ts +++ b/src/client/telemetry/index.ts @@ -2305,10 +2305,15 @@ export interface IEventNamePropertyMapping { */ /* __GDPR__ "repl" : { - "duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "karthiknadig" } + "duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "anthonykim1" } } */ - [EventName.REPL]: never | undefined; + [EventName.REPL]: { + /** + * Whether the user launched the Terminal REPL or Native REPL + */ + replType: 'Terminal' | 'Native'; + }; /** * Telemetry event sent if and when user configure tests command. This command can be trigerred from multiple places in the extension. (Command palette, prompt etc.) */ diff --git a/src/client/terminals/codeExecution/terminalReplWatcher.ts b/src/client/terminals/codeExecution/terminalReplWatcher.ts new file mode 100644 index 000000000000..5921bf8b07c4 --- /dev/null +++ b/src/client/terminals/codeExecution/terminalReplWatcher.ts @@ -0,0 +1,19 @@ +import { Disposable, TerminalShellExecutionStartEvent } from 'vscode'; +import { onDidStartTerminalShellExecution } from '../../common/vscodeApis/windowApis'; +import { sendTelemetryEvent } from '../../telemetry'; +import { EventName } from '../../telemetry/constants'; + +function checkREPLCommand(command: string): boolean { + const lower = command.toLowerCase().trimStart(); + return lower.startsWith('python ') || lower.startsWith('py '); +} + +export function registerTriggerForTerminalREPL(disposables: Disposable[]): void { + disposables.push( + onDidStartTerminalShellExecution(async (e: TerminalShellExecutionStartEvent) => { + if (e.execution.commandLine.isTrusted && checkREPLCommand(e.execution.commandLine.value)) { + sendTelemetryEvent(EventName.REPL, undefined, { replType: 'Terminal' }); + } + }), + ); +}