diff --git a/ide-common/src/main/java/org/digma/intellij/plugin/insights/view/BuildersHolder.java b/ide-common/src/main/java/org/digma/intellij/plugin/insights/view/BuildersHolder.java index a773531f6..0d908eca7 100644 --- a/ide-common/src/main/java/org/digma/intellij/plugin/insights/view/BuildersHolder.java +++ b/ide-common/src/main/java/org/digma/intellij/plugin/insights/view/BuildersHolder.java @@ -1,7 +1,17 @@ package org.digma.intellij.plugin.insights.view; import org.digma.intellij.plugin.model.InsightType; -import org.digma.intellij.plugin.model.rest.insights.*; +import org.digma.intellij.plugin.model.rest.insights.CodeObjectInsight; +import org.digma.intellij.plugin.model.rest.insights.ErrorInsight; +import org.digma.intellij.plugin.model.rest.insights.HighUsageInsight; +import org.digma.intellij.plugin.model.rest.insights.HotspotInsight; +import org.digma.intellij.plugin.model.rest.insights.LowUsageInsight; +import org.digma.intellij.plugin.model.rest.insights.NormalUsageInsight; +import org.digma.intellij.plugin.model.rest.insights.SlowEndpointInsight; +import org.digma.intellij.plugin.model.rest.insights.SlowestSpansInsight; +import org.digma.intellij.plugin.model.rest.insights.SpanDurationsInsight; +import org.digma.intellij.plugin.model.rest.insights.SpanUsagesInsight; +import org.digma.intellij.plugin.model.rest.insights.UnmappedInsight; import org.digma.intellij.plugin.ui.model.insights.InsightGroupType; import org.digma.intellij.plugin.view.EmptyListViewItemBuilder; import org.digma.intellij.plugin.view.ListViewItemBuilder; @@ -36,7 +46,7 @@ private ListViewItemBuilder newBuilder(InsightType case Errors: return new NoGroupListViewItemBuilder(); case SpanUsages: - return new GroupListViewItemBuilder(InsightGroupType.Span, SpanInsight::getSpan); + return new GroupListViewItemBuilder(InsightGroupType.Span, SpanUsagesInsight::getSpan); case SpanDurations: return new GroupListViewItemBuilder(InsightGroupType.Span, spanDurationsInsight -> spanDurationsInsight.getSpan().getName()); case SlowestSpans: diff --git a/model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/CodeObjectInsight.kt b/model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/CodeObjectInsight.kt index 95e87454c..b0681d945 100644 --- a/model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/CodeObjectInsight.kt +++ b/model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/CodeObjectInsight.kt @@ -17,7 +17,7 @@ import org.digma.intellij.plugin.model.InsightType @JsonSubTypes( JsonSubTypes.Type(value = HotspotInsight::class, name = "HotSpot"), JsonSubTypes.Type(value = ErrorInsight::class, name = "Errors"), - JsonSubTypes.Type(value = SpanInsight::class, name = "SpanUsages"), + JsonSubTypes.Type(value = SpanUsagesInsight::class, name = "SpanUsages"), JsonSubTypes.Type(value = SlowestSpansInsight::class, name = "SlowestSpans"), JsonSubTypes.Type(value = LowUsageInsight::class, name = "LowUsage"), JsonSubTypes.Type(value = NormalUsageInsight::class, name = "NormalUsage"), diff --git a/model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/SpanFlow.kt b/model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/SpanFlow.kt index f537eb242..f16857f21 100644 --- a/model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/SpanFlow.kt +++ b/model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/SpanFlow.kt @@ -7,18 +7,22 @@ import java.beans.ConstructorProperties @JsonIgnoreProperties(ignoreUnknown = true) data class SpanFlow @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) -@ConstructorProperties("percentage", "intermediateSpan", "lastServiceSpan", "firstService", "lastService") -constructor(val percentage: Float, - val intermediateSpan: String?, - val lastServiceSpan: String?, - val firstService: Service?, - val lastService: Service?) { - +@ConstructorProperties("percentage", "intermediateSpan", "lastServiceSpan", "firstService", "lastService", "sampleTraceIds") +constructor( + val percentage: Float, + val intermediateSpan: String?, + val lastServiceSpan: String?, + val firstService: Service?, + val lastService: Service?, + val sampleTraceIds: List, +) { data class Service @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) @ConstructorProperties("service", "span") - constructor(val service: String, - val span: String) + constructor( + val service: String, + val span: String, + ) } \ No newline at end of file diff --git a/model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/SpanInsight.kt b/model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/SpanUsagesInsight.kt similarity index 94% rename from model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/SpanInsight.kt rename to model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/SpanUsagesInsight.kt index b6e4369c5..fcd1fa5ce 100644 --- a/model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/SpanInsight.kt +++ b/model/src/main/kotlin/org/digma/intellij/plugin/model/rest/insights/SpanUsagesInsight.kt @@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonCreator import org.digma.intellij.plugin.model.InsightType import java.beans.ConstructorProperties -data class SpanInsight +data class SpanUsagesInsight @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) @ConstructorProperties("codeObjectId", "span", "flows") constructor( diff --git a/src/main/kotlin/org/digma/intellij/plugin/ui/list/insights/InsightsListCellRenderer.kt b/src/main/kotlin/org/digma/intellij/plugin/ui/list/insights/InsightsListCellRenderer.kt index 596b3f0e5..35506a415 100644 --- a/src/main/kotlin/org/digma/intellij/plugin/ui/list/insights/InsightsListCellRenderer.kt +++ b/src/main/kotlin/org/digma/intellij/plugin/ui/list/insights/InsightsListCellRenderer.kt @@ -4,7 +4,12 @@ import com.intellij.openapi.project.Project import com.intellij.ui.dsl.builder.RightGap import com.intellij.ui.dsl.builder.panel import com.intellij.ui.dsl.gridLayout.HorizontalAlign +import org.digma.intellij.plugin.model.rest.insights.EndpointSchema +import org.digma.intellij.plugin.model.rest.insights.EndpointSchema.Companion.CONSUMER_SCHEMA +import org.digma.intellij.plugin.model.rest.insights.EndpointSchema.Companion.HTTP_SCHEMA +import org.digma.intellij.plugin.model.rest.insights.EndpointSchema.Companion.RPC_SCHEMA import org.digma.intellij.plugin.model.rest.insights.ErrorInsight +import org.digma.intellij.plugin.model.rest.insights.GroupViewModel import org.digma.intellij.plugin.model.rest.insights.HighUsageInsight import org.digma.intellij.plugin.model.rest.insights.HotspotInsight import org.digma.intellij.plugin.model.rest.insights.LowUsageInsight @@ -12,7 +17,7 @@ import org.digma.intellij.plugin.model.rest.insights.NormalUsageInsight import org.digma.intellij.plugin.model.rest.insights.SlowEndpointInsight import org.digma.intellij.plugin.model.rest.insights.SlowestSpansInsight import org.digma.intellij.plugin.model.rest.insights.SpanDurationsInsight -import org.digma.intellij.plugin.model.rest.insights.SpanInsight +import org.digma.intellij.plugin.model.rest.insights.SpanUsagesInsight import org.digma.intellij.plugin.model.rest.insights.UnmappedInsight import org.digma.intellij.plugin.ui.common.CopyableLabelHtml import org.digma.intellij.plugin.ui.common.Laf @@ -20,10 +25,6 @@ import org.digma.intellij.plugin.ui.common.asHtml import org.digma.intellij.plugin.ui.common.span import org.digma.intellij.plugin.ui.common.spanBold import org.digma.intellij.plugin.ui.common.spanGrayed -import org.digma.intellij.plugin.model.rest.insights.* -import org.digma.intellij.plugin.model.rest.insights.EndpointSchema.Companion.CONSUMER_SCHEMA -import org.digma.intellij.plugin.model.rest.insights.EndpointSchema.Companion.HTTP_SCHEMA -import org.digma.intellij.plugin.model.rest.insights.EndpointSchema.Companion.RPC_SCHEMA import org.digma.intellij.plugin.ui.list.AbstractPanelListCellRenderer import org.digma.intellij.plugin.ui.list.PanelsLayoutHelper import org.digma.intellij.plugin.ui.model.insights.InsightGroupType.HttpEndpoint @@ -61,7 +62,7 @@ class InsightsListCellRenderer : AbstractPanelListCellRenderer() { panelsLayoutHelper) is SlowestSpansInsight -> slowestSpansPanel(project, value.modelObject as SlowestSpansInsight, value.moreData, panelsLayoutHelper) - is SpanInsight -> spanPanel(value.modelObject as SpanInsight) + is SpanUsagesInsight -> spanUsagesPanel(project, value.modelObject as SpanUsagesInsight) is SpanDurationsInsight -> spanDurationPanel(project, value.modelObject as SpanDurationsInsight, panelsLayoutHelper) is UnmappedInsight -> unmappedInsightPanel(value.modelObject as UnmappedInsight, @@ -96,7 +97,7 @@ class InsightsListCellRenderer : AbstractPanelListCellRenderer() { } private fun endpointGroupTitle(value: InsightsList.GroupTitleModel): JPanel { - val groupViewModel = createEndpointGroupViewModel(value.groupId); + val groupViewModel = createEndpointGroupViewModel(value.groupId) return groupTitlePanel(groupViewModel.titleText, groupViewModel.labelText,groupViewModel.icon) } @@ -116,7 +117,7 @@ class InsightsListCellRenderer : AbstractPanelListCellRenderer() { } private fun createEndpointGroupViewModel(fullRouteName: String): GroupViewModel{ - val routeInfo = EndpointSchema.getRouteInfo(fullRouteName); + val routeInfo = EndpointSchema.getRouteInfo(fullRouteName) val endpoint = routeInfo.shortName if(routeInfo.schema == HTTP_SCHEMA){ val split =endpoint.split(' ') diff --git a/src/main/kotlin/org/digma/intellij/plugin/ui/list/insights/SpanPanels.kt b/src/main/kotlin/org/digma/intellij/plugin/ui/list/insights/SpanPanels.kt index 0dcea5736..15e334de1 100644 --- a/src/main/kotlin/org/digma/intellij/plugin/ui/list/insights/SpanPanels.kt +++ b/src/main/kotlin/org/digma/intellij/plugin/ui/list/insights/SpanPanels.kt @@ -10,12 +10,13 @@ import com.intellij.ui.dsl.builder.panel import com.intellij.ui.dsl.gridLayout.HorizontalAlign import com.intellij.util.containers.isNullOrEmpty import com.intellij.util.ui.JBUI.Borders.empty +import com.intellij.util.ui.WrapLayout import org.digma.intellij.plugin.analytics.AnalyticsService import org.digma.intellij.plugin.model.rest.insights.SpanDurationsInsight import org.digma.intellij.plugin.model.rest.insights.SpanDurationsPercentile import org.digma.intellij.plugin.model.rest.insights.SpanFlow import org.digma.intellij.plugin.model.rest.insights.SpanInfo -import org.digma.intellij.plugin.model.rest.insights.SpanInsight +import org.digma.intellij.plugin.model.rest.insights.SpanUsagesInsight import org.digma.intellij.plugin.settings.SettingsState import org.digma.intellij.plugin.ui.common.CopyableLabel import org.digma.intellij.plugin.ui.common.CopyableLabelHtml @@ -31,6 +32,7 @@ import org.ocpsoft.prettytime.PrettyTime import org.threeten.extra.AmountFormats import java.awt.BorderLayout import java.awt.Dimension +import java.awt.FlowLayout import java.awt.GridLayout import java.io.InputStreamReader import java.sql.Timestamp @@ -58,29 +60,34 @@ class SpanPanels { } -fun spanPanel(spanInsight: SpanInsight): JPanel { +fun spanUsagesPanel(project: Project, spanUsagesInsight: SpanUsagesInsight): JPanel { val title = JLabel(asHtml(spanBold("Top Usage")), SwingConstants.LEFT) title.isOpaque = false val flowsListPanel = JBPanel>() - flowsListPanel.layout = GridLayout(spanInsight.flows.size, 1, 0, 3) + flowsListPanel.layout = GridLayout(spanUsagesInsight.flows.size, 1, 0, 3) flowsListPanel.border = empty() flowsListPanel.isOpaque = false - spanInsight.flows.forEach { spanFlow: SpanFlow -> + spanUsagesInsight.flows.forEach { spanFlow: SpanFlow -> - val builder = - StringBuilder("${span(String.format("%.1f", spanFlow.percentage))}% " + - "${spanGrayed(spanFlow.firstService?.service.toString())}: " + - " ${span(spanFlow.firstService?.span.toString())}") + val builder = StringBuilder("${span(String.format("%.1f", spanFlow.percentage))}% ") + + var spanName = spanUsagesInsight.span // default, just in case first service is not found + spanFlow.firstService?.let { firstService -> + builder.append(spanGrayed(firstService.service + ": ")) + builder.append(span(firstService.span)) + spanName = firstService.span + } spanFlow.intermediateSpan?.let { intermediateSpan -> builder.append(" ${spanGrayed(ARROW_RIGHT)} ") builder.append(span(intermediateSpan)) } spanFlow.lastService?.let { lastService -> builder.append(" ${spanGrayed(ARROW_RIGHT)} ") - builder.append(span("${lastService.service}: ${lastService.span}")) + builder.append(spanGrayed(lastService.service + ": ")) + builder.append(span(lastService.span)) } spanFlow.lastServiceSpan?.let { lastServiceSpan -> builder.append(" ${spanGrayed(ARROW_RIGHT)} ") @@ -89,7 +96,24 @@ fun spanPanel(spanInsight: SpanInsight): JPanel { val label = CopyableLabelHtml(asHtml(builder.toString())) label.alignmentX = 0.0f - flowsListPanel.add(label) + + var traceSample: TraceSample? = null + spanFlow.sampleTraceIds.firstOrNull()?.let { sampleTraceId -> + traceSample = TraceSample(spanName, sampleTraceId) + } + val buttonToJaeger = buildButtonToJaeger(project, "Trace", spanName, traceSample) + if (buttonToJaeger == null) { + flowsListPanel.add(label) + } else { + val wrapperPanel = JBPanel>() + wrapperPanel.andTransparent() + wrapperPanel.layout = WrapLayout(FlowLayout.LEFT, 3, 3) + wrapperPanel.add(label) + wrapperPanel.add(buttonToJaeger) + + flowsListPanel.add(wrapperPanel) + } + } @@ -193,7 +217,7 @@ fun spanDurationPanel( } val buttonToGraph = buildButtonToPercentilesGraph(project, spanDurationsInsight.span) - val buttonToJaeger = buildButtonToJaeger(project, spanDurationsInsight.span, traceSamples) + val buttonToJaeger = buildButtonToJaeger(project, "Compare", spanDurationsInsight.span.name, traceSamples) val iconPanel = buildIconPanelWithLinks(buttonToGraph, buttonToJaeger) val result = JBPanel>() @@ -226,9 +250,10 @@ fun buildIconPanelWithLinks( return iconPanel } + // if cannot create the button then would return null fun buildButtonToJaeger( - project: Project, spanInfo: SpanInfo, traceSamples: List + project: Project, linkCaption: String, spanName: String, traceSamples: List ): JButton? { val settingsState = SettingsState.getInstance(project) @@ -261,9 +286,9 @@ fun buildButtonToJaeger( .replace("__JAEGER_EMBEDDED_URL__", jaegerUrl) .replace("__CAPTION__", caption) - val editorTitle = "Jaeger sample traces of Span ${spanInfo.name}" + val editorTitle = "Jaeger sample traces of Span ${spanName}" - val button = ActionLink("Compare") + val button = ActionLink(linkCaption) button.addActionListener { HTMLEditorProvider.openEditor(project, editorTitle, htmlContent) } @@ -271,6 +296,16 @@ fun buildButtonToJaeger( return button } +// if cannot create the button then would return null +fun buildButtonToJaeger( + project: Project, linkCaption: String, spanName: String, traceSample: TraceSample? +): JButton? { + if (traceSample == null) { + return null + } + return buildButtonToJaeger(project, linkCaption, spanName, listOf(traceSample)) +} + fun buildButtonToPercentilesGraph(project: Project, span: SpanInfo): ActionLink { val analyticsService = AnalyticsService.getInstance(project) val button = ActionLink("Histogram")