Do not collect FUS statistics when `BuildUidService` was not found #KT-79576
diff --git a/libraries/tools/gradle/fus-statistics-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/fus/internal/BuildFinishFlowAction.kt b/libraries/tools/gradle/fus-statistics-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/fus/internal/BuildFinishFlowAction.kt index 2b6a44c..110e1ea 100644 --- a/libraries/tools/gradle/fus-statistics-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/fus/internal/BuildFinishFlowAction.kt +++ b/libraries/tools/gradle/fus-statistics-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/fus/internal/BuildFinishFlowAction.kt
@@ -33,6 +33,7 @@ ) { it.parameters.configurationTimeMetrics.addAll(fusService.get().getConfigurationReportedMetrics()) it.parameters.buildId.set(buildUid) + it.parameters.buildId.finalizeValue() } } }
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/FusPluginIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/FusPluginIT.kt index 5f8d2d3..00a4efd 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/FusPluginIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/FusPluginIT.kt
@@ -50,7 +50,7 @@ @DisplayName("with configuration cache and project isolation") @GradleTestVersions( - additionalVersions = [TestVersions.Gradle.G_8_0, TestVersions.Gradle.G_8_1], + minVersion = TestVersions.Gradle.G_8_14 ) @GradleTest fun withConfigurationCacheAndProjectIsolation(gradleVersion: GradleVersion) {
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/FusStatisticsIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/FusStatisticsIT.kt index 9d1bdc7..145f539 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/FusStatisticsIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/FusStatisticsIT.kt
@@ -249,15 +249,15 @@ @DisplayName("for project with buildSrc") @GradleTest @GradleTestVersions( - additionalVersions = [TestVersions.Gradle.G_8_0, TestVersions.Gradle.G_8_2] + minVersion = TestVersions.Gradle.G_8_14 ) fun testProjectWithBuildSrcForGradleVersion7(gradleVersion: GradleVersion) { - //KT-64022 there are a different build instances in buildSrc and rest project: + //KT-64022 there are different build instances in buildSrc and rest project: project( "instantExecutionWithBuildSrc", gradleVersion, ) { - build("compileKotlin", "-Pkotlin.session.logger.root.path=$projectPath") { + build("compileKotlin", "-Pkotlin.session.logger.root.path=$projectPath", buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)) { assertFilesCombinedContains( projectPath.resolve("kotlin-profile").listDirectoryEntries(), *expectedMetrics,
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt index d3921d3..8a3ff3b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt
@@ -78,7 +78,8 @@ BuildFinishedListenerService.registerIfAbsent(project) val buildUidService = BuildUidService.registerIfAbsent(project.gradle) - BuildFusService.registerIfAbsent(project, pluginVersion, buildUidService) + val buildFinishBuildService = BuildFinishBuildService.registerIfAbsent(project, buildUidService, pluginVersion) + BuildFusService.registerIfAbsent(project, pluginVersion, buildUidService, buildFinishBuildService) PropertiesBuildService.registerIfAbsent(project) project.gradle.projectsEvaluated { @@ -99,7 +100,7 @@ BuildMetricsService.registerIfAbsent(project) KotlinNativeBundleBuildService.registerIfAbsent(project) - BuildFinishBuildService.registerIfAbsent(project, buildUidService, pluginVersion) + } private fun addKotlinCompilerConfiguration(project: Project) {
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/StatisticsBuildFlowManager.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/StatisticsBuildFlowManager.kt index 50559fa..5e13073 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/StatisticsBuildFlowManager.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/StatisticsBuildFlowManager.kt
@@ -14,6 +14,7 @@ import org.gradle.api.tasks.Input import org.jetbrains.kotlin.gradle.fus.BuildUidService import org.jetbrains.kotlin.gradle.internal.report.BuildScanApi +import org.jetbrains.kotlin.gradle.plugin.statistics.BuildFinishBuildService import org.jetbrains.kotlin.gradle.plugin.statistics.FlowActionBuildFusService import org.jetbrains.kotlin.gradle.plugin.statistics.ConfigurationMetricParameterFlowActionBuildFusService import org.jetbrains.kotlin.gradle.plugin.statistics.MetricContainer @@ -29,20 +30,27 @@ project.objects.newInstance(StatisticsBuildFlowManager::class.java) } - fun subscribeForBuildResultAndConfigurationTimeMetrics(buildFusServiceProvider: Provider<FlowActionBuildFusService>) { + fun subscribeForBuildResultAndConfigurationTimeMetrics( + buildFusServiceProvider: Provider<FlowActionBuildFusService>, + buildUidServiceProvider: Provider<BuildUidService>, + buildFinishBuildService: Provider<BuildFinishBuildService>? + ) { flowScope.always( BuildFinishAndConfigurationTimeMetricsFlowAction::class.java ) { spec -> spec.parameters.buildFailed.set(flowProviders.buildWorkResult.map { it.failure.isPresent }) spec.parameters.configurationTimeMetrics.addAll(buildFusServiceProvider.get().getConfigurationTimeMetrics()) + spec.parameters.buildUidProperty.set(buildUidServiceProvider.map { it.buildId }) + buildFinishBuildService?.get() } } - fun subscribeForBuildResult() { + fun subscribeForBuildResult(buildUidServiceProvider: Provider<BuildUidService>) { flowScope.always( BuildFinishFlowAction::class.java ) { spec -> spec.parameters.buildFailed.set(flowProviders.buildWorkResult.map { it.failure.isPresent }) + spec.parameters.buildUidProperty.set(buildUidServiceProvider.map { it.buildId }) } } @@ -74,17 +82,18 @@ @get:ServiceReference val buildFusServiceProperty: Property<ConfigurationMetricParameterFlowActionBuildFusService> - @get:ServiceReference - val buildUidServiceProperty: Property<BuildUidService?> + @get:Input + val buildUidProperty: Property<String> @get:Input val buildFailed: Property<Boolean> } override fun execute(parameters: Parameters) { +// val buildId = parameters.buildUidProperty.orNull ?: return parameters.buildFusServiceProperty.orNull?.recordBuildFinished( parameters.buildFailed.get(), - parameters.buildUidServiceProperty.orNull?.buildId ?: "unknown_id", +// buildId, parameters.buildFusServiceProperty.orNull?.parameters?.configurationMetrics?.orNull ?: emptyList() ) } @@ -95,8 +104,8 @@ @get:ServiceReference val buildFusServiceProperty: Property<FlowActionBuildFusService> - @get:ServiceReference - val buildUidServiceProperty: Property<BuildUidService?> + @get:Input + val buildUidProperty: Property<String?> @get:Input val buildFailed: Property<Boolean> @@ -106,9 +115,10 @@ } override fun execute(parameters: Parameters) { +// val buildId = parameters.buildUidProperty.orNull ?: return parameters.buildFusServiceProperty.orNull?.recordBuildFinished( parameters.buildFailed.get(), - parameters.buildUidServiceProperty.orNull?.buildId ?: "unknown_id", +// buildId, parameters.configurationTimeMetrics.get() ) }
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFinishBuildService.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFinishBuildService.kt index 2b31fe1..717f60c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFinishBuildService.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFinishBuildService.kt
@@ -13,11 +13,15 @@ import org.gradle.api.provider.Provider import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters +import org.gradle.tooling.events.FinishEvent +import org.gradle.tooling.events.OperationCompletionListener import org.gradle.util.GradleVersion import org.jetbrains.kotlin.gradle.fus.BuildUidService import org.jetbrains.kotlin.gradle.logging.Errors import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger +import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.logging.reportToIde +import org.jetbrains.kotlin.gradle.plugin.BuildEventsListenerRegistryHolder import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider import org.jetbrains.kotlin.gradle.utils.kotlinErrorsDir import org.jetbrains.kotlin.statistics.fileloggers.MetricsContainer @@ -25,11 +29,15 @@ import java.util.concurrent.atomic.AtomicBoolean import kotlin.String -internal abstract class BuildFinishBuildService : BuildService<BuildFinishBuildService.Parameters>, AutoCloseable { +abstract class BuildFinishBuildService : BuildService<BuildFinishBuildService.Parameters>, AutoCloseable, OperationCompletionListener { protected val buildId = parameters.buildId.get() private val log = Logging.getLogger(this.javaClass) private val errorWasReported = AtomicBoolean(false) + init { + log.kotlinDebug("Initialize build service $serviceName: class \"${this.javaClass.simpleName}\", build \"$buildId\"") + } + interface Parameters : BuildServiceParameters { val buildId: Property<String> val fusReportDirectory: Property<File> @@ -41,19 +49,19 @@ private val serviceName = "${BuildFinishBuildService::class.java.canonicalName}_${BuildFinishBuildService::class.java.classLoader.hashCode()}" - fun registerIfAbsent(project: Project, buildUidService: Provider<BuildUidService>, kotlinPluginVersion: String) { + fun registerIfAbsent(project: Project, buildUidService: Provider<BuildUidService>, kotlinPluginVersion: String): Provider<BuildFinishBuildService>? { if (!project.buildServiceShouldBeCreated) { - return + return null } - if (project.gradle.sharedServices.registrations.findByName(serviceName) != null) { - return + project.gradle.sharedServices.registrations.findByName(serviceName)?.let { + @Suppress("UNCHECKED_CAST") + return (it.service as Provider<BuildFinishBuildService>) } val reportDir = project.getFusDirectoryFromPropertyService() - val useFlowAction = GradleVersion.current().baseVersion >= GradleVersion.version("8.1") - project.gradle.sharedServices.registerIfAbsent(serviceName, BuildFinishBuildService::class.java) { spec -> + val service = project.gradle.sharedServices.registerIfAbsent(serviceName, BuildFinishBuildService::class.java) { spec -> spec.parameters.buildId.value(buildUidService.map { it.buildId }).disallowChanges() spec.parameters.fusReportDirectory.value(reportDir).disallowChanges() spec.parameters.errorDirs.add(project.kotlinErrorsDir) @@ -62,11 +70,16 @@ } spec.parameters.errorDirs.disallowChanges() spec.parameters.kotlinVersion.value(kotlinPluginVersion).disallowChanges() - }.get() - - if (useFlowAction) { //otherwise CloseActionBuildFusService.close() will aggregate fus metrics into single file - BuildFinishFlowProviderManager.getInstance(project).subscribeForBuildResults() } + +// if (useFlowAction) { //otherwise, CloseActionBuildFusService.close() will aggregate fus metrics into a single file +// BuildFinishFlowProviderManager.getInstance(project).subscribeForBuildResults() +// } + + //ensure BuildFinishBuildService is created at the same time as BuildFusService + BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(service) + + return service } internal fun collectAllFusReportsIntoOne( @@ -107,8 +120,13 @@ } } + override fun onFinish(p0: FinishEvent?) { + //Do nothing + } + override fun close() { - log.debug("Build service $serviceName closed for build $buildId") + log.kotlinDebug("Close build service $serviceName: class \"${this.javaClass.simpleName}\", build \"$buildId\"") + collectAllFusReportsIntoOne() } private fun File.errorFile() = resolve("errors-$buildId-${System.currentTimeMillis()}.log")
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFusService.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFusService.kt index cc726e1..ca7662a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFusService.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFusService.kt
@@ -52,7 +52,7 @@ protected val buildId = parameters.buildId.get() init { - log.kotlinDebug("Initialize ${this.javaClass.simpleName}") + log.kotlinDebug("Initialize build service $serviceName: class \"${this.javaClass.simpleName}\", build \"$buildId\"") KotlinBuildStatsBeanService.recordBuildStart(buildId) } @@ -95,9 +95,9 @@ } - fun registerIfAbsent(project: Project, pluginVersion: String, buildUidService: Provider<BuildUidService>) = + fun registerIfAbsent(project: Project, pluginVersion: String, buildUidService: Provider<BuildUidService>, buildFinishBuildService: Provider<BuildFinishBuildService>?) = if (project.buildServiceShouldBeCreated) { - registerIfAbsentImpl(project, pluginVersion, buildUidService).also { serviceProvider -> + registerIfAbsentImpl(project, pluginVersion, buildUidService, buildFinishBuildService).also { serviceProvider -> SingleActionPerProject.run(project, UsesBuildFusService::class.java.name) { project.tasks.withType<UsesBuildFusService>().configureEach { task -> task.buildFusService.value(serviceProvider).disallowChanges() @@ -120,6 +120,7 @@ project: Project, pluginVersion: String, buildUidService: Provider<BuildUidService>, + buildFinishBuildService: Provider<BuildFinishBuildService>? ): Provider<out BuildFusService<out Parameters>> { val isProjectIsolationEnabled = project.isProjectIsolationEnabled @@ -155,7 +156,7 @@ // when this OperationCompletionListener is called services can be already closed for Gradle 8, // so there is a change that no VariantImplementationFactory will be found val fusService = if (GradleVersion.current().baseVersion >= GradleVersion.version("8.9")) { - FlowActionBuildFusService.registerIfAbsentImpl(project, buildUidService, generalConfigurationMetricsProvider) + FlowActionBuildFusService.registerIfAbsentImpl(project, buildUidService, generalConfigurationMetricsProvider, buildFinishBuildService) } else if (GradleVersion.current().baseVersion >= GradleVersion.version("8.1")) { ConfigurationMetricParameterFlowActionBuildFusService.registerIfAbsentImpl( project, @@ -196,7 +197,11 @@ override fun close() { KotlinBuildStatsBeanService.closeServices() - log.kotlinDebug("Close ${this.javaClass.simpleName}") + log.kotlinDebug("Close build service $serviceName: class \"${this.javaClass.simpleName}\", build \"$buildId\"") + } + + internal fun recordBuildFinished(buildFailed: Boolean, configurationMetrics: List<MetricContainer>) { + recordBuildFinished(buildFailed, buildId, configurationMetrics) } internal fun recordBuildFinished(buildFailed: Boolean, buildId: String, configurationMetrics: List<MetricContainer>) {
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/ConfigurationMetricParameterFlowActionBuildFusService.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/ConfigurationMetricParameterFlowActionBuildFusService.kt index d516131..e72955d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/ConfigurationMetricParameterFlowActionBuildFusService.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/ConfigurationMetricParameterFlowActionBuildFusService.kt
@@ -29,7 +29,7 @@ //init value to avoid `java.lang.IllegalStateException: GradleScopeServices has been closed` exception on close spec.parameters.configurationMetrics.add(MetricContainer()) }.also { - StatisticsBuildFlowManager.getInstance(project).subscribeForBuildResult() + StatisticsBuildFlowManager.getInstance(project).subscribeForBuildResult(buildUidService) } } }
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/FlowActionBuildFusService.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/FlowActionBuildFusService.kt index 5d57354..2709a28 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/FlowActionBuildFusService.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/FlowActionBuildFusService.kt
@@ -31,6 +31,7 @@ project: Project, buildUidService: Provider<BuildUidService>, generalConfigurationMetricsProvider: Provider<MetricContainer>, + buildFinishBuildService: Provider<BuildFinishBuildService>? ): Provider<out BuildFusService<out Parameters>> { return project.gradle.sharedServices.registerIfAbsent(serviceName, FlowActionBuildFusService::class.java) { spec -> spec.parameters.generalConfigurationMetrics.set(generalConfigurationMetricsProvider) @@ -38,7 +39,7 @@ spec.parameters.buildStatisticsConfiguration.set(KotlinBuildStatsConfiguration(project)) spec.parameters.buildId.value(buildUidService.map { it.buildId }).disallowChanges() }.also { buildService -> - StatisticsBuildFlowManager.getInstance(project).subscribeForBuildResultAndConfigurationTimeMetrics(buildService) + StatisticsBuildFlowManager.getInstance(project).subscribeForBuildResultAndConfigurationTimeMetrics(buildService, buildUidService, buildFinishBuildService) } } }