diff --git a/buildSrc/src/main/kotlin/GradleCommon.kt b/buildSrc/src/main/kotlin/GradleCommon.kt index 7806b458703..628fb5d2d0e 100644 --- a/buildSrc/src/main/kotlin/GradleCommon.kt +++ b/buildSrc/src/main/kotlin/GradleCommon.kt @@ -124,7 +124,7 @@ fun Project.createGradleCommonSourceSet(): SourceSet { dependencies { compileOnlyConfigurationName(kotlinStdlib()) - "commonGradleApiCompileOnly"("dev.gradleplugins:gradle-api:8.0") + "commonGradleApiCompileOnly"("dev.gradleplugins:gradle-api:8.1") if (this@createGradleCommonSourceSet.name !in testPlugins) { compileOnlyConfigurationName(project(":kotlin-gradle-plugin-api")) { capabilities { diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 1ccd07dc9be..60cc42ea903 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -16,6 +16,7 @@ + @@ -44,6 +45,8 @@ + + @@ -62,8 +65,6 @@ - - @@ -5684,6 +5685,12 @@ + + + + + + @@ -5702,6 +5709,12 @@ + + + + + + @@ -5720,6 +5733,12 @@ + + + + + + @@ -5738,6 +5757,12 @@ + + + + + + @@ -5756,6 +5781,12 @@ + + + + + + @@ -5774,6 +5805,12 @@ + + + + + + @@ -5792,6 +5829,12 @@ + + + + + + @@ -5810,6 +5853,12 @@ + + + + + + @@ -5828,6 +5877,12 @@ + + + + + + @@ -5846,6 +5901,12 @@ + + + + + + @@ -5864,6 +5925,12 @@ + + + + + + @@ -5882,6 +5949,12 @@ + + + + + + @@ -5900,6 +5973,12 @@ + + + + + + @@ -5918,6 +5997,12 @@ + + + + + + @@ -5936,6 +6021,12 @@ + + + + + + @@ -5954,6 +6045,12 @@ + + + + + + @@ -5972,6 +6069,12 @@ + + + + + + @@ -5990,6 +6093,12 @@ + + + + + + @@ -6008,6 +6117,12 @@ + + + + + + @@ -6026,6 +6141,12 @@ + + + + + + @@ -6050,6 +6171,12 @@ + + + + + + @@ -6458,6 +6585,12 @@ + + + + + + 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 a5e60418c56..0d4bffe6e3e 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 @@ -15,8 +15,23 @@ import java.nio.file.Path @DisplayName("FUS statistic") //Tests for FUS statistics have to create new instance of KotlinBuildStatsService class FusStatisticsIT : KGPDaemonsBaseTest() { + private val expectedMetrics = arrayOf( + "OS_TYPE", + "BUILD_FAILED=false", + "EXECUTED_FROM_IDEA=false", + "BUILD_FINISH_TIME", + "GRADLE_VERSION", + "KOTLIN_STDLIB_VERSION", + "KOTLIN_COMPILER_VERSION", + ) + @DisplayName("for dokka") @GradleTest + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) fun testDokka(gradleVersion: GradleVersion) { project( "simpleProject", @@ -48,6 +63,11 @@ class FusStatisticsIT : KGPDaemonsBaseTest() { @DisplayName("general fields") @GradleTest + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) fun testFusStatistics(gradleVersion: GradleVersion) { project( "simpleProject", @@ -57,13 +77,7 @@ class FusStatisticsIT : KGPDaemonsBaseTest() { val fusStatisticsPath = fusStatisticsPath assertFileContains( fusStatisticsPath, - "OS_TYPE", - "BUILD_FAILED=false", - "EXECUTED_FROM_IDEA=false", - "BUILD_FINISH_TIME", - "GRADLE_VERSION", - "KOTLIN_STDLIB_VERSION", - "KOTLIN_COMPILER_VERSION", + *expectedMetrics, ) assertFileDoesNotContain( fusStatisticsPath, @@ -74,8 +88,65 @@ class FusStatisticsIT : KGPDaemonsBaseTest() { } } + @DisplayName("for project with buildSrc") + @GradleTest + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) + fun testProjectWithBuildSrc(gradleVersion: GradleVersion) { + project( + "instantExecutionWithBuildSrc", + gradleVersion, + ) { + build("compileKotlin", "-Pkotlin.session.logger.root.path=$projectPath") { + val fusStatisticsPath = fusStatisticsPath + assertFileContains( + fusStatisticsPath, + *expectedMetrics, + "BUILD_SRC_EXISTS=true" + ) + } + } + } + + @DisplayName("for project with included build") + @GradleTest + @GradleTestVersions( + minVersion = TestVersions.Gradle.G_7_6, + maxVersion = TestVersions.Gradle.G_8_0 + ) + fun testProjectWithIncludedBuild(gradleVersion: GradleVersion) { + project( + "instantExecutionWithIncludedBuildPlugin", + gradleVersion, + buildOptions = defaultBuildOptions.copy(configurationCache = true) + ) { + build("compileKotlin", "-Pkotlin.session.logger.root.path=$projectPath") { + val fusStatisticsPath = fusStatisticsPath + assertFileContains( + fusStatisticsPath, + *expectedMetrics, + ) + } + build("compileKotlin", "-Pkotlin.session.logger.root.path=$projectPath") { + val fusStatisticsPath = fusStatisticsPath + assertFileContains( + fusStatisticsPath, + *expectedMetrics, + ) + } + } + } + @DisplayName("for failed build") @GradleTest + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) fun testFusStatisticsForFailedBuild(gradleVersion: GradleVersion) { project( "simpleProject", @@ -98,4 +169,33 @@ class FusStatisticsIT : KGPDaemonsBaseTest() { } } } + + @DisplayName("general fields with configuration cache") + @GradleTest + @GradleTestVersions( + minVersion = TestVersions.Gradle.MIN_SUPPORTED, + additionalVersions = [TestVersions.Gradle.G_7_6, TestVersions.Gradle.G_8_0], + maxVersion = TestVersions.Gradle.G_8_1 + ) + fun testFusStatisticsWithConfigurationCache(gradleVersion: GradleVersion) { + project( + "simpleProject", + gradleVersion, + buildOptions = defaultBuildOptions.copy(configurationCache = true), + ) { + build( + "compileKotlin", + "-Pkotlin.session.logger.root.path=$projectPath", + ) { + assertConfigurationCacheStored() + } + + build( + "compileKotlin", + "-Pkotlin.session.logger.root.path=$projectPath", + ) { + assertConfigurationCacheReused() + } + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/fileAssertions.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/fileAssertions.kt index 54b154ca816..d9f8c90b0ee 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/fileAssertions.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/fileAssertions.kt @@ -191,7 +191,7 @@ fun assertFileContains( |${textNotInTheFile.joinToString(separator = "\n")} | |actual file content: - |$text" + |"$text" | """.trimMargin() } 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 b77f49600e9..d601f1c2087 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 @@ -42,6 +42,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSetFactory import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.report.BuildMetricsService +import org.jetbrains.kotlin.gradle.plugin.statistics.BuildFlowService import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute import org.jetbrains.kotlin.gradle.targets.js.KotlinJsPlugin import org.jetbrains.kotlin.gradle.targets.js.npm.addNpmDependencyExtension @@ -65,10 +66,11 @@ abstract class DefaultKotlinBasePlugin : KotlinBasePlugin { override val pluginVersion: String = getKotlinPluginVersion(logger) override fun apply(project: Project) { - val kotlinPluginVersion = project.getKotlinPluginVersion() - val statisticsReporter = KotlinBuildStatsService.getOrCreateInstance(project) - statisticsReporter?.report(StringMetrics.KOTLIN_COMPILER_VERSION, kotlinPluginVersion) + KotlinBuildStatsService.getOrCreateInstance(project)?.apply { + report(StringMetrics.KOTLIN_COMPILER_VERSION, pluginVersion) + } + BuildFlowService.registerIfAbsent(project) checkGradleCompatibility() @@ -89,7 +91,7 @@ abstract class DefaultKotlinBasePlugin : KotlinBasePlugin { val kotlinGradleBuildServices = KotlinGradleBuildServices.registerIfAbsent(project.gradle).get() if (!project.isProjectIsolationEnabled) { - kotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion) + kotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, pluginVersion) } BuildMetricsService.registerIfAbsent(project) @@ -212,7 +214,6 @@ abstract class KotlinBasePluginWrapper : DefaultKotlinBasePlugin() { override fun apply(project: Project) { super.apply(project) - val kotlinPluginVersion = project.getKotlinPluginVersion() project.logger.info("Using Kotlin Gradle Plugin $pluginVariant variant") @@ -225,7 +226,7 @@ abstract class KotlinBasePluginWrapper : DefaultKotlinBasePlugin() { project.maybeCreateCommonizerClasspathConfiguration() project.createKotlinExtension(projectExtensionClass).apply { - coreLibrariesVersion = kotlinPluginVersion + coreLibrariesVersion = pluginVersion fun kotlinSourceSetContainer(factory: NamedDomainObjectFactory) = project.container(KotlinSourceSet::class.java, factory) 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 new file mode 100644 index 00000000000..7bcaf476786 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/StatisticsBuildFlowManager.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin + +import org.gradle.api.Project +import org.gradle.api.flow.* +import org.gradle.api.provider.Property +import org.gradle.api.services.ServiceReference +import org.gradle.api.tasks.Input +import org.jetbrains.kotlin.gradle.plugin.statistics.BuildFlowService +import org.jetbrains.kotlin.gradle.report.BuildMetricsService +import org.jetbrains.kotlin.gradle.report.BuildScanExtensionHolder +import javax.inject.Inject + +internal abstract class StatisticsBuildFlowManager @Inject constructor( + private val flowScope: FlowScope, + private val flowProviders: FlowProviders, +) { + companion object { + fun getInstance(project: Project) = + project.objects.newInstance(StatisticsBuildFlowManager::class.java) + } + + fun subscribeForBuildResult() { + flowScope.always( + BuildFinishFlowAction::class.java + ) { spec -> + spec.parameters.buildFailed.set(flowProviders.buildWorkResult.map { it.failure.isPresent }) + } + } + + fun subscribeForBuildScan(project: Project) { + val buildScanExtension = project.rootProject.extensions.findByName("buildScan") + val buildScanHolder = buildScanExtension?.let { BuildScanExtensionHolder(it) } + + flowScope.always( + BuildScanFlowAction::class.java + ) { spec -> + spec.parameters.buildScanExtensionHolder.set(buildScanHolder) + } + } +} + +internal class BuildScanFlowAction : FlowAction { + interface Parameters : FlowParameters { + @get:ServiceReference + val buildMetricService: Property + + @get: Input + val buildScanExtensionHolder: Property + } + + override fun execute(parameters: Parameters) { + parameters.buildMetricService.orNull?.addCollectedTagsToBuildScan(parameters.buildScanExtensionHolder.orNull) + } +} + +internal class BuildFinishFlowAction : FlowAction { + interface Parameters : FlowParameters { + @get:ServiceReference + val buildFlowServiceProperty: Property + + @get:Input + val action: Property + + @get:Input + val buildFailed: Property + + } + + override fun execute(parameters: Parameters) { + parameters.buildFlowServiceProperty.get().recordBuildFinished( + parameters.action.orNull, parameters.buildFailed.get() + ) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFlowService.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFlowService.kt new file mode 100644 index 00000000000..229669d8ec9 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/BuildFlowService.kt @@ -0,0 +1,126 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin.statistics + +import org.gradle.api.Project +import org.gradle.api.invocation.Gradle +import org.gradle.api.provider.Property +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.tooling.events.task.TaskFailureResult +import org.gradle.tooling.events.task.TaskFinishEvent +import org.gradle.util.GradleVersion +import org.jetbrains.kotlin.gradle.plugin.BuildEventsListenerRegistryHolder +import org.jetbrains.kotlin.gradle.plugin.StatisticsBuildFlowManager +import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable +import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics +import org.jetbrains.kotlin.statistics.metrics.IStatisticsValuesConsumer +import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics +import org.jetbrains.kotlin.statistics.metrics.StringMetrics +import java.io.Serializable + +internal abstract class BuildFlowService : BuildService, AutoCloseable, OperationCompletionListener { + private var buildFailed: Boolean = false + + interface Parameters : BuildServiceParameters { + val configurationMetrics: Property + val fusStatisticsAvailable: Property + } + + companion object { + private val serviceName = "${BuildFlowService::class.simpleName}_${BuildFlowService::class.java.classLoader.hashCode()}" + + private fun fusStatisticsAvailable(gradle: Gradle): Boolean { + return when { + //known issue for Gradle with configurationCache: https://github.com/gradle/gradle/issues/20001 + GradleVersion.current().baseVersion < GradleVersion.version("7.4") -> !isConfigurationCacheAvailable(gradle) + GradleVersion.current().baseVersion < GradleVersion.version("8.1") -> true + //known issue. Cant reuse cache if file is changed in gradle_user_home dir: KT-58768 + else -> !isConfigurationCacheAvailable(gradle) + } + } + fun registerIfAbsent( + project: Project, + ): Provider { + + project.gradle.sharedServices.registrations.findByName(serviceName)?.let { + @Suppress("UNCHECKED_CAST") + return it.service as Provider + } + + val fusStatisticsAvailable = fusStatisticsAvailable(project.gradle) + return project.gradle.sharedServices.registerIfAbsent(serviceName, BuildFlowService::class.java) { spec -> + if (fusStatisticsAvailable) { + KotlinBuildStatsService.applyIfInitialised { + it.recordProjectsEvaluated(project.gradle) + } + } + + spec.parameters.configurationMetrics.set(project.provider { + KotlinBuildStatsService.getInstance()?.collectStartMetrics(project) + }) + spec.parameters.fusStatisticsAvailable.set(fusStatisticsAvailable) + }.also { buildService -> + if (fusStatisticsAvailable) { + when { + GradleVersion.current().baseVersion < GradleVersion.version("8.1") -> + BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(buildService) + else -> StatisticsBuildFlowManager.getInstance(project).subscribeForBuildResult() + } + } + if (GradleVersion.current().baseVersion >= GradleVersion.version("8.1")) { + StatisticsBuildFlowManager.getInstance(project).subscribeForBuildScan(project) + } + } + } + } + + override fun onFinish(event: FinishEvent?) { + if ((event is TaskFinishEvent) && (event.result is TaskFailureResult)) { + buildFailed = true + } + } + + override fun close() { + if (parameters.fusStatisticsAvailable.get()) { + recordBuildFinished(null, buildFailed) + } + KotlinBuildStatsService.applyIfInitialised { + it.close() + } + } + + internal fun recordBuildFinished(action: String?, buildFailed: Boolean) { + KotlinBuildStatsService.applyIfInitialised { + it.recordBuildFinish(action, buildFailed, parameters.configurationMetrics.orElse(MetricContainer()).get()) + } + } +} + +internal class MetricContainer : Serializable { + private val numericalMetrics = HashMap() + private val booleanMetrics = HashMap() + private val stringMetrics = HashMap() + + fun report(sessionLogger: IStatisticsValuesConsumer) { + for ((key, value) in numericalMetrics) { + sessionLogger.report(key, value) + } + for ((key, value) in booleanMetrics) { + sessionLogger.report(key, value) + } + for ((key, value) in stringMetrics) { + sessionLogger.report(key, value) + } + } + + fun put(metric: StringMetrics, value: String) = stringMetrics.put(metric, value) + fun put(metric: BooleanMetrics, value: Boolean) = booleanMetrics.put(metric, value) + fun put(metric: NumericalMetrics, value: Long) = numericalMetrics.put(metric, value) +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatHandler.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatHandler.kt index 927e5da77e0..bc2e5f6ad87 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatHandler.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatHandler.kt @@ -7,12 +7,9 @@ package org.jetbrains.kotlin.gradle.plugin.statistics import org.gradle.api.Project import org.gradle.api.artifacts.DependencySet -import org.gradle.api.invocation.Gradle import org.gradle.api.logging.Logging -import org.jetbrains.kotlin.gradle.utils.API -import org.jetbrains.kotlin.gradle.utils.COMPILE -import org.jetbrains.kotlin.gradle.utils.IMPLEMENTATION -import org.jetbrains.kotlin.gradle.utils.RUNTIME +import org.jetbrains.kotlin.gradle.plugin.internal.isProjectIsolationEnabled +import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.statistics.BuildSessionLogger import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics @@ -61,92 +58,102 @@ class KotlinBuildStatHandler { } } - fun reportGlobalMetricsAndBuildFinished( - gradle: Gradle?, - beanName: ObjectName, + fun reportGlobalMetrics( sessionLogger: BuildSessionLogger, - action: String?, - failure: Throwable? ) { runSafe("${KotlinBuildStatHandler::class.java}.reportGlobalMetrics") { - try { - try { - if (gradle != null) reportGlobalMetrics(gradle, sessionLogger) - } finally { - sessionLogger.finishBuildSession(action, failure) - } - } finally { - buildFinished(beanName) - } + System.getProperty("os.name")?.also { sessionLogger.report(StringMetrics.OS_TYPE, System.getProperty("os.name")) } + sessionLogger.report(NumericalMetrics.CPU_NUMBER_OF_CORES, Runtime.getRuntime().availableProcessors().toLong()) + sessionLogger.report(BooleanMetrics.EXECUTED_FROM_IDEA, System.getProperty("idea.active") != null) + sessionLogger.report(NumericalMetrics.GRADLE_DAEMON_HEAP_SIZE, Runtime.getRuntime().maxMemory()) } } - internal fun reportGlobalMetrics(gradle: Gradle, sessionLogger: BuildSessionLogger) { - sessionLogger.report(StringMetrics.PROJECT_PATH, gradle.rootProject.projectDir.absolutePath) - System.getProperty("os.name")?.also { sessionLogger.report(StringMetrics.OS_TYPE, System.getProperty("os.name")) } - sessionLogger.report(NumericalMetrics.CPU_NUMBER_OF_CORES, Runtime.getRuntime().availableProcessors().toLong()) - sessionLogger.report(StringMetrics.GRADLE_VERSION, gradle.gradleVersion) - sessionLogger.report(BooleanMetrics.EXECUTED_FROM_IDEA, System.getProperty("idea.active") != null) - sessionLogger.report(NumericalMetrics.GRADLE_DAEMON_HEAP_SIZE, Runtime.getRuntime().maxMemory()) - sessionLogger.report( - BooleanMetrics.KOTLIN_OFFICIAL_CODESTYLE, - gradle.rootProject.providers.gradleProperty("kotlin.code.style").orNull == "official" - ) // constants are saved in IDEA plugin and could not be accessed directly + internal fun reportBuildFinished( + sessionLogger: BuildSessionLogger, + action: String?, + buildFailed: Boolean, + configurationMetrics: MetricContainer, + ) { + runSafe("${KotlinBuildStatHandler::class.java}.reportBuildFinish") { + configurationMetrics.report(sessionLogger) + sessionLogger.finishBuildSession(action, buildFailed) + } + } - gradle.taskGraph.whenReady() { taskExecutionGraph -> - val executedTaskNames = taskExecutionGraph.allTasks.map { it.name }.distinct() - report(sessionLogger, BooleanMetrics.MAVEN_PUBLISH_EXECUTED, executedTaskNames.contains("install"), null) + internal fun collectConfigurationTimeMetrics( + project: Project, + sessionLogger: BuildSessionLogger, + ): MetricContainer { + val gradle = project.gradle + val configurationTimeMetrics = MetricContainer() + configurationTimeMetrics.put(StringMetrics.PROJECT_PATH, gradle.rootProject.projectDir.absolutePath) + configurationTimeMetrics.put(StringMetrics.GRADLE_VERSION, gradle.gradleVersion) + + if (project.isProjectIsolationEnabled) { //support project isolation - KT-58768 + return configurationTimeMetrics } + gradle.taskGraph.whenReady { taskExecutionGraph -> + val executedTaskNames = taskExecutionGraph.allTasks.map { it.name }.distinct() + configurationTimeMetrics.put(BooleanMetrics.MAVEN_PUBLISH_EXECUTED, executedTaskNames.contains("install")) + }// constants are saved in IDEA plugin and could not be accessed directly fun buildSrcExists(project: Project) = File(project.projectDir, "buildSrc").exists() - sessionLogger.report(BooleanMetrics.BUILD_SRC_EXISTS, buildSrcExists(gradle.rootProject)) + configurationTimeMetrics.put(BooleanMetrics.BUILD_SRC_EXISTS, buildSrcExists(gradle.rootProject)) val statisticOverhead = measureTimeMillis { gradle.allprojects { project -> project.plugins.findPlugin(DOKKA_PLUGIN)?.also { - sessionLogger.report(BooleanMetrics.ENABLED_DOKKA, true) + configurationTimeMetrics.put(BooleanMetrics.ENABLED_DOKKA, true) } for (configuration in project.configurations) { - val configurationName = configuration.name - val dependencies = configuration.dependencies + try { + val configurationName = configuration.name + val dependencies = configuration.dependencies - when (configurationName) { - "KoverEngineConfig" -> { - sessionLogger.report(BooleanMetrics.ENABLED_KOVER, true) - } - "kapt" -> { - sessionLogger.report(BooleanMetrics.ENABLED_KAPT, true) - for (dependency in dependencies) { - when (dependency.group) { - "com.google.dagger" -> sessionLogger.report(BooleanMetrics.ENABLED_DAGGER, true) - "com.android.databinding" -> sessionLogger.report(BooleanMetrics.ENABLED_DATABINDING, true) + when (configurationName) { + "KoverEngineConfig" -> { + configurationTimeMetrics.put(BooleanMetrics.ENABLED_KOVER, true) + } + "kapt" -> { + configurationTimeMetrics.put(BooleanMetrics.ENABLED_KAPT, true) + for (dependency in dependencies) { + when (dependency.group) { + "com.google.dagger" -> configurationTimeMetrics.put(BooleanMetrics.ENABLED_DAGGER, true) + "com.android.databinding" -> configurationTimeMetrics.put(BooleanMetrics.ENABLED_DATABINDING, true) + } } } + API -> { + configurationTimeMetrics.put(NumericalMetrics.CONFIGURATION_API_COUNT, 1) + reportLibrariesVersions(configurationTimeMetrics, dependencies) + } + IMPLEMENTATION -> { + configurationTimeMetrics.put(NumericalMetrics.CONFIGURATION_IMPLEMENTATION_COUNT, 1) + reportLibrariesVersions(configurationTimeMetrics, dependencies) + } + COMPILE -> { + configurationTimeMetrics.put(NumericalMetrics.CONFIGURATION_COMPILE_COUNT, 1) + reportLibrariesVersions(configurationTimeMetrics, dependencies) + } + RUNTIME -> { + configurationTimeMetrics.put(NumericalMetrics.CONFIGURATION_RUNTIME_COUNT, 1) + reportLibrariesVersions(configurationTimeMetrics, dependencies) + } } - API -> { - sessionLogger.report(NumericalMetrics.CONFIGURATION_API_COUNT, 1) - reportLibrariesVersions(sessionLogger, dependencies) - } - IMPLEMENTATION -> { - sessionLogger.report(NumericalMetrics.CONFIGURATION_IMPLEMENTATION_COUNT, 1) - reportLibrariesVersions(sessionLogger, dependencies) - } - COMPILE -> { - sessionLogger.report(NumericalMetrics.CONFIGURATION_COMPILE_COUNT, 1) - reportLibrariesVersions(sessionLogger, dependencies) - } - RUNTIME -> { - sessionLogger.report(NumericalMetrics.CONFIGURATION_RUNTIME_COUNT, 1) - reportLibrariesVersions(sessionLogger, dependencies) - } + } catch (e: Throwable) { + // log? } } val taskNames = project.tasks.names - sessionLogger.report(NumericalMetrics.NUMBER_OF_SUBPROJECTS, 1) - sessionLogger.report(BooleanMetrics.KOTLIN_KTS_USED, project.buildscript.sourceFile?.name?.endsWith(".kts") ?: false) - sessionLogger.report(NumericalMetrics.GRADLE_NUMBER_OF_TASKS, taskNames.size.toLong()) - sessionLogger.report( + configurationTimeMetrics.put(NumericalMetrics.NUMBER_OF_SUBPROJECTS, 1) + configurationTimeMetrics.put( + BooleanMetrics.KOTLIN_KTS_USED, + project.buildscript.sourceFile?.name?.endsWith(".kts") ?: false + ) + configurationTimeMetrics.put(NumericalMetrics.GRADLE_NUMBER_OF_TASKS, taskNames.size.toLong()) + configurationTimeMetrics.put( NumericalMetrics.GRADLE_NUMBER_OF_UNCONFIGURED_TASKS, taskNames.count { name -> try { @@ -157,52 +164,54 @@ class KotlinBuildStatHandler { }.toLong() ) - if (buildSrcExists(project)) { - sessionLogger.report(NumericalMetrics.BUILD_SRC_COUNT, 1) - sessionLogger.report(BooleanMetrics.BUILD_SRC_EXISTS, true) + if (project.name == "buildSrc") { + configurationTimeMetrics.put(NumericalMetrics.BUILD_SRC_COUNT, 1) + configurationTimeMetrics.put(BooleanMetrics.BUILD_SRC_EXISTS, true) } } } sessionLogger.report(NumericalMetrics.STATISTICS_VISIT_ALL_PROJECTS_OVERHEAD, statisticOverhead) + + return configurationTimeMetrics } - private fun reportLibrariesVersions(sessionLogger: BuildSessionLogger, dependencies: DependencySet?) { + private fun reportLibrariesVersions(configurationTimeMetrics: MetricContainer, dependencies: DependencySet?) { dependencies?.forEach { dependency -> when { - dependency.group?.startsWith("org.springframework") ?: false -> sessionLogger.report( + dependency.group?.startsWith("org.springframework") ?: false -> configurationTimeMetrics.put( StringMetrics.LIBRARY_SPRING_VERSION, dependency.version ?: "0.0.0" ) - dependency.group?.startsWith("com.vaadin") ?: false -> sessionLogger.report( + dependency.group?.startsWith("com.vaadin") ?: false -> configurationTimeMetrics.put( StringMetrics.LIBRARY_VAADIN_VERSION, dependency.version ?: "0.0.0" ) - dependency.group?.startsWith("com.google.gwt") ?: false -> sessionLogger.report( + dependency.group?.startsWith("com.google.gwt") ?: false -> configurationTimeMetrics.put( StringMetrics.LIBRARY_GWT_VERSION, dependency.version ?: "0.0.0" ) - dependency.group?.startsWith("org.hibernate") ?: false -> sessionLogger.report( + dependency.group?.startsWith("org.hibernate") ?: false -> configurationTimeMetrics.put( StringMetrics.LIBRARY_HIBERNATE_VERSION, dependency.version ?: "0.0.0" ) - dependency.group == "org.jetbrains.kotlin" && dependency.name.startsWith("kotlin-stdlib") -> sessionLogger.report( + dependency.group == "org.jetbrains.kotlin" && dependency.name.startsWith("kotlin-stdlib") -> configurationTimeMetrics.put( StringMetrics.KOTLIN_STDLIB_VERSION, dependency.version ?: "0.0.0" ) - dependency.group == "org.jetbrains.kotlinx" && dependency.name == "kotlinx-coroutines" -> sessionLogger.report( + dependency.group == "org.jetbrains.kotlinx" && dependency.name == "kotlinx-coroutines" -> configurationTimeMetrics.put( StringMetrics.KOTLIN_COROUTINES_VERSION, dependency.version ?: "0.0.0" ) - dependency.group == "org.jetbrains.kotlin" && dependency.name == "kotlin-reflect" -> sessionLogger.report( + dependency.group == "org.jetbrains.kotlin" && dependency.name == "kotlin-reflect" -> configurationTimeMetrics.put( StringMetrics.KOTLIN_REFLECT_VERSION, dependency.version ?: "0.0.0" ) dependency.group == "org.jetbrains.kotlinx" && dependency.name - .startsWith("kotlinx-serialization-runtime") -> sessionLogger.report( + .startsWith("kotlinx-serialization-runtime") -> configurationTimeMetrics.put( StringMetrics.KOTLIN_SERIALIZATION_VERSION, dependency.version ?: "0.0.0" ) - dependency.group == "com.android.tools.build" && dependency.name.startsWith("gradle") -> sessionLogger.report( + dependency.group == "com.android.tools.build" && dependency.name.startsWith("gradle") -> configurationTimeMetrics.put( StringMetrics.ANDROID_GRADLE_PLUGIN_VERSION, dependency.version ?: "0.0.0" ) @@ -215,7 +224,7 @@ class KotlinBuildStatHandler { metric: BooleanMetrics, value: Boolean, subprojectName: String?, - weight: Long? = null + weight: Long? = null, ) = runSafe("report metric ${metric.name}") { sessionLogger.report(metric, value, subprojectName, weight) } ?: false @@ -225,7 +234,7 @@ class KotlinBuildStatHandler { metric: NumericalMetrics, value: Long, subprojectName: String?, - weight: Long? = null + weight: Long? = null, ) = runSafe("report metric ${metric.name}") { sessionLogger.report(metric, value, subprojectName, weight) } ?: false @@ -235,7 +244,7 @@ class KotlinBuildStatHandler { metric: StringMetrics, value: String, subprojectName: String?, - weight: Long? = null + weight: Long? = null, ) = runSafe("report metric ${metric.name}") { sessionLogger.report(metric, value, subprojectName, weight) } ?: false diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatsService.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatsService.kt index 466e87a509d..6e8abfff994 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatsService.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/statistics/KotlinBuildStatsService.kt @@ -5,8 +5,6 @@ package org.jetbrains.kotlin.gradle.plugin.statistics -import org.gradle.BuildAdapter -import org.gradle.BuildResult import org.gradle.api.Project import org.gradle.api.invocation.Gradle import org.gradle.api.logging.Logger @@ -19,13 +17,13 @@ import org.jetbrains.kotlin.gradle.plugin.BuildEventsListenerRegistryHolder import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatHandler.Companion.runSafe import org.jetbrains.kotlin.gradle.plugin.statistics.old.Pre232IdeaKotlinBuildStatsMXBean import org.jetbrains.kotlin.gradle.plugin.statistics.old.Pre232IdeaKotlinBuildStatsService -import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable import org.jetbrains.kotlin.statistics.BuildSessionLogger import org.jetbrains.kotlin.statistics.BuildSessionLogger.Companion.STATISTICS_FOLDER_NAME import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics import org.jetbrains.kotlin.statistics.metrics.IStatisticsValuesConsumer import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics import org.jetbrains.kotlin.statistics.metrics.StringMetrics +import java.io.Closeable import java.io.File import java.lang.management.ManagementFactory import javax.management.MBeanServer @@ -48,7 +46,7 @@ interface KotlinBuildStatsMXBean { } -internal abstract class KotlinBuildStatsService internal constructor() : BuildAdapter(), IStatisticsValuesConsumer { +internal abstract class KotlinBuildStatsService internal constructor() : IStatisticsValuesConsumer, Closeable { companion object { // Do not rename this bean otherwise compatibility with the older Kotlin Gradle Plugins would be lost private const val JMX_BEAN_NAME_BEFORE_232_IDEA = "org.jetbrains.kotlin.gradle.plugin.statistics:type=StatsService" @@ -77,7 +75,7 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd */ @JvmStatic @Synchronized - fun getInstance(): IStatisticsValuesConsumer? { + fun getInstance(): KotlinBuildStatsService? { if (statisticsIsEnabled != true) { return null } @@ -101,7 +99,7 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd */ @JvmStatic @Synchronized - internal fun getOrCreateInstance(project: Project): IStatisticsValuesConsumer? { + internal fun getOrCreateInstance(project: Project): KotlinBuildStatsService? { return runSafe("${KotlinBuildStatsService::class.java}.getOrCreateInstance") { val gradle = project.gradle @@ -131,11 +129,7 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd registerPre232IdeaStatsBean(mbs, gradle, log) } - if (!isConfigurationCacheAvailable(gradle)) { - gradle.addBuildListener(instance!!) - } - - BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(project.provider { + BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(project.provider { OperationCompletionListener { event -> if (event is TaskFinishEvent) { reportTaskIfNeed(event.descriptor.name) @@ -181,7 +175,7 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd * Invokes provided collector if the reporting service is initialised. * The duration of collector's wall time is reported into overall overhead metric. */ - fun applyIfInitialised(collector: (IStatisticsValuesConsumer) -> Unit) { + fun applyIfInitialised(collector: (KotlinBuildStatsService) -> Unit) { getInstance()?.apply { try { val duration = measureTimeMillis { @@ -213,6 +207,22 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd } } } + + override fun close() { + instance = null + } + + /** + * Collects metrics at the end of a build + */ + open fun recordBuildFinish(action: String?, buildFailed: Boolean, configurationTimeMetrics: MetricContainer) {} + + /** + * Collect project general and configuration metrics at the start of a build + */ + open fun collectStartMetrics(project: Project): MetricContainer = MetricContainer() + + open fun recordProjectsEvaluated(gradle: Gradle) {} } internal class JMXKotlinBuildStatsService(private val mbs: MBeanServer, private val beanName: ObjectName) : @@ -242,14 +252,11 @@ internal class JMXKotlinBuildStatsService(private val mbs: MBeanServer, private callJmx("reportString", "java.lang.String", metric.name, value, subprojectName, weight) } as? Boolean ?: false - override fun buildFinished(result: BuildResult) { - instance = null - } } internal abstract class AbstractKotlinBuildStatsService( gradle: Gradle, - protected val beanName: ObjectName, + private val beanName: ObjectName, ) : KotlinBuildStatsService() { companion object { //test only @@ -275,13 +282,16 @@ internal abstract class AbstractKotlinBuildStatsService( private val sessionLoggerRootPath = customSessionLoggerRootPath?.let { File(it) } ?: gradle.gradleUserHomeDir - protected val sessionLogger = BuildSessionLogger(sessionLoggerRootPath, forceValuesValidation = forcePropertiesValidation) + protected val sessionLogger = BuildSessionLogger( + sessionLoggerRootPath, + forceValuesValidation = forcePropertiesValidation, + ) private fun gradleBuildStartTime(gradle: Gradle): Long? { return (gradle as? DefaultGradle)?.services?.get(BuildRequestMetaData::class.java)?.startTime } - override fun projectsEvaluated(gradle: Gradle) { + override fun recordProjectsEvaluated(gradle: Gradle) { runSafe("${DefaultKotlinBuildStatsService::class.java}.projectEvaluated") { if (!sessionLogger.isBuildSessionStarted()) { sessionLogger.startBuildSession( @@ -293,15 +303,15 @@ internal abstract class AbstractKotlinBuildStatsService( } @Synchronized - override fun buildFinished(result: BuildResult) { + override fun close() { KotlinBuildStatHandler().buildFinished(beanName) - instance = null + super.close() } } internal class DefaultKotlinBuildStatsService internal constructor( gradle: Gradle, - beanName: ObjectName + beanName: ObjectName, ) : AbstractKotlinBuildStatsService(gradle, beanName), KotlinBuildStatsMXBean { override fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String?, weight: Long?): Boolean = @@ -323,9 +333,11 @@ internal class DefaultKotlinBuildStatsService internal constructor( report(StringMetrics.valueOf(name), value, subprojectName, weight) //only one jmx bean service should report global metrics - @Synchronized - override fun buildFinished(result: BuildResult) { - KotlinBuildStatHandler().reportGlobalMetricsAndBuildFinished(result.gradle, beanName, sessionLogger, result.action, result.failure) - instance = null + override fun recordBuildFinish(action: String?, buildFailed: Boolean, configurationTimeMetrics: MetricContainer) { + KotlinBuildStatHandler().reportGlobalMetrics(sessionLogger) + KotlinBuildStatHandler().reportBuildFinished(sessionLogger, action, buildFailed, configurationTimeMetrics) } + + override fun collectStartMetrics(project: Project) = KotlinBuildStatHandler().collectConfigurationTimeMetrics(project, sessionLogger) + } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildMetricsService.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildMetricsService.kt index 7707f56b745..3348468ae5c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildMetricsService.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/report/BuildMetricsService.kt @@ -22,6 +22,7 @@ import org.gradle.tooling.events.task.TaskExecutionResult import org.gradle.tooling.events.task.TaskFailureResult import org.gradle.tooling.events.task.TaskFinishEvent import org.gradle.tooling.events.task.TaskSkippedResult +import org.gradle.util.GradleVersion import org.jetbrains.kotlin.build.report.metrics.BuildMetrics import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.BuildPerformanceMetric @@ -224,25 +225,27 @@ abstract class BuildMetricsService : BuildService if (event is TaskFinishEvent) { val buildOperation = buildMetricService.get().updateBuildOperationRecord(event) val buildParameters = buildMetricService.get().parameters.toBuildReportParameters() + val buildReportService = buildMetricService.map { it.buildReportService } buildReportService.get().onFinish(event, buildOperation, buildParameters, buildScan) } } }) - - val buildScanReportSettings = buildMetricService.get().parameters.reportingSettings.orNull?.buildScanReportSettings if (buildScanReportSettings != null) { buildScan?.also { - buildReportService.get().initBuildScanTags( + buildMetricService.map { it.buildReportService }.get().initBuildScanTags( it, buildMetricService.get().parameters.label.orNull ) - it.buildScan.buildFinished { - buildReportService.get().addCollectedTags(buildScan) + if (GradleVersion.current().baseVersion < GradleVersion.version("8.0")) { + it.buildScan.buildFinished { + buildMetricService.map { it.addCollectedTagsToBuildScan(buildScan) } + } } } } @@ -273,6 +276,11 @@ abstract class BuildMetricsService : BuildService assertTrue( @@ -69,21 +69,21 @@ class BuildSessionLoggerTest { val maxFileSize = 10_000 val logger = BuildSessionLogger(rootFolder, 100, maxFileSize.toLong()) logger.startBuildSession(0, null) - logger.finishBuildSession("", null) + logger.finishBuildSession("", false) assertEquals(1, statFilesCount()) val file2edit = rootFolder.listFiles()?.first()?.listFiles()?.first() ?: fail("Could not find single stat file") logger.startBuildSession(0, 0) - logger.finishBuildSession("", null) + logger.finishBuildSession("", false) //new file should not be created assertEquals(1, statFilesCount()) file2edit.appendBytes(ByteArray(maxFileSize)) logger.startBuildSession(0, 0) - logger.finishBuildSession("", null) + logger.finishBuildSession("", false) // a new file should be created as maximal file size assertEquals(2, statFilesCount()) @@ -94,7 +94,7 @@ class BuildSessionLoggerTest { val maxFiles = 100 val logger = BuildSessionLogger(rootFolder, maxFiles) logger.startBuildSession(0, null) - logger.finishBuildSession("", null) + logger.finishBuildSession("", false) assertEquals(1, statFilesCount()) val statsFolder = rootFolder.listFiles()?.single() ?: fail("${rootFolder.absolutePath} was not created") @@ -107,7 +107,7 @@ class BuildSessionLoggerTest { } logger.startBuildSession(0, 0) - logger.finishBuildSession("", null) + logger.finishBuildSession("", false) assertTrue( statsFolder.listFiles()?.count { it.name == singleStatFile.name } == 1, @@ -139,7 +139,7 @@ class BuildSessionLoggerTest { val startTime = System.currentTimeMillis() - 1001 logger.startBuildSession(1, startTime) - logger.finishBuildSession("Build", null) + logger.finishBuildSession("Build", false) assertEquals(1, statFilesCount()) val statFile = rootFolder.listFiles()?.single()?.listFiles()?.single() ?: fail("Could not find stat file") @@ -158,7 +158,7 @@ class BuildSessionLoggerTest { } - logger.finishBuildSession("", null) + logger.finishBuildSession("", false) val metrics = ArrayList() MetricsContainer.readFromFile(statFile) { @@ -194,7 +194,7 @@ class BuildSessionLoggerTest { for (metric in NumericalMetrics.values()) { logger.report(metric, System.currentTimeMillis()) } - logger.finishBuildSession("Build", null) + logger.finishBuildSession("Build", false) MetricsContainer.readFromFile(rootFolder.listFiles()?.single()?.listFiles()?.single() ?: fail("Could not find stat file")) { for (metric in StringMetrics.values()) { @@ -217,7 +217,7 @@ class BuildSessionLoggerTest { logger.report(NumericalMetrics.ANALYSIS_LINES_PER_SECOND, 10, null, 9) logger.report(NumericalMetrics.ANALYSIS_LINES_PER_SECOND, 100, null, 1) - logger.finishBuildSession("Build", null) + logger.finishBuildSession("Build", false) MetricsContainer.readFromFile(rootFolder.listFiles()?.single()?.listFiles()?.single() ?: fail("Could not find stat file")) { assertEquals(19L, it.getMetric(NumericalMetrics.ANALYSIS_LINES_PER_SECOND)?.getValue()) } diff --git a/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/BuildSessionLogger.kt b/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/BuildSessionLogger.kt index f4a66f36e20..0c8c6c9edb0 100644 --- a/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/BuildSessionLogger.kt +++ b/libraries/tools/kotlin-gradle-statistics/src/main/kotlin/org/jetbrains/kotlin/statistics/BuildSessionLogger.kt @@ -20,7 +20,7 @@ class BuildSessionLogger( private val maxProfileFiles: Int = DEFAULT_MAX_PROFILE_FILES, private val maxFileSize: Long = DEFAULT_MAX_PROFILE_FILE_SIZE, private val maxFileAge: Long = DEFAULT_MAX_FILE_AGE, - private val forceValuesValidation: Boolean = false + private val forceValuesValidation: Boolean = false, ) : IStatisticsValuesConsumer { companion object { @@ -131,7 +131,10 @@ class BuildSessionLogger( } @Synchronized - fun finishBuildSession(@Suppress("UNUSED_PARAMETER") action: String?, failure: Throwable?) { + fun finishBuildSession( + @Suppress("UNUSED_PARAMETER") action: String?, + buildFailed: Boolean, + ) { try { // nanotime could not be used as build start time in nanotime is unknown. As result, the measured duration // could be affected by system clock correction @@ -142,7 +145,7 @@ class BuildSessionLogger( } report(NumericalMetrics.GRADLE_EXECUTION_DURATION, finishTime - it.projectEvaluatedTime) report(NumericalMetrics.BUILD_FINISH_TIME, finishTime) - report(BooleanMetrics.BUILD_FAILED, failure != null) + report(BooleanMetrics.BUILD_FAILED, buildFailed) } buildSession = null } finally {