Provide method for extracting startup metrics

GitOrigin-RevId: 723e10d55e4128785ad46f266995934cbcd76231
This commit is contained in:
Maxim.Kolmakov
2023-11-08 17:59:01 +01:00
committed by intellij-monorepo-bot
parent f8f5f0df90
commit 8bf1ee0f74
5 changed files with 60 additions and 4 deletions

View File

@@ -7,7 +7,7 @@ import com.intellij.tools.ide.util.common.withRetry
import java.io.File
import kotlin.time.Duration.Companion.milliseconds
class OpentelemetryJsonParser(private val spanFilter: SpanFilter) {
open class OpentelemetryJsonParser(private val spanFilter: SpanFilter) {
private fun getSpans(file: File): JsonNode {
val spanData: JsonNode? = withRetry(messageOnFailure = "Failure during spans extraction from OpenTelemetry json file",
@@ -58,7 +58,7 @@ class OpentelemetryJsonParser(private val spanFilter: SpanFilter) {
return result.asSequence()
}
private fun processChild(result: MutableSet<SpanElement>, parent: SpanElement, index: Map<String, Collection<SpanElement>>) {
protected open fun processChild(result: MutableSet<SpanElement>, parent: SpanElement, index: Map<String, Collection<SpanElement>>) {
index[parent.spanId]?.forEach {
if (parent.isWarmup) {
it.isWarmup = true

View File

@@ -0,0 +1,17 @@
package com.intellij.tools.ide.metrics.collector.telemetry
class OpentelemetryJsonParserWithChildrenFiltering(spanFilter: SpanFilter, private val childFilter: SpanFilter) : OpentelemetryJsonParser(spanFilter){
override fun processChild(result: MutableSet<SpanElement>, parent: SpanElement, index: Map<String, Collection<SpanElement>>) {
index[parent.spanId]?.forEach {
if (parent.isWarmup) {
it.isWarmup = true
}
if (!childFilter.filter(it)) {
return@forEach
}
result.add(it)
processChild(result, it, index)
}
}
}

View File

@@ -86,6 +86,27 @@ fun getSpansMetricsMap(file: File,
return spanToMetricMap
}
fun getMetricsForStartup(file: File): List<Metric> {
val spansToPublish = listOf("bootstrap", "startApplication", "ProjectImpl container")
val spansSuffixesToIgnore = listOf(": scheduled", ": completing")
val filter = SpanFilter.containsIn(spansToPublish)
val childFilter = SpanFilter { span -> spansSuffixesToIgnore.none { span.name.endsWith(it) } }
val spanElements = OpentelemetryJsonParserWithChildrenFiltering(filter, childFilter).getSpanElements(file)
val startTime = spanElements.first { it.name == "bootstrap" }.startTimestamp
val spansWithoutDuplicatedNames = spanElements.groupBy { it.name }.filter { it.value.size == 1 }.flatMap { it.value }
val metricSpanProcessor = MetricSpanProcessor()
val spanToMetricMap = spansWithoutDuplicatedNames.mapNotNull { metricSpanProcessor.process(it) }.groupBy { it.metric.id.name }
val spanElementsWithoutRoots = spansWithoutDuplicatedNames.filterNot { it.name in spansToPublish }
val startMetrics = spanElementsWithoutRoots.map { span -> Metric(Duration(span.name + ".start"), span.startTimestamp - startTime) }
val endMetrics = spanElementsWithoutRoots.map { span ->
Metric(Duration(span.name + ".end"), span.startTimestamp - startTime + span.duration)
}
return combineMetrics(spanToMetricMap) + startMetrics + endMetrics
}
private fun combineMetrics(metrics: Map<String, List<MetricWithAttributes>>): List<Metric> {
val result = mutableListOf<Metric>()
metrics.forEach { entry ->

File diff suppressed because one or more lines are too long

View File

@@ -3,11 +3,14 @@ package com.intellij.tools.ide.metrics.collector
import com.intellij.tools.ide.metrics.collector.metrics.PerformanceMetrics.Metric
import com.intellij.tools.ide.metrics.collector.metrics.PerformanceMetrics.MetricId.Counter
import com.intellij.tools.ide.metrics.collector.metrics.PerformanceMetrics.MetricId.Duration
import com.intellij.tools.ide.metrics.collector.telemetry.getMetricsBasedOnDiffBetweenSpans
import com.intellij.tools.ide.metrics.collector.telemetry.getMetricsFromSpanAndChildren
import com.intellij.tools.ide.metrics.collector.telemetry.SpanFilter
import com.intellij.tools.ide.metrics.collector.telemetry.getMetricsBasedOnDiffBetweenSpans
import com.intellij.tools.ide.metrics.collector.telemetry.getMetricsForStartup
import com.intellij.tools.ide.metrics.collector.telemetry.getMetricsFromSpanAndChildren
import io.kotest.matchers.collections.shouldContain
import io.kotest.matchers.collections.shouldContainAll
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder
import io.kotest.matchers.collections.shouldHaveSize
import org.junit.jupiter.api.Test
import java.nio.file.Paths
import kotlin.io.path.div
@@ -19,6 +22,20 @@ class OpenTelemetryTest {
Paths.get(this::class.java.classLoader.getResource("opentelemetry")!!.toURI())
}
@Test
fun startupMetricsCollected(){
val file = (openTelemetryReports / "startup.json").toFile()
val result = getMetricsForStartup(file)
result.shouldHaveSize(560)
result.shouldContain(Metric(Duration("bootstrap"), 58))
result.shouldContain(Metric(Duration("startApplication"), 3036))
result.shouldContain(Metric(Duration("status bar pre-init"), 136))
result.shouldContain(Metric(Duration("status bar pre-init.start"), 1584))
result.shouldContain(Metric(Duration("status bar pre-init.end"), 1584 + 136))
result.filter { it.id.name.contains(": scheduling") }.shouldHaveSize(0)
result.filter { it.id.name.contains(": completing") }.shouldHaveSize(0)
}
@Test
fun testContainsInFilter() {
val spanNames = listOf("%findUsages", "run activity")