@@ -11,15 +11,16 @@ import { AuthUtil } from '../util/authUtil'
1111import { getSelectedCustomization } from '../util/customizationUtil'
1212import { codeWhispererClient as client } from '../client/codewhisperer'
1313import { isAwsError } from '../../shared/errors'
14+ import { CodewhispererLanguage } from '../../shared'
1415
1516/**
1617 * This singleton class is mainly used for calculating the user written code
1718 * for active Amazon Q users.
1819 * It reports the user written code per 5 minutes when the user is coding and using Amazon Q features
1920 */
2021export class UserWrittenCodeTracker {
21- private _userWrittenNewCodeCharacterCount : number
22- private _userWrittenNewCodeLineCount : number
22+ private _userWrittenNewCodeCharacterCount : Map < CodewhispererLanguage , number >
23+ private _userWrittenNewCodeLineCount : Map < CodewhispererLanguage , number >
2324 private _qIsMakingEdits : boolean
2425 private _timer ?: NodeJS . Timer
2526 private _qUsageCount : number
@@ -30,22 +31,14 @@ export class UserWrittenCodeTracker {
3031 static resetQIsEditingTimeoutMs = 5 * 60 * 1000
3132 static defaultCheckPeriodMillis = 1000 * 60 * 5
3233 private constructor ( ) {
33- this . _userWrittenNewCodeLineCount = 0
34- this . _userWrittenNewCodeCharacterCount = 0
34+ this . _userWrittenNewCodeLineCount = new Map < CodewhispererLanguage , number > ( )
35+ this . _userWrittenNewCodeCharacterCount = new Map < CodewhispererLanguage , number > ( )
3536 this . _qUsageCount = 0
3637 this . _qIsMakingEdits = false
3738 this . _timer = undefined
3839 this . _lastQInvocationTime = 0
3940 }
4041
41- private resetTracker ( ) {
42- this . _userWrittenNewCodeLineCount = 0
43- this . _userWrittenNewCodeCharacterCount = 0
44- this . _qUsageCount = 0
45- this . _qIsMakingEdits = false
46- this . _lastQInvocationTime = 0
47- }
48-
4942 public static get instance ( ) {
5043 return ( this . #instance ??= new this ( ) )
5144 }
@@ -69,34 +62,61 @@ export class UserWrittenCodeTracker {
6962 this . _qIsMakingEdits = false
7063 }
7164
72- public emitCodeContribution ( ) {
65+ public getUserWrittenCharacters ( language : CodewhispererLanguage ) {
66+ return this . _userWrittenNewCodeCharacterCount . get ( language ) || 0
67+ }
68+
69+ public getUserWrittenLines ( language : CodewhispererLanguage ) {
70+ return this . _userWrittenNewCodeLineCount . get ( language ) || 0
71+ }
72+
73+ public reset ( ) {
74+ this . _userWrittenNewCodeLineCount = new Map < CodewhispererLanguage , number > ( )
75+ this . _userWrittenNewCodeCharacterCount = new Map < CodewhispererLanguage , number > ( )
76+ this . _qUsageCount = 0
77+ this . _qIsMakingEdits = false
78+ this . _lastQInvocationTime = 0
79+ if ( this . _timer !== undefined ) {
80+ clearTimeout ( this . _timer )
81+ this . _timer = undefined
82+ }
83+ }
84+
85+ public emitCodeContributions ( ) {
7386 const selectedCustomization = getSelectedCustomization ( )
74- client
75- . sendTelemetryEvent ( {
76- telemetryEvent : {
77- codeCoverageEvent : {
78- customizationArn : selectedCustomization . arn === '' ? undefined : selectedCustomization . arn ,
79- programmingLanguage : {
80- languageName : 'plaintext' ,
87+
88+ for ( const [ language , charCount ] of this . _userWrittenNewCodeCharacterCount ) {
89+ const lineCount = this . _userWrittenNewCodeLineCount . get ( language ) || 0
90+ if ( charCount > 0 ) {
91+ client
92+ . sendTelemetryEvent ( {
93+ telemetryEvent : {
94+ codeCoverageEvent : {
95+ customizationArn :
96+ selectedCustomization . arn === '' ? undefined : selectedCustomization . arn ,
97+ programmingLanguage : {
98+ languageName : language ,
99+ } ,
100+ acceptedCharacterCount : 0 ,
101+ totalCharacterCount : 0 ,
102+ timestamp : new Date ( Date . now ( ) ) ,
103+ userWrittenCodeCharacterCount : charCount ,
104+ userWrittenCodeLineCount : lineCount ,
105+ } ,
81106 } ,
82- acceptedCharacterCount : 0 ,
83- totalCharacterCount : 0 ,
84- timestamp : new Date ( Date . now ( ) ) ,
85- userWrittenCodeCharacterCount : this . _userWrittenNewCodeCharacterCount ,
86- userWrittenCodeLineCount : this . _userWrittenNewCodeLineCount ,
87- } ,
88- } ,
89- } )
90- . then ( )
91- . catch ( ( error ) => {
92- let requestId : string | undefined
93- if ( isAwsError ( error ) ) {
94- requestId = error . requestId
95- }
96- getLogger ( ) . debug (
97- `Failed to sendTelemetryEvent, requestId: ${ requestId ?? '' } , message: ${ error . message } `
98- )
99- } )
107+ } )
108+ . then ( )
109+ . catch ( ( error ) => {
110+ let requestId : string | undefined
111+ if ( isAwsError ( error ) ) {
112+ requestId = error . requestId
113+ }
114+ getLogger ( ) . debug (
115+ `Failed to sendTelemetryEvent, requestId: ${ requestId ?? '' } , message: ${ error . message } `
116+ )
117+ } )
118+ }
119+ }
100120 }
101121
102122 private tryStartTimer ( ) {
@@ -105,8 +125,7 @@ export class UserWrittenCodeTracker {
105125 }
106126 if ( ! this . isActive ( ) ) {
107127 getLogger ( ) . debug ( `Skip emiting code contribution metric. Telemetry disabled or not logged in. ` )
108- this . resetTracker ( )
109- this . closeTimer ( )
128+ this . reset ( )
110129 return
111130 }
112131 const startTime = performance . now ( )
@@ -120,28 +139,20 @@ export class UserWrittenCodeTracker {
120139 getLogger ( ) . debug ( `Skip emiting code contribution metric. There is no active Amazon Q usage. ` )
121140 return
122141 }
123- if ( this . _userWrittenNewCodeCharacterCount === 0 ) {
142+ if ( this . _userWrittenNewCodeCharacterCount . size === 0 ) {
124143 getLogger ( ) . debug ( `Skip emiting code contribution metric. There is no new code added. ` )
125144 return
126145 }
127- this . emitCodeContribution ( )
146+ this . emitCodeContributions ( )
128147 }
129148 } catch ( e ) {
130149 getLogger ( ) . verbose ( `Exception Thrown from QCodeGenTracker: ${ e } ` )
131150 } finally {
132- this . resetTracker ( )
133- this . closeTimer ( )
151+ this . reset ( )
134152 }
135153 } , UserWrittenCodeTracker . defaultCheckPeriodMillis )
136154 }
137155
138- private closeTimer ( ) {
139- if ( this . _timer !== undefined ) {
140- clearTimeout ( this . _timer )
141- this . _timer = undefined
142- }
143- }
144-
145156 private countNewLines ( str : string ) {
146157 return str . split ( '\n' ) . length - 1
147158 }
@@ -170,9 +181,14 @@ export class UserWrittenCodeTracker {
170181 if ( contentChange . text . length > UserWrittenCodeTracker . copySnippetThreshold ) {
171182 return
172183 }
173- this . _userWrittenNewCodeCharacterCount += contentChange . text . length
174- this . _userWrittenNewCodeLineCount += this . countNewLines ( contentChange . text )
175- // start 5 min data reporting once valid user input is detected
176- this . tryStartTimer ( )
184+ const language = runtimeLanguageContext . normalizeLanguage ( e . document . languageId )
185+ if ( language ) {
186+ const charCount = this . _userWrittenNewCodeCharacterCount . get ( language ) || 0
187+ this . _userWrittenNewCodeCharacterCount . set ( language , charCount + contentChange . text . length )
188+ const lineCount = this . _userWrittenNewCodeLineCount . get ( language ) || 0
189+ this . _userWrittenNewCodeLineCount . set ( language , lineCount + this . countNewLines ( contentChange . text ) )
190+ // start 5 min data reporting once valid user input is detected
191+ this . tryStartTimer ( )
192+ }
177193 }
178194}
0 commit comments