diff --git a/src/common/telemetry/helpers.ts b/src/common/telemetry/helpers.ts index 6e4e2e1b..4c089ba7 100644 --- a/src/common/telemetry/helpers.ts +++ b/src/common/telemetry/helpers.ts @@ -169,11 +169,9 @@ export async function logDiscoverySummary(envManagers: EnvironmentManagers): Pro try { const envs = await manager.getEnvironments('all'); totalEnvCount += envs.length; - if (envs.length > 0) { - managerSummaries.push(`${manager.displayName}: ${envs.length}`); - } + managerSummaries.push(`${manager.displayName}: ${envs.length}`); } catch { - // Discovery errors are already logged by InternalEnvironmentManager.refresh() + managerSummaries.push(`${manager.displayName}: error`); } } diff --git a/src/extension.ts b/src/extension.ts index 04bcb3e8..eec5e1c3 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -573,10 +573,12 @@ export async function activate(context: ExtensionContext): Promise p.uri); const env = await manager.create(scope, undefined); if (env) { + traceInfo(`Environment created: ${env.displayName}`); await em.setEnvironmentsIfUnset(scope, env); } return env; @@ -216,6 +218,9 @@ export async function createAnyEnvironmentCommand( const manager = em.managers.find((m) => m.id === managerId); if (manager) { const env = await manager.create('global', { ...options }); + if (env) { + traceInfo(`Environment created: ${env.displayName}`); + } if (select && env) { await manager.set(undefined, env); } @@ -270,6 +275,9 @@ export async function createAnyEnvironmentCommand( selected.map((p) => p.uri), { ...options, quickCreate }, ); + if (env) { + traceInfo(`Environment created: ${env.displayName}`); + } if (select && env) { await em.setEnvironments( selected.map((p) => p.uri), @@ -739,12 +747,12 @@ export async function copyPathToClipboard(item: unknown): Promise { if (item instanceof ProjectItem) { const projectPath = item.project.uri.fsPath; await clipboardWriteText(projectPath); - traceInfo(`Copied project path to clipboard: ${projectPath}`); + traceVerbose(`Copied project path to clipboard: ${projectPath}`); } else if (item instanceof ProjectEnvironment || item instanceof PythonEnvTreeItem) { const run = item.environment.execInfo.run; const envPath = run.executable; await clipboardWriteText(envPath); - traceInfo(`Copied environment path to clipboard: ${envPath}`); + traceVerbose(`Copied environment path to clipboard: ${envPath}`); } else { traceVerbose(`Invalid context for copy path to clipboard: ${item}`); } diff --git a/src/features/envManagers.ts b/src/features/envManagers.ts index 036194a0..97b9b635 100644 --- a/src/features/envManagers.ts +++ b/src/features/envManagers.ts @@ -15,7 +15,7 @@ import { EnvironmentManagerAlreadyRegisteredError, PackageManagerAlreadyRegisteredError, } from '../common/errors/AlreadyRegisteredError'; -import { traceError, traceVerbose } from '../common/logging'; +import { traceError, traceInfo, traceVerbose } from '../common/logging'; import { StopWatch } from '../common/stopWatch'; import { EventNames } from '../common/telemetry/constants'; import { sendTelemetryEvent } from '../common/telemetry/sender'; @@ -315,6 +315,10 @@ export class PythonEnvironmentManagers implements EnvironmentManagers { return; } await manager.set(scope, environment); + traceInfo( + `[setEnvironment] env=${environment?.displayName ?? 'none'} (${environment?.envId?.id ?? 'undefined'}), ` + + `scope=${scope instanceof Uri ? scope.fsPath : scope ?? 'global'}, manager=${manager.id}`, + ); const project = scope ? this.pm.get(scope) : undefined; // Only persist to settings when explicitly requested @@ -330,11 +334,8 @@ export class PythonEnvironmentManagers implements EnvironmentManagers { ]); } traceVerbose( - `[setEnvironment] scope=${scope instanceof Uri ? scope.fsPath : scope}, ` + - `env=${environment?.envId?.id ?? 'undefined'}, manager=${manager.id}, ` + - `project=${project?.uri?.toString() ?? 'none'}, ` + - `packageManager=${this.getPackageManager(environment)?.id ?? 'UNDEFINED'}, ` + - `settingsPersisted=${!!(project && this.getPackageManager(environment))}`, + `[setEnvironment] Settings persisted: project=${project?.uri?.toString() ?? 'none'}, ` + + `packageManager=${this.getPackageManager(environment)?.id ?? 'UNDEFINED'}`, ); } diff --git a/src/features/terminal/terminalEnvVarInjector.ts b/src/features/terminal/terminalEnvVarInjector.ts index 1af2269c..2bbc0201 100644 --- a/src/features/terminal/terminalEnvVarInjector.ts +++ b/src/features/terminal/terminalEnvVarInjector.ts @@ -48,7 +48,7 @@ export class TerminalEnvVarInjector implements Disposable { if (!args.uri) { // No specific URI, reload all workspaces this.updateEnvironmentVariables().catch((error) => { - traceError('Failed to update environment variables:', error); + traceError('Failed to update environment variables (global reload):', error); }); return; } @@ -57,7 +57,7 @@ export class TerminalEnvVarInjector implements Disposable { if (!affectedWorkspace) { // No workspace folder found for this URI, reloading all workspaces this.updateEnvironmentVariables().catch((error) => { - traceError('Failed to update environment variables:', error); + traceError('Failed to update environment variables (no workspace folder for URI):', error); }); return; } @@ -79,7 +79,7 @@ export class TerminalEnvVarInjector implements Disposable { this.clearWorkspaceVariables(affectedWorkspace); } else { this.updateEnvironmentVariables(affectedWorkspace).catch((error) => { - traceError('Failed to update environment variables:', error); + traceError(`Failed to update environment variables for workspace: ${affectedWorkspace?.name}`, error); }); } }), @@ -93,7 +93,7 @@ export class TerminalEnvVarInjector implements Disposable { 'TerminalEnvVarInjector: python.envFile or python.terminal.useEnvFile setting changed, updating environment variables', ); this.updateEnvironmentVariables().catch((error) => { - traceError('Failed to update environment variables:', error); + traceError('Failed to update environment variables (settings change):', error); }); } }), diff --git a/src/internal.api.ts b/src/internal.api.ts index 8637da75..6d851697 100644 --- a/src/internal.api.ts +++ b/src/internal.api.ts @@ -29,7 +29,7 @@ import { } from './api'; import { ISSUES_URL } from './common/constants'; import { CreateEnvironmentNotSupported, RemoveEnvironmentNotSupported } from './common/errors/NotSupportedError'; -import { traceWarn } from './common/logging'; +import { traceInfo, traceWarn } from './common/logging'; import { StopWatch } from './common/stopWatch'; import { EventNames } from './common/telemetry/constants'; import { sendTelemetryEvent } from './common/telemetry/sender'; @@ -206,12 +206,14 @@ export class InternalEnvironmentManager implements EnvironmentManager { } async refresh(options: RefreshEnvironmentsScope): Promise { + traceInfo(`[${this.displayName}] Discovering environments...`); const sw = new StopWatch(); const SLOW_DISCOVERY_THRESHOLD_MS = 15000; try { await this.manager.refresh(options); const envs = await this.manager.getEnvironments('all').catch(() => []); const duration = sw.elapsedTime; + traceInfo(`[${this.displayName}] Discovery complete: ${envs.length} environments found (${(duration / 1000).toFixed(1)}s)`); sendTelemetryEvent(EventNames.ENVIRONMENT_DISCOVERY, duration, { managerId: this.id, result: 'success', diff --git a/src/managers/builtin/uvPythonInstaller.ts b/src/managers/builtin/uvPythonInstaller.ts index 9b1fcdcc..c4006a53 100644 --- a/src/managers/builtin/uvPythonInstaller.ts +++ b/src/managers/builtin/uvPythonInstaller.ts @@ -10,7 +10,7 @@ import { } from 'vscode'; import { spawnProcess } from '../../common/childProcess.apis'; import { Common, UvInstallStrings } from '../../common/localize'; -import { traceError, traceInfo, traceLog } from '../../common/logging'; +import { traceError, traceInfo, traceLog, traceWarn } from '../../common/logging'; import { getGlobalPersistentState } from '../../common/persistentState'; import { executeTask, onDidEndTaskProcess } from '../../common/tasks.apis'; import { EventNames } from '../../common/telemetry/constants'; @@ -82,7 +82,7 @@ async function getUvInstallCommand(): Promise<{ executable: string; args: string } // Default to curl and let it fail with a clear error if neither is available - traceError('Neither curl nor wget found, attempting curl anyway'); + traceWarn('Neither curl nor wget found, attempting curl anyway'); return { executable: 'sh', args: ['-c', 'curl -LsSf https://astral.sh/uv/install.sh | sh'], diff --git a/src/managers/common/nativePythonFinder.ts b/src/managers/common/nativePythonFinder.ts index 6efed7af..2f11f92f 100644 --- a/src/managers/common/nativePythonFinder.ts +++ b/src/managers/common/nativePythonFinder.ts @@ -1384,7 +1384,7 @@ function getWorkspaceSearchPaths(scope?: Uri): string[] { if (inspection?.globalValue && !workspaceSearchPathsGlobalWarningShown) { workspaceSearchPathsGlobalWarningShown = true; - traceError( + traceWarn( 'python-envs.workspaceSearchPaths is set at the user/global level, but this setting can only be set at the workspace or workspace folder level.', ); } diff --git a/src/managers/pyenv/pyenvUtils.ts b/src/managers/pyenv/pyenvUtils.ts index ba4194ee..6e6a0ec6 100644 --- a/src/managers/pyenv/pyenvUtils.ts +++ b/src/managers/pyenv/pyenvUtils.ts @@ -138,6 +138,7 @@ export async function getPyenv(): Promise { if (pyenvRoot) { const pyenvPath = path.join(pyenvRoot, 'bin', pyenvBin); if (await fs.exists(pyenvPath)) { + traceInfo(`Using pyenv from PYENV_ROOT: ${pyenvPath}`); return pyenvPath; } } @@ -146,12 +147,14 @@ export async function getPyenv(): Promise { if (home) { const pyenvPath = path.join(home, '.pyenv', 'bin', pyenvBin); if (await fs.exists(pyenvPath)) { + traceInfo(`Using pyenv from home directory: ${pyenvPath}`); return pyenvPath; } if (isWindows()) { const pyenvPathWin = path.join(home, '.pyenv', 'pyenv-win', 'bin', pyenvBin); if (await fs.exists(pyenvPathWin)) { + traceInfo(`Using pyenv-win from home directory: ${pyenvPathWin}`); return pyenvPathWin; } } @@ -159,9 +162,11 @@ export async function getPyenv(): Promise { pyenvPath = await findPyenv(); if (pyenvPath) { + traceInfo(`Using pyenv from PATH: ${pyenvPath}`); return pyenvPath; } + traceInfo('pyenv not found in PYENV_ROOT, home directory, or PATH'); return undefined; } catch (ex) { const err = ex instanceof Error ? ex : new Error(String(ex)); @@ -268,6 +273,7 @@ export async function refreshPyenv( } }); + traceInfo(`Pyenv discovery complete: ${collection.length} environments found`); return sortEnvironments(collection); } diff --git a/src/test/managers/common/nativePythonFinder.getAllExtraSearchPaths.unit.test.ts b/src/test/managers/common/nativePythonFinder.getAllExtraSearchPaths.unit.test.ts index 617d38d7..0e66d5d9 100644 --- a/src/test/managers/common/nativePythonFinder.getAllExtraSearchPaths.unit.test.ts +++ b/src/test/managers/common/nativePythonFinder.getAllExtraSearchPaths.unit.test.ts @@ -331,8 +331,8 @@ suite('getAllExtraSearchPaths Integration Tests', () => { assert.deepStrictEqual(result, []); // Check that error was logged with key terms - don't be brittle about exact wording assert( - mockTraceError.calledWith(sinon.match(/workspaceSearchPaths.*global.*level/i)), - 'Should log error about incorrect setting level', + mockTraceWarn.calledWith(sinon.match(/workspaceSearchPaths.*global.*level/i)), + 'Should log warning about incorrect setting level', ); }); @@ -350,8 +350,8 @@ suite('getAllExtraSearchPaths Integration Tests', () => { await getAllExtraSearchPaths(); await getAllExtraSearchPaths(); - // Assert - error should only be logged once, not three times - const matchingCalls = mockTraceError + // Assert - warning should only be logged once, not three times + const matchingCalls = mockTraceWarn .getCalls() .filter((call: sinon.SinonSpyCall) => /workspaceSearchPaths.*global.*level/i.test(String(call.args[0])), @@ -359,7 +359,7 @@ suite('getAllExtraSearchPaths Integration Tests', () => { assert.strictEqual( matchingCalls.length, 1, - `Expected exactly 1 error about workspaceSearchPaths global level, got ${matchingCalls.length}`, + `Expected exactly 1 warning about workspaceSearchPaths global level, got ${matchingCalls.length}`, ); });