Skip to content

Commit f5e4144

Browse files
committed
ai gen
1 parent c09b09a commit f5e4144

File tree

1 file changed

+163
-0
lines changed

1 file changed

+163
-0
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import * as vscode from 'vscode'
7+
import { getLogger } from '../../shared/logger/logger'
8+
import * as CodeWhispererConstants from '../models/constants'
9+
import globals from '../../shared/extensionGlobals'
10+
import { vsCodeState } from '../models/model'
11+
import { CodewhispererLanguage, telemetry } from '../../shared/telemetry/telemetry'
12+
import { runtimeLanguageContext } from '../util/runtimeLanguageContext'
13+
import { TelemetryHelper } from '../util/telemetryHelper'
14+
import { AuthUtil } from '../util/authUtil'
15+
import { getSelectedCustomization } from '../util/customizationUtil'
16+
import { codeWhispererClient as client } from '../client/codewhisperer'
17+
import { isAwsError } from '../../shared/errors'
18+
19+
/**
20+
* This singleton class is mainly used for calculating the total code written by Amazon Q and user
21+
* It is meant to replace `CodeWhispererCodeCoverageTracker`
22+
*/
23+
export class QCodeGenTracker {
24+
private _totalNewCodeCharacterCount: number
25+
private _totalNewCodeLineCount: number
26+
private _timer?: NodeJS.Timer
27+
private _serviceInvocationCount: number
28+
29+
static #instance: QCodeGenTracker
30+
31+
private constructor() {
32+
this._totalNewCodeLineCount = 0
33+
this._totalNewCodeCharacterCount = 0
34+
this._serviceInvocationCount = 0
35+
}
36+
37+
public static get instance() {
38+
return (this.#instance ??= new this())
39+
}
40+
41+
public get serviceInvocationCount(): number {
42+
return this._serviceInvocationCount
43+
}
44+
45+
public isActive(): boolean {
46+
return TelemetryHelper.instance.isTelemetryEnabled() && AuthUtil.instance.isConnected()
47+
}
48+
49+
public onQFeatureInvoked() {
50+
this._serviceInvocationCount += 1
51+
}
52+
53+
public flush() {
54+
if (!this.isActive()) {
55+
this._totalNewCodeLineCount = 0
56+
this._totalNewCodeCharacterCount = 0
57+
this.closeTimer()
58+
return
59+
}
60+
try {
61+
this.emitCodeContribution()
62+
} catch (error) {
63+
getLogger().error(`Encountered ${error} when emitting code contribution metric`)
64+
}
65+
}
66+
67+
public emitCodeContribution() {
68+
const selectedCustomization = getSelectedCustomization()
69+
if (this._serviceInvocationCount <= 0) {
70+
getLogger().debug(`Skip emiting code contribution metric. There is no Amazon Q active usage. `)
71+
return
72+
}
73+
client
74+
.sendTelemetryEvent({
75+
telemetryEvent: {
76+
codeCoverageEvent: {
77+
customizationArn: selectedCustomization.arn === '' ? undefined : selectedCustomization.arn,
78+
programmingLanguage: {
79+
languageName: runtimeLanguageContext.toRuntimeLanguage(this._language),
80+
},
81+
acceptedCharacterCount: 0,
82+
totalCharacterCount: 0,
83+
timestamp: new Date(Date.now()),
84+
totalNewCodeCharacterCount: 0,
85+
totalNewCodeLineCount: 0,
86+
},
87+
},
88+
})
89+
.then()
90+
.catch((error) => {
91+
let requestId: string | undefined
92+
if (isAwsError(error)) {
93+
requestId = error.requestId
94+
}
95+
96+
getLogger().debug(
97+
`Failed to sendTelemetryEvent to CodeWhisperer, requestId: ${requestId ?? ''}, message: ${
98+
error.message
99+
}`
100+
)
101+
})
102+
}
103+
104+
private tryStartTimer() {
105+
if (this._timer !== undefined) {
106+
return
107+
}
108+
const currentDate = new globals.clock.Date()
109+
const startTime = performance.now()
110+
this._timer = setTimeout(() => {
111+
try {
112+
const currentTime = new globals.clock.Date().getTime()
113+
const delay: number = CodeWhispererConstants.defaultCheckPeriodMillis
114+
const diffTime: number = startTime + delay
115+
if (diffTime <= currentTime) {
116+
if (this._totalNewCodeCharacterCount > 0) {
117+
this.flush()
118+
} else {
119+
getLogger().debug(
120+
`CodeWhispererCodeCoverageTracker: skipped telemetry due to empty tokens array`
121+
)
122+
}
123+
}
124+
} catch (e) {
125+
getLogger().verbose(`Exception Thrown from CodeWhispererCodeCoverageTracker: ${e}`)
126+
} finally {
127+
this.resetTracker()
128+
this.closeTimer()
129+
}
130+
}, CodeWhispererConstants.defaultCheckPeriodMillis)
131+
}
132+
133+
private resetTracker() {
134+
this._totalTokens = {}
135+
this._acceptedTokens = {}
136+
this._startTime = 0
137+
this._serviceInvocationCount = 0
138+
}
139+
140+
private closeTimer() {
141+
if (this._timer !== undefined) {
142+
clearTimeout(this._timer)
143+
this._timer = undefined
144+
}
145+
}
146+
147+
public onTextDocumentChange(e: vscode.TextDocumentChangeEvent) {
148+
if (
149+
!runtimeLanguageContext.isLanguageSupported(e.document.languageId) ||
150+
vsCodeState.isCodeWhispererEditing ||
151+
e.contentChanges.length === 0
152+
) {
153+
return
154+
}
155+
const contentChange = e.contentChanges[0]
156+
if (contentChange.text.length > 50) {
157+
return
158+
}
159+
this._totalNewCodeCharacterCount += contentChange.text.length
160+
// start 5 min data reporting once valid user input is detected
161+
this.tryStartTimer()
162+
}
163+
}

0 commit comments

Comments
 (0)