ability to filter by deployment environment service map (#2506)

This commit is contained in:
Palash Gupta 2023-03-29 18:31:59 +05:30 committed by GitHub
parent 99ed314fc9
commit 3f96325ad8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 111 additions and 85 deletions

View File

@ -17,6 +17,7 @@ import { Card, GraphContainer, GraphTitle, Row } from '../styles';
import { Button } from './styles';
import {
dbSystemTags,
handleNonInQueryRange,
onGraphClickHandler,
onViewTracePopupClick,
} from './util';
@ -25,10 +26,13 @@ function DBCall({ getWidgetQueryBuilder }: DBCallProps): JSX.Element {
const { servicename } = useParams<{ servicename?: string }>();
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
const { queries } = useResourceAttribute();
const tagFilterItems = useMemo(
() => resourceAttributesToTagFilterItems(queries) || [],
() =>
handleNonInQueryRange(resourceAttributesToTagFilterItems(queries)) || [],
[queries],
);
const selectedTraceTags: string = useMemo(
() =>
JSON.stringify(

View File

@ -18,7 +18,11 @@ import { Widgets } from 'types/api/dashboard/getAll';
import { Card, GraphContainer, GraphTitle, Row } from '../styles';
import { legend } from './constant';
import { Button } from './styles';
import { onGraphClickHandler, onViewTracePopupClick } from './util';
import {
handleNonInQueryRange,
onGraphClickHandler,
onViewTracePopupClick,
} from './util';
function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
@ -27,7 +31,8 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element {
const { queries } = useResourceAttribute();
const tagFilterItems = useMemo(
() => resourceAttributesToTagFilterItems(queries) || [],
() =>
handleNonInQueryRange(resourceAttributesToTagFilterItems(queries)) || [],
[queries],
);

View File

@ -26,7 +26,11 @@ import {
import { Card, Col, GraphContainer, GraphTitle, Row } from '../styles';
import TopOperationsTable from '../TopOperationsTable';
import { Button } from './styles';
import { onGraphClickHandler, onViewTracePopupClick } from './util';
import {
handleNonInQueryRange,
onGraphClickHandler,
onViewTracePopupClick,
} from './util';
function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element {
const { servicename } = useParams<{ servicename?: string }>();
@ -67,7 +71,8 @@ function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element {
);
const tagFilterItems = useMemo(
() => resourceAttributesToTagFilterItems(queries) || [],
() =>
handleNonInQueryRange(resourceAttributesToTagFilterItems(queries)) || [],
[queries],
);

View File

@ -2,6 +2,7 @@ import { ActiveElement, Chart, ChartData, ChartEvent } from 'chart.js';
import { METRICS_PAGE_QUERY_PARAM } from 'constants/query';
import ROUTES from 'constants/routes';
import history from 'lib/history';
import { IQueryBuilderTagFilterItems } from 'types/api/dashboard/getAll';
import { Tags } from 'types/reducer/trace';
export const dbSystemTags: Tags[] = [
@ -84,3 +85,16 @@ export function onGraphClickHandler(
}
};
}
export const handleNonInQueryRange = (
tags: IQueryBuilderTagFilterItems[],
): IQueryBuilderTagFilterItems[] =>
tags.map((tag) => {
if (tag.op === 'Not IN') {
return {
...tag,
op: 'NIN',
};
}
return tag;
});

View File

@ -17,7 +17,6 @@ import {
GetTagKeys,
GetTagValues,
OperatorSchema,
resourceAttributesQueryToPromQL,
} from './utils';
function ResourceProvider({ children }: Props): JSX.Element {
@ -29,10 +28,6 @@ function ResourceProvider({ children }: Props): JSX.Element {
getResourceAttributeQueriesFromURL(),
);
const [promQLQuery, setpromQLQuery] = useState<string>(
resourceAttributesQueryToPromQL(queries),
);
const [optionsData, setOptionsData] = useState<OptionsData>({
mode: undefined,
options: [],
@ -55,7 +50,6 @@ function ResourceProvider({ children }: Props): JSX.Element {
: '',
});
setQueries(queries);
setpromQLQuery(resourceAttributesQueryToPromQL(queries));
},
[pathname],
);
@ -144,7 +138,6 @@ function ResourceProvider({ children }: Props): JSX.Element {
() => ({
queries,
staging,
promQLQuery,
handleClearAll,
handleClose,
handleBlur,
@ -161,7 +154,6 @@ function ResourceProvider({ children }: Props): JSX.Element {
handleClose,
handleFocus,
loading,
promQLQuery,
queries,
staging,
selectedQuery,

View File

@ -20,7 +20,6 @@ export interface OptionsData {
export interface IResourceAttributeProps {
queries: IResourceAttribute[];
staging: string[];
promQLQuery: string;
handleClearAll: VoidFunction;
handleClose: (id: string) => void;
handleBlur: VoidFunction;

View File

@ -57,26 +57,6 @@ export const convertRawQueriesToTraceSelectedTags = (
TagType: tagType,
}));
/**
* Converts Resource Attribute Queries to PromQL query string
*/
export const resourceAttributesQueryToPromQL = (
queries: IResourceAttribute[],
): string => {
let parsedQueryString = '';
if (Array.isArray(queries))
queries.forEach((query) => {
parsedQueryString += `, ${
query.tagKey
}${convertOperatorLabelToMetricOperator(
query.operator,
)}"${query.tagValue.join('|')}"`;
});
return parsedQueryString;
};
/* Convert resource attributes to tagFilter items for queryBuilder */
export const resourceAttributesToTagFilterItems = (
queries: IResourceAttribute[],

View File

@ -0,0 +1,56 @@
/* eslint-disable */
//@ts-nocheck
import { useIsDarkMode } from 'hooks/useDarkMode';
import React, { memo } from 'react';
import { ForceGraph2D } from 'react-force-graph';
import { getGraphData, getTooltip, transformLabel } from './utils';
function Map({ fgRef, serviceMap }: any): JSX.Element {
const isDarkMode = useIsDarkMode();
const { nodes, links } = getGraphData(serviceMap, isDarkMode);
const graphData = { nodes, links };
return (
<ForceGraph2D
ref={fgRef}
cooldownTicks={100}
graphData={graphData}
linkLabel={getTooltip}
linkAutoColorBy={(d) => d.target}
linkDirectionalParticles="value"
linkDirectionalParticleSpeed={(d) => d.value}
nodeCanvasObject={(node, ctx) => {
const label = transformLabel(node.id);
const { fontSize } = node;
ctx.font = `${fontSize}px Roboto`;
const { width } = node;
ctx.fillStyle = node.color;
ctx.beginPath();
ctx.arc(node.x, node.y, width, 0, 2 * Math.PI, false);
ctx.fill();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = isDarkMode ? '#ffffff' : '#000000';
ctx.fillText(label, node.x, node.y);
}}
onLinkHover={(node) => {
const tooltip = document.querySelector('.graph-tooltip');
if (tooltip && node) {
tooltip.innerHTML = getTooltip(node);
}
}}
nodePointerAreaPaint={(node, color, ctx) => {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(node.x, node.y, 5, 0, 2 * Math.PI, false);
ctx.fill();
}}
/>
);
}
export default memo(Map);

View File

@ -3,9 +3,10 @@
import { Card } from 'antd';
import Spinner from 'components/Spinner';
import { useIsDarkMode } from 'hooks/useDarkMode';
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
import useResourceAttribute from 'hooks/useResourceAttribute';
import { IResourceAttribute } from 'hooks/useResourceAttribute/types';
import React, { useEffect, useRef } from 'react';
import { ForceGraph2D } from 'react-force-graph';
import { connect } from 'react-redux';
import { RouteComponentProps, withRouter } from 'react-router-dom';
import { getDetailedServiceMapItems, ServiceMapStore } from 'store/actions';
@ -13,7 +14,7 @@ import { AppState } from 'store/reducers';
import styled from 'styled-components';
import { GlobalTime } from 'types/actions/globalTime';
import { getGraphData, getTooltip, getZoomPx, transformLabel } from './utils';
import Map from './Map';
const Container = styled.div`
.force-graph-container {
@ -38,7 +39,10 @@ const Container = styled.div`
interface ServiceMapProps extends RouteComponentProps<any> {
serviceMap: ServiceMapStore;
globalTime: GlobalTime;
getDetailedServiceMapItems: (time: GlobalTime) => void;
getDetailedServiceMapItems: (
time: GlobalTime,
queries: IResourceAttribute[],
) => void;
}
interface graphNode {
id: string;
@ -60,17 +64,17 @@ export interface graphDataType {
function ServiceMap(props: ServiceMapProps): JSX.Element {
const fgRef = useRef();
const isDarkMode = useIsDarkMode();
const { getDetailedServiceMapItems, globalTime, serviceMap } = props;
const { queries } = useResourceAttribute();
useEffect(() => {
/*
Call the apis only when the route is loaded.
Check this issue: https://github.com/SigNoz/signoz/issues/110
*/
getDetailedServiceMapItems(globalTime);
}, [globalTime, getDetailedServiceMapItems]);
getDetailedServiceMapItems(globalTime, queries);
}, [globalTime, getDetailedServiceMapItems, queries]);
useEffect(() => {
fgRef.current && fgRef.current.d3Force('charge').strength(-400);
@ -83,51 +87,15 @@ function ServiceMap(props: ServiceMapProps): JSX.Element {
if (!serviceMap.loading && serviceMap.items.length === 0) {
return (
<Container>
<ResourceAttributesFilter />
<Card>No Service Found</Card>
</Container>
);
}
const { nodes, links } = getGraphData(serviceMap, isDarkMode);
const graphData = { nodes, links };
return (
<Container>
<ForceGraph2D
ref={fgRef}
cooldownTicks={100}
graphData={graphData}
linkLabel={getTooltip}
linkAutoColorBy={(d) => d.target}
linkDirectionalParticles="value"
linkDirectionalParticleSpeed={(d) => d.value}
nodeCanvasObject={(node, ctx) => {
const label = transformLabel(node.id);
const { fontSize } = node;
ctx.font = `${fontSize}px Roboto`;
const { width } = node;
ctx.fillStyle = node.color;
ctx.beginPath();
ctx.arc(node.x, node.y, width, 0, 2 * Math.PI, false);
ctx.fill();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = isDarkMode ? '#ffffff' : '#000000';
ctx.fillText(label, node.x, node.y);
}}
onLinkHover={(node) => {
const tooltip = document.querySelector('.graph-tooltip');
if (tooltip && node) {
tooltip.innerHTML = getTooltip(node);
}
}}
nodePointerAreaPaint={(node, color, ctx) => {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(node.x, node.y, 5, 0, 2 * Math.PI, false);
ctx.fill();
}}
/>
<ResourceAttributesFilter />
<Map fgRef={fgRef} serviceMap={serviceMap} />
</Container>
);
}

View File

@ -1,4 +1,6 @@
import api from 'api';
import { IResourceAttribute } from 'hooks/useResourceAttribute/types';
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
import { Dispatch } from 'redux';
import { GlobalTime } from 'types/actions/globalTime';
@ -30,16 +32,17 @@ export interface ServiceMapLoading {
};
}
export const getDetailedServiceMapItems = (globalTime: GlobalTime) => async (
dispatch: Dispatch,
): Promise<void> => {
export const getDetailedServiceMapItems = (
globalTime: GlobalTime,
queries: IResourceAttribute[],
) => async (dispatch: Dispatch): Promise<void> => {
const start = `${globalTime.minTime}`;
const end = `${globalTime.maxTime}`;
const serviceMapPayload = {
start,
end,
tags: [],
tags: convertRawQueriesToTraceSelectedTags(queries),
};
const [dependencyGraphResponse] = await Promise.all([
api.post<ServicesMapItem[]>(`/dependency_graph`, serviceMapPayload),