@@ -10,21 +10,31 @@ import com.intellij.internal.statistic.eventLog.FeatureUsageData
10
10
import com.intellij.internal.statistic.eventLog.StatisticsEventLogProviderUtil.getEventLogProvider
11
11
import com.intellij.internal.statistic.eventLog.StatisticsEventLogger
12
12
import com.intellij.internal.statistic.eventLog.fus.FeatureUsageLogger.logState
13
+ import com.intellij.internal.statistic.eventLog.fus.FeatureUsageStateEventTracker
13
14
import com.intellij.internal.statistic.service.fus.collectors.FUStateUsagesLogger.Companion.LOG
15
+ import com.intellij.internal.statistic.updater.StatisticsStateCollectorsScheduler
16
+ import com.intellij.internal.statistic.utils.StatisticsUploadAssistant
14
17
import com.intellij.internal.statistic.utils.getPluginInfo
15
18
import com.intellij.openapi.application.ApplicationManager
16
19
import com.intellij.openapi.components.Service
17
20
import com.intellij.openapi.components.service
18
21
import com.intellij.openapi.diagnostic.Logger
19
22
import com.intellij.openapi.progress.blockingContext
20
23
import com.intellij.openapi.project.Project
24
+ import com.intellij.openapi.project.waitForSmartMode
21
25
import kotlinx.coroutines.*
22
- import kotlinx.coroutines.flow.MutableSharedFlow
23
- import kotlinx.coroutines.flow.collectLatest
24
- import kotlinx.coroutines.flow.filterNotNull
25
26
import kotlinx.coroutines.future.asDeferred
26
27
import org.jetbrains.annotations.ApiStatus.Internal
28
+ import org.jetbrains.annotations.ApiStatus.ScheduledForRemoval
27
29
import org.jetbrains.concurrency.asDeferred
30
+ import kotlin.time.Duration.Companion.hours
31
+ import kotlin.time.Duration.Companion.minutes
32
+
33
+ private val LOG_APPLICATION_STATES_INITIAL_DELAY = 10 .minutes
34
+ private val LOG_APPLICATION_STATES_DELAY = 24 .hours
35
+ private val LOG_PROJECTS_STATES_INITIAL_DELAY = 5 .minutes
36
+ private val LOG_PROJECTS_STATES_DELAY = 12 .hours
37
+ private const val REDUCE_DELAY_FLAG_KEY = " fus.internal.reduce.initial.delay"
28
38
29
39
/* *
30
40
* Called by a scheduler once a day and records IDE/project state. <br></br>
@@ -37,15 +47,14 @@ import org.jetbrains.concurrency.asDeferred
37
47
*/
38
48
@Service(Service .Level .APP )
39
49
@Internal
40
- class FUStateUsagesLogger private constructor(cs : CoroutineScope ) : UsagesCollectorConsumer {
41
- // https://github.com/Kotlin/kotlinx.coroutines/issues/2603#issuecomment-808859170
42
- private val logAppStateRequests = MutableSharedFlow <Boolean ?>()
50
+ class FUStateUsagesLogger private constructor(private val cs : CoroutineScope ) : UsagesCollectorConsumer {
43
51
44
52
init {
45
53
cs.launch {
46
- logAppStateRequests
47
- .filterNotNull()
48
- .collectLatest(::logApplicationStates)
54
+ if (! StatisticsUploadAssistant .isSendAllowed()) {
55
+ return @launch
56
+ }
57
+ logApplicationStateRegularly()
49
58
}
50
59
}
51
60
@@ -141,18 +150,22 @@ class FUStateUsagesLogger private constructor(cs: CoroutineScope) : UsagesCollec
141
150
}
142
151
}
143
152
144
- suspend fun logProjectStates (project : Project ) {
145
- project.service<ProjectFUStateUsagesLogger >().logProjectStates()
153
+ private suspend fun logApplicationStateRegularly () {
154
+ StatisticsStateCollectorsScheduler .allowExecution.set(true )
155
+ delay(LOG_APPLICATION_STATES_INITIAL_DELAY )
156
+ StatisticsStateCollectorsScheduler .allowExecution.set(false )
157
+ while (true ) {
158
+ logApplicationStates(onStartup = false )
159
+ delay(LOG_APPLICATION_STATES_DELAY )
160
+ }
146
161
}
147
162
148
- suspend fun logApplicationStates () {
149
- logAppStateRequests.emit(false )
150
- logAppStateRequests.emit(null )
163
+ fun scheduleLogApplicationStatesOnStartup (): Job = cs.launch {
164
+ logApplicationStates(onStartup = true )
151
165
}
152
166
153
- suspend fun logApplicationStatesOnStartup () {
154
- logAppStateRequests.emit(true )
155
- logAppStateRequests.emit(null )
167
+ fun scheduleLogApplicationState (): Job = cs.launch {
168
+ logApplicationStates(onStartup = false )
156
169
}
157
170
158
171
private suspend fun logApplicationStates (onStartup : Boolean ) {
@@ -179,47 +192,91 @@ class FUStateUsagesLogger private constructor(cs: CoroutineScope) : UsagesCollec
179
192
}
180
193
}
181
194
}
195
+
196
+ @ScheduledForRemoval
197
+ @Deprecated(
198
+ message = " Use ProjectFUStateUsagesLogger.scheduleLogProjectState" ,
199
+ ReplaceWith (
200
+ " project.service<ProjectFUStateUsagesLogger>().scheduleLogProjectState().join()" ,
201
+ " com.intellij.openapi.components.service"
202
+ ),
203
+ )
204
+ suspend fun logProjectStates (project : Project ) {
205
+ project.service<ProjectFUStateUsagesLogger >().scheduleLogProjectState().join()
206
+ }
207
+
208
+ @ScheduledForRemoval
209
+ @Deprecated(
210
+ message = " Use FUStateUsagesLogger.scheduleLogProjectState" ,
211
+ replaceWith = ReplaceWith (
212
+ " scheduleLogApplicationState().join()"
213
+ ),
214
+ )
215
+ suspend fun logApplicationStates () {
216
+ scheduleLogApplicationState().join()
217
+ }
182
218
}
183
219
220
+ @Internal
184
221
@Service(Service .Level .PROJECT )
185
- private class ProjectFUStateUsagesLogger (
222
+ class ProjectFUStateUsagesLogger (
186
223
private val project : Project ,
187
- cs : CoroutineScope ,
224
+ private val cs : CoroutineScope ,
188
225
) : UsagesCollectorConsumer {
189
- // https://github.com/Kotlin/kotlinx.coroutines/issues/2603#issuecomment-808859170
190
- private val logProjectStateRequests = MutableSharedFlow <Unit ?>()
191
226
192
227
init {
193
228
cs.launch {
194
- logProjectStateRequests
195
- .filterNotNull()
196
- .collectLatest {
197
- coroutineScope {
198
- val recorderLoggers = HashMap <String , StatisticsEventLogger >()
199
- for (usagesCollector in ProjectUsagesCollector .getExtensions(this @ProjectFUStateUsagesLogger)) {
200
- if (! getPluginInfo(usagesCollector.javaClass).isDevelopedByJetBrains()) {
201
- @Suppress(" removal" , " DEPRECATION" )
202
- LOG .warn(" Skip '${usagesCollector.groupId} ' because its registered in a third-party plugin" )
203
- continue
204
- }
205
-
206
- launch {
207
- val metrics = blockingContext { usagesCollector.getMetrics(project, null ) }
208
- FUStateUsagesLogger .logMetricsOrError(
209
- project = project,
210
- recorderLoggers = recorderLoggers,
211
- usagesCollector = usagesCollector,
212
- metrics = metrics.asDeferred().await() ? : emptySet(),
213
- )
214
- }
215
- }
216
- }
217
- }
229
+ project.waitForSmartMode()
230
+ logProjectStateRegularly()
231
+ }
232
+ }
233
+
234
+ private suspend fun logProjectStateRegularly () {
235
+ val reduceInitialDelay = System .getProperty(REDUCE_DELAY_FLAG_KEY ).toBoolean()
236
+ if (! reduceInitialDelay) {
237
+ delay(LOG_PROJECTS_STATES_INITIAL_DELAY )
238
+ }
239
+ while (true ) {
240
+ logProjectState()
241
+ delay(LOG_PROJECTS_STATES_DELAY )
242
+ }
243
+ }
244
+
245
+ fun scheduleLogProjectState (): Job = cs.launch {
246
+ logProjectState()
247
+ }
248
+
249
+ private suspend fun logProjectState (): Unit = coroutineScope {
250
+ val recorderLoggers = HashMap <String , StatisticsEventLogger >()
251
+ for (usagesCollector in ProjectUsagesCollector .getExtensions(this @ProjectFUStateUsagesLogger)) {
252
+ if (! getPluginInfo(usagesCollector.javaClass).isDevelopedByJetBrains()) {
253
+ @Suppress(" removal" , " DEPRECATION" )
254
+ LOG .warn(" Skip '${usagesCollector.groupId} ' because its registered in a third-party plugin" )
255
+ continue
256
+ }
257
+
258
+ launch {
259
+ val metrics = blockingContext { usagesCollector.getMetrics(project, null ) }
260
+ FUStateUsagesLogger .logMetricsOrError(
261
+ project = project,
262
+ recorderLoggers = recorderLoggers,
263
+ usagesCollector = usagesCollector,
264
+ metrics = metrics.asDeferred().await() ? : emptySet(),
265
+ )
266
+ }
218
267
}
219
268
}
220
269
221
- suspend fun logProjectStates () {
222
- logProjectStateRequests.emit(Unit )
223
- logProjectStateRequests.emit(null )
270
+ fun scheduleLogApplicationAndProjectState (): Deferred <Unit > = cs.async {
271
+ launch {
272
+ FUStateUsagesLogger .getInstance().scheduleLogApplicationState().join()
273
+ logProjectState()
274
+ }
275
+
276
+ for (extension in FeatureUsageStateEventTracker .EP_NAME .extensions) {
277
+ launch {
278
+ extension.reportNow()
279
+ }
280
+ }
224
281
}
225
282
}
0 commit comments