mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-09-20 08:43:14 +08:00
Key Operation to Metrics using USE_SPAN_METRIC feature flag (#3188)
* refactor: generic querybuilderWithFormula * refactor: added generic datasource * refactor: dynamic disabled in getQueryBuilderQueriesWithFormula * refactor: generic legend for building query with formulas * feat: added new TopOperationMetrics component for key operation * refactor: added feature flag for key operation * refactor: shifted types and fixed typos * refactor: separated types and renamed file * refactor: one on one mapping * refactor: added clickable link for navigating to traces * chore: separated types * chore: removed unnecessary comments * refactor: one on one mapping for DBCallQueries * refactor: seperated types and one on one mapping for externalQueries * refactor: separate type from metricsPagesQueriesFactory * refactor: separated types and one on one mapping for overviewQueries * refactor: remove the type inforcement from TopOperationQueries.ts * refactor: one on one mapping in TopOperationQueries.ts * refactor: one on one mapping and remove the unwanted code * refactor: shifted logic of navigating to traces to utils * refactor: separated renderColumnCell from the TopOperationMetric component * refactor: generic tableRenderer * refactor: made getTableColumnRenderer more generic * chore: title is updated --------- Co-authored-by: Palash Gupta <palashgdev@gmail.com>
This commit is contained in:
parent
5c83d133a2
commit
bc4a4edc7f
@ -1,17 +1,19 @@
|
|||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
export const getWidgetQueryBuilder = (
|
import { GetWidgetQueryBuilderProps } from './types';
|
||||||
query: Widgets['query'],
|
|
||||||
|
export const getWidgetQueryBuilder = ({
|
||||||
|
query,
|
||||||
title = '',
|
title = '',
|
||||||
): Widgets => ({
|
panelTypes,
|
||||||
|
}: GetWidgetQueryBuilderProps): Widgets => ({
|
||||||
description: '',
|
description: '',
|
||||||
id: v4(),
|
id: v4(),
|
||||||
isStacked: false,
|
isStacked: false,
|
||||||
nullZeroValues: '',
|
nullZeroValues: '',
|
||||||
opacity: '0',
|
opacity: '0',
|
||||||
panelTypes: PANEL_TYPES.TIME_SERIES,
|
panelTypes,
|
||||||
query,
|
query,
|
||||||
timePreferance: 'GLOBAL_TIME',
|
timePreferance: 'GLOBAL_TIME',
|
||||||
title,
|
title,
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import { OPERATORS } from 'constants/queryBuilder';
|
import { OPERATORS } from 'constants/queryBuilder';
|
||||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||||
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { DataSource, QueryBuilderData } from 'types/common/queryBuilder';
|
import {
|
||||||
|
DataSource,
|
||||||
|
MetricAggregateOperator,
|
||||||
|
QueryBuilderData,
|
||||||
|
} from 'types/common/queryBuilder';
|
||||||
|
|
||||||
import { DataType, FORMULA, MetricsType, WidgetKeys } from '../constant';
|
import { DataType, FORMULA, MetricsType, WidgetKeys } from '../constant';
|
||||||
import { IServiceName } from '../Tabs/types';
|
import { IServiceName } from '../Tabs/types';
|
||||||
@ -44,13 +48,14 @@ export const databaseCallsRPS = ({
|
|||||||
];
|
];
|
||||||
|
|
||||||
const legends = [legend];
|
const legends = [legend];
|
||||||
|
const dataSource = DataSource.METRICS;
|
||||||
|
|
||||||
return getQueryBuilderQueries({
|
return getQueryBuilderQueries({
|
||||||
autocompleteData,
|
autocompleteData,
|
||||||
groupBy,
|
groupBy,
|
||||||
legends,
|
legends,
|
||||||
filterItems,
|
filterItems,
|
||||||
dataSource: DataSource.METRICS,
|
dataSource,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,17 +90,36 @@ export const databaseCallsAvgDuration = ({
|
|||||||
},
|
},
|
||||||
...tagFilterItems,
|
...tagFilterItems,
|
||||||
];
|
];
|
||||||
const additionalItemsB = additionalItemsA;
|
|
||||||
|
|
||||||
return getQueryBuilderQuerieswithFormula({
|
const autocompleteData: BaseAutocompleteData[] = [
|
||||||
autocompleteDataA,
|
autocompleteDataA,
|
||||||
autocompleteDataB,
|
autocompleteDataB,
|
||||||
|
];
|
||||||
|
|
||||||
|
const additionalItems: TagFilterItem[][] = [
|
||||||
additionalItemsA,
|
additionalItemsA,
|
||||||
additionalItemsB,
|
additionalItemsA,
|
||||||
legend: '',
|
];
|
||||||
disabled: true,
|
|
||||||
expression: FORMULA.DATABASE_CALLS_AVG_DURATION,
|
const legends = ['', ''];
|
||||||
legendFormula: 'Average Duration',
|
const disabled = [true, true];
|
||||||
|
const legendFormula = 'Average Duration';
|
||||||
|
const expression = FORMULA.DATABASE_CALLS_AVG_DURATION;
|
||||||
|
const aggregateOperators = [
|
||||||
|
MetricAggregateOperator.SUM,
|
||||||
|
MetricAggregateOperator.SUM,
|
||||||
|
];
|
||||||
|
const dataSource = DataSource.METRICS;
|
||||||
|
|
||||||
|
return getQueryBuilderQuerieswithFormula({
|
||||||
|
autocompleteData,
|
||||||
|
additionalItems,
|
||||||
|
legends,
|
||||||
|
disabled,
|
||||||
|
expression,
|
||||||
|
legendFormula,
|
||||||
|
aggregateOperators,
|
||||||
|
dataSource,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
import { OPERATORS } from 'constants/queryBuilder';
|
import { OPERATORS } from 'constants/queryBuilder';
|
||||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||||
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { DataSource, QueryBuilderData } from 'types/common/queryBuilder';
|
import {
|
||||||
|
DataSource,
|
||||||
|
MetricAggregateOperator,
|
||||||
|
QueryBuilderData,
|
||||||
|
} from 'types/common/queryBuilder';
|
||||||
|
|
||||||
import { DataType, FORMULA, MetricsType, WidgetKeys } from '../constant';
|
import { DataType, FORMULA, MetricsType, WidgetKeys } from '../constant';
|
||||||
import { IServiceName } from '../Tabs/types';
|
import {
|
||||||
|
ExternalCallDurationByAddressProps,
|
||||||
|
ExternalCallProps,
|
||||||
|
} from '../Tabs/types';
|
||||||
import {
|
import {
|
||||||
getQueryBuilderQueries,
|
getQueryBuilderQueries,
|
||||||
getQueryBuilderQuerieswithFormula,
|
getQueryBuilderQuerieswithFormula,
|
||||||
@ -36,6 +43,7 @@ export const externalCallErrorPercent = ({
|
|||||||
isColumn: true,
|
isColumn: true,
|
||||||
type: null,
|
type: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const additionalItemsA: TagFilterItem[] = [
|
const additionalItemsA: TagFilterItem[] = [
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
@ -71,23 +79,38 @@ export const externalCallErrorPercent = ({
|
|||||||
type: MetricsType.Resource,
|
type: MetricsType.Resource,
|
||||||
},
|
},
|
||||||
op: OPERATORS.IN,
|
op: OPERATORS.IN,
|
||||||
value: [`${servicename}`],
|
value: [servicename],
|
||||||
},
|
},
|
||||||
...tagFilterItems,
|
...tagFilterItems,
|
||||||
];
|
];
|
||||||
|
|
||||||
const legendFormula = legend;
|
const legendFormula = legend;
|
||||||
const expression = FORMULA.ERROR_PERCENTAGE;
|
const expression = FORMULA.ERROR_PERCENTAGE;
|
||||||
const disabled = true;
|
const autocompleteData: BaseAutocompleteData[] = [
|
||||||
return getQueryBuilderQuerieswithFormula({
|
|
||||||
autocompleteDataA,
|
autocompleteDataA,
|
||||||
autocompleteDataB,
|
autocompleteDataB,
|
||||||
|
];
|
||||||
|
|
||||||
|
const additionalItems: TagFilterItem[][] = [
|
||||||
additionalItemsA,
|
additionalItemsA,
|
||||||
additionalItemsB,
|
additionalItemsB,
|
||||||
legend,
|
];
|
||||||
|
|
||||||
|
const legends = Array(2).fill(legend);
|
||||||
|
const aggregateOperators = Array(2).fill(MetricAggregateOperator.SUM);
|
||||||
|
const disabled = Array(2).fill(true);
|
||||||
|
const dataSource = DataSource.METRICS;
|
||||||
|
|
||||||
|
return getQueryBuilderQuerieswithFormula({
|
||||||
|
autocompleteData,
|
||||||
|
additionalItems,
|
||||||
|
legends,
|
||||||
groupBy,
|
groupBy,
|
||||||
disabled,
|
disabled,
|
||||||
expression,
|
expression,
|
||||||
legendFormula,
|
legendFormula,
|
||||||
|
aggregateOperators,
|
||||||
|
dataSource,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -107,10 +130,11 @@ export const externalCallDuration = ({
|
|||||||
key: WidgetKeys.SignozExternalCallLatencyCount,
|
key: WidgetKeys.SignozExternalCallLatencyCount,
|
||||||
type: null,
|
type: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const expression = FORMULA.DATABASE_CALLS_AVG_DURATION;
|
const expression = FORMULA.DATABASE_CALLS_AVG_DURATION;
|
||||||
const legendFormula = 'Average Duration';
|
const legendFormula = 'Average Duration';
|
||||||
const legend = '';
|
const legend = '';
|
||||||
const disabled = true;
|
const disabled = Array(2).fill(true);
|
||||||
const additionalItemsA: TagFilterItem[] = [
|
const additionalItemsA: TagFilterItem[] = [
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
@ -125,17 +149,29 @@ export const externalCallDuration = ({
|
|||||||
},
|
},
|
||||||
...tagFilterItems,
|
...tagFilterItems,
|
||||||
];
|
];
|
||||||
const additionalItemsB = additionalItemsA;
|
|
||||||
|
|
||||||
return getQueryBuilderQuerieswithFormula({
|
const autocompleteData: BaseAutocompleteData[] = [
|
||||||
autocompleteDataA,
|
autocompleteDataA,
|
||||||
autocompleteDataB,
|
autocompleteDataB,
|
||||||
|
];
|
||||||
|
|
||||||
|
const additionalItems: TagFilterItem[][] = [
|
||||||
additionalItemsA,
|
additionalItemsA,
|
||||||
additionalItemsB,
|
additionalItemsA,
|
||||||
legend,
|
];
|
||||||
|
|
||||||
|
const legends = Array(2).fill(legend);
|
||||||
|
const aggregateOperators = Array(2).fill(MetricAggregateOperator.SUM);
|
||||||
|
|
||||||
|
return getQueryBuilderQuerieswithFormula({
|
||||||
|
autocompleteData,
|
||||||
|
additionalItems,
|
||||||
|
legends,
|
||||||
disabled,
|
disabled,
|
||||||
expression,
|
expression,
|
||||||
legendFormula,
|
legendFormula,
|
||||||
|
aggregateOperators,
|
||||||
|
dataSource: DataSource.METRICS,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -169,13 +205,15 @@ export const externalCallRpsByAddress = ({
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
const legends: string[] = [legend];
|
const legends = [legend];
|
||||||
|
const dataSource = DataSource.METRICS;
|
||||||
|
|
||||||
return getQueryBuilderQueries({
|
return getQueryBuilderQueries({
|
||||||
autocompleteData,
|
autocompleteData,
|
||||||
groupBy,
|
groupBy,
|
||||||
legends,
|
legends,
|
||||||
filterItems,
|
filterItems,
|
||||||
dataSource: DataSource.METRICS,
|
dataSource,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -198,7 +236,7 @@ export const externalCallDurationByAddress = ({
|
|||||||
};
|
};
|
||||||
const expression = FORMULA.DATABASE_CALLS_AVG_DURATION;
|
const expression = FORMULA.DATABASE_CALLS_AVG_DURATION;
|
||||||
const legendFormula = legend;
|
const legendFormula = legend;
|
||||||
const disabled = true;
|
const disabled = [true, true];
|
||||||
const additionalItemsA: TagFilterItem[] = [
|
const additionalItemsA: TagFilterItem[] = [
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
@ -213,26 +251,30 @@ export const externalCallDurationByAddress = ({
|
|||||||
},
|
},
|
||||||
...tagFilterItems,
|
...tagFilterItems,
|
||||||
];
|
];
|
||||||
const additionalItemsB = additionalItemsA;
|
|
||||||
|
|
||||||
return getQueryBuilderQuerieswithFormula({
|
const autocompleteData: BaseAutocompleteData[] = [
|
||||||
autocompleteDataA,
|
autocompleteDataA,
|
||||||
autocompleteDataB,
|
autocompleteDataB,
|
||||||
|
];
|
||||||
|
|
||||||
|
const additionalItems: TagFilterItem[][] = [
|
||||||
additionalItemsA,
|
additionalItemsA,
|
||||||
additionalItemsB,
|
additionalItemsA,
|
||||||
legend,
|
];
|
||||||
|
|
||||||
|
const legends = Array(2).fill(legend);
|
||||||
|
const aggregateOperators = Array(2).fill(MetricAggregateOperator.SUM_RATE);
|
||||||
|
const dataSource = DataSource.METRICS;
|
||||||
|
|
||||||
|
return getQueryBuilderQuerieswithFormula({
|
||||||
|
autocompleteData,
|
||||||
|
additionalItems,
|
||||||
|
legends,
|
||||||
groupBy,
|
groupBy,
|
||||||
disabled,
|
disabled,
|
||||||
expression,
|
expression,
|
||||||
legendFormula,
|
legendFormula,
|
||||||
|
aggregateOperators,
|
||||||
|
dataSource,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ExternalCallDurationByAddressProps extends ExternalCallProps {
|
|
||||||
legend: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExternalCallProps {
|
|
||||||
servicename: IServiceName['servicename'];
|
|
||||||
tagFilterItems: TagFilterItem[];
|
|
||||||
}
|
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
import {
|
import {
|
||||||
|
alphabet,
|
||||||
initialFormulaBuilderFormValues,
|
initialFormulaBuilderFormValues,
|
||||||
initialQueryBuilderFormValuesMap,
|
initialQueryBuilderFormValuesMap,
|
||||||
} from 'constants/queryBuilder';
|
} from 'constants/queryBuilder';
|
||||||
import getStep from 'lib/getStep';
|
import getStep from 'lib/getStep';
|
||||||
import store from 'store';
|
import store from 'store';
|
||||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import {
|
import {
|
||||||
IBuilderQuery,
|
|
||||||
TagFilterItem,
|
|
||||||
} from 'types/api/queryBuilder/queryBuilderData';
|
|
||||||
import {
|
|
||||||
DataSource,
|
|
||||||
MetricAggregateOperator,
|
MetricAggregateOperator,
|
||||||
QueryBuilderData,
|
QueryBuilderData,
|
||||||
} from 'types/common/queryBuilder';
|
} from 'types/common/queryBuilder';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BuilderQueriesProps,
|
||||||
|
BuilderQuerieswithFormulaProps,
|
||||||
|
} from '../Tabs/types';
|
||||||
|
|
||||||
export const getQueryBuilderQueries = ({
|
export const getQueryBuilderQueries = ({
|
||||||
autocompleteData,
|
autocompleteData,
|
||||||
groupBy = [],
|
groupBy = [],
|
||||||
@ -61,15 +62,15 @@ export const getQueryBuilderQueries = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const getQueryBuilderQuerieswithFormula = ({
|
export const getQueryBuilderQuerieswithFormula = ({
|
||||||
autocompleteDataA,
|
autocompleteData,
|
||||||
autocompleteDataB,
|
additionalItems,
|
||||||
additionalItemsA,
|
legends,
|
||||||
additionalItemsB,
|
|
||||||
legend,
|
|
||||||
groupBy = [],
|
groupBy = [],
|
||||||
disabled,
|
disabled,
|
||||||
expression,
|
expression,
|
||||||
legendFormula,
|
legendFormula,
|
||||||
|
aggregateOperators,
|
||||||
|
dataSource,
|
||||||
}: BuilderQuerieswithFormulaProps): QueryBuilderData => ({
|
}: BuilderQuerieswithFormulaProps): QueryBuilderData => ({
|
||||||
queryFormulas: [
|
queryFormulas: [
|
||||||
{
|
{
|
||||||
@ -78,66 +79,25 @@ export const getQueryBuilderQuerieswithFormula = ({
|
|||||||
legend: legendFormula,
|
legend: legendFormula,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
queryData: [
|
queryData: autocompleteData.map((_, index) => ({
|
||||||
{
|
...initialQueryBuilderFormValuesMap.metrics,
|
||||||
...initialQueryBuilderFormValuesMap.metrics,
|
aggregateOperator: aggregateOperators[index],
|
||||||
aggregateOperator: MetricAggregateOperator.SUM_RATE,
|
disabled: disabled[index],
|
||||||
disabled,
|
groupBy,
|
||||||
groupBy,
|
legend: legends[index],
|
||||||
legend,
|
aggregateAttribute: autocompleteData[index],
|
||||||
aggregateAttribute: autocompleteDataA,
|
queryName: alphabet[index],
|
||||||
reduceTo: 'sum',
|
expression: alphabet[index],
|
||||||
filters: {
|
reduceTo: 'sum',
|
||||||
items: additionalItemsA,
|
filters: {
|
||||||
op: 'AND',
|
items: additionalItems[index],
|
||||||
},
|
op: 'AND',
|
||||||
stepInterval: getStep({
|
|
||||||
end: store.getState().globalTime.maxTime,
|
|
||||||
inputFormat: 'ns',
|
|
||||||
start: store.getState().globalTime.minTime,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
{
|
stepInterval: getStep({
|
||||||
...initialQueryBuilderFormValuesMap.metrics,
|
end: store.getState().globalTime.maxTime,
|
||||||
aggregateOperator: MetricAggregateOperator.SUM_RATE,
|
inputFormat: 'ns',
|
||||||
disabled,
|
start: store.getState().globalTime.minTime,
|
||||||
groupBy,
|
}),
|
||||||
legend,
|
dataSource,
|
||||||
aggregateAttribute: autocompleteDataB,
|
})),
|
||||||
queryName: 'B',
|
|
||||||
expression: 'B',
|
|
||||||
reduceTo: 'sum',
|
|
||||||
filters: {
|
|
||||||
items: additionalItemsB,
|
|
||||||
op: 'AND',
|
|
||||||
},
|
|
||||||
stepInterval: getStep({
|
|
||||||
end: store.getState().globalTime.maxTime,
|
|
||||||
inputFormat: 'ns',
|
|
||||||
start: store.getState().globalTime.minTime,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
interface BuilderQueriesProps {
|
|
||||||
autocompleteData: BaseAutocompleteData[];
|
|
||||||
groupBy?: BaseAutocompleteData[];
|
|
||||||
legends: string[];
|
|
||||||
filterItems: TagFilterItem[][];
|
|
||||||
aggregateOperator?: string[];
|
|
||||||
dataSource: DataSource;
|
|
||||||
queryNameAndExpression?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BuilderQuerieswithFormulaProps {
|
|
||||||
autocompleteDataA: BaseAutocompleteData;
|
|
||||||
autocompleteDataB: BaseAutocompleteData;
|
|
||||||
legend: string;
|
|
||||||
disabled: boolean;
|
|
||||||
groupBy?: BaseAutocompleteData[];
|
|
||||||
expression: string;
|
|
||||||
legendFormula: string;
|
|
||||||
additionalItemsA: TagFilterItem[];
|
|
||||||
additionalItemsB: TagFilterItem[];
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import { OPERATORS } from 'constants/queryBuilder';
|
import { OPERATORS } from 'constants/queryBuilder';
|
||||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||||
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { DataSource, QueryBuilderData } from 'types/common/queryBuilder';
|
import {
|
||||||
|
DataSource,
|
||||||
|
MetricAggregateOperator,
|
||||||
|
QueryBuilderData,
|
||||||
|
} from 'types/common/queryBuilder';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DataType,
|
DataType,
|
||||||
@ -14,7 +18,7 @@ import {
|
|||||||
QUERYNAME_AND_EXPRESSION,
|
QUERYNAME_AND_EXPRESSION,
|
||||||
WidgetKeys,
|
WidgetKeys,
|
||||||
} from '../constant';
|
} from '../constant';
|
||||||
import { IServiceName } from '../Tabs/types';
|
import { LatencyProps, OperationPerSecProps } from '../Tabs/types';
|
||||||
import {
|
import {
|
||||||
getQueryBuilderQueries,
|
getQueryBuilderQueries,
|
||||||
getQueryBuilderQuerieswithFormula,
|
getQueryBuilderQuerieswithFormula,
|
||||||
@ -35,9 +39,7 @@ export const latency = ({
|
|||||||
type: isSpanMetricEnable ? null : MetricsType.Tag,
|
type: isSpanMetricEnable ? null : MetricsType.Tag,
|
||||||
};
|
};
|
||||||
|
|
||||||
const autocompleteData: BaseAutocompleteData[] = Array(3).fill(
|
const autocompleteData = Array(3).fill(newAutoCompleteData);
|
||||||
newAutoCompleteData,
|
|
||||||
);
|
|
||||||
|
|
||||||
const filterItem: TagFilterItem[] = [
|
const filterItem: TagFilterItem[] = [
|
||||||
{
|
{
|
||||||
@ -65,17 +67,21 @@ export const latency = ({
|
|||||||
...tagFilterItems,
|
...tagFilterItems,
|
||||||
];
|
];
|
||||||
|
|
||||||
const filterItems: TagFilterItem[][] = Array(3).fill([...filterItem]);
|
const filterItems = Array(3).fill([...filterItem]);
|
||||||
|
const legends = LATENCY_AGGREGATEOPERATOR;
|
||||||
|
const aggregateOperator = isSpanMetricEnable
|
||||||
|
? LATENCY_AGGREGATEOPERATOR_SPAN_METRICS
|
||||||
|
: LATENCY_AGGREGATEOPERATOR;
|
||||||
|
const dataSource = isSpanMetricEnable ? DataSource.METRICS : DataSource.TRACES;
|
||||||
|
const queryNameAndExpression = QUERYNAME_AND_EXPRESSION;
|
||||||
|
|
||||||
return getQueryBuilderQueries({
|
return getQueryBuilderQueries({
|
||||||
autocompleteData,
|
autocompleteData,
|
||||||
legends: LATENCY_AGGREGATEOPERATOR,
|
legends,
|
||||||
filterItems,
|
filterItems,
|
||||||
aggregateOperator: isSpanMetricEnable
|
aggregateOperator,
|
||||||
? LATENCY_AGGREGATEOPERATOR_SPAN_METRICS
|
dataSource,
|
||||||
: LATENCY_AGGREGATEOPERATOR,
|
queryNameAndExpression,
|
||||||
dataSource: isSpanMetricEnable ? DataSource.METRICS : DataSource.TRACES,
|
|
||||||
queryNameAndExpression: QUERYNAME_AND_EXPRESSION,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -121,11 +127,14 @@ export const operationPerSec = ({
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const legends = OPERATION_LEGENDS;
|
||||||
|
const dataSource = DataSource.METRICS;
|
||||||
|
|
||||||
return getQueryBuilderQueries({
|
return getQueryBuilderQueries({
|
||||||
autocompleteData,
|
autocompleteData,
|
||||||
legends: OPERATION_LEGENDS,
|
legends,
|
||||||
filterItems,
|
filterItems,
|
||||||
dataSource: DataSource.METRICS,
|
dataSource,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -146,6 +155,9 @@ export const errorPercentage = ({
|
|||||||
isColumn: true,
|
isColumn: true,
|
||||||
type: null,
|
type: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const autocompleteData = [autocompleteDataA, autocompleteDataB];
|
||||||
|
|
||||||
const additionalItemsA: TagFilterItem[] = [
|
const additionalItemsA: TagFilterItem[] = [
|
||||||
{
|
{
|
||||||
id: '',
|
id: '',
|
||||||
@ -209,27 +221,25 @@ export const errorPercentage = ({
|
|||||||
...tagFilterItems,
|
...tagFilterItems,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const additionalItems = [additionalItemsA, additionalItemsB];
|
||||||
|
const legends = [GraphTitle.ERROR_PERCENTAGE];
|
||||||
|
const disabled = [true, true];
|
||||||
|
const expression = FORMULA.ERROR_PERCENTAGE;
|
||||||
|
const legendFormula = GraphTitle.ERROR_PERCENTAGE;
|
||||||
|
const aggregateOperators = [
|
||||||
|
MetricAggregateOperator.SUM_RATE,
|
||||||
|
MetricAggregateOperator.SUM_RATE,
|
||||||
|
];
|
||||||
|
const dataSource = DataSource.METRICS;
|
||||||
|
|
||||||
return getQueryBuilderQuerieswithFormula({
|
return getQueryBuilderQuerieswithFormula({
|
||||||
autocompleteDataA,
|
autocompleteData,
|
||||||
autocompleteDataB,
|
additionalItems,
|
||||||
additionalItemsA,
|
legends,
|
||||||
additionalItemsB,
|
disabled,
|
||||||
legend: GraphTitle.ERROR_PERCENTAGE,
|
expression,
|
||||||
disabled: true,
|
legendFormula,
|
||||||
expression: FORMULA.ERROR_PERCENTAGE,
|
aggregateOperators,
|
||||||
legendFormula: GraphTitle.ERROR_PERCENTAGE,
|
dataSource,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface OperationPerSecProps {
|
|
||||||
servicename: IServiceName['servicename'];
|
|
||||||
tagFilterItems: TagFilterItem[];
|
|
||||||
topLevelOperations: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LatencyProps {
|
|
||||||
servicename: IServiceName['servicename'];
|
|
||||||
tagFilterItems: TagFilterItem[];
|
|
||||||
isSpanMetricEnable?: boolean;
|
|
||||||
topLevelOperationsRoute: string[];
|
|
||||||
}
|
|
||||||
|
@ -0,0 +1,142 @@
|
|||||||
|
import { OPERATORS } from 'constants/queryBuilder';
|
||||||
|
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||||
|
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
|
import {
|
||||||
|
DataSource,
|
||||||
|
MetricAggregateOperator,
|
||||||
|
QueryBuilderData,
|
||||||
|
} from 'types/common/queryBuilder';
|
||||||
|
|
||||||
|
import {
|
||||||
|
DataType,
|
||||||
|
GraphTitle,
|
||||||
|
KeyOperationTableHeader,
|
||||||
|
MetricsType,
|
||||||
|
WidgetKeys,
|
||||||
|
} from '../constant';
|
||||||
|
import { TopOperationQueryFactoryProps } from '../Tabs/types';
|
||||||
|
import { getQueryBuilderQuerieswithFormula } from './MetricsPageQueriesFactory';
|
||||||
|
|
||||||
|
export const topOperationQueries = ({
|
||||||
|
servicename,
|
||||||
|
}: TopOperationQueryFactoryProps): QueryBuilderData => {
|
||||||
|
const latencyAutoCompleteData: BaseAutocompleteData = {
|
||||||
|
key: WidgetKeys.Signoz_latency_bucket,
|
||||||
|
dataType: DataType.FLOAT64,
|
||||||
|
isColumn: true,
|
||||||
|
type: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const errorRateAutoCompleteData: BaseAutocompleteData = {
|
||||||
|
key: WidgetKeys.SignozCallsTotal,
|
||||||
|
dataType: DataType.FLOAT64,
|
||||||
|
isColumn: true,
|
||||||
|
type: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const numOfCallAutoCompleteData: BaseAutocompleteData = {
|
||||||
|
key: WidgetKeys.SignozLatencyCount,
|
||||||
|
dataType: DataType.FLOAT64,
|
||||||
|
isColumn: true,
|
||||||
|
type: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const latencyAndNumberOfCallAdditionalItems: TagFilterItem[] = [
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: {
|
||||||
|
key: WidgetKeys.Service_name,
|
||||||
|
dataType: DataType.STRING,
|
||||||
|
isColumn: false,
|
||||||
|
type: MetricsType.Resource,
|
||||||
|
},
|
||||||
|
value: [servicename],
|
||||||
|
op: OPERATORS.IN,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const errorRateAdditionalItemsA: TagFilterItem[] = [
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: {
|
||||||
|
dataType: DataType.STRING,
|
||||||
|
isColumn: false,
|
||||||
|
key: WidgetKeys.Service_name,
|
||||||
|
type: MetricsType.Resource,
|
||||||
|
},
|
||||||
|
op: OPERATORS.IN,
|
||||||
|
value: [servicename],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '',
|
||||||
|
key: {
|
||||||
|
dataType: DataType.INT64,
|
||||||
|
isColumn: false,
|
||||||
|
key: WidgetKeys.StatusCode,
|
||||||
|
type: MetricsType.Tag,
|
||||||
|
},
|
||||||
|
op: OPERATORS.IN,
|
||||||
|
value: ['STATUS_CODE_ERROR'],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const errorRateAdditionalItemsB = latencyAndNumberOfCallAdditionalItems;
|
||||||
|
|
||||||
|
const groupBy: BaseAutocompleteData[] = [
|
||||||
|
{
|
||||||
|
dataType: DataType.STRING,
|
||||||
|
isColumn: false,
|
||||||
|
key: WidgetKeys.Operation,
|
||||||
|
type: MetricsType.Tag,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const autocompleteData = [
|
||||||
|
latencyAutoCompleteData,
|
||||||
|
latencyAutoCompleteData,
|
||||||
|
latencyAutoCompleteData,
|
||||||
|
errorRateAutoCompleteData,
|
||||||
|
errorRateAutoCompleteData,
|
||||||
|
numOfCallAutoCompleteData,
|
||||||
|
];
|
||||||
|
const additionalItems = [
|
||||||
|
latencyAndNumberOfCallAdditionalItems,
|
||||||
|
latencyAndNumberOfCallAdditionalItems,
|
||||||
|
latencyAndNumberOfCallAdditionalItems,
|
||||||
|
errorRateAdditionalItemsA,
|
||||||
|
errorRateAdditionalItemsB,
|
||||||
|
latencyAndNumberOfCallAdditionalItems,
|
||||||
|
];
|
||||||
|
const disabled = [false, false, false, true, true, false];
|
||||||
|
const legends = [
|
||||||
|
KeyOperationTableHeader.P50,
|
||||||
|
KeyOperationTableHeader.P90,
|
||||||
|
KeyOperationTableHeader.P99,
|
||||||
|
KeyOperationTableHeader.ERROR_RATE,
|
||||||
|
KeyOperationTableHeader.ERROR_RATE,
|
||||||
|
KeyOperationTableHeader.NUM_OF_CALLS,
|
||||||
|
];
|
||||||
|
const aggregateOperators = [
|
||||||
|
MetricAggregateOperator.HIST_QUANTILE_50,
|
||||||
|
MetricAggregateOperator.HIST_QUANTILE_90,
|
||||||
|
MetricAggregateOperator.HIST_QUANTILE_99,
|
||||||
|
MetricAggregateOperator.SUM_RATE,
|
||||||
|
MetricAggregateOperator.SUM_RATE,
|
||||||
|
MetricAggregateOperator.SUM_RATE,
|
||||||
|
];
|
||||||
|
const expression = 'D*100/E';
|
||||||
|
const legendFormula = GraphTitle.ERROR_PERCENTAGE;
|
||||||
|
const dataSource = DataSource.METRICS;
|
||||||
|
|
||||||
|
return getQueryBuilderQuerieswithFormula({
|
||||||
|
autocompleteData,
|
||||||
|
additionalItems,
|
||||||
|
disabled,
|
||||||
|
legends,
|
||||||
|
aggregateOperators,
|
||||||
|
expression,
|
||||||
|
legendFormula,
|
||||||
|
dataSource,
|
||||||
|
groupBy,
|
||||||
|
});
|
||||||
|
};
|
@ -1,4 +1,5 @@
|
|||||||
import { Col } from 'antd';
|
import { Col } from 'antd';
|
||||||
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import Graph from 'container/GridGraphLayout/Graph/';
|
import Graph from 'container/GridGraphLayout/Graph/';
|
||||||
import {
|
import {
|
||||||
databaseCallsAvgDuration,
|
databaseCallsAvgDuration,
|
||||||
@ -50,8 +51,8 @@ function DBCall(): JSX.Element {
|
|||||||
|
|
||||||
const databaseCallsRPSWidget = useMemo(
|
const databaseCallsRPSWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder(
|
getWidgetQueryBuilder({
|
||||||
{
|
query: {
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
promql: [],
|
promql: [],
|
||||||
builder: databaseCallsRPS({
|
builder: databaseCallsRPS({
|
||||||
@ -62,14 +63,15 @@ function DBCall(): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
},
|
},
|
||||||
GraphTitle.DATABASE_CALLS_RPS,
|
title: GraphTitle.DATABASE_CALLS_RPS,
|
||||||
),
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
|
}),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
const databaseCallsAverageDurationWidget = useMemo(
|
const databaseCallsAverageDurationWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder(
|
getWidgetQueryBuilder({
|
||||||
{
|
query: {
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
promql: [],
|
promql: [],
|
||||||
builder: databaseCallsAvgDuration({
|
builder: databaseCallsAvgDuration({
|
||||||
@ -79,8 +81,9 @@ function DBCall(): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
},
|
},
|
||||||
GraphTitle.DATABASE_CALLS_AVG_DURATION,
|
title: GraphTitle.DATABASE_CALLS_AVG_DURATION,
|
||||||
),
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
|
}),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Col } from 'antd';
|
import { Col } from 'antd';
|
||||||
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import Graph from 'container/GridGraphLayout/Graph/';
|
import Graph from 'container/GridGraphLayout/Graph/';
|
||||||
import {
|
import {
|
||||||
externalCallDuration,
|
externalCallDuration,
|
||||||
@ -41,8 +42,8 @@ function External(): JSX.Element {
|
|||||||
|
|
||||||
const externalCallErrorWidget = useMemo(
|
const externalCallErrorWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder(
|
getWidgetQueryBuilder({
|
||||||
{
|
query: {
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
promql: [],
|
promql: [],
|
||||||
builder: externalCallErrorPercent({
|
builder: externalCallErrorPercent({
|
||||||
@ -53,8 +54,9 @@ function External(): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
},
|
},
|
||||||
GraphTitle.EXTERNAL_CALL_ERROR_PERCENTAGE,
|
title: GraphTitle.EXTERNAL_CALL_ERROR_PERCENTAGE,
|
||||||
),
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
|
}),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -65,8 +67,8 @@ function External(): JSX.Element {
|
|||||||
|
|
||||||
const externalCallDurationWidget = useMemo(
|
const externalCallDurationWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder(
|
getWidgetQueryBuilder({
|
||||||
{
|
query: {
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
promql: [],
|
promql: [],
|
||||||
builder: externalCallDuration({
|
builder: externalCallDuration({
|
||||||
@ -76,15 +78,16 @@ function External(): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
},
|
},
|
||||||
GraphTitle.EXTERNAL_CALL_DURATION,
|
title: GraphTitle.EXTERNAL_CALL_DURATION,
|
||||||
),
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
|
}),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
const externalCallRPSWidget = useMemo(
|
const externalCallRPSWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder(
|
getWidgetQueryBuilder({
|
||||||
{
|
query: {
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
promql: [],
|
promql: [],
|
||||||
builder: externalCallRpsByAddress({
|
builder: externalCallRpsByAddress({
|
||||||
@ -95,15 +98,16 @@ function External(): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
},
|
},
|
||||||
GraphTitle.EXTERNAL_CALL_RPS_BY_ADDRESS,
|
title: GraphTitle.EXTERNAL_CALL_RPS_BY_ADDRESS,
|
||||||
),
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
|
}),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
const externalCallDurationAddressWidget = useMemo(
|
const externalCallDurationAddressWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder(
|
getWidgetQueryBuilder({
|
||||||
{
|
query: {
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
promql: [],
|
promql: [],
|
||||||
builder: externalCallDurationByAddress({
|
builder: externalCallDurationByAddress({
|
||||||
@ -114,8 +118,9 @@ function External(): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
},
|
},
|
||||||
GraphTitle.EXTERNAL_CALL_DURATION_BY_ADDRESS,
|
title: GraphTitle.EXTERNAL_CALL_DURATION_BY_ADDRESS,
|
||||||
),
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
|
}),
|
||||||
[servicename, tagFilterItems],
|
[servicename, tagFilterItems],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2,10 +2,13 @@ import getTopLevelOperations, {
|
|||||||
ServiceDataProps,
|
ServiceDataProps,
|
||||||
} from 'api/metrics/getTopLevelOperations';
|
} from 'api/metrics/getTopLevelOperations';
|
||||||
import { ActiveElement, Chart, ChartData, ChartEvent } from 'chart.js';
|
import { ActiveElement, Chart, ChartData, ChartEvent } from 'chart.js';
|
||||||
|
import { FeatureKeys } from 'constants/features';
|
||||||
import { QueryParams } from 'constants/query';
|
import { QueryParams } from 'constants/query';
|
||||||
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
import { routeConfig } from 'container/SideNav/config';
|
import { routeConfig } from 'container/SideNav/config';
|
||||||
import { getQueryString } from 'container/SideNav/helper';
|
import { getQueryString } from 'container/SideNav/helper';
|
||||||
|
import useFeatureFlag from 'hooks/useFeatureFlag';
|
||||||
import useResourceAttribute from 'hooks/useResourceAttribute';
|
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||||
import {
|
import {
|
||||||
convertRawQueriesToTraceSelectedTags,
|
convertRawQueriesToTraceSelectedTags,
|
||||||
@ -29,10 +32,11 @@ import {
|
|||||||
errorPercentage,
|
errorPercentage,
|
||||||
operationPerSec,
|
operationPerSec,
|
||||||
} from '../MetricsPageQueries/OverviewQueries';
|
} from '../MetricsPageQueries/OverviewQueries';
|
||||||
import { Col, Row } from '../styles';
|
import { Card, Col, Row } from '../styles';
|
||||||
import ServiceOverview from './Overview/ServiceOverview';
|
import ServiceOverview from './Overview/ServiceOverview';
|
||||||
import TopLevelOperation from './Overview/TopLevelOperations';
|
import TopLevelOperation from './Overview/TopLevelOperations';
|
||||||
import TopOperation from './Overview/TopOperation';
|
import TopOperation from './Overview/TopOperation';
|
||||||
|
import TopOperationMetrics from './Overview/TopOperationMetrics';
|
||||||
import { Button } from './styles';
|
import { Button } from './styles';
|
||||||
import { IServiceName } from './types';
|
import { IServiceName } from './types';
|
||||||
import {
|
import {
|
||||||
@ -53,6 +57,8 @@ function Application(): JSX.Element {
|
|||||||
() => (convertRawQueriesToTraceSelectedTags(queries) as Tags[]) || [],
|
() => (convertRawQueriesToTraceSelectedTags(queries) as Tags[]) || [],
|
||||||
[queries],
|
[queries],
|
||||||
);
|
);
|
||||||
|
const isSpanMetricEnabled = useFeatureFlag(FeatureKeys.USE_SPAN_METRICS)
|
||||||
|
?.active;
|
||||||
|
|
||||||
const handleSetTimeStamp = useCallback((selectTime: number) => {
|
const handleSetTimeStamp = useCallback((selectTime: number) => {
|
||||||
setSelectedTimeStamp(selectTime);
|
setSelectedTimeStamp(selectTime);
|
||||||
@ -104,8 +110,8 @@ function Application(): JSX.Element {
|
|||||||
|
|
||||||
const operationPerSecWidget = useMemo(
|
const operationPerSecWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder(
|
getWidgetQueryBuilder({
|
||||||
{
|
query: {
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
promql: [],
|
promql: [],
|
||||||
builder: operationPerSec({
|
builder: operationPerSec({
|
||||||
@ -116,15 +122,16 @@ function Application(): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
},
|
},
|
||||||
GraphTitle.RATE_PER_OPS,
|
title: GraphTitle.RATE_PER_OPS,
|
||||||
),
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
|
}),
|
||||||
[servicename, tagFilterItems, topLevelOperationsRoute],
|
[servicename, tagFilterItems, topLevelOperationsRoute],
|
||||||
);
|
);
|
||||||
|
|
||||||
const errorPercentageWidget = useMemo(
|
const errorPercentageWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder(
|
getWidgetQueryBuilder({
|
||||||
{
|
query: {
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
promql: [],
|
promql: [],
|
||||||
builder: errorPercentage({
|
builder: errorPercentage({
|
||||||
@ -135,8 +142,9 @@ function Application(): JSX.Element {
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
},
|
},
|
||||||
GraphTitle.ERROR_PERCENTAGE,
|
title: GraphTitle.ERROR_PERCENTAGE,
|
||||||
),
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
|
}),
|
||||||
[servicename, tagFilterItems, topLevelOperationsRoute],
|
[servicename, tagFilterItems, topLevelOperationsRoute],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -239,7 +247,9 @@ function Application(): JSX.Element {
|
|||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<TopOperation />
|
<Card>
|
||||||
|
{isSpanMetricEnabled ? <TopOperationMetrics /> : <TopOperation />}
|
||||||
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</>
|
</>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { FeatureKeys } from 'constants/features';
|
import { FeatureKeys } from 'constants/features';
|
||||||
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import Graph from 'container/GridGraphLayout/Graph/';
|
import Graph from 'container/GridGraphLayout/Graph/';
|
||||||
import { GraphTitle } from 'container/MetricsApplication/constant';
|
import { GraphTitle } from 'container/MetricsApplication/constant';
|
||||||
import { getWidgetQueryBuilder } from 'container/MetricsApplication/MetricsApplication.factory';
|
import { getWidgetQueryBuilder } from 'container/MetricsApplication/MetricsApplication.factory';
|
||||||
@ -31,8 +32,8 @@ function ServiceOverview({
|
|||||||
|
|
||||||
const latencyWidget = useMemo(
|
const latencyWidget = useMemo(
|
||||||
() =>
|
() =>
|
||||||
getWidgetQueryBuilder(
|
getWidgetQueryBuilder({
|
||||||
{
|
query: {
|
||||||
queryType: EQueryType.QUERY_BUILDER,
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
promql: [],
|
promql: [],
|
||||||
builder: latency({
|
builder: latency({
|
||||||
@ -44,8 +45,9 @@ function ServiceOverview({
|
|||||||
clickhouse_sql: [],
|
clickhouse_sql: [],
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
},
|
},
|
||||||
GraphTitle.LATENCY,
|
title: GraphTitle.LATENCY,
|
||||||
),
|
panelTypes: PANEL_TYPES.TIME_SERIES,
|
||||||
|
}),
|
||||||
[servicename, tagFilterItems, isSpanMetricEnable, topLevelOperationsRoute],
|
[servicename, tagFilterItems, isSpanMetricEnable, topLevelOperationsRoute],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
import { Tooltip, Typography } from 'antd';
|
||||||
|
import { navigateToTrace } from 'container/MetricsApplication/utils';
|
||||||
|
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||||
|
|
||||||
|
function ColumnWithLink({
|
||||||
|
servicename,
|
||||||
|
minTime,
|
||||||
|
maxTime,
|
||||||
|
selectedTraceTags,
|
||||||
|
record,
|
||||||
|
}: LinkColumnProps): JSX.Element {
|
||||||
|
const text = record.toString();
|
||||||
|
|
||||||
|
const handleOnClick = (operation: string) => (): void => {
|
||||||
|
navigateToTrace({
|
||||||
|
servicename,
|
||||||
|
operation,
|
||||||
|
minTime,
|
||||||
|
maxTime,
|
||||||
|
selectedTraceTags,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip placement="topLeft" title={text}>
|
||||||
|
<Typography.Link onClick={handleOnClick(text)}>{text}</Typography.Link>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LinkColumnProps {
|
||||||
|
servicename: string;
|
||||||
|
minTime: number;
|
||||||
|
maxTime: number;
|
||||||
|
selectedTraceTags: string;
|
||||||
|
record: RowData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ColumnWithLink;
|
@ -0,0 +1,11 @@
|
|||||||
|
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
import { TableRendererProps } from '../../types';
|
||||||
|
|
||||||
|
export const getTableColumnRenderer = ({
|
||||||
|
columnName,
|
||||||
|
renderFunction,
|
||||||
|
}: TableRendererProps): Record<string, (record: RowData) => ReactNode> => ({
|
||||||
|
[columnName]: renderFunction,
|
||||||
|
});
|
@ -1,6 +1,5 @@
|
|||||||
import getTopOperations from 'api/metrics/getTopOperations';
|
import getTopOperations from 'api/metrics/getTopOperations';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import { Card } from 'container/MetricsApplication/styles';
|
|
||||||
import TopOperationsTable from 'container/MetricsApplication/TopOperationsTable';
|
import TopOperationsTable from 'container/MetricsApplication/TopOperationsTable';
|
||||||
import useResourceAttribute from 'hooks/useResourceAttribute';
|
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||||
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
||||||
@ -35,11 +34,13 @@ function TopOperation(): JSX.Element {
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const topOperationData = data || [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<>
|
||||||
{isLoading && <Spinner size="large" tip="Loading..." height="40vh" />}
|
{isLoading && <Spinner size="large" tip="Loading..." height="40vh" />}
|
||||||
{!isLoading && <TopOperationsTable data={data || []} />}
|
{!isLoading && <TopOperationsTable data={topOperationData} />}
|
||||||
</Card>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,122 @@
|
|||||||
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
|
import { getWidgetQueryBuilder } from 'container/MetricsApplication/MetricsApplication.factory';
|
||||||
|
import { topOperationQueries } from 'container/MetricsApplication/MetricsPageQueries/TopOperationQueries';
|
||||||
|
import { QueryTable } from 'container/QueryTable';
|
||||||
|
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||||
|
import { useStepInterval } from 'hooks/queryBuilder/useStepInterval';
|
||||||
|
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||||
|
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
||||||
|
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
||||||
|
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||||
|
import { isEmpty } from 'lodash-es';
|
||||||
|
import { ReactNode, useMemo, useState } from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
|
import { IServiceName } from '../types';
|
||||||
|
import { title } from './config';
|
||||||
|
import ColumnWithLink from './TableRenderer/ColumnWithLink';
|
||||||
|
import { getTableColumnRenderer } from './TableRenderer/TableColumnRenderer';
|
||||||
|
|
||||||
|
function TopOperationMetrics(): JSX.Element {
|
||||||
|
const { servicename } = useParams<IServiceName>();
|
||||||
|
|
||||||
|
const [errorMessage, setErrorMessage] = useState<string | undefined>('');
|
||||||
|
const { minTime, maxTime, selectedTime: globalSelectedInterval } = useSelector<
|
||||||
|
AppState,
|
||||||
|
GlobalReducer
|
||||||
|
>((state) => state.globalTime);
|
||||||
|
const { queries } = useResourceAttribute();
|
||||||
|
|
||||||
|
const selectedTraceTags = JSON.stringify(
|
||||||
|
convertRawQueriesToTraceSelectedTags(queries) || [],
|
||||||
|
);
|
||||||
|
|
||||||
|
const keyOperationWidget = useMemo(
|
||||||
|
() =>
|
||||||
|
getWidgetQueryBuilder({
|
||||||
|
query: {
|
||||||
|
queryType: EQueryType.QUERY_BUILDER,
|
||||||
|
promql: [],
|
||||||
|
builder: topOperationQueries({
|
||||||
|
servicename,
|
||||||
|
}),
|
||||||
|
clickhouse_sql: [],
|
||||||
|
id: uuid(),
|
||||||
|
},
|
||||||
|
panelTypes: PANEL_TYPES.TABLE,
|
||||||
|
}),
|
||||||
|
[servicename],
|
||||||
|
);
|
||||||
|
|
||||||
|
const updatedQuery = useStepInterval(keyOperationWidget.query);
|
||||||
|
|
||||||
|
const isEmptyWidget = useMemo(
|
||||||
|
() => keyOperationWidget.id === 'empty' || isEmpty(keyOperationWidget),
|
||||||
|
[keyOperationWidget],
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data, isLoading } = useGetQueryRange(
|
||||||
|
{
|
||||||
|
selectedTime: keyOperationWidget?.timePreferance,
|
||||||
|
graphType: keyOperationWidget?.panelTypes,
|
||||||
|
query: updatedQuery,
|
||||||
|
globalSelectedInterval,
|
||||||
|
variables: getDashboardVariables(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
queryKey: [
|
||||||
|
`GetMetricsQueryRange-${keyOperationWidget?.timePreferance}-${globalSelectedInterval}-${keyOperationWidget?.id}`,
|
||||||
|
keyOperationWidget,
|
||||||
|
maxTime,
|
||||||
|
minTime,
|
||||||
|
globalSelectedInterval,
|
||||||
|
],
|
||||||
|
keepPreviousData: true,
|
||||||
|
enabled: !isEmptyWidget,
|
||||||
|
refetchOnMount: false,
|
||||||
|
onError: (error) => {
|
||||||
|
setErrorMessage(error.message);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const queryTableData = data?.payload.data.newResult.data.result || [];
|
||||||
|
|
||||||
|
const renderColumnCell = useMemo(
|
||||||
|
() =>
|
||||||
|
getTableColumnRenderer({
|
||||||
|
columnName: 'operation',
|
||||||
|
renderFunction: (record: RowData): ReactNode => (
|
||||||
|
<ColumnWithLink
|
||||||
|
servicename={servicename}
|
||||||
|
minTime={minTime}
|
||||||
|
maxTime={maxTime}
|
||||||
|
selectedTraceTags={selectedTraceTags}
|
||||||
|
record={record}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
[servicename, minTime, maxTime, selectedTraceTags],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (errorMessage) {
|
||||||
|
return <div>{errorMessage}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<QueryTable
|
||||||
|
title={title}
|
||||||
|
query={updatedQuery}
|
||||||
|
queryTableData={queryTableData}
|
||||||
|
loading={isLoading}
|
||||||
|
renderColumnCell={renderColumnCell}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TopOperationMetrics;
|
@ -0,0 +1 @@
|
|||||||
|
export const title = (): string => 'Key Operations';
|
@ -1,3 +1,62 @@
|
|||||||
|
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||||
|
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
|
import { DataSource, MetricAggregateOperator } from 'types/common/queryBuilder';
|
||||||
|
|
||||||
export interface IServiceName {
|
export interface IServiceName {
|
||||||
servicename: string;
|
servicename: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TopOperationQueryFactoryProps {
|
||||||
|
servicename: IServiceName['servicename'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExternalCallDurationByAddressProps extends ExternalCallProps {
|
||||||
|
legend: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExternalCallProps {
|
||||||
|
servicename: IServiceName['servicename'];
|
||||||
|
tagFilterItems: TagFilterItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BuilderQueriesProps {
|
||||||
|
autocompleteData: BaseAutocompleteData[];
|
||||||
|
groupBy?: BaseAutocompleteData[];
|
||||||
|
legends: string[];
|
||||||
|
filterItems: TagFilterItem[][];
|
||||||
|
aggregateOperator?: string[];
|
||||||
|
dataSource: DataSource;
|
||||||
|
queryNameAndExpression?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BuilderQuerieswithFormulaProps {
|
||||||
|
autocompleteData: BaseAutocompleteData[];
|
||||||
|
legends: string[];
|
||||||
|
disabled: boolean[];
|
||||||
|
groupBy?: BaseAutocompleteData[];
|
||||||
|
expression: string;
|
||||||
|
legendFormula: string;
|
||||||
|
additionalItems: TagFilterItem[][];
|
||||||
|
aggregateOperators: MetricAggregateOperator[];
|
||||||
|
dataSource: DataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OperationPerSecProps {
|
||||||
|
servicename: IServiceName['servicename'];
|
||||||
|
tagFilterItems: TagFilterItem[];
|
||||||
|
topLevelOperations: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LatencyProps {
|
||||||
|
servicename: IServiceName['servicename'];
|
||||||
|
tagFilterItems: TagFilterItem[];
|
||||||
|
isSpanMetricEnable?: boolean;
|
||||||
|
topLevelOperationsRoute: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TableRendererProps {
|
||||||
|
columnName: string;
|
||||||
|
renderFunction: (record: RowData) => ReactNode;
|
||||||
|
}
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
import { Tooltip, Typography } from 'antd';
|
import { Tooltip, Typography } from 'antd';
|
||||||
import { ColumnsType } from 'antd/lib/table';
|
import { ColumnsType } from 'antd/lib/table';
|
||||||
import { ResizeTable } from 'components/ResizeTable';
|
import { ResizeTable } from 'components/ResizeTable';
|
||||||
import { QueryParams } from 'constants/query';
|
|
||||||
import ROUTES from 'constants/routes';
|
|
||||||
import useResourceAttribute from 'hooks/useResourceAttribute';
|
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||||
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
||||||
import history from 'lib/history';
|
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
|
||||||
import { getErrorRate } from './utils';
|
import { getErrorRate, navigateToTrace } from './utils';
|
||||||
|
|
||||||
function TopOperationsTable(props: TopOperationsTableProps): JSX.Element {
|
function TopOperationsTable(props: TopOperationsTableProps): JSX.Element {
|
||||||
const { minTime, maxTime } = useSelector<AppState, GlobalReducer>(
|
const { minTime, maxTime } = useSelector<AppState, GlobalReducer>(
|
||||||
@ -28,16 +25,15 @@ function TopOperationsTable(props: TopOperationsTableProps): JSX.Element {
|
|||||||
const params = useParams<{ servicename: string }>();
|
const params = useParams<{ servicename: string }>();
|
||||||
|
|
||||||
const handleOnClick = (operation: string): void => {
|
const handleOnClick = (operation: string): void => {
|
||||||
const urlParams = new URLSearchParams();
|
|
||||||
const { servicename } = params;
|
const { servicename } = params;
|
||||||
urlParams.set(QueryParams.startTime, (minTime / 1000000).toString());
|
|
||||||
urlParams.set(QueryParams.endTime, (maxTime / 1000000).toString());
|
|
||||||
|
|
||||||
history.push(
|
navigateToTrace({
|
||||||
`${
|
servicename,
|
||||||
ROUTES.TRACE
|
operation,
|
||||||
}?${urlParams.toString()}&selected={"serviceName":["${servicename}"],"operation":["${operation}"]}&filterToFetchData=["duration","status","serviceName","operation"]&spanAggregateCurrentPage=1&selectedTags=${selectedTraceTags}&&isFilterExclude={"serviceName":false,"operation":false}&userSelectedFilter={"status":["error","ok"],"serviceName":["${servicename}"],"operation":["${operation}"]}&spanAggregateCurrentPage=1`,
|
minTime,
|
||||||
);
|
maxTime,
|
||||||
|
selectedTraceTags,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns: ColumnsType<TopOperationList> = [
|
const columns: ColumnsType<TopOperationList> = [
|
||||||
|
@ -28,6 +28,14 @@ export enum GraphTitle {
|
|||||||
EXTERNAL_CALL_DURATION_BY_ADDRESS = 'External Call duration(by Address)',
|
EXTERNAL_CALL_DURATION_BY_ADDRESS = 'External Call duration(by Address)',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum KeyOperationTableHeader {
|
||||||
|
P50 = 'P50',
|
||||||
|
P90 = 'P90',
|
||||||
|
P99 = 'P99',
|
||||||
|
NUM_OF_CALLS = 'Number of Calls',
|
||||||
|
ERROR_RATE = 'Error Rate',
|
||||||
|
}
|
||||||
|
|
||||||
export enum DataType {
|
export enum DataType {
|
||||||
STRING = 'string',
|
STRING = 'string',
|
||||||
FLOAT64 = 'float64',
|
FLOAT64 = 'float64',
|
||||||
|
15
frontend/src/container/MetricsApplication/types.ts
Normal file
15
frontend/src/container/MetricsApplication/types.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Widgets } from 'types/api/dashboard/getAll';
|
||||||
|
|
||||||
|
export interface GetWidgetQueryBuilderProps {
|
||||||
|
query: Widgets['query'];
|
||||||
|
title?: string;
|
||||||
|
panelTypes: Widgets['panelTypes'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NavigateToTraceProps {
|
||||||
|
servicename: string;
|
||||||
|
operation: string;
|
||||||
|
minTime: number;
|
||||||
|
maxTime: number;
|
||||||
|
selectedTraceTags: string;
|
||||||
|
}
|
@ -1,4 +1,26 @@
|
|||||||
|
import { QueryParams } from 'constants/query';
|
||||||
|
import ROUTES from 'constants/routes';
|
||||||
|
import history from 'lib/history';
|
||||||
|
|
||||||
import { TopOperationList } from './TopOperationsTable';
|
import { TopOperationList } from './TopOperationsTable';
|
||||||
|
import { NavigateToTraceProps } from './types';
|
||||||
|
|
||||||
export const getErrorRate = (list: TopOperationList): number =>
|
export const getErrorRate = (list: TopOperationList): number =>
|
||||||
(list.errorCount / list.numCalls) * 100;
|
(list.errorCount / list.numCalls) * 100;
|
||||||
|
|
||||||
|
export const navigateToTrace = ({
|
||||||
|
servicename,
|
||||||
|
operation,
|
||||||
|
minTime,
|
||||||
|
maxTime,
|
||||||
|
selectedTraceTags,
|
||||||
|
}: NavigateToTraceProps): void => {
|
||||||
|
const urlParams = new URLSearchParams();
|
||||||
|
urlParams.set(QueryParams.startTime, (minTime / 1000000).toString());
|
||||||
|
urlParams.set(QueryParams.endTime, (maxTime / 1000000).toString());
|
||||||
|
history.push(
|
||||||
|
`${
|
||||||
|
ROUTES.TRACE
|
||||||
|
}?${urlParams.toString()}&selected={"serviceName":["${servicename}"],"operation":["${operation}"]}&filterToFetchData=["duration","status","serviceName","operation"]&spanAggregateCurrentPage=1&selectedTags=${selectedTraceTags}&&isFilterExclude={"serviceName":false,"operation":false}&userSelectedFilter={"status":["error","ok"],"serviceName":["${servicename}"],"operation":["${operation}"]}&spanAggregateCurrentPage=1`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user