Skip to content

Commit 02e4b1b

Browse files
Merge pull request #1335 from digma-ai/feauture/performance-anomaly-highlight
Add Performance Anomaly highlight card
2 parents f582f1a + 919449c commit 02e4b1b

File tree

7 files changed

+240
-1
lines changed

7 files changed

+240
-1
lines changed

src/components/Highlights/TopIssues/HighlightCardRenderer/index.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
isEndpointSpanNPlusOneHighlight,
99
isHotSpotHighlight,
1010
isSpanEndpointBottleneckHighlight,
11+
isSpanPerformanceAnomalyHighlight,
1112
isSpaNPlusOneHighlight,
1213
isSpanQueryOptimizationHighlight,
1314
isSpanScalingHighlight
@@ -21,6 +22,7 @@ import { EndpointSlowdownSourceHighlightCard } from "../highlightCards/EndpointS
2122
import { EndpointSpanNPlusOneHighlightCard } from "../highlightCards/EndpointSpanNPlusOneHighlightCard";
2223
import { HotSpotHighlightCard } from "../highlightCards/HotSpotHighlightCard";
2324
import { SpanEndpointBottleneckHighlightCard } from "../highlightCards/SpanEndpointBottleneckHighlightCard";
25+
import { SpanPerformanceAnomalyHighlightCard } from "../highlightCards/SpanPerformanceAnomalyHighlightCard";
2426
import { SpaNPlusOneHighlightCard } from "../highlightCards/SpaNPlusOneHighlightCard";
2527
import { SpanQueryOptimizationHighlightCard } from "../highlightCards/SpanQueryOptimizationHighlightCard";
2628
import { SpanScalingHighlightCard } from "../highlightCards/SpanScalingHighlightCard";
@@ -76,4 +78,8 @@ export const HighlightCardRenderer = ({
7678
if (isSpanScalingHighlight(highlight)) {
7779
return <SpanScalingHighlightCard data={highlight} />;
7880
}
81+
82+
if (isSpanPerformanceAnomalyHighlight(highlight)) {
83+
return <SpanPerformanceAnomalyHighlightCard data={highlight} />;
84+
}
7985
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
import { SpanPerformanceAnomalyHighlightCard } from ".";
3+
import { mockedSpanPerformanceAnomalyHighlightData } from "./mockData";
4+
5+
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
6+
const meta: Meta<typeof SpanPerformanceAnomalyHighlightCard> = {
7+
title:
8+
"Highlights/TopIssues/highlightCards/SpanPerformanceAnomalyHighlightCard",
9+
component: SpanPerformanceAnomalyHighlightCard,
10+
parameters: {
11+
// More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
12+
layout: "fullscreen"
13+
}
14+
};
15+
16+
export default meta;
17+
18+
type Story = StoryObj<typeof meta>;
19+
20+
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
21+
22+
export const Default: Story = {
23+
args: {
24+
data: mockedSpanPerformanceAnomalyHighlightData
25+
}
26+
};
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import type { Row } from "@tanstack/react-table";
2+
import { createColumnHelper } from "@tanstack/react-table";
3+
import type {
4+
EnvironmentData,
5+
SpanPerformanceAnomalyMetrics
6+
} from "../../../../../redux/services/types";
7+
import { useConfigSelector } from "../../../../../store/config/useConfigSelector";
8+
import { ScopeChangeEvent } from "../../../../../types";
9+
import { sendUserActionTrackingEvent } from "../../../../../utils/actions/sendUserActionTrackingEvent";
10+
import { getDurationString } from "../../../../../utils/getDurationString";
11+
import { roundTo } from "../../../../../utils/roundTo";
12+
import { Tag } from "../../../../common/v3/Tag";
13+
import { Table } from "../../../common/Table";
14+
import { TableText } from "../../../common/TableText";
15+
import { handleEnvironmentTableRowClick } from "../../../handleEnvironmentTableRowClick";
16+
import { trackingEvents } from "../../../tracking";
17+
import { HighlightCard } from "../../common/HighlightCard";
18+
import { addEnvironmentColumns } from "../addEnvironmentColumns";
19+
import type { SpanPerformanceAnomalyHighlightCardProps } from "./types";
20+
21+
export const SpanPerformanceAnomalyHighlightCard = ({
22+
data
23+
}: SpanPerformanceAnomalyHighlightCardProps) => {
24+
const { scope, environments } = useConfigSelector();
25+
26+
const columnHelper =
27+
createColumnHelper<EnvironmentData<SpanPerformanceAnomalyMetrics>>();
28+
29+
const metricsColumns = [
30+
columnHelper.accessor((x) => x.metrics.find((x) => x.id === "P50"), {
31+
header: "Median",
32+
cell: (info) => {
33+
const metric = info.getValue();
34+
const value = metric ? getDurationString(metric.value) : "";
35+
return metric ? <Tag title={value} content={value} /> : null;
36+
}
37+
}),
38+
columnHelper.accessor((x) => x.metrics.find((x) => x.id === "P95"), {
39+
header: "Slowest 5%",
40+
cell: (info) => {
41+
const metric = info.getValue();
42+
const value = metric ? getDurationString(metric.value) : "";
43+
return metric ? <Tag title={value} content={value} /> : null;
44+
}
45+
}),
46+
columnHelper.accessor(
47+
(x) => x.metrics.find((x) => x.id === "SlowerByPercentage"),
48+
{
49+
header: "The slowest 5% slower than the Median by",
50+
cell: (info) => {
51+
const metric = info.getValue();
52+
const value = metric ? `${String(roundTo(metric.value, 2))}%` : "";
53+
return metric ? <TableText title={value}>{value}</TableText> : null;
54+
}
55+
}
56+
)
57+
];
58+
59+
const columns = addEnvironmentColumns(columnHelper, metricsColumns);
60+
61+
const handleTableRowClick = (
62+
row: Row<EnvironmentData<SpanPerformanceAnomalyMetrics>>
63+
) => {
64+
sendUserActionTrackingEvent(
65+
trackingEvents.TOP_ISSUES_CARD_TABLE_ROW_CLICKED,
66+
{
67+
insightType: data.insightType
68+
}
69+
);
70+
handleEnvironmentTableRowClick(
71+
scope,
72+
environments,
73+
row.original.environmentId,
74+
ScopeChangeEvent.HighlightsTopIssuesCardItemClicked
75+
);
76+
};
77+
78+
return (
79+
<HighlightCard
80+
highlight={data}
81+
content={
82+
<Table<EnvironmentData<SpanPerformanceAnomalyMetrics>>
83+
columns={columns}
84+
data={data.environments}
85+
onRowClick={handleTableRowClick}
86+
/>
87+
}
88+
/>
89+
);
90+
};
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import type {
2+
HighlightData,
3+
SpanPerformanceAnomalyMetrics
4+
} from "../../../../../redux/services/types";
5+
import { InsightType } from "../../../../../types";
6+
import { InsightStatus } from "../../../../Insights/types";
7+
8+
export const mockedSpanPerformanceAnomalyMetrics: SpanPerformanceAnomalyMetrics =
9+
[
10+
{
11+
id: "P50",
12+
value: {
13+
value: 22.71,
14+
unit: "ms",
15+
raw: 22705900.0
16+
}
17+
},
18+
{
19+
id: "P95",
20+
value: {
21+
value: 22.71,
22+
unit: "ms",
23+
raw: 22705900.0
24+
}
25+
},
26+
{
27+
id: "SlowerByPercentage",
28+
value: 50
29+
}
30+
];
31+
32+
export const mockedSpanPerformanceAnomalyHighlightData: HighlightData<SpanPerformanceAnomalyMetrics> =
33+
{
34+
insightType: InsightType.SpanPerformanceAnomaly,
35+
asset: {
36+
name: "spanName",
37+
displayName: "displayName",
38+
instrumentationLibrary: "instrumentationLibrary",
39+
spanCodeObjectId: "spanCodeObjectId",
40+
methodCodeObjectId: "methodCodeObjectId",
41+
kind: "kind"
42+
},
43+
environments: [
44+
{
45+
environmentId: "1",
46+
environmentName: "Dev",
47+
insightStatus: InsightStatus.Active,
48+
insightCriticality: 0.8,
49+
metrics: mockedSpanPerformanceAnomalyMetrics
50+
},
51+
{
52+
environmentId: "2",
53+
environmentName: "Staging",
54+
insightStatus: InsightStatus.Active,
55+
insightCriticality: 0.8,
56+
metrics: mockedSpanPerformanceAnomalyMetrics
57+
},
58+
{
59+
environmentId: "3",
60+
environmentName: "Production",
61+
insightStatus: InsightStatus.Active,
62+
insightCriticality: 0.8,
63+
metrics: mockedSpanPerformanceAnomalyMetrics
64+
},
65+
{
66+
environmentId: "4",
67+
environmentName: "Env1",
68+
insightStatus: InsightStatus.Active,
69+
insightCriticality: 0.8,
70+
metrics: mockedSpanPerformanceAnomalyMetrics
71+
},
72+
{
73+
environmentId: "5",
74+
environmentName: "Env2",
75+
insightStatus: InsightStatus.Active,
76+
insightCriticality: 0.8,
77+
metrics: mockedSpanPerformanceAnomalyMetrics
78+
},
79+
{
80+
environmentId: "6",
81+
environmentName: "Env3",
82+
insightStatus: InsightStatus.Active,
83+
insightCriticality: 0.8,
84+
metrics: mockedSpanPerformanceAnomalyMetrics
85+
}
86+
]
87+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type {
2+
HighlightData,
3+
SpanPerformanceAnomalyMetrics
4+
} from "../../../../../redux/services/types";
5+
6+
export interface SpanPerformanceAnomalyHighlightCardProps {
7+
data: HighlightData<SpanPerformanceAnomalyMetrics>;
8+
}

src/redux/services/typeGuards.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type {
1212
HotSpotMetrics,
1313
SpaNPlusOneMetrics,
1414
SpanEndpointBottleneckMetrics,
15+
SpanPerformanceAnomalyMetrics,
1516
SpanQueryOptimizationMetrics,
1617
SpanScalingMetrics
1718
} from "./types";
@@ -75,3 +76,8 @@ export const isSpanScalingHighlight = (
7576
highlight: HighlightData<GenericMetrics>
7677
): highlight is HighlightData<SpanScalingMetrics> =>
7778
highlight.insightType === InsightType.SpanScaling;
79+
80+
export const isSpanPerformanceAnomalyHighlight = (
81+
highlight: HighlightData<GenericMetrics>
82+
): highlight is HighlightData<SpanPerformanceAnomalyMetrics> =>
83+
highlight.insightType === InsightType.SpanPerformanceAnomaly;

src/redux/services/types.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,21 @@ export type SpanScalingMetrics = [
413413
}
414414
];
415415

416+
export type SpanPerformanceAnomalyMetrics = [
417+
{
418+
id: "P50";
419+
value: Duration;
420+
},
421+
{
422+
id: "P95";
423+
value: Duration;
424+
},
425+
{
426+
id: "SlowerByPercentage";
427+
value: number;
428+
}
429+
];
430+
416431
export type GenericMetrics =
417432
| EndpointBottleneckMetrics
418433
| SpanEndpointBottleneckMetrics
@@ -425,7 +440,8 @@ export type GenericMetrics =
425440
| EndpointSpanNPlusOneMetrics
426441
| SpaNPlusOneMetrics
427442
| HotSpotMetrics
428-
| SpanScalingMetrics;
443+
| SpanScalingMetrics
444+
| SpanPerformanceAnomalyMetrics;
429445

430446
export interface GetTopIssuesHighlightsResponse {
431447
topInsights: HighlightData<GenericMetrics>[];

0 commit comments

Comments
 (0)