Skip to content

Commit c2901d3

Browse files
authored
Feature/root cause spans (#289)
* RootCauseSpan * remove redundant commas * additional data to the ScalingInsight #247 * Add a "Histogram" button in the bottom of the SpanScalingInsight block * add spanInstrumentationLibrary to SpanScalingInsight * Revert "remove redundant commas" This reverts commit 1b40172.
1 parent 4085528 commit c2901d3

File tree

5 files changed

+135
-12
lines changed

5 files changed

+135
-12
lines changed

ide-common/src/main/java/org/digma/intellij/plugin/insights/view/GroupListViewItemBuilder.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,23 @@ public List<ListViewItem<?>> build(Project project, T insight, ListGroupManager
4444
WorkspaceUrisHelper.findWorkspaceUrisForSpans(project,theListView, getSpanIds((SpanDurationBreakdownInsight) insight), insight.getCodeObjectId());
4545
break;
4646
}
47+
case SpanScaling:{
48+
WorkspaceUrisHelper.findWorkspaceUrisForSpans(project,theListView, getSpanIds((SpanScalingInsight) insight), insight.getCodeObjectId());
49+
break;
50+
}
4751
}
4852

4953
theGroup.addItem(theListView);
5054

5155
return List.of();
5256
}
5357

58+
private List<String> getSpanIds(SpanScalingInsight insight) {
59+
return insight.getRootCauseSpans().stream()
60+
.map(it -> CodeObjectsUtil.createSpanId(it.getInstrumentationLibrary(), it.getName()))
61+
.collect(Collectors.toList());
62+
}
63+
5464
private List<String> getSpanIds(SlowestSpansInsight insight) {
5565
return insight.getSpans().stream()
5666
.map(it -> CodeObjectsUtil.createSpanId(it.getSpanInfo().getInstrumentationLibrary(), it.getSpanInfo().getName()))
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.digma.intellij.plugin.model.rest.insights
2+
3+
import com.fasterxml.jackson.annotation.JsonCreator
4+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
5+
import java.beans.ConstructorProperties
6+
7+
@JsonIgnoreProperties(ignoreUnknown = true)
8+
data class RootCauseSpan
9+
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
10+
@ConstructorProperties("sampleTraceId",
11+
"name",
12+
"displayName",
13+
"instrumentationLibrary",
14+
"serviceName",
15+
"codeObjectId",
16+
"kind")
17+
constructor(val sampleTraceId: String,
18+
val name: String,
19+
val displayName: String,
20+
val instrumentationLibrary: String,
21+
val serviceName: String?,
22+
val codeObjectId: String?,
23+
val kind: String = "Internal")
24+

model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/SpanScalingInsight.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonCreator
44
import org.digma.intellij.plugin.model.InsightType
55
import java.beans.ConstructorProperties
66
import java.util.*
7+
import kotlin.collections.ArrayList
78

89
data class SpanScalingInsight
910
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
@@ -17,10 +18,12 @@ data class SpanScalingInsight
1718
"customStartTime",
1819
"prefixedCodeObjectId",
1920
"spanName",
21+
"spanInstrumentationLibrary",
2022
"turningPointConcurrency",
2123
"maxConcurrency",
2224
"minDuration",
2325
"maxDuration",
26+
"rootCauseSpans"
2427
)
2528
constructor(
2629
override val codeObjectId: String,
@@ -32,10 +35,12 @@ constructor(
3235
override val customStartTime: Date?,
3336
override val prefixedCodeObjectId: String?,
3437
val spanName: String,
38+
val spanInstrumentationLibrary: String,
3539
val turningPointConcurrency: Int,
3640
val maxConcurrency: Int,
3741
val minDuration: Duration,
3842
val maxDuration: Duration,
43+
val rootCauseSpans: List<RootCauseSpan> = ArrayList()
3944
) : CodeObjectInsight {
4045

4146
override val type: InsightType = InsightType.SpanScaling

src/main/kotlin/org/digma/intellij/plugin/ui/list/insights/InsightsListCellRenderer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class InsightsListCellRenderer : AbstractPanelListCellRenderer() {
4848
is SpanDurationBreakdownInsight -> spanDurationBreakdownPanel(project,
4949
value.modelObject as SpanDurationBreakdownInsight, value.moreData)
5050
is SpanSlowEndpointsInsight -> spanSlowEndpointsPanel(project, value.modelObject as SpanSlowEndpointsInsight)
51-
is SpanScalingInsight -> spanScalingListViewItemsPanel(project, value.modelObject as SpanScalingInsight)
51+
is SpanScalingInsight -> spanScalingListViewItemsPanel(project, value.modelObject as SpanScalingInsight, value.moreData)
5252
is UnmappedInsight -> unmappedInsightPanel(project, value.modelObject as UnmappedInsight)
5353
else -> genericPanelForSingleInsight(project, value.modelObject)
5454
}
Lines changed: 95 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,34 @@
11
package org.digma.intellij.plugin.ui.list.insights
22

3+
import com.intellij.openapi.fileEditor.impl.HTMLEditorProvider
34
import com.intellij.openapi.project.Project
4-
import org.digma.intellij.plugin.model.rest.insights.*
5-
import org.digma.intellij.plugin.ui.common.CopyableLabelHtmlWithForegroundColor
6-
import org.digma.intellij.plugin.ui.common.Laf
7-
import org.digma.intellij.plugin.ui.common.asHtml
8-
import org.digma.intellij.plugin.ui.common.spanBold
9-
import javax.swing.Box
10-
import javax.swing.JLabel
11-
import javax.swing.JPanel
12-
13-
fun spanScalingListViewItemsPanel(project: Project, insight: SpanScalingInsight): JPanel {
5+
import com.intellij.ui.components.ActionLink
6+
import com.intellij.ui.components.JBLabel
7+
import com.intellij.util.ui.JBUI.Borders.empty
8+
import com.intellij.util.ui.JBUI.Borders.emptyBottom
9+
import org.apache.commons.lang3.StringUtils
10+
import org.digma.intellij.plugin.analytics.AnalyticsService
11+
import org.digma.intellij.plugin.document.CodeObjectsUtil
12+
import org.digma.intellij.plugin.model.rest.insights.RootCauseSpan
13+
import org.digma.intellij.plugin.model.rest.insights.SpanScalingInsight
14+
import org.digma.intellij.plugin.ui.common.*
15+
import org.digma.intellij.plugin.ui.list.ListItemActionButton
16+
import org.digma.intellij.plugin.ui.list.openWorkspaceFileForSpan
17+
import org.digma.intellij.plugin.ui.model.TraceSample
18+
import java.awt.BorderLayout
19+
import javax.swing.*
20+
21+
fun spanScalingListViewItemsPanel(project: Project, insight: SpanScalingInsight, moreData: HashMap<String, Any>): JPanel {
1422
val scalingPanel = createDefaultBoxLayoutYAxisPanel()
1523
scalingPanel.add(getScalingDescriptionPanel(insight))
1624
scalingPanel.add(getScalingCalculationsPanel(insight))
25+
scalingPanel.border = emptyBottom(2)
26+
27+
if (insight.rootCauseSpans.isNotEmpty()) {
28+
scalingPanel.add(getRootCauseSpansPanel(project,moreData,insight))
29+
}
30+
31+
val buttonToGraph = buildButtonToPercentilesGraph(project, insight.spanName,insight.spanInstrumentationLibrary)
1732

1833
return createInsightPanel(
1934
project = project,
@@ -22,11 +37,68 @@ fun spanScalingListViewItemsPanel(project: Project, insight: SpanScalingInsight)
2237
description = "",
2338
iconsList = listOf(Laf.Icons.Insight.SCALE),
2439
bodyPanel = scalingPanel,
25-
buttons = null,
40+
buttons = listOf(buttonToGraph),
2641
paginationComponent = null
2742
)
2843
}
2944

45+
fun getRootCauseSpansPanel(project: Project, moreData: HashMap<String, Any>, insight: SpanScalingInsight): JPanel {
46+
47+
val rootCauseSpansPanel = createDefaultBoxLayoutYAxisPanel()
48+
49+
val causedByLabel = JLabel("Caused By:")
50+
causedByLabel.horizontalAlignment = SwingConstants.LEFT
51+
val causedByPanel = JPanel(BorderLayout())
52+
causedByPanel.border = empty()
53+
causedByPanel.isOpaque = false
54+
causedByPanel.add(causedByLabel,BorderLayout.WEST)
55+
rootCauseSpansPanel.add(causedByPanel)
56+
57+
insight.rootCauseSpans.let { spans ->
58+
repeat(spans.size) {index ->
59+
rootCauseSpansPanel.add(getRootCauseSpanPanel(project,moreData,spans[index]))
60+
}
61+
}
62+
63+
return rootCauseSpansPanel
64+
}
65+
66+
fun getRootCauseSpanPanel(project: Project, moreData: HashMap<String, Any>, rootCauseSpan: RootCauseSpan): JPanel {
67+
68+
val rootCausePanel = JPanel(BorderLayout())
69+
rootCausePanel.border = empty()
70+
rootCausePanel.isOpaque = false
71+
72+
val normalizedDisplayName = StringUtils.normalizeSpace(rootCauseSpan.displayName)
73+
val spanId = CodeObjectsUtil.createSpanId(rootCauseSpan.instrumentationLibrary, rootCauseSpan.name)
74+
75+
if (moreData.contains(spanId)) {
76+
val link = ActionLink(normalizedDisplayName) {
77+
openWorkspaceFileForSpan(project, moreData, spanId)
78+
}
79+
link.toolTipText = asHtml(spanId)
80+
rootCausePanel.add(link,BorderLayout.CENTER)
81+
}else{
82+
val displayNameLabel = JBLabel(normalizedDisplayName, SwingConstants.TRAILING)
83+
displayNameLabel.toolTipText = asHtml(spanId)
84+
displayNameLabel.horizontalAlignment = SwingConstants.LEFT
85+
rootCausePanel.add(displayNameLabel,BorderLayout.CENTER)
86+
}
87+
88+
val spanName = rootCauseSpan.name
89+
val sampleTraceId = rootCauseSpan.sampleTraceId
90+
val traceSample = TraceSample(spanName, sampleTraceId)
91+
val buttonToJaeger = buildButtonToJaeger(project, "Trace", spanName, listOf(traceSample))
92+
if(buttonToJaeger != null) {
93+
rootCausePanel.add(buttonToJaeger, BorderLayout.EAST)
94+
}
95+
96+
return rootCausePanel
97+
}
98+
99+
100+
101+
30102
private fun getScalingDescriptionPanel(insight: SpanScalingInsight): CopyableLabelHtmlWithForegroundColor {
31103
val description = "Significant performance degradation at ${insight.turningPointConcurrency} executions/second"
32104
return CopyableLabelHtmlWithForegroundColor(description, Laf.Colors.GRAY)
@@ -43,4 +115,16 @@ private fun getScalingCalculationsPanel(insight: SpanScalingInsight): JPanel {
43115
scalingBodyPanel.add(Box.createHorizontalGlue())
44116
scalingBodyPanel.add(durationLabel)
45117
return scalingBodyPanel
118+
}
119+
120+
121+
private fun buildButtonToPercentilesGraph(project: Project, spanName: String,instLibrary: String): JButton {
122+
val analyticsService = AnalyticsService.getInstance(project)
123+
val button = ListItemActionButton("Histogram")
124+
button.addActionListener {
125+
val htmlContent = analyticsService.getHtmlGraphForSpanPercentiles(instLibrary, spanName, Laf.Colors.PLUGIN_BACKGROUND.getHex())
126+
HTMLEditorProvider.openEditor(project, "Percentiles Graph of Span $spanName", htmlContent)
127+
}
128+
129+
return button
46130
}

0 commit comments

Comments
 (0)