diff --git a/plugins/gradle/plugin-resources/META-INF/plugin.xml b/plugins/gradle/plugin-resources/META-INF/plugin.xml
index b0eb08ca6b1a..123509b3c688 100644
--- a/plugins/gradle/plugin-resources/META-INF/plugin.xml
+++ b/plugins/gradle/plugin-resources/META-INF/plugin.xml
@@ -173,6 +173,7 @@
+
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/modelAction/GradleModelFetchActionRunner.kt b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/modelAction/GradleModelFetchActionRunner.kt
index 47ca5d421cc4..3bee1260c4f5 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/modelAction/GradleModelFetchActionRunner.kt
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/modelAction/GradleModelFetchActionRunner.kt
@@ -2,6 +2,7 @@
package org.jetbrains.plugins.gradle.service.modelAction
import com.intellij.gradle.toolingExtension.impl.modelAction.GradleModelFetchAction
+import com.intellij.gradle.toolingExtension.modelAction.GradleModelFetchPhase
import com.intellij.gradle.toolingExtension.util.GradleVersionUtil
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.registry.Registry
@@ -15,7 +16,7 @@ import org.jetbrains.plugins.gradle.service.execution.GradleExecutionHelper
import org.jetbrains.plugins.gradle.service.project.DefaultProjectResolverContext
import org.jetbrains.plugins.gradle.service.project.GradleOperationHelperExtension
import org.jetbrains.plugins.gradle.settings.GradleExecutionSettings
-
+import org.jetbrains.plugins.gradle.statistics.GradleSyncCollector
/**
* This class handles setting up and running the [BuildActionExecuter] it deals with calling the correct APIs based on the version of
* Gradle that is present.
@@ -32,7 +33,7 @@ class GradleModelFetchActionRunner private constructor(
private val resolverContext: DefaultProjectResolverContext,
private val settings: GradleExecutionSettings,
private val modelFetchAction: GradleModelFetchAction,
- private val modelFetchActionListener: GradleModelFetchActionListener
+ private val modelFetchActionListener: GradleModelFetchActionListener,
) {
/**
@@ -114,14 +115,36 @@ class GradleModelFetchActionRunner private constructor(
companion object {
- @JvmStatic
- fun runBuildAction(
+ private fun runBuildAction(
resolverContext: DefaultProjectResolverContext,
settings: GradleExecutionSettings,
modelFetchAction: GradleModelFetchAction,
- modelFetchActionListener: GradleModelFetchActionListener
+ modelFetchActionListener: GradleModelFetchActionListener,
) {
GradleModelFetchActionRunner(resolverContext, settings, modelFetchAction, modelFetchActionListener).runBuildAction()
}
+
+ @JvmStatic
+ fun runAndTraceBuildAction(
+ resolverContext: DefaultProjectResolverContext,
+ settings: GradleExecutionSettings,
+ modelFetchAction: GradleModelFetchAction,
+ modelFetchActionListener: GradleModelFetchActionListener,
+ ) {
+ GradleSyncCollector.ModelFetchCollector(resolverContext).use { collector ->
+ val modelFetchActionListenerWithTrace = object : GradleModelFetchActionListener by modelFetchActionListener {
+ override suspend fun onModelFetchPhaseCompleted(phase: GradleModelFetchPhase) {
+ modelFetchActionListener.onModelFetchPhaseCompleted(phase)
+ collector.logModelFetchPhaseCompleted(phase)
+ }
+
+ override suspend fun onModelFetchFailed(exception: Throwable) {
+ modelFetchActionListener.onModelFetchFailed(exception)
+ collector.logModelFetchFailure(exception)
+ }
+ }
+ runBuildAction(resolverContext, settings, modelFetchAction, modelFetchActionListenerWithTrace)
+ }
+ }
}
}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/DefaultProjectResolverContext.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/DefaultProjectResolverContext.java
index 9e9593fbe337..50f4aa970a1c 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/DefaultProjectResolverContext.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/DefaultProjectResolverContext.java
@@ -318,7 +318,6 @@ public class DefaultProjectResolverContext extends UserDataHolderBase implements
return myProjectGradleVersion;
}
- @Override
public boolean isBuildSrcProject() {
return myBuildSrcProject;
}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java
index 11126037f3fe..98a432ef850c 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java
@@ -335,7 +335,7 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver GradleVersion.version(it));
if (gradleVersion != null && GradleJvmSupportMatrix.isGradleDeprecatedByIdea(gradleVersion)) {
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java
index 462dd7a247b3..281fba3c0e7d 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java
@@ -101,8 +101,6 @@ public interface ProjectResolverContext extends UserDataHolderEx {
@Nullable
String getProjectGradleVersion();
- boolean isBuildSrcProject();
-
@Nullable
String getBuildSrcGroup();
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/statistics/GradleSyncCollector.kt b/plugins/gradle/src/org/jetbrains/plugins/gradle/statistics/GradleSyncCollector.kt
new file mode 100644
index 000000000000..5fdab4d6348d
--- /dev/null
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/statistics/GradleSyncCollector.kt
@@ -0,0 +1,116 @@
+// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package org.jetbrains.plugins.gradle.statistics
+
+import com.intellij.gradle.toolingExtension.modelAction.GradleModelFetchPhase
+import com.intellij.gradle.toolingExtension.modelAction.GradleModelFetchPhase.*
+import com.intellij.internal.statistic.eventLog.EventLogGroup
+import com.intellij.internal.statistic.eventLog.events.EventFields
+import com.intellij.internal.statistic.eventLog.events.LongEventField
+import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector
+import org.jetbrains.annotations.ApiStatus
+import org.jetbrains.plugins.gradle.service.project.DefaultProjectResolverContext
+import java.util.*
+
+
+@ApiStatus.Internal
+internal object GradleSyncCollector : CounterUsagesCollector() {
+
+ override fun getGroup(): EventLogGroup = GROUP
+
+ private val GROUP = EventLogGroup("gradle.sync", 1)
+
+ private val ACTIVITY_ID = EventFields.Long("ide_activity_id")
+
+ private val MODEL_FETCH_FOR_BUILD_SRC = EventFields.Boolean("model_fetch_for_build_src")
+ private val MODEL_FETCH_ERROR_COUNT = EventFields.Int("model_fetch_error_count")
+ private val MODEL_FETCH_COMPLETION_STAMP = EventFields.Long("model_fetch_completion_stamp")
+
+ private val PROJECT_LOADED_PHASE_COMPLETION_STAMP = EventFields.Long("project_loaded_phase_completion_stamp")
+ private val WARM_UP_PHASE_COMPLETION_STAMP = EventFields.Long("warm_up_phase_completion_stamp")
+ private val PROJECT_MODEL_PHASE_COMPLETION_STAMP = EventFields.Long("project_model_phase_completion_stamp")
+ private val PROJECT_SOURCE_SET_PHASE_COMPLETION_STAMP = EventFields.Long("project_source_set_phase_completion_stamp")
+ private val PROJECT_SOURCE_SET_DEPENDENCY_PHASE_COMPLETION_STAMP = EventFields.Long("project_source_set_dependency_phase_completion_stamp")
+ private val ADDITIONAL_MODEL_PHASE_COMPLETION_STAMP = EventFields.Long("additional_model_phase_completion_stamp")
+
+ private val MODEL_FETCH_COMPLETED_EVENT = GROUP.registerVarargEvent(
+ "gradle.sync.model.fetch.completed",
+
+ ACTIVITY_ID,
+ MODEL_FETCH_FOR_BUILD_SRC,
+ MODEL_FETCH_ERROR_COUNT,
+ MODEL_FETCH_COMPLETION_STAMP,
+
+ PROJECT_LOADED_PHASE_COMPLETION_STAMP,
+ WARM_UP_PHASE_COMPLETION_STAMP,
+ PROJECT_MODEL_PHASE_COMPLETION_STAMP,
+ PROJECT_SOURCE_SET_PHASE_COMPLETION_STAMP,
+ PROJECT_SOURCE_SET_DEPENDENCY_PHASE_COMPLETION_STAMP,
+ ADDITIONAL_MODEL_PHASE_COMPLETION_STAMP
+ )
+
+ class ModelFetchCollector(
+ private val context: DefaultProjectResolverContext,
+ ) : AutoCloseable {
+
+ private val modelFetchStartStamp: GlobalStamp = GlobalStamp.now()
+
+ private val phaseCompletionStamps: MutableMap = EnumMap(GradleModelFetchPhase::class.java)
+
+ private val exceptions = ArrayList()
+
+ fun logModelFetchPhaseCompleted(phase: GradleModelFetchPhase) {
+ val currentStamp = GlobalStamp.now()
+ val phaseCompletionStamp = currentStamp - modelFetchStartStamp
+ phaseCompletionStamps[phase] = phaseCompletionStamp
+ }
+
+ fun logModelFetchFailure(exception: Throwable) {
+ exceptions.add(exception)
+ }
+
+ override fun close() {
+ val currentStamp = GlobalStamp.now()
+ val project = context.externalSystemTaskId.findProject()
+ MODEL_FETCH_COMPLETED_EVENT.log(project) {
+ add(ACTIVITY_ID with context.externalSystemTaskId.id)
+ add(MODEL_FETCH_FOR_BUILD_SRC with context.isBuildSrcProject)
+ add(MODEL_FETCH_ERROR_COUNT with exceptions.size)
+ val modelFetchStamp = currentStamp - modelFetchStartStamp
+ add(MODEL_FETCH_COMPLETION_STAMP with modelFetchStamp.time)
+ for (phase in entries) {
+ val field = phase.getModelFetchPhaseStampEventField()
+ val stamp = phaseCompletionStamps[phase] ?: continue
+ add(field with stamp.time)
+ }
+ }
+ }
+
+ private fun GradleModelFetchPhase.getModelFetchPhaseStampEventField(): LongEventField {
+ return when (this) {
+ PROJECT_LOADED_PHASE -> PROJECT_LOADED_PHASE_COMPLETION_STAMP
+ WARM_UP_PHASE -> WARM_UP_PHASE_COMPLETION_STAMP
+ PROJECT_MODEL_PHASE -> PROJECT_MODEL_PHASE_COMPLETION_STAMP
+ PROJECT_SOURCE_SET_PHASE -> PROJECT_SOURCE_SET_PHASE_COMPLETION_STAMP
+ PROJECT_SOURCE_SET_DEPENDENCY_PHASE -> PROJECT_SOURCE_SET_DEPENDENCY_PHASE_COMPLETION_STAMP
+ ADDITIONAL_MODEL_PHASE -> ADDITIONAL_MODEL_PHASE_COMPLETION_STAMP
+ }
+ }
+ }
+
+ @JvmInline
+ private value class GlobalStamp(val time: Long) {
+
+ operator fun minus(stamp: GlobalStamp): LocalStamp {
+ return LocalStamp(time - stamp.time)
+ }
+
+ companion object {
+ fun now(): GlobalStamp {
+ return GlobalStamp(System.currentTimeMillis())
+ }
+ }
+ }
+
+ @JvmInline
+ private value class LocalStamp(val time: Long)
+}
\ No newline at end of file