Added FUS extensions and new metrics for reporting statistics from gradle

This commit is contained in:
Andrey Uskov
2020-01-17 09:14:59 +03:00
parent bac0309a9b
commit beb3165839
28 changed files with 440 additions and 119 deletions
@@ -28,12 +28,14 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.sources.checkSourceSetVisibilityRequirements
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget.*
import org.jetbrains.kotlin.konan.target.presetName
import org.jetbrains.kotlin.statistics.metrics.StringMetrics
class KotlinMultiplatformPlugin(
private val kotlinPluginVersion: String,
@@ -261,6 +263,8 @@ class KotlinMultiplatformPlugin(
target.compilations.findByName(KotlinCompilation.TEST_COMPILATION_NAME)?.let { testCompilation ->
sourceSets.findByName(testCompilation.defaultSourceSetName)?.dependsOn(test)
}
KotlinBuildStatsService.getInstance()?.report(StringMetrics.MPP_PLATFORMS, target.targetName)
}
UnusedSourceSetsChecker.checkSourceSets(project)
@@ -12,11 +12,9 @@ import javax.management.ObjectName
import javax.management.StandardMBean
interface IDaemonReuseCounterMXBean {
fun getOrdinal(): Long
fun incrementAndGetOrdinal(): Long
}
/**
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.gradle.plugin.statistics
import org.gradle.BuildAdapter
import org.gradle.BuildResult
import org.gradle.api.artifacts.DependencySet
import org.gradle.api.invocation.Gradle
import org.gradle.api.logging.Logging
import org.gradle.initialization.BuildCompletionListener
import org.gradle.initialization.BuildRequestMetaData
import org.gradle.invocation.DefaultGradle
import org.jetbrains.kotlin.statistics.BuildSessionLogger
@@ -20,6 +20,7 @@ import java.lang.management.ManagementFactory
import javax.management.MBeanServer
import javax.management.ObjectName
import javax.management.StandardMBean
import kotlin.system.measureTimeMillis
/**
* Interface for populating statistics collection method via JXM interface
@@ -27,21 +28,16 @@ import javax.management.StandardMBean
* of Kotlin Plugin and other classloaders
*/
interface KotlinBuildStatsMXBean {
fun reportBoolean(name: String, value: Boolean, subprojectName: String?)
fun reportNumber(name: String, value: Long, subprojectName: String?)
fun reportString(name: String, value: String, subprojectName: String?)
}
internal abstract class KotlinBuildStatsService internal constructor() : BuildAdapter(), IStatisticsValuesConsumer,
BuildCompletionListener {
internal abstract class KotlinBuildStatsService internal constructor() : BuildAdapter(), IStatisticsValuesConsumer {
companion object {
// Do not rename this bean otherwise compatibility with the older Kotlin Gradle Plugins would be lost
const val JMX_BEAN_NAME = "org.jetbrains.kotlin.gradle.plugin.statistics:type=StatsService"
@@ -54,7 +50,6 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd
// "emergency file" collecting statistics is disabled it the file exists
const val DISABLE_STATISTICS_FILE_NAME = "${STATISTICS_FOLDER_NAME}/.disable"
/**
* Method for getting IStatisticsValuesConsumer for reporting some statistics
* Could be invoked during any build phase after applying first Kotlin plugin and
@@ -145,16 +140,11 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd
}
}
}
}
internal class JMXKotlinBuildStatsService(private val mbs: MBeanServer, private val beanName: ObjectName) :
KotlinBuildStatsService() {
override fun buildFinished(result: BuildResult) {
}
private fun callJmx(method: String, type: String, metricName: String, value: Any, subprojectName: String?) {
mbs.invoke(
beanName,
@@ -182,50 +172,89 @@ internal class JMXKotlinBuildStatsService(private val mbs: MBeanServer, private
}
}
override fun completed() {
override fun buildFinished(result: BuildResult) {
instance = null
}
}
internal class DefaultKotlinBuildStatsService internal constructor(
gradle: Gradle,
val beanName: ObjectName
) : KotlinBuildStatsService(), KotlinBuildStatsMXBean {
private val sessionLogger = BuildSessionLogger(gradle.gradleUserHomeDir)
private fun gradleBuildStartTime(gradle: Gradle): Long? {
return (gradle as? DefaultGradle)?.services?.get(BuildRequestMetaData::class.java)?.startTime
}
private fun reportLibrariesVersions(dependencies: DependencySet?) {
dependencies?.forEach { dependency ->
when {
dependency.group?.startsWith("org.springframework") ?: false -> sessionLogger.report(
StringMetrics.LIBRARY_SPRING_VERSION,
dependency.version ?: "0.0.0"
)
dependency.group?.startsWith("com.vaadin") ?: false -> sessionLogger.report(
StringMetrics.LIBRARY_VAADIN_VERSION,
dependency.version ?: "0.0.0"
)
dependency.group?.startsWith("com.google.gwt") ?: false -> sessionLogger.report(
StringMetrics.LIBRARY_GWT_VERSION,
dependency.version ?: "0.0.0"
)
dependency.group?.startsWith("org.hibernate") ?: false -> sessionLogger.report(
StringMetrics.LIBRARY_HIBERNATE_VERSION,
dependency.version ?: "0.0.0"
)
}
}
}
private fun reportGlobalMetrics(gradle: Gradle) {
System.getProperty("os.name")?.also {
sessionLogger.report(StringMetrics.OS_TYPE, gradle.gradleVersion)
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)
val statisticOverhead = measureTimeMillis {
gradle.allprojects { project ->
for (configuration in project.configurations) {
val configurationName = configuration.name
val dependencies = configuration.dependencies
gradle.allprojects { project ->
for (configuration in project.configurations) {
val configurationName = configuration.name
val dependencies = configuration.dependencies
when (configurationName) {
"kapt" -> {
sessionLogger.report(BooleanMetrics.ENABLED_KAPT, true)
dependencies.forEach { dependency ->
when (dependency.group) {
"com.google.dagger" -> sessionLogger.report(BooleanMetrics.ENABLED_DAGGER, true)
"com.android.databinding" -> sessionLogger.report(BooleanMetrics.ENABLED_DATABINDING, true)
when (configurationName) {
"kapt" -> {
sessionLogger.report(BooleanMetrics.ENABLED_KAPT, true)
dependencies?.forEach { dependency ->
when (dependency.group) {
"com.google.dagger" -> sessionLogger.report(BooleanMetrics.ENABLED_DAGGER, true)
"com.android.databinding" -> sessionLogger.report(BooleanMetrics.ENABLED_DATABINDING, true)
}
}
}
"api" -> {
sessionLogger.report(NumericalMetrics.CONFIGURATION_API_COUNT, 1)
reportLibrariesVersions(dependencies)
}
"implementation" -> {
sessionLogger.report(NumericalMetrics.CONFIGURATION_IMPLEMENTATION_COUNT, 1)
reportLibrariesVersions(dependencies)
}
"compile" -> {
sessionLogger.report(NumericalMetrics.CONFIGURATION_COMPILE_COUNT, 1)
reportLibrariesVersions(dependencies)
}
"runtime" -> {
sessionLogger.report(NumericalMetrics.CONFIGURATION_RUNTIME_COUNT, 1)
reportLibrariesVersions(dependencies)
}
}
}
}
}
sessionLogger.report(NumericalMetrics.STATISTICS_VISIT_ALL_PROJECTS_OVERHEAD, statisticOverhead)
}
override fun projectsEvaluated(gradle: Gradle) {
@@ -243,16 +272,8 @@ internal class DefaultKotlinBuildStatsService internal constructor(
@Synchronized
override fun buildFinished(result: BuildResult) {
runSafe("${DefaultKotlinBuildStatsService::class.java}.buildFinished") {
sessionLogger.finishBuildSession(result.action, result.failure)
}
}
@Synchronized
override fun completed() {
runSafe("${DefaultKotlinBuildStatsService::class.java}.completed") {
try {
sessionLogger.unlockJournalFile()
sessionLogger.finishBuildSession(result.action, result.failure)
} finally {
val mbs: MBeanServer = ManagementFactory.getPlatformMBeanServer()
if (mbs.isRegistered(beanName)) {
@@ -25,7 +25,5 @@ class BuildStatServiceTest {
jmxService.report(StringMetrics.KOTLIN_COMPILER_VERSION, "1.2.3")
jmxService.report(NumericalMetrics.NUMBER_OF_SUBPROJECTS, 10)
jmxService.report(BooleanMetrics.ENABLED_DATABINDING, true)
jmxService.completed()
}
}
@@ -7,7 +7,7 @@ plugins {
dependencies {
compileOnly(kotlinStdlib())
testCompile(project(":kotlin-test::kotlin-test-junit"))
testCompile(project(":kotlin-test:kotlin-test-junit"))
testCompile("junit:junit:4.12")
}
@@ -19,5 +19,3 @@ sourceSets {
projectTest {
workingDir = rootDir
}
runtimeJar(rewriteDefaultJarDepsToShadedCompiler())
@@ -21,8 +21,9 @@ internal val salt: String by lazy {
fun anonymizeComponentVersion(version: String): String {
return version.replace('-', '.')
.split(".")
.filterIndexed { i, _ -> i < 3 }
.map { s -> s.toIntOrNull() ?: "?" }
.plus(listOf("0", "0")) // pad with zeros
.take(3)
.map { s -> s.toIntOrNull() ?: "0" }
.joinToString(".")
}
@@ -6,7 +6,5 @@
package org.jetbrains.kotlin.statistics
class BuildSession(val buildStartedTime: Long?) {
val projectEvaluatedTime = System.currentTimeMillis()
}
}
@@ -16,17 +16,23 @@ import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
class BuildSessionLogger(
private val rootPath: File,
rootPath: File,
private val maxProfileFiles: Int = DEFAULT_MAX_PROFILE_FILES,
private val maxFileSize: Long = DEFAULT_MAX_PROFILE_FILE_SIZE
private val maxFileSize: Long = DEFAULT_MAX_PROFILE_FILE_SIZE,
private val maxFileAge: Long = DEFAULT_MAX_FILE_AGE
) : IStatisticsValuesConsumer {
companion object {
const val STATISTICS_FOLDER_NAME = "kotlin-profile"
const val STATISTICS_FILE_NAME_PATTERN = "\\d{4}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{3}.profile"
internal const val STATISTICS_FILE_NAME_PATTERN = "\\d{4}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{3}.profile"
private const val DEFAULT_MAX_PROFILE_FILES = 1_000
private const val DEFAULT_MAX_PROFILE_FILE_SIZE = 100_000L
private const val DEFAULT_MAX_FILE_AGE = 30 * 24 * 3600 * 1000L //30 days
fun listProfileFiles(statisticsFolder: File): List<File>? {
return statisticsFolder.listFiles()?.filterTo(ArrayList()) { it.name.matches(STATISTICS_FILE_NAME_PATTERN.toRegex()) }?.sorted()
}
}
private val profileFileNameFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd-HH-mm-ss-SSS'.profile'")
@@ -53,29 +59,44 @@ class BuildSessionLogger(
@Synchronized
private fun closeTrackingFile() {
metricsContainer.flush(trackingFile)
trackingFile?.close()
trackingFile = null
trackingFile?.let {
metricsContainer.flush(it)
it.close()
trackingFile = null
}
}
/**
* Initializes a new tracking file
* The following contracts are implemented:
* - number of tracking files should not be more than maxProfileFiles (the earlier file created the earlier deleted)
* - files with age (current time - last modified) more than maxFileAge should be deleted (if we trust lastModified returned by FS)
* - files are ordered on the basis of name (creation timestamp)
* - if the last file has size less then maxFileSize, the next record will be append to it (new file created otherwise)
* -
*/
@Synchronized
private fun initTrackingFile() {
closeTrackingFile()
// Get list of existing files. Try to create folder if possible, return from function if failed to create folder
val fileCandidates =
statisticsFolder.listFiles()?.filter { it.name.matches(STATISTICS_FILE_NAME_PATTERN.toRegex()) }?.toMutableList()
?: if (statisticsFolder.mkdirs()) emptyList<File>() else return
val fileCandidates = listProfileFiles(statisticsFolder) ?: if (statisticsFolder.mkdirs()) emptyList<File>() else return
for (i in 0 until fileCandidates.size - maxProfileFiles) {
val file2delete = fileCandidates[i]
if (file2delete.isFile) {
file2delete.delete()
for ((index, file) in fileCandidates.withIndex()) {
val toDelete = if (index < fileCandidates.size - maxProfileFiles)
true
else {
val lastModified = file.lastModified()
(lastModified > 0) && (System.currentTimeMillis() - maxFileAge > lastModified)
}
if (toDelete) {
file.delete()
}
}
// emergency check. What if a lot of files are locked due to some reason
if (statisticsFolder.listFiles()?.size ?: 0 > maxProfileFiles * 2) {
if (listProfileFiles(statisticsFolder)?.size ?: 0 > maxProfileFiles * 2) {
trackingFile = NullRecordLogger()
return
}
@@ -99,20 +120,24 @@ class BuildSessionLogger(
@Synchronized
fun finishBuildSession(action: String?, failure: Throwable?) {
// 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
val finishTime = System.currentTimeMillis()
buildSession?.also {
if (it.buildStartedTime != null) {
report(NumericalMetrics.GRADLE_BUILD_DURATION, finishTime - it.buildStartedTime)
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
val finishTime = System.currentTimeMillis()
buildSession?.also {
if (it.buildStartedTime != null) {
report(NumericalMetrics.GRADLE_BUILD_DURATION, finishTime - it.buildStartedTime)
}
report(NumericalMetrics.GRADLE_EXECUTION_DURATION, finishTime - it.projectEvaluatedTime)
}
report(NumericalMetrics.GRADLE_EXECUTION_DURATION, finishTime - it.projectEvaluatedTime)
buildSession = null
} finally {
unlockJournalFile()
}
buildSession = null
}
@Synchronized
fun unlockJournalFile() {
private fun unlockJournalFile() {
closeTrackingFile()
}
@@ -15,7 +15,6 @@ import java.nio.file.Paths
import java.nio.file.StandardOpenOption
class FileRecordLogger(file: File) : IRecordLogger {
private val channel: FileChannel =
FileChannel.open(Paths.get(file.toURI()), StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.APPEND)
?: throw IOException("Could not open file $file")
@@ -8,7 +8,5 @@ package org.jetbrains.kotlin.statistics.fileloggers
import java.io.Closeable
interface IRecordLogger : Closeable {
fun append(s: String)
}
}
@@ -15,11 +15,11 @@ import java.nio.file.StandardOpenOption
import java.util.*
class MetricsContainer : IStatisticsValuesConsumer {
data class MetricDescriptor(val name: String, val projectHash: String?) : Comparable<MetricDescriptor> {
override fun compareTo(other: MetricDescriptor): Int {
val compareNames = name.compareTo(other.name)
return when {
name.compareTo(other.name) != 0 -> name.compareTo(other.name)
compareNames != 0 -> compareNames
projectHash == other.projectHash -> 0
else -> (projectHash ?: "").compareTo(other.projectHash ?: "")
}
@@ -33,16 +33,15 @@ class MetricsContainer : IStatisticsValuesConsumer {
private val stringMetrics = TreeMap<MetricDescriptor, IMetricContainer<String>>()
companion object {
private const val BUILD_SESSION_SEPARATOR = "BUILD FINISHED"
val ENCODING = Charsets.UTF_8
private val stringMetricsMap = StringMetrics.values().map { m -> m.name to m }.toMap()
private val stringMetricsMap = StringMetrics.values().associateBy(StringMetrics::name)
private val booleanMetricsMap = BooleanMetrics.values().map { m -> m.name to m }.toMap()
private val booleanMetricsMap = BooleanMetrics.values().associateBy(BooleanMetrics::name)
private val numericalMetricsMap = NumericalMetrics.values().map { m -> m.name to m }.toMap()
private val numericalMetricsMap = NumericalMetrics.values().associateBy(NumericalMetrics::name)
fun readFromFile(file: File, consumer: (MetricsContainer) -> Unit) {
val channel = FileChannel.open(Paths.get(file.toURI()), StandardOpenOption.WRITE, StandardOpenOption.READ)
@@ -13,7 +13,6 @@ interface IMetricContainer<T> {
fun toStringRepresentation(): String
fun getValue(): T?
}
interface IMetricContainerFactory<T> {
@@ -23,7 +22,6 @@ interface IMetricContainerFactory<T> {
}
open class OverrideMetricContainer<T>() : IMetricContainer<T> {
internal var myValue: T? = null
override fun addValue(t: T) {
@@ -41,8 +39,19 @@ open class OverrideMetricContainer<T>() : IMetricContainer<T> {
override fun getValue() = myValue
}
class SumMetricContainer() : OverrideMetricContainer<Long>() {
class OverrideVersionMetricContainer() : OverrideMetricContainer<String>() {
constructor(v: String) : this() {
myValue = v
}
override fun addValue(t: String) {
if (myValue == null || myValue == "0.0.0") {
myValue = t
}
}
}
class SumMetricContainer() : OverrideMetricContainer<Long>() {
constructor(v: Long) : this() {
myValue = v
}
@@ -85,7 +94,6 @@ class OrMetricContainer() : OverrideMetricContainer<Boolean>() {
}
class ConcatMetricContainer() : IMetricContainer<String> {
private val myValues = TreeSet<String>()
companion object {
@@ -101,9 +109,8 @@ class ConcatMetricContainer() : IMetricContainer<String> {
}
override fun toStringRepresentation(): String {
return myValues.joinToString(SEPARATOR)
return myValues.sorted().joinToString(SEPARATOR)
}
override fun getValue() = toStringRepresentation()
}
@@ -16,6 +16,11 @@ enum class StringOverridePolicy: IMetricContainerFactory<String> {
override fun fromStringRepresentation(state: String): IMetricContainer<String>? = OverrideMetricContainer(state)
},
OVERRIDE_VERSION_IF_NOT_SET {
override fun newMetricContainer(): IMetricContainer<String> = OverrideVersionMetricContainer()
override fun fromStringRepresentation(state: String): IMetricContainer<String>? = OverrideVersionMetricContainer(state)
},
CONCAT {
override fun newMetricContainer(): IMetricContainer<String> = ConcatMetricContainer()
@@ -47,6 +47,8 @@ enum class NumericalMetrics(val type: NumberOverridePolicy, val anonymization: N
NUMBER_OF_SUBPROJECTS(OVERRIDE, RANDOM_10_PERCENT),
STATISTICS_VISIT_ALL_PROJECTS_OVERHEAD(SUM, RANDOM_10_PERCENT),
// User scenarios
// this value is not reported, only time intervals from the previous build are used
@@ -18,11 +18,9 @@ interface AdditiveStatisticsValue<T> : ReportStatisticsValue<T> {
}
interface IStatisticsValuesConsumer {
fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String? = null)
fun report(metric: NumericalMetrics, value: Long, subprojectName: String? = null)
fun report(metric: StringMetrics, value: String, subprojectName: String? = null)
}
}
@@ -23,10 +23,10 @@ enum class StringMetrics(val type: StringOverridePolicy, val anonymization: Stri
MPP_PLATFORMS(CONCAT, SAFE),
// Component versions
LIBRARY_SPRING_VERSION(OVERRIDE, COMPONENT_VERSION),
LIBRARY_VAADIN_VERSION(OVERRIDE, COMPONENT_VERSION),
LIBRARY_GWT_VERSION(OVERRIDE, COMPONENT_VERSION),
LIBRARY_HYBERNATE_VERSION(OVERRIDE, COMPONENT_VERSION),
LIBRARY_SPRING_VERSION(OVERRIDE_VERSION_IF_NOT_SET, COMPONENT_VERSION),
LIBRARY_VAADIN_VERSION(OVERRIDE_VERSION_IF_NOT_SET, COMPONENT_VERSION),
LIBRARY_GWT_VERSION(OVERRIDE_VERSION_IF_NOT_SET, COMPONENT_VERSION),
LIBRARY_HIBERNATE_VERSION(OVERRIDE_VERSION_IF_NOT_SET, COMPONENT_VERSION),
KOTLIN_COMPILER_VERSION(OVERRIDE, COMPONENT_VERSION),
KOTLIN_STDLIB_VERSION(OVERRIDE, COMPONENT_VERSION),
@@ -39,9 +39,4 @@ enum class StringMetrics(val type: StringOverridePolicy, val anonymization: Stri
// Features
KOTLIN_LANGUAGE_VERSION(OVERRIDE, COMPONENT_VERSION),
KOTLIN_API_VERSION(OVERRIDE, COMPONENT_VERSION),
}
@@ -5,25 +5,21 @@
package org.jetbrains.kotlin.statistics
import com.sun.javafx.font.Metrics
import org.jetbrains.kotlin.statistics.BuildSessionLogger.Companion.STATISTICS_FILE_NAME_PATTERN
import org.jetbrains.kotlin.statistics.BuildSessionLogger.Companion.listProfileFiles
import org.jetbrains.kotlin.statistics.fileloggers.MetricsContainer
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics
import org.jetbrains.kotlin.statistics.metrics.OverrideMetricContainer
import org.jetbrains.kotlin.statistics.metrics.StringMetrics
import org.junit.After
import org.junit.Before
import java.io.File
import java.lang.IllegalStateException
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlin.test.fail
import kotlin.test.*
class BuildSessionLoggerTest {
lateinit var rootFolder: File
private lateinit var rootFolder: File
private fun statFilesCount() = rootFolder.listFiles().single().listFiles().size
@@ -74,7 +70,6 @@ class BuildSessionLoggerTest {
val logger = BuildSessionLogger(rootFolder, 100, maxFileSize.toLong())
logger.startBuildSession(0, null)
logger.finishBuildSession("", null)
logger.unlockJournalFile()
assertEquals(1, statFilesCount())
@@ -82,7 +77,6 @@ class BuildSessionLoggerTest {
logger.startBuildSession(0, 0)
logger.finishBuildSession("", null)
logger.unlockJournalFile()
//new file should not be created
assertEquals(1, statFilesCount())
@@ -90,7 +84,6 @@ class BuildSessionLoggerTest {
logger.startBuildSession(0, 0)
logger.finishBuildSession("", null)
logger.unlockJournalFile()
// a new file should be created as maximal file size
assertEquals(2, statFilesCount())
@@ -102,7 +95,6 @@ class BuildSessionLoggerTest {
val logger = BuildSessionLogger(rootFolder, maxFiles)
logger.startBuildSession(0, null)
logger.finishBuildSession("", null)
logger.unlockJournalFile()
assertEquals(1, statFilesCount())
val statsFolder = rootFolder.listFiles().single()
@@ -116,7 +108,6 @@ class BuildSessionLoggerTest {
logger.startBuildSession(0, 0)
logger.finishBuildSession("", null)
logger.unlockJournalFile()
assertTrue(
statsFolder.listFiles().filter { it.name == singleStatFile.name }.count() == 1,
@@ -135,6 +126,10 @@ class BuildSessionLoggerTest {
statsFolder.listFiles().filter { it.name.matches(STATISTICS_FILE_NAME_PATTERN.toRegex()) }.count(),
"Some files which should not be affected, were removed"
)
assertEquals(
statsFolder.listFiles().filter { it.name.matches(STATISTICS_FILE_NAME_PATTERN.toRegex()) }.sorted(),
listProfileFiles(statsFolder)
)
}
@Test
@@ -142,10 +137,9 @@ class BuildSessionLoggerTest {
val logger = BuildSessionLogger(rootFolder)
logger.report(StringMetrics.KOTLIN_COMPILER_VERSION, "1.2.3.4-snapshot")
val startTime = System.currentTimeMillis() - 1000
val startTime = System.currentTimeMillis() - 1001
logger.startBuildSession(1, startTime)
logger.finishBuildSession("Build", null)
logger.unlockJournalFile()
assertEquals(1, statFilesCount())
val statFile = rootFolder.listFiles().single().listFiles().single()
@@ -165,7 +159,6 @@ class BuildSessionLoggerTest {
logger.finishBuildSession("", null)
logger.unlockJournalFile()
val metrics = ArrayList<MetricsContainer>()
MetricsContainer.readFromFile(statFile) {
@@ -186,4 +179,33 @@ class BuildSessionLoggerTest {
val buildDuration = metrics[0].getMetric(NumericalMetrics.GRADLE_BUILD_DURATION)?.getValue() ?: 0L
assertTrue(buildDuration > 1000, "It was expected that build duration is > 1000, but got $buildDuration")
}
@Test
fun testSaveAndReadAllMetrics() {
val logger = BuildSessionLogger(rootFolder)
logger.startBuildSession(1, 1)
for (metric in StringMetrics.values()) {
logger.report(metric, "value")
logger.report(metric, metric.name)
}
for (metric in BooleanMetrics.values()) {
logger.report(metric, true)
}
for (metric in NumericalMetrics.values()) {
logger.report(metric, System.currentTimeMillis())
}
logger.finishBuildSession("Build", null)
MetricsContainer.readFromFile(rootFolder.listFiles().single().listFiles().single()) {
for (metric in StringMetrics.values()) {
assertNotNull(it.getMetric(metric), "Could not find metric ${metric.name}")
}
for (metric in BooleanMetrics.values()) {
assertTrue(it.getMetric(metric)?.getValue() ?: false, "Could not find metric ${metric.name}")
}
for (metric in NumericalMetrics.values()) {
assertNotNull(it.getMetric(metric), "Could not find metric ${metric.name}")
}
}
}
}