From ee57f1cc6a33ca08bc07532767d7dd86c3cbfb21 Mon Sep 17 00:00:00 2001 From: hkobew Date: Thu, 6 Feb 2025 15:46:02 -0500 Subject: [PATCH 1/5] logs: migrate LSPController to log topic --- .../core/src/amazonq/lsp/lspController.ts | 25 ++++++++++--------- packages/core/src/shared/logger/logger.ts | 11 +++++++- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/packages/core/src/amazonq/lsp/lspController.ts b/packages/core/src/amazonq/lsp/lspController.ts index f556a070775..07a212fc3a8 100644 --- a/packages/core/src/amazonq/lsp/lspController.ts +++ b/packages/core/src/amazonq/lsp/lspController.ts @@ -31,7 +31,7 @@ export interface BuildIndexConfig { } /* - * LSP Controller manages the status of Amazon Q LSP: + * LSP Controller manages the status of Amazon Q Workspace Indexing LSP: * 1. Downloading, verifying and installing LSP using DEXP LSP manifest and CDN. * 2. Managing the LSP states. There are a couple of possible LSP states: * Not installed. Installed. Running. Indexing. Indexing Done. @@ -44,6 +44,7 @@ export interface BuildIndexConfig { export class LspController { static #instance: LspController private _isIndexingInProgress = false + private logger = getLogger('workspaceContextLsp') public static get instance() { return (this.#instance ??= new this()) @@ -83,18 +84,18 @@ export class LspController { return await LspClient.instance.queryInlineProjectContext(query, path, target) } catch (e) { if (e instanceof Error) { - getLogger().error(`unexpected error while querying inline project context, e=${e.message}`) + this.logger.error(`unexpected error while querying inline project context, e=${e.message}`) } return [] } } async buildIndex(buildIndexConfig: BuildIndexConfig) { - getLogger().info(`LspController: Starting to build index of project`) + this.logger.info(`LspController: Starting to build index of project`) const start = performance.now() const projPaths = (vscode.workspace.workspaceFolders ?? []).map((folder) => folder.uri.fsPath) if (projPaths.length === 0) { - getLogger().info(`LspController: Skipping building index. No projects found in workspace`) + this.logger.info(`LspController: Skipping building index. No projects found in workspace`) return } projPaths.sort() @@ -111,12 +112,12 @@ export class LspController { (accumulator, currentFile) => accumulator + currentFile.fileSizeBytes, 0 ) - getLogger().info(`LspController: Found ${files.length} files in current project ${projPaths}`) + this.logger.info(`LspController: Found ${files.length} files in current project ${projPaths}`) const config = buildIndexConfig.isVectorIndexEnabled ? 'all' : 'default' const r = files.map((f) => f.fileUri.fsPath) const resp = await LspClient.instance.buildIndex(r, projRoot, config) if (resp) { - getLogger().debug(`LspController: Finish building index of project`) + this.logger.debug(`LspController: Finish building index of project`) const usage = await LspClient.instance.getLspServerUsage() telemetry.amazonq_indexWorkspace.emit({ duration: performance.now() - start, @@ -128,7 +129,7 @@ export class LspController { credentialStartUrl: buildIndexConfig.startUrl, }) } else { - getLogger().error(`LspController: Failed to build index of project`) + this.logger.error(`LspController: Failed to build index of project`) telemetry.amazonq_indexWorkspace.emit({ duration: performance.now() - start, result: 'Failed', @@ -139,7 +140,7 @@ export class LspController { } } catch (error) { // TODO: use telemetry.run() - getLogger().error(`LspController: Failed to build index of project`) + this.logger.error(`LspController: Failed to build index of project`) telemetry.amazonq_indexWorkspace.emit({ duration: performance.now() - start, result: 'Failed', @@ -155,7 +156,7 @@ export class LspController { async trySetupLsp(context: vscode.ExtensionContext, buildIndexConfig: BuildIndexConfig) { if (isCloud9() || isWeb() || isAmazonInternalOs()) { - getLogger().warn('LspController: Skipping LSP setup. LSP is not compatible with the current environment. ') + this.logger.warn('LspController: Skipping LSP setup. LSP is not compatible with the current environment. ') // do not do anything if in Cloud9 or Web mode or in AL2 (AL2 does not support node v18+) return } @@ -168,7 +169,7 @@ export class LspController { async () => { const usage = await LspClient.instance.getLspServerUsage() if (usage) { - getLogger().info( + this.logger.info( `LspController: LSP server CPU ${usage.cpuUsage}%, LSP server Memory ${ usage.memoryUsage / (1024 * 1024) }MB ` @@ -178,7 +179,7 @@ export class LspController { 30 * 60 * 1000 ) } catch (e) { - getLogger().error(`LspController: LSP failed to activate ${e}`) + this.logger.error(`LspController: LSP failed to activate ${e}`) } }) } @@ -187,7 +188,7 @@ export class LspController { await lspSetupStage('all', async () => { const installResult = await new WorkspaceLSPResolver().resolve() await lspSetupStage('launch', async () => activateLsp(context, installResult.resourcePaths)) - getLogger().info('LspController: LSP activated') + this.logger.info('LspController: LSP activated') }) } } diff --git a/packages/core/src/shared/logger/logger.ts b/packages/core/src/shared/logger/logger.ts index 98a7e29d48e..aba38f71576 100644 --- a/packages/core/src/shared/logger/logger.ts +++ b/packages/core/src/shared/logger/logger.ts @@ -5,7 +5,16 @@ import * as vscode from 'vscode' -export type LogTopic = 'crashMonitoring' | 'dev/beta' | 'notifications' | 'test' | 'childProcess' | 'lsp' | 'unknown' +export type LogTopic = + | 'crashMonitoring' + | 'dev/beta' + | 'notifications' + | 'test' + | 'childProcess' + | 'lsp' + | 'workspaceContextLsp' + | 'codewhispererLsp' + | 'unknown' class ErrorLog { constructor( From ed8ac5a1aecf88ded9cc6de1e9dacd16b35155e0 Mon Sep 17 00:00:00 2001 From: hkobew Date: Fri, 7 Feb 2025 10:44:52 -0500 Subject: [PATCH 2/5] refactor: add more logging information --- packages/amazonq/src/lsp/lspInstaller.ts | 11 ++++++++-- .../core/src/amazonq/lsp/lspController.ts | 2 +- .../src/amazonq/lsp/workspaceInstaller.ts | 9 ++++++-- packages/core/src/shared/logger/logger.ts | 4 ++-- packages/core/src/shared/lsp/utils/cleanup.ts | 13 +++++++++--- .../src/test/shared/lsp/utils/cleanup.test.ts | 21 ++++++++++++++----- 6 files changed, 45 insertions(+), 15 deletions(-) diff --git a/packages/amazonq/src/lsp/lspInstaller.ts b/packages/amazonq/src/lsp/lspInstaller.ts index 72d0746cdcf..bc0cacc2aa0 100644 --- a/packages/amazonq/src/lsp/lspInstaller.ts +++ b/packages/amazonq/src/lsp/lspInstaller.ts @@ -13,16 +13,18 @@ import { LspResolution, getNodeExecutableName, cleanLspDownloads, + getLogger, } from 'aws-core-vscode/shared' import path from 'path' const manifestURL = 'https://aws-toolkit-language-servers.amazonaws.com/codewhisperer/0/manifest.json' export const supportedLspServerVersions = '^2.3.0' - +const logger = getLogger('QLSP') export class AmazonQLSPResolver implements LspResolver { async resolve(): Promise { const overrideLocation = process.env.AWS_LANGUAGE_SERVER_OVERRIDE if (overrideLocation) { + logger.info(`Using language server override location: ${overrideLocation}`) void vscode.window.showInformationMessage(`Using language server override location: ${overrideLocation}`) return { assetDirectory: overrideLocation, @@ -47,7 +49,12 @@ export class AmazonQLSPResolver implements LspResolver { const nodePath = path.join(installationResult.assetDirectory, `servers/${getNodeExecutableName()}`) await fs.chmod(nodePath, 0o755) - await cleanLspDownloads(manifest.versions, path.dirname(installationResult.assetDirectory)) + const deletedVersions = await cleanLspDownloads( + manifest.versions, + path.dirname(installationResult.assetDirectory) + ) + logger.debug(`cleaning old LSP versions deleted ${deletedVersions.length} versions`) + return { ...installationResult, resourcePaths: { diff --git a/packages/core/src/amazonq/lsp/lspController.ts b/packages/core/src/amazonq/lsp/lspController.ts index 07a212fc3a8..02d69f62281 100644 --- a/packages/core/src/amazonq/lsp/lspController.ts +++ b/packages/core/src/amazonq/lsp/lspController.ts @@ -44,7 +44,7 @@ export interface BuildIndexConfig { export class LspController { static #instance: LspController private _isIndexingInProgress = false - private logger = getLogger('workspaceContextLsp') + private logger = getLogger('QWorkspaceLsp') public static get instance() { return (this.#instance ??= new this()) diff --git a/packages/core/src/amazonq/lsp/workspaceInstaller.ts b/packages/core/src/amazonq/lsp/workspaceInstaller.ts index c4c688d7bc1..d989bb06a7d 100644 --- a/packages/core/src/amazonq/lsp/workspaceInstaller.ts +++ b/packages/core/src/amazonq/lsp/workspaceInstaller.ts @@ -10,11 +10,12 @@ import { LanguageServerResolver } from '../../shared/lsp/lspResolver' import { Range } from 'semver' import { getNodeExecutableName } from '../../shared/lsp/utils/platform' import { fs } from '../../shared/fs/fs' -import { cleanLspDownloads } from '../../shared' +import { cleanLspDownloads, getLogger } from '../../shared' const manifestUrl = 'https://aws-toolkit-language-servers.amazonaws.com/q-context/manifest.json' // this LSP client in Q extension is only going to work with these LSP server versions const supportedLspServerVersions = '0.1.32' +const logger = getLogger('QWorkspaceLsp') export class WorkspaceLSPResolver implements LspResolver { async resolve(): Promise { @@ -31,7 +32,11 @@ export class WorkspaceLSPResolver implements LspResolver { const nodePath = path.join(installationResult.assetDirectory, nodeName) await fs.chmod(nodePath, 0o755) - await cleanLspDownloads(manifest.versions, path.basename(installationResult.assetDirectory)) + const deletedVersions = await cleanLspDownloads( + manifest.versions, + path.basename(installationResult.assetDirectory) + ) + logger.debug(`cleaning old LSP versions deleted ${deletedVersions.length} versions`) return { ...installationResult, resourcePaths: { diff --git a/packages/core/src/shared/logger/logger.ts b/packages/core/src/shared/logger/logger.ts index aba38f71576..5a7f2a409d5 100644 --- a/packages/core/src/shared/logger/logger.ts +++ b/packages/core/src/shared/logger/logger.ts @@ -12,8 +12,8 @@ export type LogTopic = | 'test' | 'childProcess' | 'lsp' - | 'workspaceContextLsp' - | 'codewhispererLsp' + | 'QWorkspaceLsp' + | 'QLSP' | 'unknown' class ErrorLog { diff --git a/packages/core/src/shared/lsp/utils/cleanup.ts b/packages/core/src/shared/lsp/utils/cleanup.ts index 874f56e46ff..031afbe0888 100644 --- a/packages/core/src/shared/lsp/utils/cleanup.ts +++ b/packages/core/src/shared/lsp/utils/cleanup.ts @@ -19,23 +19,30 @@ function isDelisted(manifestVersions: LspVersion[], targetVersion: string): bool /** * Delete all delisted versions and keep the two newest versions that remain - * @param manifest + * @param manifestVersions * @param downloadDirectory + * @returns array of deleted versions. */ -export async function cleanLspDownloads(manifestVersions: LspVersion[], downloadDirectory: string): Promise { +export async function cleanLspDownloads(manifestVersions: LspVersion[], downloadDirectory: string): Promise { const downloadedVersions = await getDownloadedVersions(downloadDirectory) const [delistedVersions, remainingVersions] = partition(downloadedVersions, (v: string) => isDelisted(manifestVersions, v) ) + const deletedVersions: string[] = [] + for (const v of delistedVersions) { await fs.delete(path.join(downloadDirectory, v), { force: true, recursive: true }) + deletedVersions.push(v) } if (remainingVersions.length <= 2) { - return + return deletedVersions } for (const v of sort(remainingVersions).slice(0, -2)) { await fs.delete(path.join(downloadDirectory, v), { force: true, recursive: true }) + deletedVersions.push(v) } + + return deletedVersions } diff --git a/packages/core/src/test/shared/lsp/utils/cleanup.test.ts b/packages/core/src/test/shared/lsp/utils/cleanup.test.ts index 377039566de..75d0654f04f 100644 --- a/packages/core/src/test/shared/lsp/utils/cleanup.test.ts +++ b/packages/core/src/test/shared/lsp/utils/cleanup.test.ts @@ -41,27 +41,32 @@ describe('cleanLSPDownloads', function () { it('keeps two newest versions', async function () { await fakeInstallVersions(['1.0.0', '1.0.1', '1.1.1', '2.1.1'], installationDir.fsPath) - await cleanLspDownloads([], installationDir.fsPath) + const deleted = await cleanLspDownloads([], installationDir.fsPath) const result = (await fs.readdir(installationDir.fsPath)).map(([filename, _filetype], _index) => filename) assert.strictEqual(result.length, 2) assert.ok(result.includes('2.1.1')) assert.ok(result.includes('1.1.1')) + assert.strictEqual(deleted.length, 2) }) it('deletes delisted versions', async function () { await fakeInstallVersions(['1.0.0', '1.0.1', '1.1.1', '2.1.1'], installationDir.fsPath) - await cleanLspDownloads([{ serverVersion: '1.1.1', isDelisted: true, targets: [] }], installationDir.fsPath) + const deleted = await cleanLspDownloads( + [{ serverVersion: '1.1.1', isDelisted: true, targets: [] }], + installationDir.fsPath + ) const result = (await fs.readdir(installationDir.fsPath)).map(([filename, _filetype], _index) => filename) assert.strictEqual(result.length, 2) assert.ok(result.includes('2.1.1')) assert.ok(result.includes('1.0.1')) + assert.strictEqual(deleted.length, 2) }) it('handles case where less than 2 versions are not delisted', async function () { await fakeInstallVersions(['1.0.0', '1.0.1', '1.1.1', '2.1.1'], installationDir.fsPath) - await cleanLspDownloads( + const deleted = await cleanLspDownloads( [ { serverVersion: '1.1.1', isDelisted: true, targets: [] }, { serverVersion: '2.1.1', isDelisted: true, targets: [] }, @@ -73,21 +78,27 @@ describe('cleanLSPDownloads', function () { const result = (await fs.readdir(installationDir.fsPath)).map(([filename, _filetype], _index) => filename) assert.strictEqual(result.length, 1) assert.ok(result.includes('1.0.1')) + assert.strictEqual(deleted.length, 3) }) it('handles case where less than 2 versions exist', async function () { await fakeInstallVersions(['1.0.0'], installationDir.fsPath) - await cleanLspDownloads([], installationDir.fsPath) + const deleted = await cleanLspDownloads([], installationDir.fsPath) const result = (await fs.readdir(installationDir.fsPath)).map(([filename, _filetype], _index) => filename) assert.strictEqual(result.length, 1) + assert.strictEqual(deleted.length, 0) }) it('does not install delisted version when no other option exists', async function () { await fakeInstallVersions(['1.0.0'], installationDir.fsPath) - await cleanLspDownloads([{ serverVersion: '1.0.0', isDelisted: true, targets: [] }], installationDir.fsPath) + const deleted = await cleanLspDownloads( + [{ serverVersion: '1.0.0', isDelisted: true, targets: [] }], + installationDir.fsPath + ) const result = (await fs.readdir(installationDir.fsPath)).map(([filename, _filetype], _index) => filename) assert.strictEqual(result.length, 0) + assert.strictEqual(deleted.length, 1) }) }) From 55e848f6fb409b475cdcdbd4e94f7c9918408993 Mon Sep 17 00:00:00 2001 From: hkobew Date: Fri, 7 Feb 2025 14:30:11 -0500 Subject: [PATCH 3/5] refactor: rename logging topics --- packages/amazonq/src/lsp/lspInstaller.ts | 2 +- packages/core/src/amazonq/lsp/lspController.ts | 2 +- packages/core/src/amazonq/lsp/workspaceInstaller.ts | 2 +- packages/core/src/shared/logger/logger.ts | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amazonq/src/lsp/lspInstaller.ts b/packages/amazonq/src/lsp/lspInstaller.ts index bc0cacc2aa0..53a39630008 100644 --- a/packages/amazonq/src/lsp/lspInstaller.ts +++ b/packages/amazonq/src/lsp/lspInstaller.ts @@ -19,7 +19,7 @@ import path from 'path' const manifestURL = 'https://aws-toolkit-language-servers.amazonaws.com/codewhisperer/0/manifest.json' export const supportedLspServerVersions = '^2.3.0' -const logger = getLogger('QLSP') +const logger = getLogger('amazonqLSP') export class AmazonQLSPResolver implements LspResolver { async resolve(): Promise { const overrideLocation = process.env.AWS_LANGUAGE_SERVER_OVERRIDE diff --git a/packages/core/src/amazonq/lsp/lspController.ts b/packages/core/src/amazonq/lsp/lspController.ts index 02d69f62281..9233b2e06ef 100644 --- a/packages/core/src/amazonq/lsp/lspController.ts +++ b/packages/core/src/amazonq/lsp/lspController.ts @@ -44,7 +44,7 @@ export interface BuildIndexConfig { export class LspController { static #instance: LspController private _isIndexingInProgress = false - private logger = getLogger('QWorkspaceLsp') + private logger = getLogger('amazonqWorkspaceLSP') public static get instance() { return (this.#instance ??= new this()) diff --git a/packages/core/src/amazonq/lsp/workspaceInstaller.ts b/packages/core/src/amazonq/lsp/workspaceInstaller.ts index a0834f8d0b5..8b8e4856b27 100644 --- a/packages/core/src/amazonq/lsp/workspaceInstaller.ts +++ b/packages/core/src/amazonq/lsp/workspaceInstaller.ts @@ -15,7 +15,7 @@ import { cleanLspDownloads, getLogger } from '../../shared' const manifestUrl = 'https://aws-toolkit-language-servers.amazonaws.com/q-context/manifest.json' // this LSP client in Q extension is only going to work with these LSP server versions const supportedLspServerVersions = '0.1.35' -const logger = getLogger('QWorkspaceLsp') +const logger = getLogger('amazonqWorkspaceLSP') export class WorkspaceLSPResolver implements LspResolver { async resolve(): Promise { diff --git a/packages/core/src/shared/logger/logger.ts b/packages/core/src/shared/logger/logger.ts index 5a7f2a409d5..1f65b1f494e 100644 --- a/packages/core/src/shared/logger/logger.ts +++ b/packages/core/src/shared/logger/logger.ts @@ -12,8 +12,8 @@ export type LogTopic = | 'test' | 'childProcess' | 'lsp' - | 'QWorkspaceLsp' - | 'QLSP' + | 'amazonqWorkspaceLSP' + | 'amazonqLSP' | 'unknown' class ErrorLog { From 8ff5f406ede2a2c99af0593a6154e436e9d3a950 Mon Sep 17 00:00:00 2001 From: hkobew Date: Fri, 7 Feb 2025 14:31:10 -0500 Subject: [PATCH 4/5] refactor: improve logging message --- packages/amazonq/src/lsp/lspInstaller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amazonq/src/lsp/lspInstaller.ts b/packages/amazonq/src/lsp/lspInstaller.ts index 53a39630008..b4cf8710b66 100644 --- a/packages/amazonq/src/lsp/lspInstaller.ts +++ b/packages/amazonq/src/lsp/lspInstaller.ts @@ -53,7 +53,7 @@ export class AmazonQLSPResolver implements LspResolver { manifest.versions, path.dirname(installationResult.assetDirectory) ) - logger.debug(`cleaning old LSP versions deleted ${deletedVersions.length} versions`) + logger.debug(`Cleaned up ${deletedVersions.length} old versions`) return { ...installationResult, From 0df0720d836ea299fdcfd2be0b49535704c9f800 Mon Sep 17 00:00:00 2001 From: hkobew Date: Fri, 7 Feb 2025 16:14:27 -0500 Subject: [PATCH 5/5] refactor: rename topic headers --- packages/amazonq/src/lsp/lspInstaller.ts | 2 +- packages/core/src/amazonq/lsp/lspController.ts | 2 +- packages/core/src/amazonq/lsp/workspaceInstaller.ts | 2 +- packages/core/src/shared/logger/logger.ts | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amazonq/src/lsp/lspInstaller.ts b/packages/amazonq/src/lsp/lspInstaller.ts index b4cf8710b66..391e9c03ff8 100644 --- a/packages/amazonq/src/lsp/lspInstaller.ts +++ b/packages/amazonq/src/lsp/lspInstaller.ts @@ -19,7 +19,7 @@ import path from 'path' const manifestURL = 'https://aws-toolkit-language-servers.amazonaws.com/codewhisperer/0/manifest.json' export const supportedLspServerVersions = '^2.3.0' -const logger = getLogger('amazonqLSP') +const logger = getLogger('amazonqLsp') export class AmazonQLSPResolver implements LspResolver { async resolve(): Promise { const overrideLocation = process.env.AWS_LANGUAGE_SERVER_OVERRIDE diff --git a/packages/core/src/amazonq/lsp/lspController.ts b/packages/core/src/amazonq/lsp/lspController.ts index 9233b2e06ef..e6b9c5e7260 100644 --- a/packages/core/src/amazonq/lsp/lspController.ts +++ b/packages/core/src/amazonq/lsp/lspController.ts @@ -44,7 +44,7 @@ export interface BuildIndexConfig { export class LspController { static #instance: LspController private _isIndexingInProgress = false - private logger = getLogger('amazonqWorkspaceLSP') + private logger = getLogger('amazonqWorkspaceLsp') public static get instance() { return (this.#instance ??= new this()) diff --git a/packages/core/src/amazonq/lsp/workspaceInstaller.ts b/packages/core/src/amazonq/lsp/workspaceInstaller.ts index 8b8e4856b27..b4c4bc614ff 100644 --- a/packages/core/src/amazonq/lsp/workspaceInstaller.ts +++ b/packages/core/src/amazonq/lsp/workspaceInstaller.ts @@ -15,7 +15,7 @@ import { cleanLspDownloads, getLogger } from '../../shared' const manifestUrl = 'https://aws-toolkit-language-servers.amazonaws.com/q-context/manifest.json' // this LSP client in Q extension is only going to work with these LSP server versions const supportedLspServerVersions = '0.1.35' -const logger = getLogger('amazonqWorkspaceLSP') +const logger = getLogger('amazonqWorkspaceLsp') export class WorkspaceLSPResolver implements LspResolver { async resolve(): Promise { diff --git a/packages/core/src/shared/logger/logger.ts b/packages/core/src/shared/logger/logger.ts index 1f65b1f494e..c2334b68add 100644 --- a/packages/core/src/shared/logger/logger.ts +++ b/packages/core/src/shared/logger/logger.ts @@ -12,8 +12,8 @@ export type LogTopic = | 'test' | 'childProcess' | 'lsp' - | 'amazonqWorkspaceLSP' - | 'amazonqLSP' + | 'amazonqWorkspaceLsp' + | 'amazonqLsp' | 'unknown' class ErrorLog {