mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 16:28:59 +08:00
chore: added kakfa analytics (#7127)
This commit is contained in:
parent
e86c7c970a
commit
1f52139ed3
@ -2,6 +2,7 @@
|
|||||||
import '../MQDetails.style.scss';
|
import '../MQDetails.style.scss';
|
||||||
|
|
||||||
import { Table, Typography } from 'antd';
|
import { Table, Typography } from 'antd';
|
||||||
|
import logEvent from 'api/common/logEvent';
|
||||||
import { MessagingQueueServicePayload } from 'api/messagingQueues/getConsumerLagDetails';
|
import { MessagingQueueServicePayload } from 'api/messagingQueues/getConsumerLagDetails';
|
||||||
import { getKafkaSpanEval } from 'api/messagingQueues/getKafkaSpanEval';
|
import { getKafkaSpanEval } from 'api/messagingQueues/getKafkaSpanEval';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
@ -15,7 +16,7 @@ import {
|
|||||||
MessagingQueuesViewType,
|
MessagingQueuesViewType,
|
||||||
RowData,
|
RowData,
|
||||||
} from 'pages/MessagingQueues/MessagingQueuesUtils';
|
} from 'pages/MessagingQueues/MessagingQueuesUtils';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useMutation } from 'react-query';
|
import { useMutation } from 'react-query';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
@ -93,6 +94,9 @@ export function getColumns(
|
|||||||
className="traceid-text"
|
className="traceid-text"
|
||||||
onClick={(): void => {
|
onClick={(): void => {
|
||||||
window.open(`${ROUTES.TRACE}/${item}`, '_blank');
|
window.open(`${ROUTES.TRACE}/${item}`, '_blank');
|
||||||
|
logEvent(`MQ Kafka: Drop Rate - traceid navigation`, {
|
||||||
|
item,
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{item}
|
{item}
|
||||||
@ -227,6 +231,22 @@ function DropRateView(): JSX.Element {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [minTime, maxTime, evaluationTime]);
|
}, [minTime, maxTime, evaluationTime]);
|
||||||
|
|
||||||
|
const prevTableDataRef = useRef<string>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (tableData.length > 0) {
|
||||||
|
const currentTableData = JSON.stringify(tableData);
|
||||||
|
|
||||||
|
if (currentTableData !== prevTableDataRef.current) {
|
||||||
|
logEvent(`MQ Kafka: Drop Rate View`, {
|
||||||
|
dataRender: tableData.length,
|
||||||
|
});
|
||||||
|
prevTableDataRef.current = currentTableData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [JSON.stringify(tableData)]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cx('mq-overview-container', 'droprate-view')}>
|
<div className={cx('mq-overview-container', 'droprate-view')}>
|
||||||
<div className="mq-overview-title">
|
<div className="mq-overview-title">
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import './MQTables.styles.scss';
|
import './MQTables.styles.scss';
|
||||||
|
|
||||||
import { Skeleton, Table, Typography } from 'antd';
|
import { Skeleton, Table, Typography } from 'antd';
|
||||||
|
import logEvent from 'api/common/logEvent';
|
||||||
import {
|
import {
|
||||||
MessagingQueueServicePayload,
|
MessagingQueueServicePayload,
|
||||||
MessagingQueuesPayloadProps,
|
MessagingQueuesPayloadProps,
|
||||||
@ -23,11 +24,12 @@ import {
|
|||||||
MessagingQueueServiceDetailType,
|
MessagingQueueServiceDetailType,
|
||||||
MessagingQueuesViewType,
|
MessagingQueuesViewType,
|
||||||
MessagingQueuesViewTypeOptions,
|
MessagingQueuesViewTypeOptions,
|
||||||
|
ProducerLatencyOptions,
|
||||||
RowData,
|
RowData,
|
||||||
SelectedTimelineQuery,
|
SelectedTimelineQuery,
|
||||||
setConfigDetail,
|
setConfigDetail,
|
||||||
} from 'pages/MessagingQueues/MessagingQueuesUtils';
|
} from 'pages/MessagingQueues/MessagingQueuesUtils';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useMutation } from 'react-query';
|
import { useMutation } from 'react-query';
|
||||||
import { useHistory, useLocation } from 'react-router-dom';
|
import { useHistory, useLocation } from 'react-router-dom';
|
||||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||||
@ -130,6 +132,7 @@ function MessagingQueuesTable({
|
|||||||
tableApi,
|
tableApi,
|
||||||
validConfigPresent = false,
|
validConfigPresent = false,
|
||||||
type = 'Detail',
|
type = 'Detail',
|
||||||
|
option = ProducerLatencyOptions.Producers,
|
||||||
}: {
|
}: {
|
||||||
currentTab?: MessagingQueueServiceDetailType;
|
currentTab?: MessagingQueueServiceDetailType;
|
||||||
selectedView: MessagingQueuesViewTypeOptions;
|
selectedView: MessagingQueuesViewTypeOptions;
|
||||||
@ -141,6 +144,7 @@ function MessagingQueuesTable({
|
|||||||
>;
|
>;
|
||||||
validConfigPresent?: boolean;
|
validConfigPresent?: boolean;
|
||||||
type?: 'Detail' | 'Overview';
|
type?: 'Detail' | 'Overview';
|
||||||
|
option?: ProducerLatencyOptions;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const [columns, setColumns] = useState<any[]>([]);
|
const [columns, setColumns] = useState<any[]>([]);
|
||||||
const [tableData, setTableData] = useState<any[]>([]);
|
const [tableData, setTableData] = useState<any[]>([]);
|
||||||
@ -262,6 +266,43 @@ function MessagingQueuesTable({
|
|||||||
configDetailQueryData?.topic || ''
|
configDetailQueryData?.topic || ''
|
||||||
} ${configDetailQueryData?.partition || ''}`;
|
} ${configDetailQueryData?.partition || ''}`;
|
||||||
|
|
||||||
|
const prevTableDataRef = useRef<string>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (tableData.length > 0 && type === 'Overview') {
|
||||||
|
const currentTableData = JSON.stringify(tableData);
|
||||||
|
|
||||||
|
if (currentTableData !== prevTableDataRef.current) {
|
||||||
|
logEvent(`MQ Kafka: ${MessagingQueuesViewType[selectedView].label}`, {
|
||||||
|
dataRender: tableData.length,
|
||||||
|
});
|
||||||
|
prevTableDataRef.current = currentTableData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [option, JSON.stringify(tableData), selectedView]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (tableData.length > 0 && type === 'Detail') {
|
||||||
|
const currentTableData = JSON.stringify(tableData);
|
||||||
|
|
||||||
|
if (currentTableData !== prevTableDataRef.current) {
|
||||||
|
logEvent(
|
||||||
|
`MQ Kafka: ${MessagingQueuesViewType[selectedView].label} - details`,
|
||||||
|
{
|
||||||
|
dataRender: tableData.length,
|
||||||
|
activeTab: currentTab,
|
||||||
|
topic: configDetailQueryData?.topic,
|
||||||
|
partition: configDetailQueryData?.partition,
|
||||||
|
serviceName: configDetailQueryData?.service_name,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
prevTableDataRef.current = currentTableData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [currentTab, JSON.stringify(tableData), selectedView]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mq-tables-container">
|
<div className="mq-tables-container">
|
||||||
{!validConfigPresent ? (
|
{!validConfigPresent ? (
|
||||||
|
@ -112,6 +112,7 @@ function MessagingQueueOverview({
|
|||||||
tableApi={getTableApi(selectedView)}
|
tableApi={getTableApi(selectedView)}
|
||||||
validConfigPresent
|
validConfigPresent
|
||||||
type="Overview"
|
type="Overview"
|
||||||
|
option={option}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -26,12 +26,14 @@ interface MetricSectionProps {
|
|||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
graphCount: Widgets[];
|
graphCount: Widgets[];
|
||||||
|
checkIfDataExists?: (isDataAvailable: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function MetricSection({
|
function MetricSection({
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
graphCount,
|
graphCount,
|
||||||
|
checkIfDataExists,
|
||||||
}: MetricSectionProps): JSX.Element {
|
}: MetricSectionProps): JSX.Element {
|
||||||
const isDarkMode = useIsDarkMode();
|
const isDarkMode = useIsDarkMode();
|
||||||
|
|
||||||
@ -50,6 +52,7 @@ function MetricSection({
|
|||||||
<MetricPageGridGraph
|
<MetricPageGridGraph
|
||||||
key={`graph-${widgetData.id}`}
|
key={`graph-${widgetData.id}`}
|
||||||
widgetData={widgetData}
|
widgetData={widgetData}
|
||||||
|
checkIfDataExists={checkIfDataExists}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -57,7 +60,15 @@ function MetricSection({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MetricColumnGraphs(): JSX.Element {
|
MetricSection.defaultProps = {
|
||||||
|
checkIfDataExists: (): void => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
function MetricColumnGraphs({
|
||||||
|
checkIfDataExists,
|
||||||
|
}: {
|
||||||
|
checkIfDataExists: (isDataAvailable: boolean) => void;
|
||||||
|
}): JSX.Element {
|
||||||
const { t } = useTranslation('messagingQueues');
|
const { t } = useTranslation('messagingQueues');
|
||||||
|
|
||||||
const metricsData = [
|
const metricsData = [
|
||||||
@ -106,6 +117,7 @@ function MetricColumnGraphs(): JSX.Element {
|
|||||||
title={metric.title}
|
title={metric.title}
|
||||||
description={metric.description}
|
description={metric.description}
|
||||||
graphCount={metric?.graphCount || []}
|
graphCount={metric?.graphCount || []}
|
||||||
|
checkIfDataExists={checkIfDataExists}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import './MetricPage.styles.scss';
|
import './MetricPage.styles.scss';
|
||||||
|
|
||||||
import { Typography } from 'antd';
|
import { Typography } from 'antd';
|
||||||
|
import logEvent from 'api/common/logEvent';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import { CardContainer } from 'container/GridCardLayout/styles';
|
import { CardContainer } from 'container/GridCardLayout/styles';
|
||||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
import { ChevronDown, ChevronUp } from 'lucide-react';
|
import { ChevronDown, ChevronUp } from 'lucide-react';
|
||||||
import { useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
|
|
||||||
@ -28,6 +29,7 @@ interface CollapsibleMetricSectionProps {
|
|||||||
graphCount: Widgets[];
|
graphCount: Widgets[];
|
||||||
isCollapsed: boolean;
|
isCollapsed: boolean;
|
||||||
onToggle: () => void;
|
onToggle: () => void;
|
||||||
|
checkIfDataExists?: (isDataAvailable: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function CollapsibleMetricSection({
|
function CollapsibleMetricSection({
|
||||||
@ -36,6 +38,7 @@ function CollapsibleMetricSection({
|
|||||||
graphCount,
|
graphCount,
|
||||||
isCollapsed,
|
isCollapsed,
|
||||||
onToggle,
|
onToggle,
|
||||||
|
checkIfDataExists,
|
||||||
}: CollapsibleMetricSectionProps): JSX.Element {
|
}: CollapsibleMetricSectionProps): JSX.Element {
|
||||||
const isDarkMode = useIsDarkMode();
|
const isDarkMode = useIsDarkMode();
|
||||||
|
|
||||||
@ -63,6 +66,7 @@ function CollapsibleMetricSection({
|
|||||||
<MetricPageGridGraph
|
<MetricPageGridGraph
|
||||||
key={`graph-${widgetData.id}`}
|
key={`graph-${widgetData.id}`}
|
||||||
widgetData={widgetData}
|
widgetData={widgetData}
|
||||||
|
checkIfDataExists={checkIfDataExists}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -72,6 +76,10 @@ function CollapsibleMetricSection({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CollapsibleMetricSection.defaultProps = {
|
||||||
|
checkIfDataExists: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
function MetricPage(): JSX.Element {
|
function MetricPage(): JSX.Element {
|
||||||
const [collapsedSections, setCollapsedSections] = useState<{
|
const [collapsedSections, setCollapsedSections] = useState<{
|
||||||
[key: string]: boolean;
|
[key: string]: boolean;
|
||||||
@ -114,9 +122,27 @@ function MetricPage(): JSX.Element {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const [renderedGraphCount, setRenderedGraphCount] = useState(0);
|
||||||
|
const hasLoggedRef = useRef(false);
|
||||||
|
|
||||||
|
const checkIfDataExists = (isDataAvailable: boolean): void => {
|
||||||
|
if (isDataAvailable) {
|
||||||
|
const newCount = renderedGraphCount + 1;
|
||||||
|
setRenderedGraphCount(newCount);
|
||||||
|
|
||||||
|
// Only log when first graph has rendered and we haven't logged yet
|
||||||
|
if (newCount === 1 && !hasLoggedRef.current) {
|
||||||
|
logEvent('MQ Kafka: Metric view', {
|
||||||
|
graphRendered: true,
|
||||||
|
});
|
||||||
|
hasLoggedRef.current = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="metric-page">
|
<div className="metric-page">
|
||||||
<MetricColumnGraphs />
|
<MetricColumnGraphs checkIfDataExists={checkIfDataExists} />
|
||||||
{metricSections.map(({ key, title, description, graphCount }) => (
|
{metricSections.map(({ key, title, description, graphCount }) => (
|
||||||
<CollapsibleMetricSection
|
<CollapsibleMetricSection
|
||||||
key={key}
|
key={key}
|
||||||
@ -125,6 +151,7 @@ function MetricPage(): JSX.Element {
|
|||||||
graphCount={graphCount}
|
graphCount={graphCount}
|
||||||
isCollapsed={collapsedSections[key]}
|
isCollapsed={collapsedSections[key]}
|
||||||
onToggle={(): void => toggleCollapse(key)}
|
onToggle={(): void => toggleCollapse(key)}
|
||||||
|
checkIfDataExists={checkIfDataExists}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,8 +15,10 @@ import { Widgets } from 'types/api/dashboard/getAll';
|
|||||||
|
|
||||||
function MetricPageGridGraph({
|
function MetricPageGridGraph({
|
||||||
widgetData,
|
widgetData,
|
||||||
|
checkIfDataExists,
|
||||||
}: {
|
}: {
|
||||||
widgetData: Widgets;
|
widgetData: Widgets;
|
||||||
|
checkIfDataExists?: (isDataAvailable: boolean) => void;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
@ -51,9 +53,14 @@ function MetricPageGridGraph({
|
|||||||
widget={widgetData}
|
widget={widgetData}
|
||||||
headerMenuList={[...ViewMenuAction]}
|
headerMenuList={[...ViewMenuAction]}
|
||||||
onDragSelect={onDragSelect}
|
onDragSelect={onDragSelect}
|
||||||
|
dataAvailable={checkIfDataExists}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetricPageGridGraph.defaultProps = {
|
||||||
|
checkIfDataExists: (): void => {},
|
||||||
|
};
|
||||||
|
|
||||||
export default MetricPageGridGraph;
|
export default MetricPageGridGraph;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user