Skip to content

Commit 6995107

Browse files
authored
telemetry(amazonq): implement codewhisperer_clientComponentLatency (#7234)
## Problem the only metric it looks like we're missing for inline on the vscode side is `codewhisperer_clientComponentLatency` ## Solution codewhisperer_clientComponentLatency uses a very similar implementation as before the only differences are: 1. codewhispererCredentialFetchingLatency is no longer relevant because the token is always injected into the language server and it doesn't need to build the client on demand like before. - This causes the preprocessing latency to decrease, because that used to contain the time it takes to fetch the credentials 2. postProcessing latency is way lower because once we get the result vscode instantly displays it -- we no longer have control of that example metric now: ``` 2025-05-06 11:53:59.858 [debug] telemetry: codewhisperer_clientComponentLatency { Metadata: { codewhispererAllCompletionsLatency: '792.7122090000048', codewhispererCompletionType: 'Line', codewhispererCredentialFetchingLatency: '0', codewhispererCustomizationArn: 'arn:aws:codewhisperer:us-east-1:12345678910:customization/AAAAAAAAAA', codewhispererEndToEndLatency: '792.682249999998', codewhispererFirstCompletionLatency: '792.6440000000002', codewhispererLanguage: 'java', codewhispererPostprocessingLatency: '0.019500000002153683', codewhispererPreprocessingLatency: '0.007166999996115919', codewhispererRequestId: 'XXXXXXXXXXXXXXXXXXXXXXXXXXX', codewhispererTriggerType: 'AutoTrigger', credentialStartUrl: 'https://XXXXX.XXXXX.com/start', awsAccount: 'not-set', awsRegion: 'us-east-1' }, Value: 1, Unit: 'None', Passive: true } ``` --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 260fb37 commit 6995107

File tree

3 files changed

+186
-0
lines changed

3 files changed

+186
-0
lines changed

packages/amazonq/src/app/inline/completion.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
import { InlineGeneratingMessage } from './inlineGeneratingMessage'
3737
import { LineTracker } from './stateTracker/lineTracker'
3838
import { InlineTutorialAnnotation } from './tutorials/inlineTutorialAnnotation'
39+
import { TelemetryHelper } from './telemetryHelper'
3940

4041
export class InlineCompletionManager implements Disposable {
4142
private disposable: Disposable
@@ -212,6 +213,8 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
212213

213214
// tell the tutorial that completions has been triggered
214215
await this.inlineTutorialAnnotation.triggered(context.triggerKind)
216+
TelemetryHelper.instance.setInvokeSuggestionStartTime()
217+
TelemetryHelper.instance.setTriggerType(context.triggerKind)
215218

216219
// make service requests if it's a new session
217220
await this.recommendationService.getAllRecommendations(

packages/amazonq/src/app/inline/recommendationService.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { LanguageClient } from 'vscode-languageclient'
1313
import { SessionManager } from './sessionManager'
1414
import { InlineGeneratingMessage } from './inlineGeneratingMessage'
1515
import { CodeWhispererStatusBarManager } from 'aws-core-vscode/codewhisperer'
16+
import { TelemetryHelper } from './telemetryHelper'
1617

1718
export class RecommendationService {
1819
constructor(
@@ -36,6 +37,9 @@ export class RecommendationService {
3637
}
3738
const requestStartTime = Date.now()
3839
const statusBar = CodeWhispererStatusBarManager.instance
40+
TelemetryHelper.instance.setInvokeSuggestionStartTime()
41+
TelemetryHelper.instance.setPreprocessEndTime()
42+
TelemetryHelper.instance.setSdkApiCallStartTime()
3943

4044
try {
4145
// Show UI indicators that we are generating suggestions
@@ -49,6 +53,14 @@ export class RecommendationService {
4953
token
5054
)
5155

56+
// Set telemetry data for the first response
57+
TelemetryHelper.instance.setSdkApiCallEndTime()
58+
TelemetryHelper.instance.setSessionId(firstResult.sessionId)
59+
if (firstResult.items.length > 0) {
60+
TelemetryHelper.instance.setFirstResponseRequestId(firstResult.items[0].itemId)
61+
}
62+
TelemetryHelper.instance.setFirstSuggestionShowTime()
63+
5264
const firstCompletionDisplayLatency = Date.now() - requestStartTime
5365
this.sessionManager.startSession(
5466
firstResult.sessionId,
@@ -64,6 +76,10 @@ export class RecommendationService {
6476
})
6577
} else {
6678
this.sessionManager.closeSession()
79+
80+
// No more results to fetch, mark pagination as complete
81+
TelemetryHelper.instance.setAllPaginationEndTime()
82+
TelemetryHelper.instance.tryRecordClientComponentLatency()
6783
}
6884
} finally {
6985
// Remove all UI indicators of message generation since we are done
@@ -89,6 +105,11 @@ export class RecommendationService {
89105
this.sessionManager.updateSessionSuggestions(result.items)
90106
nextToken = result.partialResultToken
91107
}
108+
92109
this.sessionManager.closeSession()
110+
111+
// All pagination requests completed
112+
TelemetryHelper.instance.setAllPaginationEndTime()
113+
TelemetryHelper.instance.tryRecordClientComponentLatency()
93114
}
94115
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { AuthUtil, getSelectedCustomization } from 'aws-core-vscode/codewhisperer'
7+
import { CodewhispererLanguage } from 'aws-core-vscode/shared'
8+
import { CodewhispererTriggerType, telemetry } from 'aws-core-vscode/telemetry'
9+
import { InlineCompletionTriggerKind } from 'vscode'
10+
11+
export class TelemetryHelper {
12+
// Variables needed for client component latency
13+
private _invokeSuggestionStartTime = 0
14+
private _preprocessEndTime = 0
15+
private _sdkApiCallStartTime = 0
16+
private _sdkApiCallEndTime = 0
17+
private _allPaginationEndTime = 0
18+
private _firstSuggestionShowTime = 0
19+
private _firstResponseRequestId = ''
20+
private _sessionId = ''
21+
private _language: CodewhispererLanguage = 'java'
22+
private _triggerType: CodewhispererTriggerType = 'OnDemand'
23+
24+
constructor() {}
25+
26+
static #instance: TelemetryHelper
27+
28+
public static get instance() {
29+
return (this.#instance ??= new this())
30+
}
31+
32+
public resetClientComponentLatencyTime() {
33+
this._invokeSuggestionStartTime = 0
34+
this._preprocessEndTime = 0
35+
this._sdkApiCallStartTime = 0
36+
this._sdkApiCallEndTime = 0
37+
this._firstSuggestionShowTime = 0
38+
this._allPaginationEndTime = 0
39+
this._firstResponseRequestId = ''
40+
}
41+
42+
public setInvokeSuggestionStartTime() {
43+
this.resetClientComponentLatencyTime()
44+
this._invokeSuggestionStartTime = performance.now()
45+
}
46+
47+
get invokeSuggestionStartTime(): number {
48+
return this._invokeSuggestionStartTime
49+
}
50+
51+
public setPreprocessEndTime() {
52+
this._preprocessEndTime = performance.now()
53+
}
54+
55+
get preprocessEndTime(): number {
56+
return this._preprocessEndTime
57+
}
58+
59+
public setSdkApiCallStartTime() {
60+
if (this._sdkApiCallStartTime === 0) {
61+
this._sdkApiCallStartTime = performance.now()
62+
}
63+
}
64+
65+
get sdkApiCallStartTime(): number {
66+
return this._sdkApiCallStartTime
67+
}
68+
69+
public setSdkApiCallEndTime() {
70+
if (this._sdkApiCallEndTime === 0 && this._sdkApiCallStartTime !== 0) {
71+
this._sdkApiCallEndTime = performance.now()
72+
}
73+
}
74+
75+
get sdkApiCallEndTime(): number {
76+
return this._sdkApiCallEndTime
77+
}
78+
79+
public setAllPaginationEndTime() {
80+
if (this._allPaginationEndTime === 0 && this._sdkApiCallEndTime !== 0) {
81+
this._allPaginationEndTime = performance.now()
82+
}
83+
}
84+
85+
get allPaginationEndTime(): number {
86+
return this._allPaginationEndTime
87+
}
88+
89+
public setFirstSuggestionShowTime() {
90+
if (this._firstSuggestionShowTime === 0 && this._sdkApiCallEndTime !== 0) {
91+
this._firstSuggestionShowTime = performance.now()
92+
}
93+
}
94+
95+
get firstSuggestionShowTime(): number {
96+
return this._firstSuggestionShowTime
97+
}
98+
99+
public setFirstResponseRequestId(requestId: string) {
100+
if (this._firstResponseRequestId === '') {
101+
this._firstResponseRequestId = requestId
102+
}
103+
}
104+
105+
get firstResponseRequestId(): string {
106+
return this._firstResponseRequestId
107+
}
108+
109+
public setSessionId(sessionId: string) {
110+
if (this._sessionId === '') {
111+
this._sessionId = sessionId
112+
}
113+
}
114+
115+
get sessionId(): string {
116+
return this._sessionId
117+
}
118+
119+
public setLanguage(language: CodewhispererLanguage) {
120+
this._language = language
121+
}
122+
123+
get language(): CodewhispererLanguage {
124+
return this._language
125+
}
126+
127+
public setTriggerType(triggerType: InlineCompletionTriggerKind) {
128+
if (triggerType === InlineCompletionTriggerKind.Invoke) {
129+
this._triggerType = 'OnDemand'
130+
} else if (triggerType === InlineCompletionTriggerKind.Automatic) {
131+
this._triggerType = 'AutoTrigger'
132+
}
133+
}
134+
135+
get triggerType(): string {
136+
return this._triggerType
137+
}
138+
139+
// report client component latency after all pagination call finish
140+
// and at least one suggestion is shown to the user
141+
public tryRecordClientComponentLatency() {
142+
if (this._firstSuggestionShowTime === 0 || this._allPaginationEndTime === 0) {
143+
return
144+
}
145+
telemetry.codewhisperer_clientComponentLatency.emit({
146+
codewhispererAllCompletionsLatency: this._allPaginationEndTime - this._sdkApiCallStartTime,
147+
codewhispererCompletionType: 'Line',
148+
codewhispererCredentialFetchingLatency: 0, // no longer relevant, because we don't re-build the sdk. Flare already has that set
149+
codewhispererCustomizationArn: getSelectedCustomization().arn,
150+
codewhispererEndToEndLatency: this._firstSuggestionShowTime - this._invokeSuggestionStartTime,
151+
codewhispererFirstCompletionLatency: this._sdkApiCallEndTime - this._sdkApiCallStartTime,
152+
codewhispererLanguage: this._language,
153+
codewhispererPostprocessingLatency: this._firstSuggestionShowTime - this._sdkApiCallEndTime,
154+
codewhispererPreprocessingLatency: this._preprocessEndTime - this._invokeSuggestionStartTime,
155+
codewhispererRequestId: this._firstResponseRequestId,
156+
codewhispererSessionId: this._sessionId,
157+
codewhispererTriggerType: this._triggerType,
158+
credentialStartUrl: AuthUtil.instance.startUrl,
159+
result: 'Succeeded',
160+
})
161+
}
162+
}

0 commit comments

Comments
 (0)