|
1 | 1 | import { getDefaultEnvManagerSetting, getDefaultPkgManagerSetting } from '../../features/settings/settingHelpers'; |
2 | 2 | import { EnvironmentManagers, PythonProjectManager } from '../../internal.api'; |
| 3 | +import { getUvEnvironments } from '../../managers/builtin/uvEnvironments'; |
3 | 4 | import { ISSUES_URL } from '../constants'; |
4 | | -import { traceInfo, traceWarn } from '../logging'; |
| 5 | +import { traceInfo, traceVerbose, traceWarn } from '../logging'; |
5 | 6 | import { getWorkspaceFolders } from '../workspace.apis'; |
6 | 7 | import { EventNames } from './constants'; |
7 | 8 | import { sendTelemetryEvent } from './sender'; |
8 | 9 |
|
| 10 | +/** |
| 11 | + * Extracts the base tool name from a manager ID. |
| 12 | + * Example: 'ms-python.python:venv' -> 'venv' |
| 13 | + * Example: 'ms-python.python:conda' -> 'conda' |
| 14 | + */ |
| 15 | +function extractToolName(managerId: string): string { |
| 16 | + // Manager IDs follow the pattern 'extensionId:toolName' |
| 17 | + const parts = managerId.split(':'); |
| 18 | + return parts.length > 1 ? parts[1].toLowerCase() : managerId.toLowerCase(); |
| 19 | +} |
| 20 | + |
9 | 21 | export function sendManagerSelectionTelemetry(pm: PythonProjectManager) { |
10 | 22 | const ems: Set<string> = new Set(); |
11 | 23 | const ps: Set<string> = new Set(); |
@@ -83,6 +95,67 @@ export async function sendProjectStructureTelemetry( |
83 | 95 | }); |
84 | 96 | } |
85 | 97 |
|
| 98 | +/** |
| 99 | + * Sends telemetry about which environment tools are actively used across all projects. |
| 100 | + * This tracks ACTUAL USAGE (which environments are set for projects), not just what's installed. |
| 101 | + * |
| 102 | + * Fires one event per tool that has at least one project using it. |
| 103 | + * This allows simple deduplication: dcount(machineId) by toolName gives unique users per tool. |
| 104 | + * |
| 105 | + * Called once at extension activation to understand user's environment tool usage patterns. |
| 106 | + */ |
| 107 | +export async function sendEnvironmentToolUsageTelemetry( |
| 108 | + pm: PythonProjectManager, |
| 109 | + envManagers: EnvironmentManagers, |
| 110 | +): Promise<void> { |
| 111 | + try { |
| 112 | + const projects = pm.getProjects(); |
| 113 | + |
| 114 | + // Track which tools are used (Set ensures uniqueness) |
| 115 | + const toolsUsed = new Set<string>(); |
| 116 | + |
| 117 | + // Lazily loaded once when a venv environment is first encountered |
| 118 | + let uvEnvPaths: string[] | undefined; |
| 119 | + |
| 120 | + // Check which environment manager is used for each project |
| 121 | + for (const project of projects) { |
| 122 | + try { |
| 123 | + const env = await envManagers.getEnvironment(project.uri); |
| 124 | + if (env?.envId?.managerId) { |
| 125 | + let toolName = extractToolName(env.envId.managerId); |
| 126 | + |
| 127 | + // UV environments share the venv manager. Check the persistent UV env list instead |
| 128 | + if (toolName === 'venv' && env.environmentPath) { |
| 129 | + uvEnvPaths ??= await getUvEnvironments(); |
| 130 | + if (uvEnvPaths.includes(env.environmentPath.fsPath)) { |
| 131 | + toolName = 'uv'; |
| 132 | + } |
| 133 | + } |
| 134 | + |
| 135 | + // Normalize 'global' to 'system' for consistency |
| 136 | + if (toolName === 'global') { |
| 137 | + toolName = 'system'; |
| 138 | + } |
| 139 | + |
| 140 | + toolsUsed.add(toolName); |
| 141 | + } |
| 142 | + } catch { |
| 143 | + // Ignore errors when getting environment for a project |
| 144 | + } |
| 145 | + } |
| 146 | + |
| 147 | + // Fire one event per tool used |
| 148 | + toolsUsed.forEach((tool) => { |
| 149 | + sendTelemetryEvent(EventNames.ENVIRONMENT_TOOL_USAGE, undefined, { |
| 150 | + toolName: tool, |
| 151 | + }); |
| 152 | + }); |
| 153 | + } catch (error) { |
| 154 | + // Telemetry failures must never disrupt extension activation |
| 155 | + traceVerbose('Failed to send environment tool usage telemetry:', error); |
| 156 | + } |
| 157 | +} |
| 158 | + |
86 | 159 | /** |
87 | 160 | * Logs a summary of environment discovery results after startup. |
88 | 161 | * If no environments are found, logs guidance to help users troubleshoot. |
|
0 commit comments