From 927abe7ad5944b35067137f50472c1aacc93c308 Mon Sep 17 00:00:00 2001 From: Keegan Irby Date: Mon, 18 Nov 2024 15:52:36 -0800 Subject: [PATCH 1/3] emit telemetry on start/close live tail --- .../awsService/cloudWatchLogs/activation.ts | 7 +- .../cloudWatchLogs/commands/tailLogGroup.ts | 91 ++++++++++++------- .../document/liveTailCodeLensProvider.ts | 2 +- .../src/shared/telemetry/vscodeTelemetry.json | 51 +++++++++++ .../commands/tailLogGroup.test.ts | 7 +- 5 files changed, 116 insertions(+), 42 deletions(-) diff --git a/packages/core/src/awsService/cloudWatchLogs/activation.ts b/packages/core/src/awsService/cloudWatchLogs/activation.ts index de75d9e72a4..e0766ed7f5b 100644 --- a/packages/core/src/awsService/cloudWatchLogs/activation.ts +++ b/packages/core/src/awsService/cloudWatchLogs/activation.ts @@ -120,11 +120,12 @@ export async function activate(context: vscode.ExtensionContext, configuration: node instanceof LogGroupNode ? { regionName: node.regionCode, groupName: node.logGroup.logGroupName! } : undefined - await tailLogGroup(liveTailRegistry, logGroupInfo) + const source = node ? (logGroupInfo ? 'ExplorerLogGroupNode' : 'ExplorerServiceNode') : 'Command' + await tailLogGroup(liveTailRegistry, source, logGroupInfo) }), - Commands.register('aws.cwl.stopTailingLogGroup', async (document: vscode.TextDocument) => { - closeSession(document.uri, liveTailRegistry) + Commands.register('aws.cwl.stopTailingLogGroup', async (document: vscode.TextDocument, source: string) => { + closeSession(document.uri, liveTailRegistry, source) }), Commands.register('aws.cwl.clearDocument', async (document: vscode.TextDocument) => { diff --git a/packages/core/src/awsService/cloudWatchLogs/commands/tailLogGroup.ts b/packages/core/src/awsService/cloudWatchLogs/commands/tailLogGroup.ts index f0ad31eb0fb..87d959b9ef0 100644 --- a/packages/core/src/awsService/cloudWatchLogs/commands/tailLogGroup.ts +++ b/packages/core/src/awsService/cloudWatchLogs/commands/tailLogGroup.ts @@ -4,6 +4,7 @@ */ import * as vscode from 'vscode' +import { telemetry } from '../../../shared/telemetry/telemetry' import { TailLogGroupWizard } from '../wizard/tailLogGroupWizard' import { CancellationError } from '../../../shared/utilities/timeoutUtils' import { LiveTailSession, LiveTailSessionConfiguration } from '../registry/liveTailSession' @@ -18,48 +19,68 @@ import { uriToKey } from '../cloudWatchLogsUtils' export async function tailLogGroup( registry: LiveTailSessionRegistry, + source: string, logData?: { regionName: string; groupName: string } ): Promise { - const wizard = new TailLogGroupWizard(logData) - const wizardResponse = await wizard.run() - if (!wizardResponse) { - throw new CancellationError('user') - } - const awsCredentials = await globals.awsContext.getCredentials() - if (awsCredentials === undefined) { - throw new ToolkitError('Failed to start LiveTail session: credentials are undefined.') - } - const liveTailSessionConfig: LiveTailSessionConfiguration = { - logGroupArn: wizardResponse.regionLogGroupSubmenuResponse.data, - logStreamFilter: wizardResponse.logStreamFilter, - logEventFilterPattern: wizardResponse.filterPattern, - region: wizardResponse.regionLogGroupSubmenuResponse.region, - awsCredentials: awsCredentials, - } - const session = new LiveTailSession(liveTailSessionConfig) - if (registry.has(uriToKey(session.uri))) { - await prepareDocument(session) - return - } - registry.set(uriToKey(session.uri), session) + await telemetry.cwlLiveTail_Start.run(async (span) => { + const wizard = new TailLogGroupWizard(logData) + const wizardResponse = await wizard.run() + if (!wizardResponse) { + throw new CancellationError('user') + } + const awsCredentials = await globals.awsContext.getCredentials() + if (awsCredentials === undefined) { + throw new ToolkitError('Failed to start LiveTail session: credentials are undefined.') + } + const liveTailSessionConfig: LiveTailSessionConfiguration = { + logGroupArn: wizardResponse.regionLogGroupSubmenuResponse.data, + logStreamFilter: wizardResponse.logStreamFilter, + logEventFilterPattern: wizardResponse.filterPattern, + region: wizardResponse.regionLogGroupSubmenuResponse.region, + awsCredentials: awsCredentials, + } + const session = new LiveTailSession(liveTailSessionConfig) + if (registry.has(uriToKey(session.uri))) { + await prepareDocument(session) + span.record({ + livetailSessionAlreadyStarted: true, + source: source, + }) + return + } + span.record({ + source: source, + livetailSessionAlreadyStarted: false, + livetailHasLogEventFilterPattern: Boolean(wizardResponse.filterPattern), + livetailLogStreamFilterType: wizardResponse.logStreamFilter.type, + }) + + registry.set(uriToKey(session.uri), session) - const document = await prepareDocument(session) + const document = await prepareDocument(session) - hideShowStatusBarItemsOnActiveEditor(session, document) - registerTabChangeCallback(session, registry, document) + hideShowStatusBarItemsOnActiveEditor(session, document) + registerTabChangeCallback(session, registry, document) - const stream = await session.startLiveTailSession() + const stream = await session.startLiveTailSession() - await handleSessionStream(stream, document, session) + await handleSessionStream(stream, document, session) + }) } -export function closeSession(sessionUri: vscode.Uri, registry: LiveTailSessionRegistry) { - const session = registry.get(uriToKey(sessionUri)) - if (session === undefined) { - throw new ToolkitError(`No LiveTail session found for URI: ${sessionUri.toString()}`) - } - session.stopLiveTailSession() - registry.delete(uriToKey(sessionUri)) +export function closeSession(sessionUri: vscode.Uri, registry: LiveTailSessionRegistry, source: string) { + telemetry.cwlLiveTail_Stop.run((span) => { + const session = registry.get(uriToKey(sessionUri)) + if (session === undefined) { + throw new ToolkitError(`No LiveTail session found for URI: ${sessionUri.toString()}`) + } + session.stopLiveTailSession() + registry.delete(uriToKey(sessionUri)) + span.record({ + source: source, + duration: session.getLiveTailSessionDuration(), + }) + }) } export async function clearDocument(textDocument: vscode.TextDocument) { @@ -215,7 +236,7 @@ function registerTabChangeCallback( vscode.window.tabGroups.onDidChangeTabs((tabEvent) => { const isOpen = isLiveTailSessionOpenInAnyTab(session) if (!isOpen) { - closeSession(session.uri, registry) + closeSession(session.uri, registry, 'ClosedEditors') void clearDocument(document) } }) diff --git a/packages/core/src/awsService/cloudWatchLogs/document/liveTailCodeLensProvider.ts b/packages/core/src/awsService/cloudWatchLogs/document/liveTailCodeLensProvider.ts index 7c7bb1cd74c..0e4edcf52aa 100644 --- a/packages/core/src/awsService/cloudWatchLogs/document/liveTailCodeLensProvider.ts +++ b/packages/core/src/awsService/cloudWatchLogs/document/liveTailCodeLensProvider.ts @@ -38,7 +38,7 @@ export class LiveTailCodeLensProvider implements vscode.CodeLensProvider { const command: vscode.Command = { title: 'Stop tailing', command: 'aws.cwl.stopTailingLogGroup', - arguments: [document], + arguments: [document, 'codeLens'], } return new vscode.CodeLens(range, command) } diff --git a/packages/core/src/shared/telemetry/vscodeTelemetry.json b/packages/core/src/shared/telemetry/vscodeTelemetry.json index 5712b313eaf..c7e6d7afa00 100644 --- a/packages/core/src/shared/telemetry/vscodeTelemetry.json +++ b/packages/core/src/shared/telemetry/vscodeTelemetry.json @@ -350,6 +350,21 @@ "name": "amazonqMessageDisplayedMs", "type": "int", "description": "Duration between the partner teams code receiving the message and when the message was finally displayed in ms" + }, + { + "name": "livetailSessionAlreadyStarted", + "type": "boolean", + "description": "Session already open" + }, + { + "name": "livetailHasLogEventFilterPattern", + "type": "boolean", + "description": "If LogEvent filter pattern is applied" + }, + { + "name": "livetailLogStreamFilterType", + "type": "string", + "description": "Type of LogStream filter applied to session" } ], "metrics": [ @@ -1230,6 +1245,42 @@ } ], "passive": true + }, + { + "name": "cwlLiveTail_Start", + "description": "When user starts a new LiveTail command", + "metadata": [ + { + "type": "source", + "required": true + }, + { + "type": "livetailSessionAlreadyStarted", + "required": true + }, + { + "type": "livetailHasLogEventFilterPattern", + "required": false + }, + { + "type": "livetailLogStreamFilterType", + "required": false + } + ] + }, + { + "name": "cwlLiveTail_Stop", + "description": "When user stops a liveTailSession", + "metadata": [ + { + "type": "source", + "required": true + }, + { + "type": "duration", + "required": true + } + ] } ] } diff --git a/packages/core/src/test/awsService/cloudWatchLogs/commands/tailLogGroup.test.ts b/packages/core/src/test/awsService/cloudWatchLogs/commands/tailLogGroup.test.ts index 56819d86a8a..90accf47711 100644 --- a/packages/core/src/test/awsService/cloudWatchLogs/commands/tailLogGroup.test.ts +++ b/packages/core/src/test/awsService/cloudWatchLogs/commands/tailLogGroup.test.ts @@ -27,6 +27,7 @@ describe('TailLogGroup', function () { const testRegion = 'test-region' const testMessage = 'test-message' const testAwsAccountId = '1234' + const testSource = 'test-source' const testAwsCredentials = {} as any as AWS.Credentials let sandbox: sinon.SinonSandbox @@ -93,7 +94,7 @@ describe('TailLogGroup', function () { cloudwatchSettingsSpy = sandbox.stub(CloudWatchLogsSettings.prototype, 'get').callsFake(() => { return 1 }) - await tailLogGroup(registry, { + await tailLogGroup(registry, testSource, { groupName: testLogGroup, regionName: testRegion, }) @@ -131,7 +132,7 @@ describe('TailLogGroup', function () { return getTestWizardResponse() }) await assert.rejects(async () => { - await tailLogGroup(registry, { + await tailLogGroup(registry, testSource, { groupName: testLogGroup, regionName: testRegion, }) @@ -152,7 +153,7 @@ describe('TailLogGroup', function () { }) registry.set(uriToKey(session.uri), session) - closeSession(session.uri, registry) + closeSession(session.uri, registry, testSource) assert.strictEqual(0, registry.size) assert.strictEqual(true, stopLiveTailSessionSpy.calledOnce) assert.strictEqual(0, clock.countTimers()) From f9653807a07b586b0083d0546d617fb60566b62b Mon Sep 17 00:00:00 2001 From: Keegan Irby Date: Tue, 19 Nov 2024 10:27:56 -0800 Subject: [PATCH 2/3] Rename metric properties --- .../cloudWatchLogs/commands/tailLogGroup.ts | 8 ++++---- .../core/src/shared/telemetry/vscodeTelemetry.json | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/core/src/awsService/cloudWatchLogs/commands/tailLogGroup.ts b/packages/core/src/awsService/cloudWatchLogs/commands/tailLogGroup.ts index 87d959b9ef0..948eeb18986 100644 --- a/packages/core/src/awsService/cloudWatchLogs/commands/tailLogGroup.ts +++ b/packages/core/src/awsService/cloudWatchLogs/commands/tailLogGroup.ts @@ -43,16 +43,16 @@ export async function tailLogGroup( if (registry.has(uriToKey(session.uri))) { await prepareDocument(session) span.record({ - livetailSessionAlreadyStarted: true, + sessionAlreadyStarted: true, source: source, }) return } span.record({ source: source, - livetailSessionAlreadyStarted: false, - livetailHasLogEventFilterPattern: Boolean(wizardResponse.filterPattern), - livetailLogStreamFilterType: wizardResponse.logStreamFilter.type, + sessionAlreadyStarted: false, + hasLogEventFilterPattern: Boolean(wizardResponse.filterPattern), + logStreamFilterType: wizardResponse.logStreamFilter.type, }) registry.set(uriToKey(session.uri), session) diff --git a/packages/core/src/shared/telemetry/vscodeTelemetry.json b/packages/core/src/shared/telemetry/vscodeTelemetry.json index c7e6d7afa00..fadeda786da 100644 --- a/packages/core/src/shared/telemetry/vscodeTelemetry.json +++ b/packages/core/src/shared/telemetry/vscodeTelemetry.json @@ -352,17 +352,17 @@ "description": "Duration between the partner teams code receiving the message and when the message was finally displayed in ms" }, { - "name": "livetailSessionAlreadyStarted", + "name": "sessionAlreadyStarted", "type": "boolean", "description": "Session already open" }, { - "name": "livetailHasLogEventFilterPattern", + "name": "hasLogEventFilterPattern", "type": "boolean", "description": "If LogEvent filter pattern is applied" }, { - "name": "livetailLogStreamFilterType", + "name": "logStreamFilterType", "type": "string", "description": "Type of LogStream filter applied to session" } @@ -1255,15 +1255,15 @@ "required": true }, { - "type": "livetailSessionAlreadyStarted", + "type": "sessionAlreadyStarted", "required": true }, { - "type": "livetailHasLogEventFilterPattern", + "type": "hasLogEventFilterPattern", "required": false }, { - "type": "livetailLogStreamFilterType", + "type": "logStreamFilterType", "required": false } ] From dba811d96468be9db219b02247dc700abe54a271 Mon Sep 17 00:00:00 2001 From: Keegan Irby Date: Tue, 19 Nov 2024 14:36:48 -0800 Subject: [PATCH 3/3] Consume telemetry from commons --- package-lock.json | 8 +-- package.json | 2 +- .../cloudWatchLogs/commands/tailLogGroup.ts | 16 +++--- .../src/shared/telemetry/vscodeTelemetry.json | 51 ------------------- 4 files changed, 14 insertions(+), 63 deletions(-) diff --git a/package-lock.json b/package-lock.json index 53060c4ae28..c842de7b182 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "vscode-nls-dev": "^4.0.4" }, "devDependencies": { - "@aws-toolkits/telemetry": "^1.0.282", + "@aws-toolkits/telemetry": "^1.0.284", "@playwright/browser-chromium": "^1.43.1", "@types/he": "^1.2.3", "@types/vscode": "^1.68.0", @@ -6046,9 +6046,9 @@ } }, "node_modules/@aws-toolkits/telemetry": { - "version": "1.0.282", - "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.282.tgz", - "integrity": "sha512-MHktYmucYHvEm4Sscr93UmKr83D9pKJIvETo1bZiNtCsE0jxcNglxZwqZruy13Fks5uk523ZhaIALW22TF0Zpg==", + "version": "1.0.284", + "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.284.tgz", + "integrity": "sha512-+3uHmr4St2cw8yuvVZOUY4Recv0wmzendGODCeUPIIUjsjCANF3H7G/qzIKRN3BHCoedcvzA/eSI+l4ENRXtiA==", "dev": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 70f9d0f4c35..bc03c2b8395 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "generateNonCodeFiles": "npm run generateNonCodeFiles -w packages/ --if-present" }, "devDependencies": { - "@aws-toolkits/telemetry": "^1.0.282", + "@aws-toolkits/telemetry": "^1.0.284", "@playwright/browser-chromium": "^1.43.1", "@types/he": "^1.2.3", "@types/vscode": "^1.68.0", diff --git a/packages/core/src/awsService/cloudWatchLogs/commands/tailLogGroup.ts b/packages/core/src/awsService/cloudWatchLogs/commands/tailLogGroup.ts index 948eeb18986..c96d33dc15f 100644 --- a/packages/core/src/awsService/cloudWatchLogs/commands/tailLogGroup.ts +++ b/packages/core/src/awsService/cloudWatchLogs/commands/tailLogGroup.ts @@ -43,17 +43,12 @@ export async function tailLogGroup( if (registry.has(uriToKey(session.uri))) { await prepareDocument(session) span.record({ + result: 'Succeeded', sessionAlreadyStarted: true, source: source, }) return } - span.record({ - source: source, - sessionAlreadyStarted: false, - hasLogEventFilterPattern: Boolean(wizardResponse.filterPattern), - logStreamFilterType: wizardResponse.logStreamFilter.type, - }) registry.set(uriToKey(session.uri), session) @@ -63,7 +58,13 @@ export async function tailLogGroup( registerTabChangeCallback(session, registry, document) const stream = await session.startLiveTailSession() - + span.record({ + source: source, + result: 'Succeeded', + sessionAlreadyStarted: false, + hasLogEventFilterPattern: Boolean(wizardResponse.filterPattern), + logStreamFilterType: wizardResponse.logStreamFilter.type, + }) await handleSessionStream(stream, document, session) }) } @@ -77,6 +78,7 @@ export function closeSession(sessionUri: vscode.Uri, registry: LiveTailSessionRe session.stopLiveTailSession() registry.delete(uriToKey(sessionUri)) span.record({ + result: 'Succeeded', source: source, duration: session.getLiveTailSessionDuration(), }) diff --git a/packages/core/src/shared/telemetry/vscodeTelemetry.json b/packages/core/src/shared/telemetry/vscodeTelemetry.json index fadeda786da..5712b313eaf 100644 --- a/packages/core/src/shared/telemetry/vscodeTelemetry.json +++ b/packages/core/src/shared/telemetry/vscodeTelemetry.json @@ -350,21 +350,6 @@ "name": "amazonqMessageDisplayedMs", "type": "int", "description": "Duration between the partner teams code receiving the message and when the message was finally displayed in ms" - }, - { - "name": "sessionAlreadyStarted", - "type": "boolean", - "description": "Session already open" - }, - { - "name": "hasLogEventFilterPattern", - "type": "boolean", - "description": "If LogEvent filter pattern is applied" - }, - { - "name": "logStreamFilterType", - "type": "string", - "description": "Type of LogStream filter applied to session" } ], "metrics": [ @@ -1245,42 +1230,6 @@ } ], "passive": true - }, - { - "name": "cwlLiveTail_Start", - "description": "When user starts a new LiveTail command", - "metadata": [ - { - "type": "source", - "required": true - }, - { - "type": "sessionAlreadyStarted", - "required": true - }, - { - "type": "hasLogEventFilterPattern", - "required": false - }, - { - "type": "logStreamFilterType", - "required": false - } - ] - }, - { - "name": "cwlLiveTail_Stop", - "description": "When user stops a liveTailSession", - "metadata": [ - { - "type": "source", - "required": true - }, - { - "type": "duration", - "required": true - } - ] } ] }