From e2180107964ba1fc4ca2660c6b84e07e8e9289ea Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 19 Feb 2020 11:52:52 -0800 Subject: [PATCH 1/2] Add telemetry --- news/3 Code Health/10098.md | 1 + news/3 Code Health/10212.md | 1 + src/client/datascience/constants.ts | 3 +++ .../interactive-common/interactiveBase.ts | 16 ++++++++++++++-- .../datascience/jupyter/jupyterExecution.ts | 6 ++++++ src/client/telemetry/index.ts | 12 ++++++++++++ 6 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 news/3 Code Health/10098.md create mode 100644 news/3 Code Health/10212.md diff --git a/news/3 Code Health/10098.md b/news/3 Code Health/10098.md new file mode 100644 index 000000000000..057ae06fa5e2 --- /dev/null +++ b/news/3 Code Health/10098.md @@ -0,0 +1 @@ +Telemetry to capture connections to `localhost` using the connect to remote Jupyter server feature. diff --git a/news/3 Code Health/10212.md b/news/3 Code Health/10212.md new file mode 100644 index 000000000000..4bf0014f1470 --- /dev/null +++ b/news/3 Code Health/10212.md @@ -0,0 +1 @@ +Telemetry to capture perceived startup times of Jupyter and time to execute a cell. diff --git a/src/client/datascience/constants.ts b/src/client/datascience/constants.ts index 4ae92a96395e..725bc072f313 100644 --- a/src/client/datascience/constants.ts +++ b/src/client/datascience/constants.ts @@ -178,6 +178,7 @@ export enum Telemetry { SubmitCellThroughInput = 'DATASCIENCE.SUBMITCELLFROMREPL', ConnectLocalJupyter = 'DS_INTERNAL.CONNECTLOCALJUPYTER', ConnectRemoteJupyter = 'DS_INTERNAL.CONNECTREMOTEJUPYTER', + ConnectRemoteJupyterViaLocalHost = 'DS_INTERNAL.CONNECTREMOTEJUPYTER_VIA_LOCALHOST', ConnectFailedJupyter = 'DS_INTERNAL.CONNECTFAILEDJUPYTER', ConnectRemoteFailedJupyter = 'DS_INTERNAL.CONNECTREMOTEFAILEDJUPYTER', StartSessionFailedJupyter = 'DS_INTERNAL.START_SESSION_FAILED_JUPYTER', @@ -227,6 +228,8 @@ export enum Telemetry { ExecuteCell = 'DATASCIENCE.EXECUTE_CELL_TIME', ExecuteCellPerceivedCold = 'DS_INTERNAL.EXECUTE_CELL_PERCEIVED_COLD', ExecuteCellPerceivedWarm = 'DS_INTERNAL.EXECUTE_CELL_PERCEIVED_WARM', + PerceivedJupyterStartup = 'DS_INTERNAL.PERCEIVED_JUPYTER_STARTUP', + StartExecuteCellPerceivedCold = 'DS_INTERNAL.START_EXECUTE_CELL_PERCEIVED_COLD', WebviewStartup = 'DS_INTERNAL.WEBVIEW_STARTUP', VariableExplorerFetchTime = 'DS_INTERNAL.VARIABLE_EXPLORER_FETCH_TIME', WebviewStyleUpdate = 'DS_INTERNAL.WEBVIEW_STYLE_UPDATE', diff --git a/src/client/datascience/interactive-common/interactiveBase.ts b/src/client/datascience/interactive-common/interactiveBase.ts index 156274913c5a..33114a6c7705 100644 --- a/src/client/datascience/interactive-common/interactiveBase.ts +++ b/src/client/datascience/interactive-common/interactiveBase.ts @@ -41,6 +41,7 @@ import { IFileSystem } from '../../common/platform/types'; import { IConfigurationService, IDisposableRegistry, IExperimentsManager } from '../../common/types'; import { createDeferred, Deferred } from '../../common/utils/async'; import * as localize from '../../common/utils/localize'; +import { StopWatch } from '../../common/utils/stopWatch'; import { IInterpreterService, PythonInterpreter } from '../../interpreter/contracts'; import { captureTelemetry, sendTelemetryEvent } from '../../telemetry'; import { generateCellRangesFromDocument } from '../cellFactory'; @@ -101,6 +102,7 @@ import { InteractiveWindowMessageListener } from './interactiveWindowMessageList export abstract class InteractiveBase extends WebViewHost implements IInteractiveBase { private unfinishedCells: ICell[] = []; private restartingKernel: boolean = false; + private perceivedJupyterStartupTelemetryCaptured: boolean = false; private potentiallyUnfinishedStatus: Disposable[] = []; private addSysInfoPromise: Deferred | undefined; private _notebook: INotebook | undefined; @@ -500,8 +502,9 @@ export abstract class InteractiveBase extends WebViewHost { traceInfo(`Submitting code for ${this.id}`); + const stopWatch = + this._notebook && !this.perceivedJupyterStartupTelemetryCaptured ? new StopWatch() : undefined; let result = true; - // Do not execute or render empty code cells const cellMatcher = new CellMatcher(this.configService.getSettings().datascience); if (cellMatcher.stripFirstMarker(code).length === 0) { @@ -568,7 +571,16 @@ export abstract class InteractiveBase extends WebViewHost { + if (e === ServerStatus.Busy) { + sendTelemetryEvent(Telemetry.StartExecuteCellPerceivedCold, stopWatch?.elapsedTime); + disposable.dispose(); + } + }); + } const observable = this._notebook.executeObservable(code, file, line, id, false); // Indicate we executed some code diff --git a/src/client/datascience/jupyter/jupyterExecution.ts b/src/client/datascience/jupyter/jupyterExecution.ts index 7ddbcb773e1f..2e884e6921ac 100644 --- a/src/client/datascience/jupyter/jupyterExecution.ts +++ b/src/client/datascience/jupyter/jupyterExecution.ts @@ -31,6 +31,8 @@ import { JupyterWaitForIdleError } from './jupyterWaitForIdleError'; import { KernelSelector, KernelSpecInterpreter } from './kernels/kernelSelector'; import { NotebookStarter } from './notebookStarter'; +const LocalHosts = ['localhost', '127.0.0.1', '::1']; + export class JupyterExecutionBase implements IJupyterExecution { private usablePythonInterpreter: PythonInterpreter | undefined; private eventEmitter: EventEmitter = new EventEmitter(); @@ -159,6 +161,10 @@ export class JupyterExecutionBase implements IJupyterExecution { this.startOrConnect(options, cancelToken), kernelSpecInterpreterPromise ]); + + if (!connection.localLaunch && LocalHosts.includes(connection.hostName.toLowerCase())) { + sendTelemetryEvent(Telemetry.ConnectRemoteJupyterViaLocalHost); + } // Create a server tha t we will then attempt to connect to. result = this.serviceContainer.get(INotebookServer); diff --git a/src/client/telemetry/index.ts b/src/client/telemetry/index.ts index 89810d4b152d..15797473f4dd 100644 --- a/src/client/telemetry/index.ts +++ b/src/client/telemetry/index.ts @@ -1460,6 +1460,10 @@ export interface IEventNamePropertyMapping { [Telemetry.ConnectFailedJupyter]: never | undefined; [Telemetry.ConnectLocalJupyter]: never | undefined; [Telemetry.ConnectRemoteJupyter]: never | undefined; + /** + * Connecting to an existing Jupyter server, but connecting to localhost. + */ + [Telemetry.ConnectRemoteJupyterViaLocalHost]: never | undefined; [Telemetry.ConnectRemoteFailedJupyter]: never | undefined; [Telemetry.ConnectRemoteSelfCertFailedJupyter]: never | undefined; [Telemetry.RegisterAndUseInterpreterAsKernel]: never | undefined; @@ -1493,6 +1497,14 @@ export interface IEventNamePropertyMapping { * If `notebook = true`, this its telemetry for native editor/notebooks. */ [Telemetry.ExecuteCellPerceivedWarm]: undefined | { notebook: boolean }; + /** + * Time take for jupyter server to start and be ready to run first user cell. + */ + [Telemetry.PerceivedJupyterStartup]: never | undefined; + /** + * Time take for jupyter server to be busy from the time user first hit `run` cell until jupyter reports it is busy running a cell. + */ + [Telemetry.StartExecuteCellPerceivedCold]: never | undefined; [Telemetry.ExecuteNativeCell]: never | undefined; [Telemetry.ExpandAll]: never | undefined; [Telemetry.ExportNotebook]: never | undefined; From cefe5e6ba0f6d02fdae2d37f82e98196529f8560 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Wed, 19 Feb 2020 11:55:30 -0800 Subject: [PATCH 2/2] Only for nb --- src/client/datascience/constants.ts | 4 ++-- src/client/datascience/interactive-common/interactiveBase.ts | 4 ++-- src/client/telemetry/index.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/client/datascience/constants.ts b/src/client/datascience/constants.ts index 725bc072f313..3de1554d555f 100644 --- a/src/client/datascience/constants.ts +++ b/src/client/datascience/constants.ts @@ -228,8 +228,8 @@ export enum Telemetry { ExecuteCell = 'DATASCIENCE.EXECUTE_CELL_TIME', ExecuteCellPerceivedCold = 'DS_INTERNAL.EXECUTE_CELL_PERCEIVED_COLD', ExecuteCellPerceivedWarm = 'DS_INTERNAL.EXECUTE_CELL_PERCEIVED_WARM', - PerceivedJupyterStartup = 'DS_INTERNAL.PERCEIVED_JUPYTER_STARTUP', - StartExecuteCellPerceivedCold = 'DS_INTERNAL.START_EXECUTE_CELL_PERCEIVED_COLD', + PerceivedJupyterStartupNotebook = 'DS_INTERNAL.PERCEIVED_JUPYTER_STARTUP_NOTEBOOK', + StartExecuteNotebookCellPerceivedCold = 'DS_INTERNAL.START_EXECUTE_NOTEBOOK_CELL_PERCEIVED_COLD', WebviewStartup = 'DS_INTERNAL.WEBVIEW_STARTUP', VariableExplorerFetchTime = 'DS_INTERNAL.VARIABLE_EXPLORER_FETCH_TIME', WebviewStyleUpdate = 'DS_INTERNAL.WEBVIEW_STYLE_UPDATE', diff --git a/src/client/datascience/interactive-common/interactiveBase.ts b/src/client/datascience/interactive-common/interactiveBase.ts index 33114a6c7705..2a639432f325 100644 --- a/src/client/datascience/interactive-common/interactiveBase.ts +++ b/src/client/datascience/interactive-common/interactiveBase.ts @@ -573,10 +573,10 @@ export abstract class InteractiveBase extends WebViewHost { if (e === ServerStatus.Busy) { - sendTelemetryEvent(Telemetry.StartExecuteCellPerceivedCold, stopWatch?.elapsedTime); + sendTelemetryEvent(Telemetry.StartExecuteNotebookCellPerceivedCold, stopWatch?.elapsedTime); disposable.dispose(); } }); diff --git a/src/client/telemetry/index.ts b/src/client/telemetry/index.ts index 15797473f4dd..13f6488cb22a 100644 --- a/src/client/telemetry/index.ts +++ b/src/client/telemetry/index.ts @@ -1500,11 +1500,11 @@ export interface IEventNamePropertyMapping { /** * Time take for jupyter server to start and be ready to run first user cell. */ - [Telemetry.PerceivedJupyterStartup]: never | undefined; + [Telemetry.PerceivedJupyterStartupNotebook]: never | undefined; /** * Time take for jupyter server to be busy from the time user first hit `run` cell until jupyter reports it is busy running a cell. */ - [Telemetry.StartExecuteCellPerceivedCold]: never | undefined; + [Telemetry.StartExecuteNotebookCellPerceivedCold]: never | undefined; [Telemetry.ExecuteNativeCell]: never | undefined; [Telemetry.ExpandAll]: never | undefined; [Telemetry.ExportNotebook]: never | undefined;