Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/components/Insights/common/Info/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { InfoCircleIcon } from "../../../common/icons/InfoCircleIcon";
import { Tooltip } from "../../../common/v3/Tooltip";
import * as s from "./styles";

export const Info = (props: { text: string; name: string }) => (
<Tooltip title={props.text}>
<s.InfoContainer>
<div>{props.name}</div>
<InfoCircleIcon color={"currentColor"} size={12} />
</s.InfoContainer>
</Tooltip>
);
7 changes: 7 additions & 0 deletions src/components/Insights/common/Info/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import styled from "styled-components";

export const InfoContainer = styled.div`
display: flex;
gap: 4px;
align-items: center;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Meta, StoryObj } from "@storybook/react";
import { EndpointBottleneckInsight } from ".";
import { mockedSpanBottleneckInsight } from "./mockData";

// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta<typeof EndpointBottleneckInsight> = {
title: "Insights/common/insights/EndpointBottleneckInsight",
component: EndpointBottleneckInsight,
parameters: {
// More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
layout: "fullscreen"
}
};

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
insight: mockedSpanBottleneckInsight
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { getDurationString } from "../../../../../utils/getDurationString";
import { roundTo } from "../../../../../utils/roundTo";
import { sendTrackingEvent } from "../../../../../utils/sendTrackingEvent";
import { trackingEvents } from "../../../tracking";
import { Info } from "../../Info";
import { InsightCard } from "../../InsightCard";
import { ColumnsContainer } from "../../InsightCard/ColumnsContainer";
import { KeyValue } from "../../InsightCard/KeyValue";
import { ContentContainer, Description, Details } from "../styles";
import * as s from "./styles";
import { EndpointBottleneckInsightProps } from "./types";

export const EndpointBottleneckInsight = (
props: EndpointBottleneckInsightProps
) => {
const { insight } = props;
const { span, ticketLink } = insight;

const handleSpanLinkClick = (spanCodeObjectId: string) => {
props.onAssetLinkClick(spanCodeObjectId, insight.type);
};

const handleTicketInfoButtonClick = (
spanCodeObjectId: string,
event: string
) => {
sendTrackingEvent(trackingEvents.JIRA_TICKET_INFO_BUTTON_CLICKED, {
insightType: insight.type
});
props.onJiraTicketCreate &&
props.onJiraTicketCreate(insight, spanCodeObjectId, event);
};

const spanName = span.spanInfo.displayName;
const spanCodeObjectId = span.spanInfo.spanCodeObjectId;

return (
<InsightCard
insight={insight}
jiraTicketInfo={{
isHintEnabled: props.isJiraHintEnabled,
spanCodeObjectId: props.insight.spanInfo?.spanCodeObjectId,
ticketLink
}}
content={
<ContentContainer>
<Details>
<Description>Asset</Description>
<s.SpanListItem
name={spanName}
key={spanName}
onClick={() => handleSpanLinkClick(spanCodeObjectId)}
/>
</Details>
<ColumnsContainer>
<KeyValue label={"% of Duration"}>
{roundTo(span.probabilityOfBeingBottleneck * 100, 2)}%
</KeyValue>
<KeyValue
label={
<Info
text="The amount of requests affected by this issue."
name="Requests"
/>
}
>
{span.requestPercentage}%
</KeyValue>
<KeyValue label={"Duration"}>
{getDurationString(span.avgDurationWhenBeingBottleneck)}
</KeyValue>
</ColumnsContainer>
</ContentContainer>
}
onRecalculate={props.onRecalculate}
onRefresh={props.onRefresh}
onJiraButtonClick={handleTicketInfoButtonClick}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import {
EndpointBottleneckInsight,
InsightCategory,
InsightScope,
InsightType
} from "../../../types";

export const mockedSpanBottleneckInsight: EndpointBottleneckInsight = {
sourceSpanCodeObjectInsight: "sourceSpanCodeObjectInsightId",
id: "60b55792-8262-4c5d-9628-7dce7979ad6d",
firstDetected: "2023-12-05T17:25:47.010Z",
lastDetected: "2024-01-05T13:14:47.010Z",
criticality: 0.7,
firstCommitId: "b3f7b3f",
lastCommitId: "a1b2c3d",
deactivatedCommitId: null,
reopenCount: 0,
ticketLink: null,
impact: 0,
name: "Bottleneck Detected",
type: InsightType.EndpointBottleneck,
category: InsightCategory.Performance,
specifity: 3,
importance: 2,
span: {
spanInfo: {
name: "DelayAsync",
displayName: "DelayAsync",
instrumentationLibrary: "SampleInsightsController",
spanCodeObjectId: "span:SampleInsightsController$_$DelayAsync",
methodCodeObjectId: null,
kind: "Internal",
codeObjectId: null
},
probabilityOfBeingBottleneck: 0.6923076923076923,
avgDurationWhenBeingBottleneck: {
value: 2,
unit: "sec",
raw: 2002883447.4474475
},
criticality: 0,
ticketLink: "https://digma.ai/1",
requestPercentage: 90,
p50: {
fraction: 0,
maxDuration: {
value: 0,
unit: "ns",
raw: 0
}
},
p95: {
fraction: 0,
maxDuration: {
value: 0,
unit: "ns",
raw: 0
}
},
p99: {
fraction: 0,
maxDuration: {
value: 0,
unit: "ns",
raw: 0
}
}
},
scope: InsightScope.EntrySpan,
endpointSpan: "HTTP GET SampleInsights/lock/{milisec}",
spanCodeObjectId:
"span:OpenTelemetry.Instrumentation.AspNetCore$_$HTTP GET SampleInsights/lock/{milisec}",
route: "epHTTP:HTTP GET SampleInsights/lock/{milisec}",
serviceName: "Sample.MoneyTransfer.API",
spanInfo: {
name: "HTTP GET SampleInsights/lock/{milisec}",
displayName: "HTTP GET SampleInsights/lock/{milisec}",
instrumentationLibrary: "OpenTelemetry.Instrumentation.AspNetCore",
spanCodeObjectId:
"span:OpenTelemetry.Instrumentation.AspNetCore$_$HTTP GET SampleInsights/lock/{milisec}",
methodCodeObjectId:
"method:Sample.MoneyTransfer.API.Controllers.SampleInsightsController$_$Lock(Double)",
kind: "Server",
codeObjectId:
"Sample.MoneyTransfer.API.Controllers.SampleInsightsController$_$Lock(Double)"
},
shortDisplayInfo: {
title: "",
targetDisplayName: "HTTP GET SampleInsights/lock/{milisec}",
subtitle: "2 spans",
description: "WaitForLock 4.58 sec"
},
codeObjectId:
"Sample.MoneyTransfer.API.Controllers.SampleInsightsController$_$Lock(Double)",
decorators: null,
environment: "BOB-LAPTOP[LOCAL]",
severity: 0,
isRecalculateEnabled: true,
prefixedCodeObjectId:
"method:Sample.MoneyTransfer.API.Controllers.SampleInsightsController$_$Lock(Double)",
customStartTime: null,
actualStartTime: "2023-06-16T11:10:30.349Z"
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import styled from "styled-components";
import { ListItem } from "../../InsightCard/ListItem";

export const SpanListItem = styled(ListItem)`
padding: 4px;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {
EndpointBottleneckInsight,
InsightProps,
InsightType
} from "../../../types";

export interface EndpointBottleneckInsightProps extends InsightProps {
insight: EndpointBottleneckInsight;
onAssetLinkClick: (
spanCodeObjectId: string,
insightType: InsightType
) => void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import { useContext } from "react";
import { getDurationString } from "../../../../../utils/getDurationString";
import { sendTrackingEvent } from "../../../../../utils/sendTrackingEvent";
import { ConfigContext } from "../../../../common/App/ConfigContext";
import { InfoCircleIcon } from "../../../../common/icons/InfoCircleIcon";
import { Tooltip } from "../../../../common/v3/Tooltip";
import { trackingEvents } from "../../../tracking";
import { InsightType, Trace } from "../../../types";
import { Info } from "../../Info";
import { InsightCard } from "../../InsightCard";
import { ColumnsContainer } from "../../InsightCard/ColumnsContainer";
import { KeyValue } from "../../InsightCard/KeyValue";
Expand Down Expand Up @@ -81,14 +80,10 @@ export const EndpointNPlusOneInsight = (
<KeyValue label={"Repeats"}>{span.occurrences}</KeyValue>
<KeyValue
label={
<Tooltip
title={"The amount of requests affected by this issue."}
>
<s.InfoContainer>
<div>Requests</div>
<InfoCircleIcon color={"currentColor"} size={12} />
</s.InfoContainer>
</Tooltip>
<Info
text="The amount of requests affected by this issue."
name="Requests"
/>
}
>
{span.requestPercentage}%
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Meta, StoryObj } from "@storybook/react";
import { SpanBottleneckEndpoints } from ".";
import { mockedBottleneckInsight } from "../../../BottleneckInsight/mockData";

// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta<typeof SpanBottleneckEndpoints> = {
title: "Insights/common/insights/SpanBottleneckEndpoints",
component: SpanBottleneckEndpoints,
parameters: {
// More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
layout: "fullscreen"
}
};

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
insight: {
...mockedBottleneckInsight,
slowEndpoints: [
...mockedBottleneckInsight.slowEndpoints,
{
...mockedBottleneckInsight.slowEndpoints[0],
requestPercentage: 100,
endpointInfo: {
...mockedBottleneckInsight.slowEndpoints[0].endpointInfo,
route: `${mockedBottleneckInsight.slowEndpoints[0].endpointInfo.route}1`,
spanCodeObjectId: `${mockedBottleneckInsight.slowEndpoints[0].endpointInfo.spanCodeObjectId}1`
}
}
]
}
}
};

export const WithoutInsight: Story = {};

export const WithNoSlowEndpoints: Story = {
args: {
insight: {
...mockedBottleneckInsight,
slowEndpoints: []
}
}
};
Loading