Skip to content

Commit 896f646

Browse files
committed
add new telemetry and other checks
1 parent dafa89c commit 896f646

File tree

4 files changed

+144
-0
lines changed

4 files changed

+144
-0
lines changed

src/common/telemetry/constants.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,18 @@ export enum EventNames {
101101
* - hasPersistedSelection: boolean (whether a persisted env path existed in workspace state)
102102
*/
103103
ENV_SELECTION_RESULT = 'ENV_SELECTION.RESULT',
104+
/**
105+
* Telemetry event fired when a lazily-registered manager completes its first initialization.
106+
* Replaces MANAGER_REGISTRATION_SKIPPED and MANAGER_REGISTRATION_FAILED for managers
107+
* that now register unconditionally (pipenv, poetry, pyenv).
108+
* Properties:
109+
* - managerName: string (e.g. 'pipenv', 'poetry', 'pyenv')
110+
* - result: 'success' | 'tool_not_found' | 'error'
111+
* - envCount: number (environments discovered)
112+
* - toolSource: string (how the CLI was found: 'settings', 'cache', 'persistentState', 'path', 'pet', 'none')
113+
* - errorType: string (classified error category, on failure only)
114+
*/
115+
MANAGER_LAZY_INIT = 'MANAGER.LAZY_INIT',
104116
}
105117

106118
// Map all events to their properties
@@ -373,4 +385,22 @@ export interface IEventNamePropertyMapping {
373385
resolutionPath: string;
374386
hasPersistedSelection: boolean;
375387
};
388+
389+
/* __GDPR__
390+
"manager.lazy_init": {
391+
"managerName": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" },
392+
"result": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" },
393+
"envCount": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "eleanorjboyd" },
394+
"toolSource": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" },
395+
"errorType": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" },
396+
"<duration>": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "eleanorjboyd" }
397+
}
398+
*/
399+
[EventNames.MANAGER_LAZY_INIT]: {
400+
managerName: string;
401+
result: 'success' | 'tool_not_found' | 'error';
402+
envCount: number;
403+
toolSource: string;
404+
errorType?: string;
405+
};
376406
}

src/managers/pipenv/pipenvManager.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,18 @@ import {
1515
SetEnvironmentScope,
1616
} from '../../api';
1717
import { PipenvStrings } from '../../common/localize';
18+
import { StopWatch } from '../../common/stopWatch';
19+
import { EventNames } from '../../common/telemetry/constants';
20+
import { classifyError } from '../../common/telemetry/errorClassifier';
21+
import { sendTelemetryEvent } from '../../common/telemetry/sender';
1822
import { createDeferred, Deferred } from '../../common/utils/deferred';
1923
import { normalizePath } from '../../common/utils/pathUtils';
2024
import { withProgress } from '../../common/window.apis';
2125
import { getProjectFsPathForScope, tryFastPathGet } from '../common/fastPath';
2226
import { NativePythonFinder } from '../common/nativePythonFinder';
2327
import {
2428
clearPipenvCache,
29+
getPipenv,
2530
getPipenvForGlobal,
2631
getPipenvForWorkspace,
2732
refreshPipenv,
@@ -74,8 +79,19 @@ export class PipenvManager implements EnvironmentManager {
7479
}
7580

7681
this._initialized = createDeferred();
82+
const stopWatch = new StopWatch();
83+
let result: 'success' | 'tool_not_found' | 'error' = 'success';
84+
let envCount = 0;
85+
let toolSource = 'none';
86+
let errorType: string | undefined;
7787

7888
try {
89+
// Check if tool is findable before PET refresh (settings/cache/PATH only, no PET)
90+
const preRefreshTool = await getPipenv();
91+
if (preRefreshTool) {
92+
toolSource = 'path';
93+
}
94+
7995
await withProgress(
8096
{
8197
location: ProgressLocation.Window,
@@ -90,7 +106,29 @@ export class PipenvManager implements EnvironmentManager {
90106
);
91107
},
92108
);
109+
110+
envCount = this.collection.length;
111+
112+
// If tool wasn't found via local lookup, check if refresh discovered it via PET
113+
if (!preRefreshTool) {
114+
const postRefreshTool = await getPipenv();
115+
toolSource = postRefreshTool ? 'pet' : 'none';
116+
}
117+
118+
if (toolSource === 'none') {
119+
result = 'tool_not_found';
120+
}
121+
} catch (ex) {
122+
result = 'error';
123+
errorType = classifyError(ex);
93124
} finally {
125+
sendTelemetryEvent(EventNames.MANAGER_LAZY_INIT, stopWatch.elapsedTime, {
126+
managerName: 'pipenv',
127+
result,
128+
envCount,
129+
toolSource,
130+
errorType,
131+
});
94132
this._initialized.resolve();
95133
}
96134
}

src/managers/poetry/poetryManager.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,15 @@ import { traceError, traceInfo } from '../../common/logging';
2020
import { createDeferred, Deferred } from '../../common/utils/deferred';
2121
import { normalizePath } from '../../common/utils/pathUtils';
2222
import { withProgress } from '../../common/window.apis';
23+
import { StopWatch } from '../../common/stopWatch';
24+
import { EventNames } from '../../common/telemetry/constants';
25+
import { classifyError } from '../../common/telemetry/errorClassifier';
26+
import { sendTelemetryEvent } from '../../common/telemetry/sender';
2327
import { NativePythonFinder } from '../common/nativePythonFinder';
2428
import { getLatest } from '../common/utils';
2529
import {
2630
clearPoetryCache,
31+
getPoetry,
2732
getPoetryForGlobal,
2833
getPoetryForWorkspace,
2934
POETRY_GLOBAL,
@@ -74,8 +79,19 @@ export class PoetryManager implements EnvironmentManager, Disposable {
7479
}
7580

7681
this._initialized = createDeferred();
82+
const stopWatch = new StopWatch();
83+
let result: 'success' | 'tool_not_found' | 'error' = 'success';
84+
let envCount = 0;
85+
let toolSource = 'none';
86+
let errorType: string | undefined;
7787

7888
try {
89+
// Check if tool is findable before PET refresh (settings/cache/PATH only, no PET)
90+
const preRefreshTool = await getPoetry();
91+
if (preRefreshTool) {
92+
toolSource = 'path';
93+
}
94+
7995
await withProgress(
8096
{
8197
location: ProgressLocation.Window,
@@ -90,7 +106,29 @@ export class PoetryManager implements EnvironmentManager, Disposable {
90106
);
91107
},
92108
);
109+
110+
envCount = this.collection.length;
111+
112+
// If tool wasn't found via local lookup, check if refresh discovered it via PET
113+
if (!preRefreshTool) {
114+
const postRefreshTool = await getPoetry();
115+
toolSource = postRefreshTool ? 'pet' : 'none';
116+
}
117+
118+
if (toolSource === 'none') {
119+
result = 'tool_not_found';
120+
}
121+
} catch (ex) {
122+
result = 'error';
123+
errorType = classifyError(ex);
93124
} finally {
125+
sendTelemetryEvent(EventNames.MANAGER_LAZY_INIT, stopWatch.elapsedTime, {
126+
managerName: 'poetry',
127+
result,
128+
envCount,
129+
toolSource,
130+
errorType,
131+
});
94132
this._initialized.resolve();
95133
}
96134
}

src/managers/pyenv/pyenvManager.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ import {
1717
} from '../../api';
1818
import { PyenvStrings } from '../../common/localize';
1919
import { traceError, traceInfo } from '../../common/logging';
20+
import { StopWatch } from '../../common/stopWatch';
21+
import { EventNames } from '../../common/telemetry/constants';
22+
import { classifyError } from '../../common/telemetry/errorClassifier';
23+
import { sendTelemetryEvent } from '../../common/telemetry/sender';
2024
import { createDeferred, Deferred } from '../../common/utils/deferred';
2125
import { normalizePath } from '../../common/utils/pathUtils';
2226
import { withProgress } from '../../common/window.apis';
@@ -25,6 +29,7 @@ import { NativePythonFinder } from '../common/nativePythonFinder';
2529
import { getLatest } from '../common/utils';
2630
import {
2731
clearPyenvCache,
32+
getPyenv,
2833
getPyenvForGlobal,
2934
getPyenvForWorkspace,
3035
PYENV_VERSIONS,
@@ -75,8 +80,19 @@ export class PyEnvManager implements EnvironmentManager, Disposable {
7580
}
7681

7782
this._initialized = createDeferred();
83+
const stopWatch = new StopWatch();
84+
let result: 'success' | 'tool_not_found' | 'error' = 'success';
85+
let envCount = 0;
86+
let toolSource = 'none';
87+
let errorType: string | undefined;
7888

7989
try {
90+
// Check if tool is findable before PET refresh (settings/cache/PATH only, no PET)
91+
const preRefreshTool = await getPyenv();
92+
if (preRefreshTool) {
93+
toolSource = 'path';
94+
}
95+
8096
await withProgress(
8197
{
8298
location: ProgressLocation.Window,
@@ -91,7 +107,29 @@ export class PyEnvManager implements EnvironmentManager, Disposable {
91107
);
92108
},
93109
);
110+
111+
envCount = this.collection.length;
112+
113+
// If tool wasn't found via local lookup, check if refresh discovered it via PET
114+
if (!preRefreshTool) {
115+
const postRefreshTool = await getPyenv();
116+
toolSource = postRefreshTool ? 'pet' : 'none';
117+
}
118+
119+
if (toolSource === 'none') {
120+
result = 'tool_not_found';
121+
}
122+
} catch (ex) {
123+
result = 'error';
124+
errorType = classifyError(ex);
94125
} finally {
126+
sendTelemetryEvent(EventNames.MANAGER_LAZY_INIT, stopWatch.elapsedTime, {
127+
managerName: 'pyenv',
128+
result,
129+
envCount,
130+
toolSource,
131+
errorType,
132+
});
95133
this._initialized.resolve();
96134
}
97135
}

0 commit comments

Comments
 (0)