mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 22:49:03 +08:00
1375 overview querybuilder (#1983)
This commit is contained in:
parent
a405307c96
commit
f1c7d72fc5
@ -0,0 +1,20 @@
|
|||||||
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
export const getWidgetQueryBuilder = (query: Widgets['query']): Widgets => ({
|
||||||
|
description: '',
|
||||||
|
id: v4(),
|
||||||
|
isStacked: false,
|
||||||
|
nullZeroValues: '',
|
||||||
|
opacity: '0',
|
||||||
|
panelTypes: 'TIME_SERIES',
|
||||||
|
query,
|
||||||
|
queryData: {
|
||||||
|
data: { queryData: [] },
|
||||||
|
error: false,
|
||||||
|
errorMessage: '',
|
||||||
|
loading: false,
|
||||||
|
},
|
||||||
|
timePreferance: 'GLOBAL_TIME',
|
||||||
|
title: '',
|
||||||
|
});
|
@ -0,0 +1,112 @@
|
|||||||
|
import {
|
||||||
|
IMetricsBuilderFormula,
|
||||||
|
IMetricsBuilderQuery,
|
||||||
|
IQueryBuilderTagFilterItems,
|
||||||
|
} from 'types/api/dashboard/getAll';
|
||||||
|
|
||||||
|
import {
|
||||||
|
getQueryBuilderQueries,
|
||||||
|
getQueryBuilderQuerieswithFormula,
|
||||||
|
} from './MetricsPageQueriesFactory';
|
||||||
|
|
||||||
|
export const operationPerSec = ({
|
||||||
|
servicename,
|
||||||
|
tagFilterItems,
|
||||||
|
topLevelOperations,
|
||||||
|
}: OperationPerSecProps): IOverviewQueries => {
|
||||||
|
const metricName = 'signoz_latency_count';
|
||||||
|
const legend = 'Operations';
|
||||||
|
const itemsA = [
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: 'service_name',
|
||||||
|
op: 'IN',
|
||||||
|
value: [`${servicename}`],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: 'operation',
|
||||||
|
op: 'MATCH',
|
||||||
|
value: topLevelOperations,
|
||||||
|
},
|
||||||
|
...tagFilterItems,
|
||||||
|
];
|
||||||
|
|
||||||
|
return getQueryBuilderQueries({
|
||||||
|
metricName,
|
||||||
|
legend,
|
||||||
|
itemsA,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const errorPercentage = ({
|
||||||
|
servicename,
|
||||||
|
tagFilterItems,
|
||||||
|
topLevelOperations,
|
||||||
|
}: OperationPerSecProps): IOverviewQueries => {
|
||||||
|
const metricNameA = 'signoz_calls_total';
|
||||||
|
const metricNameB = 'signoz_calls_total';
|
||||||
|
const additionalItemsA = [
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: 'service_name',
|
||||||
|
op: 'IN',
|
||||||
|
value: [`${servicename}`],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: 'operation',
|
||||||
|
op: 'MATCH',
|
||||||
|
value: topLevelOperations,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: 'status_code',
|
||||||
|
op: 'IN',
|
||||||
|
value: ['STATUS_CODE_ERROR'],
|
||||||
|
},
|
||||||
|
...tagFilterItems,
|
||||||
|
];
|
||||||
|
|
||||||
|
const additionalItemsB = [
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: 'service_name',
|
||||||
|
op: 'IN',
|
||||||
|
value: [`${servicename}`],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: 'operation',
|
||||||
|
op: 'MATCH',
|
||||||
|
value: topLevelOperations,
|
||||||
|
},
|
||||||
|
...tagFilterItems,
|
||||||
|
];
|
||||||
|
|
||||||
|
const legendFormula = 'Error Percentage';
|
||||||
|
const legend = legendFormula;
|
||||||
|
const expression = 'A*100/B';
|
||||||
|
const disabled = true;
|
||||||
|
return getQueryBuilderQuerieswithFormula({
|
||||||
|
metricNameA,
|
||||||
|
metricNameB,
|
||||||
|
additionalItemsA,
|
||||||
|
additionalItemsB,
|
||||||
|
legend,
|
||||||
|
disabled,
|
||||||
|
expression,
|
||||||
|
legendFormula,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface OperationPerSecProps {
|
||||||
|
servicename: string | undefined;
|
||||||
|
tagFilterItems: IQueryBuilderTagFilterItems[];
|
||||||
|
topLevelOperations: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IOverviewQueries {
|
||||||
|
formulas: IMetricsBuilderFormula[];
|
||||||
|
queryBuilder: IMetricsBuilderQuery[];
|
||||||
|
}
|
@ -2,25 +2,31 @@ import { ActiveElement, Chart, ChartData, ChartEvent } from 'chart.js';
|
|||||||
import Graph from 'components/Graph';
|
import Graph from 'components/Graph';
|
||||||
import { METRICS_PAGE_QUERY_PARAM } from 'constants/query';
|
import { METRICS_PAGE_QUERY_PARAM } from 'constants/query';
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
import FullView from 'container/GridGraphLayout/Graph/FullView';
|
import FullView from 'container/GridGraphLayout/Graph/FullView/index.metricsBuilder';
|
||||||
import convertToNanoSecondsToSecond from 'lib/convertToNanoSecondsToSecond';
|
import convertToNanoSecondsToSecond from 'lib/convertToNanoSecondsToSecond';
|
||||||
import { colors } from 'lib/getRandomColor';
|
import { colors } from 'lib/getRandomColor';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
import { convertRawQueriesToTraceSelectedTags } from 'lib/resourceAttributes';
|
import {
|
||||||
import { escapeRegExp } from 'lodash-es';
|
convertRawQueriesToTraceSelectedTags,
|
||||||
|
resourceAttributesToTagFilterItems,
|
||||||
|
} from 'lib/resourceAttributes';
|
||||||
import React, { useCallback, useMemo, useRef } from 'react';
|
import React, { useCallback, useMemo, useRef } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { UpdateTimeInterval } from 'store/actions';
|
import { UpdateTimeInterval } from 'store/actions';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { PromQLWidgets } from 'types/api/dashboard/getAll';
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
import MetricReducer from 'types/reducer/metrics';
|
import MetricReducer from 'types/reducer/metrics';
|
||||||
|
|
||||||
|
import {
|
||||||
|
errorPercentage,
|
||||||
|
operationPerSec,
|
||||||
|
} from '../MetricsPageQueries/OverviewQueries';
|
||||||
import { Card, Col, GraphContainer, GraphTitle, Row } from '../styles';
|
import { Card, Col, GraphContainer, GraphTitle, Row } from '../styles';
|
||||||
import TopOperationsTable from '../TopOperationsTable';
|
import TopOperationsTable from '../TopOperationsTable';
|
||||||
import { Button } from './styles';
|
import { Button } from './styles';
|
||||||
|
|
||||||
function Application({ getWidget }: DashboardProps): JSX.Element {
|
function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element {
|
||||||
const { servicename } = useParams<{ servicename?: string }>();
|
const { servicename } = useParams<{ servicename?: string }>();
|
||||||
const selectedTimeStamp = useRef(0);
|
const selectedTimeStamp = useRef(0);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@ -28,20 +34,49 @@ function Application({ getWidget }: DashboardProps): JSX.Element {
|
|||||||
const {
|
const {
|
||||||
topOperations,
|
topOperations,
|
||||||
serviceOverview,
|
serviceOverview,
|
||||||
resourceAttributePromQLQuery,
|
|
||||||
resourceAttributeQueries,
|
resourceAttributeQueries,
|
||||||
topLevelOperations,
|
topLevelOperations,
|
||||||
} = useSelector<AppState, MetricReducer>((state) => state.metrics);
|
} = useSelector<AppState, MetricReducer>((state) => state.metrics);
|
||||||
const operationsRegex = useMemo(() => {
|
|
||||||
return encodeURIComponent(
|
|
||||||
topLevelOperations.map((e) => escapeRegExp(e)).join('|'),
|
|
||||||
);
|
|
||||||
}, [topLevelOperations]);
|
|
||||||
|
|
||||||
const selectedTraceTags: string = JSON.stringify(
|
const selectedTraceTags: string = JSON.stringify(
|
||||||
convertRawQueriesToTraceSelectedTags(resourceAttributeQueries, 'array') || [],
|
convertRawQueriesToTraceSelectedTags(resourceAttributeQueries, 'array') || [],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const tagFilterItems = useMemo(
|
||||||
|
() => resourceAttributesToTagFilterItems(resourceAttributeQueries) || [],
|
||||||
|
[resourceAttributeQueries],
|
||||||
|
);
|
||||||
|
|
||||||
|
const operationPerSecWidget = useMemo(
|
||||||
|
() =>
|
||||||
|
getWidgetQueryBuilder({
|
||||||
|
queryType: 1,
|
||||||
|
promQL: [],
|
||||||
|
metricsBuilder: operationPerSec({
|
||||||
|
servicename,
|
||||||
|
tagFilterItems,
|
||||||
|
topLevelOperations,
|
||||||
|
}),
|
||||||
|
clickHouse: [],
|
||||||
|
}),
|
||||||
|
[getWidgetQueryBuilder, servicename, topLevelOperations, tagFilterItems],
|
||||||
|
);
|
||||||
|
|
||||||
|
const errorPercentageWidget = useMemo(
|
||||||
|
() =>
|
||||||
|
getWidgetQueryBuilder({
|
||||||
|
queryType: 1,
|
||||||
|
promQL: [],
|
||||||
|
metricsBuilder: errorPercentage({
|
||||||
|
servicename,
|
||||||
|
tagFilterItems,
|
||||||
|
topLevelOperations,
|
||||||
|
}),
|
||||||
|
clickHouse: [],
|
||||||
|
}),
|
||||||
|
[servicename, topLevelOperations, tagFilterItems, getWidgetQueryBuilder],
|
||||||
|
);
|
||||||
|
|
||||||
const onTracePopupClick = (timestamp: number): void => {
|
const onTracePopupClick = (timestamp: number): void => {
|
||||||
const currentTime = timestamp;
|
const currentTime = timestamp;
|
||||||
const tPlusOne = timestamp + 1 * 60 * 1000;
|
const tPlusOne = timestamp + 1 * 60 * 1000;
|
||||||
@ -211,12 +246,7 @@ function Application({ getWidget }: DashboardProps): JSX.Element {
|
|||||||
onClickHandler={(event, element, chart, data): void => {
|
onClickHandler={(event, element, chart, data): void => {
|
||||||
onClickHandler(event, element, chart, data, 'Rate');
|
onClickHandler(event, element, chart, data, 'Rate');
|
||||||
}}
|
}}
|
||||||
widget={getWidget([
|
widget={operationPerSecWidget}
|
||||||
{
|
|
||||||
query: `sum(rate(signoz_latency_count{service_name="${servicename}", operation=~\`${operationsRegex}\`${resourceAttributePromQLQuery}}[5m]))`,
|
|
||||||
legend: 'Operations',
|
|
||||||
},
|
|
||||||
])}
|
|
||||||
yAxisUnit="ops"
|
yAxisUnit="ops"
|
||||||
onDragSelect={onDragSelect}
|
onDragSelect={onDragSelect}
|
||||||
/>
|
/>
|
||||||
@ -246,12 +276,7 @@ function Application({ getWidget }: DashboardProps): JSX.Element {
|
|||||||
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
||||||
onClickHandler(ChartEvent, activeElements, chart, data, 'Error');
|
onClickHandler(ChartEvent, activeElements, chart, data, 'Error');
|
||||||
}}
|
}}
|
||||||
widget={getWidget([
|
widget={errorPercentageWidget}
|
||||||
{
|
|
||||||
query: `max(sum(rate(signoz_calls_total{service_name="${servicename}", operation=~\`${operationsRegex}\`, status_code="STATUS_CODE_ERROR"${resourceAttributePromQLQuery}}[5m]) OR rate(signoz_calls_total{service_name="${servicename}", operation=~\`${operationsRegex}\`, http_status_code=~"5.."${resourceAttributePromQLQuery}}[5m]))*100/sum(rate(signoz_calls_total{service_name="${servicename}", operation=~\`${operationsRegex}\`${resourceAttributePromQLQuery}}[5m]))) < 1000 OR vector(0)`,
|
|
||||||
legend: 'Error Percentage',
|
|
||||||
},
|
|
||||||
])}
|
|
||||||
yAxisUnit="%"
|
yAxisUnit="%"
|
||||||
onDragSelect={onDragSelect}
|
onDragSelect={onDragSelect}
|
||||||
/>
|
/>
|
||||||
@ -270,7 +295,7 @@ function Application({ getWidget }: DashboardProps): JSX.Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface DashboardProps {
|
interface DashboardProps {
|
||||||
getWidget: (query: PromQLWidgets['query']) => PromQLWidgets;
|
getWidgetQueryBuilder: (query: Widgets['query']) => Widgets;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Application;
|
export default Application;
|
||||||
|
@ -3,58 +3,15 @@ import ROUTES from 'constants/routes';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { generatePath, useParams } from 'react-router-dom';
|
import { generatePath, useParams } from 'react-router-dom';
|
||||||
import { useLocation } from 'react-use';
|
import { useLocation } from 'react-use';
|
||||||
import { PromQLWidgets, Widgets } from 'types/api/dashboard/getAll';
|
|
||||||
import { v4 } from 'uuid';
|
|
||||||
|
|
||||||
|
import { getWidgetQueryBuilder } from './MetricsApplication.factory';
|
||||||
import ResourceAttributesFilter from './ResourceAttributesFilter';
|
import ResourceAttributesFilter from './ResourceAttributesFilter';
|
||||||
import DBCall from './Tabs/DBCall';
|
import DBCall from './Tabs/DBCall';
|
||||||
import External from './Tabs/External';
|
import External from './Tabs/External';
|
||||||
import Overview from './Tabs/Overview';
|
import Overview from './Tabs/Overview';
|
||||||
|
|
||||||
const getWidget = (query: PromQLWidgets['query']): PromQLWidgets => {
|
|
||||||
return {
|
|
||||||
description: '',
|
|
||||||
id: '',
|
|
||||||
isStacked: false,
|
|
||||||
nullZeroValues: '',
|
|
||||||
opacity: '0',
|
|
||||||
panelTypes: 'TIME_SERIES',
|
|
||||||
query,
|
|
||||||
queryData: {
|
|
||||||
data: { queryData: [] },
|
|
||||||
error: false,
|
|
||||||
errorMessage: '',
|
|
||||||
loading: false,
|
|
||||||
},
|
|
||||||
timePreferance: 'GLOBAL_TIME',
|
|
||||||
title: '',
|
|
||||||
stepSize: 60,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const getWidgetQueryBuilder = (query: Widgets['query']): Widgets => {
|
|
||||||
return {
|
|
||||||
description: '',
|
|
||||||
id: v4(),
|
|
||||||
isStacked: false,
|
|
||||||
nullZeroValues: '',
|
|
||||||
opacity: '0',
|
|
||||||
panelTypes: 'TIME_SERIES',
|
|
||||||
query,
|
|
||||||
queryData: {
|
|
||||||
data: { queryData: [] },
|
|
||||||
error: false,
|
|
||||||
errorMessage: '',
|
|
||||||
loading: false,
|
|
||||||
},
|
|
||||||
timePreferance: 'GLOBAL_TIME',
|
|
||||||
title: '',
|
|
||||||
stepSize: 60,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function OverViewTab(): JSX.Element {
|
function OverViewTab(): JSX.Element {
|
||||||
return <Overview getWidget={getWidget} />;
|
return <Overview getWidgetQueryBuilder={getWidgetQueryBuilder} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DbCallTab(): JSX.Element {
|
function DbCallTab(): JSX.Element {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user