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