Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/amazonq/src/app/amazonqScan/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { AppToWebViewMessageDispatcher } from './chat/views/connector/connector'
import { Messenger } from './chat/controller/messenger/messenger'
import { UIMessageListener } from './chat/views/actions/uiMessageListener'
import { debounce } from 'lodash'
import { ReviewTelemetryHelper } from './telemetryHelper'

export function init(appContext: AmazonQAppInitContext) {
const scanChatControllerEventEmitters: ScanChatControllerEventEmitters = {
Expand Down
65 changes: 65 additions & 0 deletions packages/amazonq/src/app/amazonqScan/telemetryHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import { telemetry } from 'aws-core-vscode/telemetry'
import { AuthUtil } from 'aws-core-vscode/codewhisperer'

export class ReviewTelemetryHelper {
static #instance: ReviewTelemetryHelper

public static get instance() {
return (this.#instance ??= new this())
}

public recordReviewStart(scope: 'file' | 'project', fileName?: string) {
telemetry.amazonq_reviewStart.emit({
result: 'Succeeded',
amazonqReviewScope: scope,
amazonqReviewFileName: fileName,
credentialStartUrl: AuthUtil.instance.startUrl,
})
}

public recordReviewComplete(
scope: 'file' | 'project',
issuesFound: number,
criticalIssues: number,
highIssues: number,
mediumIssues: number,
lowIssues: number,
infoIssues: number,
duration: number
) {
telemetry.amazonq_reviewComplete.emit({
result: 'Succeeded',
amazonqReviewScope: scope,
amazonqReviewIssuesFound: issuesFound,
amazonqReviewCriticalIssues: criticalIssues,
amazonqReviewHighIssues: highIssues,
amazonqReviewMediumIssues: mediumIssues,
amazonqReviewLowIssues: lowIssues,
amazonqReviewInfoIssues: infoIssues,
amazonqReviewDuration: duration,
credentialStartUrl: AuthUtil.instance.startUrl,
})
}

public recordReviewError(scope: 'file' | 'project', errorCode: string) {
telemetry.amazonq_reviewError.emit({
result: 'Failed',
amazonqReviewScope: scope,
amazonqReviewErrorCode: errorCode,
credentialStartUrl: AuthUtil.instance.startUrl,
})
}

public recordFixApplied(issueType: string, fixSuccess: boolean) {
telemetry.amazonq_reviewFixApplied.emit({
result: fixSuccess ? 'Succeeded' : 'Failed',
amazonqReviewIssueType: issueType,
credentialStartUrl: AuthUtil.instance.startUrl,
})
}
}
26 changes: 26 additions & 0 deletions packages/amazonq/src/app/development/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import { DevelopmentTelemetryHelper } from './telemetryHelper'

export function recordCodeGenerationUsage(
language: string,
generatedCode: string,
filesCreated: number = 1
) {
const linesGenerated = generatedCode.split('\n').length
DevelopmentTelemetryHelper.instance.recordCodeGeneration(
language,
linesGenerated,
filesCreated,
true
)
}

export function recordDevelopmentFeatureUsage(featureName: string, context?: string) {
DevelopmentTelemetryHelper.instance.recordFeatureUsage(featureName, context)
}

export { DevelopmentTelemetryHelper }
61 changes: 61 additions & 0 deletions packages/amazonq/src/app/development/telemetryHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import { telemetry } from 'aws-core-vscode/telemetry'
import { AuthUtil } from 'aws-core-vscode/codewhisperer'

export class DevelopmentTelemetryHelper {
static #instance: DevelopmentTelemetryHelper

public static get instance() {
return (this.#instance ??= new this())
}

public recordCodeGeneration(
language: string,
linesGenerated: number,
filesGenerated: number,
success: boolean
) {
telemetry.amazonq_codeGeneration.emit({
result: success ? 'Succeeded' : 'Failed',
amazonqCodeGenLanguage: language,
amazonqCodeGenLinesGenerated: linesGenerated,
amazonqCodeGenFilesGenerated: filesGenerated,
credentialStartUrl: AuthUtil.instance.startUrl,
})
}

public recordProjectCreation(projectType: string, success: boolean) {
telemetry.amazonq_projectCreation.emit({
result: success ? 'Succeeded' : 'Failed',
amazonqProjectType: projectType,
credentialStartUrl: AuthUtil.instance.startUrl,
})
}

public recordDevelopmentActivity(
activityType: 'explain' | 'optimize' | 'refactor' | 'test',
language: string,
duration: number
) {
telemetry.amazonq_developmentActivity.emit({
result: 'Succeeded',
amazonqActivityType: activityType,
amazonqActivityLanguage: language,
amazonqActivityDuration: duration,
credentialStartUrl: AuthUtil.instance.startUrl,
})
}

public recordFeatureUsage(featureName: string, context?: string) {
telemetry.amazonq_featureUsage.emit({
result: 'Succeeded',
amazonqFeatureName: featureName,
amazonqFeatureContext: context,
credentialStartUrl: AuthUtil.instance.startUrl,
})
}
}
17 changes: 16 additions & 1 deletion packages/core/src/shared/sam/cli/samCliInvoker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {

import * as nls from 'vscode-nls'
import { SamCliSettings } from './samCliSettings'
import { SamCliTelemetryHelper } from './samCliTelemetryHelper'
const localize = nls.loadMessageBundle()

/**
Expand Down Expand Up @@ -54,7 +55,9 @@ export class DefaultSamCliProcessInvoker implements SamCliProcessInvoker {

getLogger().info(localize('AWS.running.command', 'Command: {0}', `${this.childProcess}`))
log.verbose(`running: ${this.childProcess}`)
return await this.childProcess.run({

const startTime = performance.now()
const result = await this.childProcess.run({
onStdout: (text, context) => {
getDebugConsoleLogger().info(text)
log.verbose(`stdout: ${text}`)
Expand All @@ -66,5 +69,17 @@ export class DefaultSamCliProcessInvoker implements SamCliProcessInvoker {
options?.onStderr?.(text, context)
},
})

// Record telemetry
const duration = performance.now() - startTime
const command = invokeOptions.arguments[0] as 'build' | 'deploy' | 'init' | 'local-invoke' | 'start-api'
SamCliTelemetryHelper.instance.recordSamCommand(
command,
result.exitCode === 0,
duration,
result.exitCode !== 0 ? result.exitCode.toString() : undefined
)

return result
}
}
73 changes: 73 additions & 0 deletions packages/core/src/shared/sam/cli/samCliTelemetryHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import { telemetry } from '../../telemetry/telemetry'
import { AuthUtil } from '../../../codewhisperer/util/authUtil'

export class SamCliTelemetryHelper {
static #instance: SamCliTelemetryHelper

public static get instance() {
return (this.#instance ??= new this())
}

public recordSamCommand(
command: 'build' | 'deploy' | 'init' | 'local-invoke' | 'start-api',
success: boolean,
duration: number,
errorCode?: string
) {
telemetry.amazonq_samCommand.emit({
result: success ? 'Succeeded' : 'Failed',
amazonqSamCommandType: command,
amazonqSamCommandDuration: duration,
amazonqSamErrorCode: errorCode,
credentialStartUrl: AuthUtil.instance.startUrl,
})
}

public recordSamInit(
runtime: string,
template: string,
success: boolean
) {
telemetry.amazonq_samInit.emit({
result: success ? 'Succeeded' : 'Failed',
amazonqSamRuntime: runtime,
amazonqSamTemplate: template,
credentialStartUrl: AuthUtil.instance.startUrl,
})
}

public recordSamDeploy(
stackName: string,
region: string,
success: boolean,
resourceCount?: number
) {
telemetry.amazonq_samDeploy.emit({
result: success ? 'Succeeded' : 'Failed',
amazonqSamStackName: stackName,
amazonqSamRegion: region,
amazonqSamResourceCount: resourceCount,
credentialStartUrl: AuthUtil.instance.startUrl,
})
}

public recordSamLocalInvoke(
functionName: string,
runtime: string,
success: boolean,
duration: number
) {
telemetry.amazonq_samLocalInvoke.emit({
result: success ? 'Succeeded' : 'Failed',
amazonqSamFunctionName: functionName,
amazonqSamRuntime: runtime,
amazonqSamInvokeDuration: duration,
credentialStartUrl: AuthUtil.instance.startUrl,
})
}
}
105 changes: 105 additions & 0 deletions packages/core/src/shared/telemetry/amazonqTelemetryEvents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

// Additional telemetry events for Amazon Q Dashboard integration
declare module './telemetry.gen' {
interface TelemetryDefinitions {
// Review functionality
amazonq_reviewStart: {
result: Result
amazonqReviewScope: 'file' | 'project'
amazonqReviewFileName?: string
credentialStartUrl?: string
}

amazonq_reviewComplete: {
result: Result
amazonqReviewScope: 'file' | 'project'
amazonqReviewIssuesFound: number
amazonqReviewCriticalIssues: number
amazonqReviewHighIssues: number
amazonqReviewMediumIssues: number
amazonqReviewLowIssues: number
amazonqReviewInfoIssues: number
amazonqReviewDuration: number
credentialStartUrl?: string
}

amazonq_reviewError: {
result: Result
amazonqReviewScope: 'file' | 'project'
amazonqReviewErrorCode: string
credentialStartUrl?: string
}

amazonq_reviewFixApplied: {
result: Result
amazonqReviewIssueType: string
credentialStartUrl?: string
}

// Development functionality
amazonq_codeGeneration: {
result: Result
amazonqCodeGenLanguage: string
amazonqCodeGenLinesGenerated: number
amazonqCodeGenFilesGenerated: number
credentialStartUrl?: string
}

amazonq_projectCreation: {
result: Result
amazonqProjectType: string
credentialStartUrl?: string
}

amazonq_developmentActivity: {
result: Result
amazonqActivityType: 'explain' | 'optimize' | 'refactor' | 'test'
amazonqActivityLanguage: string
amazonqActivityDuration: number
credentialStartUrl?: string
}

amazonq_featureUsage: {
result: Result
amazonqFeatureName: string
amazonqFeatureContext?: string
credentialStartUrl?: string
}

// SAM CLI functionality
amazonq_samCommand: {
result: Result
amazonqSamCommandType: 'build' | 'deploy' | 'init' | 'local-invoke' | 'start-api'
amazonqSamCommandDuration: number
amazonqSamErrorCode?: string
credentialStartUrl?: string
}

amazonq_samInit: {
result: Result
amazonqSamRuntime: string
amazonqSamTemplate: string
credentialStartUrl?: string
}

amazonq_samDeploy: {
result: Result
amazonqSamStackName: string
amazonqSamRegion: string
amazonqSamResourceCount?: number
credentialStartUrl?: string
}

amazonq_samLocalInvoke: {
result: Result
amazonqSamFunctionName: string
amazonqSamRuntime: string
amazonqSamInvokeDuration: number
credentialStartUrl?: string
}
}
}