@@ -4,6 +4,17 @@ import { getWorkspaceFolders } from '../workspace.apis';
44import { EventNames } from './constants' ;
55import { sendTelemetryEvent } from './sender' ;
66
7+ /**
8+ * Extracts the base tool name from a manager ID.
9+ * Example: 'ms-python.python:venv' -> 'venv'
10+ * Example: 'ms-python.python:conda' -> 'conda'
11+ */
12+ function extractToolName ( managerId : string ) : string {
13+ // Manager IDs follow the pattern 'extensionId:toolName'
14+ const parts = managerId . split ( ':' ) ;
15+ return parts . length > 1 ? parts [ 1 ] . toLowerCase ( ) : managerId . toLowerCase ( ) ;
16+ }
17+
718export function sendManagerSelectionTelemetry ( pm : PythonProjectManager ) {
819 const ems : Set < string > = new Set ( ) ;
920 const ps : Set < string > = new Set ( ) ;
@@ -58,7 +69,7 @@ export async function sendProjectStructureTelemetry(
5869 for ( const wsFolder of workspaceFolders ) {
5970 const workspacePath = wsFolder . uri . fsPath ;
6071 const projectPath = project . uri . fsPath ;
61-
72+
6273 // Check if project is a subdirectory of workspace folder:
6374 // - Path must start with workspace path
6475 // - Path must not be equal to workspace path
@@ -80,3 +91,53 @@ export async function sendProjectStructureTelemetry(
8091 projectUnderRoot,
8192 } ) ;
8293}
94+
95+ /**
96+ * Sends telemetry about which environment tools are actively used across all projects.
97+ * This tracks ACTUAL USAGE (which environments are set for projects), not just what's installed.
98+ *
99+ * Fires one event per tool that has at least one project using it.
100+ * This allows simple deduplication: dcount(machineId) by toolName gives unique users per tool.
101+ *
102+ * Called once at extension activation to understand user's environment tool usage patterns.
103+ */
104+ export async function sendEnvironmentToolUsageTelemetry (
105+ pm : PythonProjectManager ,
106+ envManagers : EnvironmentManagers ,
107+ ) : Promise < void > {
108+ const projects = pm . getProjects ( ) ;
109+
110+ // Track which tools are used (Set ensures uniqueness)
111+ const toolsUsed = new Set < string > ( ) ;
112+
113+ // Check which environment manager is used for each project
114+ for ( const project of projects ) {
115+ try {
116+ const env = await envManagers . getEnvironment ( project . uri ) ;
117+ if ( env ?. envId ?. managerId ) {
118+ const toolName = extractToolName ( env . envId . managerId ) ;
119+
120+ // Check if this is a UV environment (UV uses venv manager but has 'uv' in description)
121+ const isUv = env . description ?. toLowerCase ( ) . includes ( 'uv' ) ?? false ;
122+
123+ // Determine the tool name
124+ if ( isUv ) {
125+ toolsUsed . add ( 'uv' ) ;
126+ } else {
127+ // Normalize 'global' to 'system' for consistency
128+ const normalizedTool = toolName === 'global' ? 'system' : toolName ;
129+ toolsUsed . add ( normalizedTool ) ;
130+ }
131+ }
132+ } catch {
133+ // Ignore errors when getting environment for a project
134+ }
135+ }
136+
137+ // Fire one event per tool used
138+ toolsUsed . forEach ( ( tool ) => {
139+ sendTelemetryEvent ( EventNames . ENVIRONMENT_TOOL_USAGE , undefined , {
140+ toolName : tool ,
141+ } ) ;
142+ } ) ;
143+ }
0 commit comments