feat: added APM to new trace filter redirection (#5225)

This commit is contained in:
SagarRajput-7 2024-06-15 13:53:56 +05:30 committed by GitHub
parent e6ee5fc9e3
commit f824aa17dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 274 additions and 40 deletions

View File

@ -255,7 +255,7 @@ function FormAlertRules({
if (
!currentQuery.builder.queryData ||
currentQuery.builder.queryData.length === 0
currentQuery.builder.queryData?.length === 0
) {
notifications.error({
message: 'Error',

View File

@ -30,8 +30,8 @@ export const constructCompositeQuery = ({
}: GetDefaultCompositeQueryParams): Query => ({
...query,
builder: {
...query.builder,
queryData: query.builder.queryData.map((item) => ({
...query?.builder,
queryData: query?.builder?.queryData?.map((item) => ({
...initialQueryData,
...item,
...customQueryData,

View File

@ -42,7 +42,7 @@ export const prepareQueryByFilter = (
...query,
builder: {
...query.builder,
queryData: query.builder.queryData.map((item) => ({
queryData: query.builder.queryData?.map((item) => ({
...item,
filters: value ? getFilter(item.filters, tagFilter, value) : item.filters,
})),
@ -57,7 +57,7 @@ export const getQueryWithoutFilterId = (query: Query): Query => {
...query,
builder: {
...query.builder,
queryData: query.builder.queryData.map((item) => ({
queryData: query.builder.queryData?.map((item) => ({
...item,
filters: {
...item.filters,

View File

@ -40,7 +40,7 @@ export const getRequestData = ({
...query,
builder: {
...query.builder,
queryData: query.builder.queryData.map((item) => ({
queryData: query.builder.queryData?.map((item) => ({
...item,
...paginateData,
pageSize,

View File

@ -27,6 +27,7 @@ import {
handleNonInQueryRange,
onGraphClickHandler,
onViewTracePopupClick,
useGetAPMToTracesQueries,
} from './util';
function DBCall(): JSX.Element {
@ -96,6 +97,11 @@ function DBCall(): JSX.Element {
[servicename, tagFilterItems],
);
const apmToTraceQuery = useGetAPMToTracesQueries({
servicename,
isDBCall: true,
});
return (
<Row gutter={24}>
<Col span={12}>
@ -107,6 +113,7 @@ function DBCall(): JSX.Element {
servicename,
selectedTraceTags,
timestamp: selectedTimeStamp,
apmToTraceQuery,
})}
>
View Traces
@ -139,6 +146,7 @@ function DBCall(): JSX.Element {
servicename,
selectedTraceTags,
timestamp: selectedTimeStamp,
apmToTraceQuery,
})}
>
View Traces

View File

@ -27,6 +27,7 @@ import {
handleNonInQueryRange,
onGraphClickHandler,
onViewTracePopupClick,
useGetAPMToTracesQueries,
} from './util';
function External(): JSX.Element {
@ -138,6 +139,11 @@ function External(): JSX.Element {
[servicename, tagFilterItems],
);
const apmToTraceQuery = useGetAPMToTracesQueries({
servicename,
isExternalCall: true,
});
return (
<>
<Row gutter={24}>
@ -150,7 +156,7 @@ function External(): JSX.Element {
servicename,
selectedTraceTags,
timestamp: selectedTimeStamp,
isExternalCall: true,
apmToTraceQuery,
})}
>
View Traces
@ -184,7 +190,7 @@ function External(): JSX.Element {
servicename,
selectedTraceTags,
timestamp: selectedTimeStamp,
isExternalCall: true,
apmToTraceQuery,
})}
>
View Traces
@ -221,7 +227,7 @@ function External(): JSX.Element {
servicename,
selectedTraceTags,
timestamp: selectedTimeStamp,
isExternalCall: true,
apmToTraceQuery,
})}
>
View Traces
@ -255,7 +261,7 @@ function External(): JSX.Element {
servicename,
selectedTraceTags,
timestamp: selectedTimeStamp,
isExternalCall: true,
apmToTraceQuery,
})}
>
View Traces

View File

@ -22,6 +22,8 @@ import { useQuery } from 'react-query';
import { useDispatch } from 'react-redux';
import { useLocation, useParams } from 'react-router-dom';
import { UpdateTimeInterval } from 'store/actions';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { v4 as uuid } from 'uuid';
@ -43,6 +45,7 @@ import {
handleNonInQueryRange,
onGraphClickHandler,
onViewTracePopupClick,
useGetAPMToTracesQueries,
} from './util';
function Application(): JSX.Element {
@ -92,6 +95,8 @@ function Application(): JSX.Element {
convertRawQueriesToTraceSelectedTags(queries) || [],
);
const apmToTraceQuery = useGetAPMToTracesQueries({ servicename });
const tagFilterItems = useMemo(
() =>
handleNonInQueryRange(resourceAttributesToTagFilterItems(queries)) || [],
@ -159,7 +164,10 @@ function Application(): JSX.Element {
[dispatch, pathname, urlQuery],
);
const onErrorTrackHandler = (timestamp: number): (() => void) => (): void => {
const onErrorTrackHandler = (
timestamp: number,
apmToTraceQuery: Query,
): (() => void) => (): void => {
const currentTime = timestamp;
const tPlusOne = timestamp + 60 * 1000;
@ -170,15 +178,38 @@ function Application(): JSX.Element {
const avialableParams = routeConfig[ROUTES.TRACE];
const queryString = getQueryString(avialableParams, urlParams);
history.replace(
`${
ROUTES.TRACE
}?selected={"serviceName":["${servicename}"],"status":["error"]}&filterToFetchData=["duration","status","serviceName"]&spanAggregateCurrentPage=1&selectedTags=${selectedTraceTags}&isFilterExclude={"serviceName":false,"status":false}&userSelectedFilter={"serviceName":["${servicename}"],"status":["error"]}&spanAggregateCurrentPage=1&${queryString.join(
'',
)}`,
const JSONCompositeQuery = encodeURIComponent(
JSON.stringify(apmToTraceQuery),
);
const newTraceExplorerPath = `${
ROUTES.TRACES_EXPLORER
}?${urlParams.toString()}&selected={"serviceName":["${servicename}"]}&filterToFetchData=["duration","status","serviceName"]&spanAggregateCurrentPage=1&selectedTags=${selectedTraceTags}&${
QueryParams.compositeQuery
}=${JSONCompositeQuery}&${queryString.join('&')}`;
history.push(newTraceExplorerPath);
};
const errorTrackQuery = useGetAPMToTracesQueries({
servicename,
filters: [
{
id: uuid().slice(0, 8),
key: {
key: 'hasError',
dataType: DataTypes.bool,
type: 'tag',
isColumn: true,
isJSON: false,
id: 'hasError--bool--tag--true',
},
op: 'in',
value: ['true'],
},
],
});
return (
<>
<Row gutter={24}>
@ -202,6 +233,7 @@ function Application(): JSX.Element {
servicename,
selectedTraceTags,
timestamp: selectedTimeStamp,
apmToTraceQuery,
})}
>
View Traces
@ -229,6 +261,7 @@ function Application(): JSX.Element {
servicename,
selectedTraceTags,
timestamp: selectedTimeStamp,
apmToTraceQuery,
})}
>
View Traces
@ -245,7 +278,7 @@ function Application(): JSX.Element {
type="default"
size="small"
id="Error_button"
onClick={onErrorTrackHandler(selectedTimeStamp)}
onClick={onErrorTrackHandler(selectedTimeStamp, errorTrackQuery)}
>
View Traces
</Button>

View File

@ -21,7 +21,11 @@ import { v4 as uuid } from 'uuid';
import { Button } from '../styles';
import { IServiceName } from '../types';
import { handleNonInQueryRange, onViewTracePopupClick } from '../util';
import {
handleNonInQueryRange,
onViewTracePopupClick,
useGetAPMToTracesQueries,
} from '../util';
function ServiceOverview({
onDragSelect,
@ -69,6 +73,8 @@ function ServiceOverview({
const isQueryEnabled =
!topLevelOperationsIsLoading && topLevelOperationsRoute.length > 0;
const apmToTraceQuery = useGetAPMToTracesQueries({ servicename });
return (
<>
<Button
@ -79,6 +85,7 @@ function ServiceOverview({
servicename,
selectedTraceTags,
timestamp: selectedTimeStamp,
apmToTraceQuery,
})}
>
View Traces

View File

@ -1,6 +1,10 @@
import { Tooltip, Typography } from 'antd';
import { navigateToTrace } from 'container/MetricsApplication/utils';
import { RowData } from 'lib/query/createTableColumnsFromQuery';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { v4 as uuid } from 'uuid';
import { useGetAPMToTracesQueries } from '../../util';
function ColumnWithLink({
servicename,
@ -11,6 +15,25 @@ function ColumnWithLink({
}: LinkColumnProps): JSX.Element {
const text = record.toString();
const apmToTraceQuery = useGetAPMToTracesQueries({
servicename,
filters: [
{
id: uuid().slice(0, 8),
key: {
key: 'name',
dataType: DataTypes.String,
type: 'tag',
isColumn: true,
isJSON: false,
id: 'name--string--tag--true',
},
op: 'in',
value: [text],
},
],
});
const handleOnClick = (operation: string) => (): void => {
navigateToTrace({
servicename,
@ -18,6 +41,7 @@ function ColumnWithLink({
minTime,
maxTime,
selectedTraceTags,
apmToTraceQuery,
});
};

View File

@ -1,11 +1,20 @@
import { QueryParams } from 'constants/query';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import ROUTES from 'constants/routes';
import { routeConfig } from 'container/SideNav/config';
import { getQueryString } from 'container/SideNav/helper';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import history from 'lib/history';
import { Dispatch, SetStateAction } from 'react';
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
import { traceFilterKeys } from 'pages/TracesExplorer/Filter/filterUtils';
import { Dispatch, SetStateAction, useMemo } from 'react';
import {
BaseAutocompleteData,
DataTypes,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { Query, TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder';
import { Tags } from 'types/reducer/trace';
import { v4 as uuid } from 'uuid';
export const dbSystemTags: Tags[] = [
{
@ -21,13 +30,13 @@ interface OnViewTracePopupClickProps {
servicename: string | undefined;
selectedTraceTags: string;
timestamp: number;
isExternalCall?: boolean;
apmToTraceQuery: Query;
}
export function onViewTracePopupClick({
selectedTraceTags,
servicename,
timestamp,
isExternalCall,
apmToTraceQuery,
}: OnViewTracePopupClickProps): VoidFunction {
return (): void => {
const currentTime = timestamp;
@ -40,13 +49,17 @@ export function onViewTracePopupClick({
const avialableParams = routeConfig[ROUTES.TRACE];
const queryString = getQueryString(avialableParams, urlParams);
history.replace(
`${
ROUTES.TRACE
}?${urlParams.toString()}&selected={"serviceName":["${servicename}"]}&filterToFetchData=["duration","status","serviceName"]&spanAggregateCurrentPage=1&selectedTags=${selectedTraceTags}&&isFilterExclude={"serviceName":false}&userSelectedFilter={"status":["error","ok"],"serviceName":["${servicename}"]}&spanAggregateCurrentPage=1${
isExternalCall ? '&spanKind=3' : ''
}&${queryString.join('&')}`,
const JSONCompositeQuery = encodeURIComponent(
JSON.stringify(apmToTraceQuery),
);
const newTraceExplorerPath = `${
ROUTES.TRACES_EXPLORER
}?${urlParams.toString()}&selected={"serviceName":["${servicename}"]}&filterToFetchData=["duration","status","serviceName"]&spanAggregateCurrentPage=1&selectedTags=${selectedTraceTags}&${
QueryParams.compositeQuery
}=${JSONCompositeQuery}&${queryString.join('&')}`;
history.push(newTraceExplorerPath);
};
}
@ -87,3 +100,104 @@ export const handleNonInQueryRange = (tags: TagFilterItem[]): TagFilterItem[] =>
}
return tag;
});
export function handleQueryChange(
query: Query,
attributeKeys: BaseAutocompleteData,
serviceAttribute: string,
filters?: TagFilterItem[],
): Query {
const filterItem: TagFilterItem[] = [
{
id: uuid().slice(0, 8),
key: attributeKeys,
op: 'in',
value: serviceAttribute,
},
];
return {
...query,
builder: {
...query.builder,
queryData: query.builder.queryData?.map((item) => ({
...item,
filters: {
...item.filters,
items: [...item.filters.items, ...filterItem, ...(filters || [])],
},
})),
},
};
}
export function useGetAPMToTracesQueries({
servicename,
isExternalCall,
isDBCall,
filters,
}: {
servicename: string;
isExternalCall?: boolean;
isDBCall?: boolean;
filters?: TagFilterItem[];
}): Query {
const { updateAllQueriesOperators } = useQueryBuilder();
const finalFilters: TagFilterItem[] = [];
let spanKindFilter: TagFilterItem;
let dbCallFilter: TagFilterItem;
if (isExternalCall) {
spanKindFilter = {
id: uuid().slice(0, 8),
key: {
key: 'spanKind',
dataType: DataTypes.String,
type: 'tag',
isColumn: true,
isJSON: false,
id: 'spanKind--string--tag--true',
},
op: '=',
value: 'Client',
};
finalFilters.push(spanKindFilter);
}
if (isDBCall) {
dbCallFilter = {
id: uuid().slice(0, 8),
key: {
key: 'dbSystem',
dataType: DataTypes.String,
type: 'tag',
isColumn: true,
isJSON: false,
id: 'dbSystem--string--tag--true',
},
op: 'exists',
value: '',
};
finalFilters.push(dbCallFilter);
}
if (filters?.length) {
finalFilters.push(...filters);
}
return useMemo(() => {
const updatedQuery = updateAllQueriesOperators(
initialQueriesMap.traces,
PANEL_TYPES.TRACE,
DataSource.TRACES,
);
return handleQueryChange(
updatedQuery,
traceFilterKeys.serviceName,
servicename,
finalFilters,
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [servicename, updateAllQueriesOperators]);
}

View File

@ -12,9 +12,13 @@ import { useRef } from 'react';
import { useSelector } from 'react-redux';
import { useParams } from 'react-router-dom';
import { AppState } from 'store/reducers';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { Query, TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
import { GlobalReducer } from 'types/reducer/globalTime';
import { v4 as uuid } from 'uuid';
import { IServiceName } from './Tabs/types';
import { useGetAPMToTracesQueries } from './Tabs/util';
import {
convertedTracesToDownloadData,
getErrorRate,
@ -38,18 +42,49 @@ function TopOperationsTable({
convertRawQueriesToTraceSelectedTags(queries) || [],
);
const apmToTraceQuery = useGetAPMToTracesQueries({ servicename });
const params = useParams<{ servicename: string }>();
const handleOnClick = (operation: string): void => {
const { servicename: encodedServiceName } = params;
const servicename = decodeURIComponent(encodedServiceName);
const opFilter: TagFilterItem = {
id: uuid().slice(0, 8),
key: {
key: 'name',
dataType: DataTypes.String,
type: 'tag',
isColumn: true,
isJSON: false,
id: 'name--string--tag--true',
},
op: 'in',
value: [operation],
};
const preparedQuery: Query = {
...apmToTraceQuery,
builder: {
...apmToTraceQuery.builder,
queryData: apmToTraceQuery.builder.queryData?.map((item) => ({
...item,
filters: {
...item.filters,
items: [...item.filters.items, opFilter],
},
})),
},
};
navigateToTrace({
servicename,
operation,
minTime,
maxTime,
selectedTraceTags,
apmToTraceQuery: preparedQuery,
});
};

View File

@ -1,6 +1,6 @@
import { ReactNode } from 'react';
import { Widgets } from 'types/api/dashboard/getAll';
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
import { Query, TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
import { IServiceName } from './Tabs/types';
@ -19,6 +19,7 @@ export interface NavigateToTraceProps {
minTime: number;
maxTime: number;
selectedTraceTags: string;
apmToTraceQuery: Query;
}
export interface DatabaseCallsRPSProps extends DatabaseCallProps {

View File

@ -18,15 +18,21 @@ export const navigateToTrace = ({
minTime,
maxTime,
selectedTraceTags,
apmToTraceQuery,
}: 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`,
);
const JSONCompositeQuery = encodeURIComponent(JSON.stringify(apmToTraceQuery));
const newTraceExplorerPath = `${
ROUTES.TRACES_EXPLORER
}?${urlParams.toString()}&selected={"serviceName":["${servicename}"],"operation":["${operation}"]}&filterToFetchData=["duration","status","serviceName","operation"]&spanAggregateCurrentPage=1&selectedTags=${selectedTraceTags}&${
QueryParams.compositeQuery
}=${JSONCompositeQuery}`;
history.push(newTraceExplorerPath);
};
export const getNearestHighestBucketValue = (

View File

@ -4,7 +4,7 @@ export const prepareQueryWithDefaultTimestamp = (query: Query): Query => ({
...query,
builder: {
...query.builder,
queryData: query.builder.queryData.map((item) => ({
queryData: query.builder.queryData?.map((item) => ({
...item,
orderBy: [{ columnName: 'timestamp', order: 'desc' }],
})),

View File

@ -148,13 +148,13 @@ export function QueryBuilderProvider({
const prepareQueryBuilderData = useCallback(
(query: Query): Query => {
const builder: QueryBuilderData = {
queryData: query.builder.queryData.map((item) => ({
queryData: query.builder.queryData?.map((item) => ({
...initialQueryBuilderFormValuesMap[
initialDataSource || DataSource.METRICS
],
...item,
})),
queryFormulas: query.builder.queryFormulas.map((item) => ({
queryFormulas: query.builder.queryFormulas?.map((item) => ({
...initialFormulaBuilderFormValues,
...item,
})),
@ -236,7 +236,7 @@ export function QueryBuilderProvider({
const updateAllQueriesOperators = useCallback(
(query: Query, panelType: PANEL_TYPES, dataSource: DataSource): Query => {
const queryData = query.builder.queryData.map((item) =>
const queryData = query.builder.queryData?.map((item) =>
getElementWithActualOperator(item, dataSource, panelType),
);
@ -682,7 +682,7 @@ export function QueryBuilderProvider({
: query.queryType;
const builder =
!query.builder || query.builder.queryData.length === 0
!query.builder || query.builder.queryData?.length === 0
? initialQueryState.builder
: query.builder;