Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional conda telemetry #23790

Merged
merged 1 commit into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,17 @@ export interface NativeEnvManagerInfo {
version?: string;
}

export type NativeCondaInfo = {
canSpawnConda: boolean;
condaRcs: string[];
envDirs: string[];
};

export interface NativeGlobalPythonFinder extends Disposable {
resolve(executable: string): Promise<NativeEnvInfo>;
refresh(): AsyncIterable<NativeEnvInfo>;
categoryToKind(category?: string): PythonEnvKind;
getCondaInfo(): Promise<NativeCondaInfo>;
}

interface NativeLog {
Expand Down Expand Up @@ -361,6 +368,10 @@ class NativeGlobalPythonFinderImpl extends DisposableBase implements NativeGloba
this.outputChannel.error('Refresh error', ex);
}
}

async getCondaInfo(): Promise<NativeCondaInfo> {
return this.connection.sendRequest<NativeCondaInfo>('condaInfo');
}
}

type ConfigurationOptions = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,18 +333,30 @@ export class EnvsCollectionService extends PythonEnvsWatcher<PythonEnvCollection
let condaInfoEnvsInvalid = 0;
let condaInfoEnvsDuplicate = 0;
let condaInfoEnvsInvalidPrefix = 0;
let condaInfoEnvsDirs: undefined | number;
let condaInfoEnvsDirs = 0;
let envsDirs: string[] = [];
let condaRcs: number | undefined;
let condaRootPrefixFoundInInfoNotInNative: undefined | boolean;
let condaDefaultPrefixFoundInInfoNotInNative: undefined | boolean;
try {
const conda = await Conda.getConda();
const info = await conda?.getInfo();
canSpawnConda = true;
canSpawnConda = !!info;
condaInfoEnvs = info?.envs?.length;
// eslint-disable-next-line camelcase
condaInfoEnvsDirs = info?.envs_dirs?.length;
// eslint-disable-next-line camelcase
envsDirs = info?.envs_dirs || [];

const condaRcFiles = new Set<string>();
await Promise.all(
// eslint-disable-next-line camelcase
[info?.rc_path, info?.user_rc_path, info?.sys_rc_path, ...(info?.config_files || [])].map(
async (rc) => {
if (rc && (await pathExists(rc))) {
condaRcFiles.add(rc);
}
},
),
).catch(noop);
condaRcs = condaRcFiles.size;
const duplicate = new Set<string>();
Promise.all(
(info?.envs || []).map(async (e) => {
Expand All @@ -361,16 +373,54 @@ export class EnvsCollectionService extends PythonEnvsWatcher<PythonEnvCollection
}
}),
);
Promise.all(
envsDirs.map(async (e) => {
if (await pathExists(e)) {
condaInfoEnvsDirs += 1;
}
}),
);
nativeEnvs
.filter((e) => this.nativeFinder.categoryToKind(e.kind) === PythonEnvKind.Conda)
.forEach((e) => {
if (e.prefix && envsDirs.some((d) => e.prefix && e.prefix.startsWith(d))) {
missingEnvironments.nativeCondaEnvsInEnvDir += 1;
}
});

// Check if we have found the conda env that matches the `root_prefix` in the conda info.
// eslint-disable-next-line camelcase
const rootPrefix = (info?.root_prefix || '').toLowerCase();
if (rootPrefix) {
// Check if we have a conda env that matches this prefix.
if (
envs.some(
(e) => e.executable.sysPrefix.toLowerCase() === rootPrefix && e.kind === PythonEnvKind.Conda,
)
) {
condaRootPrefixFoundInInfoNotInNative = nativeEnvs.some(
(e) => e.prefix?.toLowerCase() === rootPrefix.toLowerCase(),
);
}
}
// eslint-disable-next-line camelcase
const defaultPrefix = (info?.default_prefix || '').toLowerCase();
if (rootPrefix) {
// Check if we have a conda env that matches this prefix.
if (
envs.some(
(e) => e.executable.sysPrefix.toLowerCase() === defaultPrefix && e.kind === PythonEnvKind.Conda,
)
) {
condaDefaultPrefixFoundInInfoNotInNative = nativeEnvs.some(
(e) => e.prefix?.toLowerCase() === defaultPrefix.toLowerCase(),
);
}
}
} catch (ex) {
canSpawnConda = false;
}
const nativeCondaInfoPromise = this.nativeFinder.getCondaInfo();
const prefixesSeenAlready = new Set<string>();
await Promise.all(
envs.map(async (env) => {
Expand Down Expand Up @@ -480,6 +530,22 @@ export class EnvsCollectionService extends PythonEnvsWatcher<PythonEnvCollection
}),
).catch((ex) => traceError('Failed to send telemetry for missing environments', ex));

const nativeCondaInfo = await nativeCondaInfoPromise.catch((ex) =>
traceError(`Failed to get conda info from native locator`, ex),
);

type CondaTelemetry = {
nativeCanSpawnConda?: boolean;
nativeCondaInfoEnvsDirs?: number;
nativeCondaRcs?: number;
};

const condaTelemetry: CondaTelemetry = {};
if (nativeCondaInfo) {
condaTelemetry.nativeCanSpawnConda = nativeCondaInfo.canSpawnConda;
condaTelemetry.nativeCondaInfoEnvsDirs = new Set(nativeCondaInfo.envDirs).size;
condaTelemetry.nativeCondaRcs = new Set(nativeCondaInfo.condaRcs).size;
}
const environmentsWithoutPython = envs.filter(
(e) => getEnvPath(e.executable.filename, e.location).pathType === 'envFolderPath',
).length;
Expand Down Expand Up @@ -513,7 +579,7 @@ export class EnvsCollectionService extends PythonEnvsWatcher<PythonEnvCollection
if (e.executable.sysPrefix && !(await pathExists(e.executable.sysPrefix))) {
missingEnvironments.prefixNotExistsCondaEnvs += 1;
}
if (e.executable.filename && (await isCondaEnvironment(e.executable.filename))) {
if (e.executable.filename && !(await isCondaEnvironment(e.executable.filename))) {
missingEnvironments.invalidCondaEnvs += 1;
}
}),
Expand Down Expand Up @@ -568,10 +634,13 @@ export class EnvsCollectionService extends PythonEnvsWatcher<PythonEnvCollection

// Intent is to capture time taken for discovery of all envs to complete the first time.
sendTelemetryEvent(EventName.PYTHON_INTERPRETER_DISCOVERY, elapsedTime, {
telVer: 2,
telVer: 3,
condaRcs,
condaInfoEnvsInvalid,
condaInfoEnvsDuplicate,
condaInfoEnvsInvalidPrefix,
condaRootPrefixFoundInInfoNotInNative,
condaDefaultPrefixFoundInInfoNotInNative,
nativeDuration,
workspaceFolderCount: (workspace.workspaceFolders || []).length,
interpreters: this.cache.getAllEnvs().length,
Expand Down Expand Up @@ -610,6 +679,7 @@ export class EnvsCollectionService extends PythonEnvsWatcher<PythonEnvCollection
nativeVirtualEnvEnvs,
nativeVirtualEnvWrapperEnvs,
nativeGlobal,
...condaTelemetry,
...missingEnvironments,
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ export type CondaInfo = {
root_prefix?: string; // eslint-disable-line camelcase
conda_version?: string; // eslint-disable-line camelcase
conda_shlvl?: number; // eslint-disable-line camelcase
config_files?: string[]; // eslint-disable-line camelcase
rc_path?: string; // eslint-disable-line camelcase
sys_rc_path?: string; // eslint-disable-line camelcase
user_rc_path?: string; // eslint-disable-line camelcase
};

type CondaEnvInfo = {
Expand Down
32 changes: 32 additions & 0 deletions src/client/telemetry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,9 @@ export interface IEventNamePropertyMapping {
"envsNotFound" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"condaInfoEnvs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"condaInfoEnvsDirs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"nativeCondaInfoEnvsDirs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"condaRcs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"nativeCondaRcs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"condaEnvsInEnvDir" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"nativeCondaEnvsInEnvDir" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"invalidCondaEnvs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
Expand All @@ -1161,6 +1164,9 @@ export interface IEventNamePropertyMapping {
"environmentsWithoutPython" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
"usingNativeLocator" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "donjayamanne" },
"canSpawnConda" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "donjayamanne" },
"nativeCanSpawnConda" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"condaRootPrefixFoundInInfoNotInNative" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"condaDefaultPrefixFoundInInfoNotInNative" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"activeStateEnvs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
"condaEnvs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
"customEnvs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
Expand Down Expand Up @@ -1249,6 +1255,18 @@ export interface IEventNamePropertyMapping {
* The number of the envs_dirs returned by `conda info`
*/
condaInfoEnvsDirs?: number;
/**
* The number of the envs_dirs returned by native locator.
*/
nativeCondaInfoEnvsDirs?: number;
/**
* The number of the conda rc files found using conda info
*/
condaRcs?: number;
/**
* The number of the conda rc files found using native locator.
*/
nativeCondaRcs?: number;
/**
* The number of conda interpreters that are in the one of the global conda env locations.
* Global conda envs locations are returned by `conda info` in the `envs_dirs` setting.
Expand All @@ -1259,6 +1277,16 @@ export interface IEventNamePropertyMapping {
* Global conda envs locations are returned by `conda info` in the `envs_dirs` setting.
*/
nativeCondaEnvsInEnvDir?: number;
/**
* A conda env found that matches the root_prefix returned by `conda info`
* However a corresponding conda env not found by native locator.
*/
condaRootPrefixFoundInInfoNotInNative?: boolean;
/**
* A conda env found that matches the root_prefix returned by `conda info`
* However a corresponding conda env not found by native locator.
*/
condaDefaultPrefixFoundInInfoNotInNative?: boolean;
/**
* The number of conda interpreters without the `conda-meta` directory.
*/
Expand All @@ -1275,6 +1303,10 @@ export interface IEventNamePropertyMapping {
* Conda exe can be spawned.
*/
canSpawnConda?: boolean;
/**
* Conda exe can be spawned by native locator.
*/
nativeCanSpawnConda?: boolean;
/**
* The number of the interpreters not found in disc.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ import { OSType, getOSType } from '../../../../common';
import * as nativeFinder from '../../../../../client/pythonEnvironments/base/locators/common/nativePythonFinder';

class MockNativePythonFinder implements nativeFinder.NativeGlobalPythonFinder {
getCondaInfo(): Promise<nativeFinder.NativeCondaInfo> {
throw new Error('Method not implemented.');
}

categoryToKind(_category: string): PythonEnvKind {
throw new Error('Method not implemented.');
}
Expand Down
Loading