1- import axios from 'axios '
2- import { v4 as uuid } from 'uuid '
1+ import { randomUUID } from 'crypto '
2+ import * as amplitude from '@amplitude/analytics-node '
33import { version } from '../../package.json'
44import { Config } from './Config'
55import { Log } from '~/utils'
@@ -8,10 +8,17 @@ import { Global } from '~/extension'
88import { LocaleTreeItem , ProgressSubmenuItem } from '~/views'
99import { CommandOptions } from '~/commands/manipulations/common'
1010
11- const HEAP_ID_DEV = '1082064308'
12- const HEAP_ID_PROD = '4118173713'
11+ const AMPLITUDE_API = isProd
12+ ? '710028b04f0f9274085eec6885e94ceb' // Prod
13+ : '63d2a7eb46b66d43e0d20b0ba2834cc3' // Dev
1314
14- const HEAP_ID = isProd ? HEAP_ID_PROD : HEAP_ID_DEV
15+ const AMPLITUDE_SERVER_ZONE = 'EU'
16+
17+ const AMPLITUDE_FLUSH_QUEUE_SIZE = 100
18+
19+ const AMPLITUDE_FLUSH_INTERVAL_MILLIS = isProd
20+ ? 5 * 60 * 1000 // 5 minutes
21+ : 10 * 1000 // 10 seconds
1522
1623export enum TelemetryKey {
1724 Activated = 'activated' ,
@@ -46,96 +53,28 @@ export enum ActionSource {
4653 Review = 'review'
4754}
4855
49- export interface TelemetryEvent {
50- event : TelemetryKey
51- timestamp : number
52- identity : string
53- properties ?: Record < string , any >
54- }
55-
5656export class Telemetry {
57- private static _id : string
58- private static _timer : any = null
59-
60- static events : TelemetryEvent [ ] = [ ]
61-
62- static get userId ( ) {
63- if ( this . _id )
64- return this . _id
65- this . _id = Config . ctx . globalState . get ( 'i18n-ally.telemetry-user-id' ) !
66- if ( ! this . _id ) {
67- this . _id = uuid ( )
68- Config . ctx . globalState . update ( 'i18n-ally.telemetry-user-id' , this . _id )
69- }
70- Log . info ( `📈 Telemetry id: ${ this . _id } ` )
71-
72- return this . _id
73- }
74-
75- static checkVersionChange ( ) {
76- const previousVersion = Config . ctx . globalState . get ( 'i18n-ally.previous-version' )
77-
78- if ( ! previousVersion )
79- Telemetry . track ( TelemetryKey . Installed , { new_version : version } )
80- else if ( previousVersion !== version )
81- Telemetry . track ( TelemetryKey . Updated , { new_version : version , previous_version : previousVersion } )
82-
83- Config . ctx . globalState . update ( 'i18n-ally.previous-version' , version )
84- }
85-
86- static get isEnabled ( ) {
87- return Config . telemetry && ! isTest
88- }
57+ private static _userProperties : object
58+ private static _amplitude : amplitude . Types . NodeClient
8959
9060 static async track ( key : TelemetryKey , properties ?: Record < string , any > , immediate = false ) {
91- if ( ! this . isEnabled )
61+ const isEnabled = Config . telemetry && ! isTest
62+ if ( ! isEnabled )
9263 return
9364
94- const event : TelemetryEvent = {
95- event : key ,
96- identity : this . userId ,
97- timestamp : + new Date ( ) ,
98- properties,
99- }
65+ try {
66+ this . _initializeAmplitude ( )
10067
101- if ( isDev )
102- Log . info ( `[telemetry] ${ key } : ${ JSON . stringify ( properties ) } ` )
103-
104- if ( immediate ) {
105- try {
106- await axios ( {
107- url : 'https://heapanalytics.com/api/track' ,
108- method : 'POST' ,
109- headers : {
110- 'Content-Type' : 'application/json' ,
111- } ,
112- data : {
113- app_id : HEAP_ID ,
114- ...event ,
115- } ,
116- } )
117- }
118- catch ( e ) {
119- Log . error ( e , false )
120- }
121- }
122- else {
123- this . events . push ( event )
124- this . schedule ( )
125- }
126- }
68+ this . _amplitude . track ( key , properties , this . _getUserProperties ( ) )
69+
70+ if ( immediate )
71+ this . _amplitude . flush ( )
12772
128- static schedule ( ) {
129- if ( this . events . length >= 100 ) {
130- this . sendBulk ( )
73+ if ( isDev )
74+ Log . info ( `[telemetry] ${ key } : ${ JSON . stringify ( properties ) } ` )
13175 }
132- else if ( ! this . _timer && this . events . length ) {
133- this . _timer = setInterval (
134- ( ) => this . sendBulk ( ) ,
135- isDev
136- ? 10 * 1000 // 10 seconds
137- : 5 * 60 * 1000 , // 5 minutes
138- )
76+ catch ( e ) {
77+ Log . error ( e , false )
13978 }
14079 }
14180
@@ -145,73 +84,53 @@ export class Telemetry {
14584 : item ?. actionSource || ActionSource . CommandPattele
14685 }
14786
148- static async updateUserProperties ( ) {
149- if ( ! this . isEnabled )
87+ private static _initializeAmplitude ( ) {
88+ if ( this . _amplitude )
15089 return
15190
152- const data = {
153- version,
154- feature_auto_detection : ! ! Config . autoDetection ,
155- feature_annotation_in_place : ! ! Config . annotationInPlace ,
156- feature_annotations : ! ! Config . annotations ,
157- feature_disable_path_parsing : ! ! Config . disablePathParsing ,
158- feature_extract_auto_detect : ! ! Config . extractAutoDetect ,
159- feature_keep_fulfilled : ! ! Config . keepFulfilled ,
160- feature_prefer_editor : ! ! Config . preferEditor ,
161- feature_review_enabled : ! ! Config . reviewEnabled ,
162- feature_has_path_matcher : ! ! Config . _pathMatcher ,
163- feature_has_custom_framework : ! ! Global . enabledFrameworks . find ( i => i . id === 'custom' ) ,
164- }
91+ this . _amplitude = amplitude . createInstance ( )
16592
166- if ( isDev )
167- Log . info ( `[telemetry] user: ${ JSON . stringify ( data ) } ` )
93+ this . _amplitude . init ( AMPLITUDE_API , {
94+ optOut : ! Config . telemetry || isTest ,
95+ serverZone : AMPLITUDE_SERVER_ZONE ,
96+ flushQueueSize : AMPLITUDE_FLUSH_QUEUE_SIZE ,
97+ flushIntervalMillis : AMPLITUDE_FLUSH_INTERVAL_MILLIS ,
98+ } )
16899
169- try {
170- await axios ( {
171- url : 'https://heapanalytics.com/api/add_user_properties' ,
172- method : 'POST' ,
173- headers : {
174- 'Content-Type' : 'application/json' ,
175- } ,
176- data : {
177- app_id : HEAP_ID ,
178- identity : this . userId ,
179- properties : data ,
180- } ,
181- } )
182- }
183- catch ( e ) {
184- Log . error ( e , false )
185- }
100+ this . _amplitude . identify ( new amplitude . Identify ( ) , this . _getUserProperties ( ) )
186101 }
187102
188- static async sendBulk ( ) {
189- if ( ! this . events . length ) {
190- clearInterval ( this . _timer )
191- this . _timer = null
192- return
103+ private static _getUserId ( ) {
104+ let userId = Config . ctx . globalState . get ( 'i18n-ally.telemetry-user-id' ) ?? ''
105+ if ( ! userId ) {
106+ userId = randomUUID ( )
107+ Config . ctx . globalState . update ( 'i18n-ally.telemetry-user-id' , userId )
193108 }
109+ Log . info ( `📈 Telemetry id: ${ userId } ` )
110+ return userId
111+ }
194112
195- if ( isDev )
196- Log . info ( '[telemetry] sending bulk' )
197-
198- const events = Array . from ( this . events )
199- this . events . length = 0
200- try {
201- await axios ( {
202- url : 'https://heapanalytics.com/api/track' ,
203- method : 'POST' ,
204- headers : {
205- 'Content-Type' : 'application/json' ,
206- } ,
207- data : {
208- app_id : HEAP_ID ,
209- events,
113+ private static _getUserProperties ( ) {
114+ if ( ! this . _userProperties ) {
115+ this . _userProperties = {
116+ user_id : this . _getUserId ( ) ,
117+ app_version : version ,
118+ user_properties : {
119+ feature_auto_detection : ! ! Config . autoDetection ,
120+ feature_annotation_in_place : ! ! Config . annotationInPlace ,
121+ feature_annotations : ! ! Config . annotations ,
122+ feature_disable_path_parsing : ! ! Config . disablePathParsing ,
123+ feature_extract_auto_detect : ! ! Config . extractAutoDetect ,
124+ feature_keep_fulfilled : ! ! Config . keepFulfilled ,
125+ feature_prefer_editor : ! ! Config . preferEditor ,
126+ feature_review_enabled : ! ! Config . reviewEnabled ,
127+ feature_has_path_matcher : ! ! Config . _pathMatcher ,
128+ feature_has_custom_framework : ! ! Global . enabledFrameworks . find ( i => i . id === 'custom' ) ,
129+ feature_frameworks : Global . enabledFrameworks . map ( i => i . display ) ,
210130 } ,
211- } )
212- }
213- catch ( e ) {
214- Log . error ( e , false )
131+ }
215132 }
133+
134+ return this . _userProperties
216135 }
217136}
0 commit comments