feat: added view logs button for error and latency chart

This commit is contained in:
rahulkeswani101 2024-09-02 09:54:49 +05:30
parent 16738ea7e3
commit 6bc2f9125c
5 changed files with 187 additions and 42 deletions

View File

@ -38,6 +38,7 @@ import {
} from '../MetricsPageQueries/OverviewQueries';
import { Col, ColApDexContainer, ColErrorContainer, Row } from '../styles';
import ApDex from './Overview/ApDex';
import GraphControlsPanel from './Overview/GraphControlsPanel/GraphControlsPanel';
import ServiceOverview from './Overview/ServiceOverview';
import TopLevelOperation from './Overview/TopLevelOperations';
import TopOperation from './Overview/TopOperation';
@ -48,6 +49,7 @@ import {
handleNonInQueryRange,
onGraphClickHandler,
onViewTracePopupClick,
useGetAPMToLogsQueries,
useGetAPMToTracesQueries,
} from './util';
@ -194,33 +196,57 @@ function Application(): JSX.Element {
[dispatch, pathname, urlQuery],
);
const onErrorTrackHandler = (
timestamp: number,
apmToTraceQuery: Query,
): (() => void) => (): void => {
const currentTime = timestamp;
const tPlusOne = timestamp + 60 * 1000;
const onErrorTrackHandler = useCallback(
(
timestamp: number,
apmToTraceQuery: Query,
isViewLogsClicked?: boolean,
): (() => void) => (): void => {
const currentTime = timestamp;
const tPlusOne = timestamp + 60 * 1000;
const urlParams = new URLSearchParams(search);
urlParams.set(QueryParams.startTime, currentTime.toString());
urlParams.set(QueryParams.endTime, tPlusOne.toString());
const urlParams = new URLSearchParams(search);
urlParams.set(QueryParams.startTime, currentTime.toString());
urlParams.set(QueryParams.endTime, tPlusOne.toString());
const avialableParams = routeConfig[ROUTES.TRACE];
const queryString = getQueryString(avialableParams, urlParams);
const avialableParams = routeConfig[ROUTES.TRACE];
const queryString = getQueryString(avialableParams, urlParams);
const JSONCompositeQuery = encodeURIComponent(
JSON.stringify(apmToTraceQuery),
);
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('&')}`;
const basePath = isViewLogsClicked
? ROUTES.LOGS_EXPLORER
: ROUTES.TRACES_EXPLORER;
const newPath = `${basePath}?${urlParams.toString()}&selected={"serviceName":["${servicename}"]}&filterToFetchData=["duration","status","serviceName"]&spanAggregateCurrentPage=1&selectedTags=${selectedTraceTags}&${
QueryParams.compositeQuery
}=${JSONCompositeQuery}&${queryString.join('&')}`;
history.push(newTraceExplorerPath);
};
history.push(newPath);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[],
);
const logErrorQuery = useGetAPMToLogsQueries({
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: '=',
value: ['true'],
},
],
});
const errorTrackQuery = useGetAPMToTracesQueries({
servicename,
filters: [
@ -304,14 +330,18 @@ function Application(): JSX.Element {
/>
</ColApDexContainer>
<ColErrorContainer>
<Button
type="default"
size="small"
<GraphControlsPanel
id="Error_button"
onClick={onErrorTrackHandler(selectedTimeStamp, errorTrackQuery)}
>
View Traces
</Button>
onViewLogsClick={onErrorTrackHandler(
selectedTimeStamp,
logErrorQuery,
true,
)}
onViewTracesClick={onErrorTrackHandler(
selectedTimeStamp,
errorTrackQuery,
)}
/>
<TopLevelOperation
handleGraphClick={handleGraphClick}

View File

@ -0,0 +1,26 @@
.graph-controls-panel {
position: absolute;
z-index: 999;
display: none;
flex-direction: column;
width: 110px;
padding: 5px;
border-radius: 5px;
background: var(--bg-slate-400);
.ant-btn-link {
padding: 0;
margin: 0;
text-decoration: none;
color: var(--bg-vanilla-100);
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 2px;
border: none;
}
.ant-btn-link:hover {
color: var(--bg-vanilla-100);
}
}

View File

@ -0,0 +1,42 @@
import './GraphControlsPanel.styles.scss';
import { Color } from '@signozhq/design-tokens';
import { Button } from 'antd';
import { DraftingCompass, ScrollText } from 'lucide-react';
interface GraphControlsPanelProps {
id: string;
onViewLogsClick: () => void;
onViewTracesClick: () => void;
}
function GraphControlsPanel({
id,
onViewLogsClick,
onViewTracesClick,
}: GraphControlsPanelProps): JSX.Element {
return (
<div id={id} className="graph-controls-panel">
<Button
type="link"
icon={<DraftingCompass size={14} />}
size="small"
onClick={onViewTracesClick}
style={{ color: Color.BG_VANILLA_100 }}
>
View traces
</Button>
<Button
type="link"
icon={<ScrollText size={14} />}
size="small"
onClick={onViewLogsClick}
style={{ color: Color.BG_VANILLA_100 }}
>
View logs
</Button>
</div>
);
}
export default GraphControlsPanel;

View File

@ -19,13 +19,14 @@ import { useParams } from 'react-router-dom';
import { EQueryType } from 'types/common/dashboard';
import { v4 as uuid } from 'uuid';
import { Button } from '../styles';
import { IServiceName } from '../types';
import {
handleNonInQueryRange,
onViewTracePopupClick,
useGetAPMToLogsQueries,
useGetAPMToTracesQueries,
} from '../util';
import GraphControlsPanel from './GraphControlsPanel/GraphControlsPanel';
function ServiceOverview({
onDragSelect,
@ -75,21 +76,26 @@ function ServiceOverview({
const apmToTraceQuery = useGetAPMToTracesQueries({ servicename });
const apmToLogQuery = useGetAPMToLogsQueries({ servicename });
return (
<>
<Button
type="default"
size="small"
<GraphControlsPanel
id="Service_button"
onClick={onViewTracePopupClick({
onViewLogsClick={onViewTracePopupClick({
servicename,
selectedTraceTags,
timestamp: selectedTimeStamp,
apmToTraceQuery: apmToLogQuery,
isViewLogsClicked: true,
})}
onViewTracesClick={onViewTracePopupClick({
servicename,
selectedTraceTags,
timestamp: selectedTimeStamp,
apmToTraceQuery,
})}
>
View Traces
</Button>
/>
<Card data-testid="service_latency">
<GraphContainer>
{topLevelOperationsIsLoading && (

View File

@ -5,6 +5,7 @@ import { routeConfig } from 'container/SideNav/config';
import { getQueryString } from 'container/SideNav/helper';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import history from 'lib/history';
import { prepareQueryWithDefaultTimestamp } from 'pages/LogsExplorer/utils';
import { traceFilterKeys } from 'pages/TracesExplorer/Filter/filterUtils';
import { Dispatch, SetStateAction, useMemo } from 'react';
import {
@ -31,12 +32,14 @@ interface OnViewTracePopupClickProps {
selectedTraceTags: string;
timestamp: number;
apmToTraceQuery: Query;
isViewLogsClicked?: boolean;
}
export function onViewTracePopupClick({
selectedTraceTags,
servicename,
timestamp,
apmToTraceQuery,
isViewLogsClicked,
}: OnViewTracePopupClickProps): VoidFunction {
return (): void => {
const currentTime = timestamp;
@ -53,13 +56,14 @@ export function onViewTracePopupClick({
JSON.stringify(apmToTraceQuery),
);
const newTraceExplorerPath = `${
ROUTES.TRACES_EXPLORER
}?${urlParams.toString()}&selected={"serviceName":["${servicename}"]}&filterToFetchData=["duration","status","serviceName"]&spanAggregateCurrentPage=1&selectedTags=${selectedTraceTags}&${
const basePath = isViewLogsClicked
? ROUTES.LOGS_EXPLORER
: ROUTES.TRACES_EXPLORER;
const newPath = `${basePath}?${urlParams.toString()}&selected={"serviceName":["${servicename}"]}&filterToFetchData=["duration","status","serviceName"]&spanAggregateCurrentPage=1&selectedTags=${selectedTraceTags}&${
QueryParams.compositeQuery
}=${JSONCompositeQuery}&${queryString.join('&')}`;
history.push(newTraceExplorerPath);
history.push(newPath);
};
}
@ -79,7 +83,7 @@ export function onGraphClickHandler(
if (xValue) {
if (buttonElement) {
buttonElement.style.display = 'block';
buttonElement.style.display = 'flex';
buttonElement.style.left = `${mouseX}px`;
buttonElement.style.top = `${mouseY}px`;
setSelectedTimeStamp(xValue);
@ -106,12 +110,13 @@ export function handleQueryChange(
attributeKeys: BaseAutocompleteData,
serviceAttribute: string,
filters?: TagFilterItem[],
logs?: boolean,
): Query {
const filterItem: TagFilterItem[] = [
{
id: uuid().slice(0, 8),
key: attributeKeys,
op: 'in',
op: logs ? '=' : 'in',
value: serviceAttribute,
},
];
@ -130,6 +135,42 @@ export function handleQueryChange(
};
}
export function useGetAPMToLogsQueries({
servicename,
filters,
}: {
servicename: string;
filters?: TagFilterItem[];
}): Query {
const finalFilters: TagFilterItem[] = [];
const { updateAllQueriesOperators } = useQueryBuilder();
let updatedQuery = updateAllQueriesOperators(
initialQueriesMap.logs,
PANEL_TYPES.LIST,
DataSource.LOGS,
);
const serviceName = {
id: 'service.name--string--resource--true',
dataType: DataTypes.String,
isColumn: true,
key: 'service.name',
type: 'resource',
isJSON: false,
};
if (filters?.length) {
finalFilters.push(...filters);
}
updatedQuery = prepareQueryWithDefaultTimestamp(updatedQuery);
return handleQueryChange(
updatedQuery,
serviceName,
servicename,
finalFilters,
true,
);
}
export function useGetAPMToTracesQueries({
servicename,
isExternalCall,