mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-13 15:59:00 +08:00
Refactor the Metric Application Layer (#2984)
* refactor: seperate the dependency of top overview query * refactor: added error handle for api call using usequery * refactor: update api layar and condition in component * fix: onDragSelect re-render all graph data * refactor: removed console * refactor: corrected names and updated implemented required condition * fix: the api call issue * refactor: removed useeffect * refactor: reverted the unnecessary changes * refactor: removed the login from service level * refactor: removed the unwanted code * refactor: reverted the unwanted changes in getDashboardVariable * refactor: instead of useQuery used useQueries * refactor: changed the dependencies of useQuery key * refactor: linter fixes * refactor: delete the unrequired files * fix: generecity of the type * fix: moved the type to component * fix: move the logic from container layer to pages layer * refactor: optimised some part of the code * refactor: review changes * refactor: optimised the checks * refactor: checking if the dependency data loaded in full view * refactor: resolve the error of props in overview.ts * refactor: small changes * refactor: enforced the typecasting of constant variable * refactor: refactoring in some of the changes are updated * refactor: refactoring in some of the changes are updated * refactor: removed the extra parameter from useGetQueryRange * refactor: revert the changes back for tab * refactor: metrics application is updated * chore: loading condition is updated for full view component * chore: moved the serviceDataProps type to api layer * chore: message name is updated --------- Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com> Co-authored-by: Palash Gupta <palashgdev@gmail.com>
This commit is contained in:
parent
08d496e314
commit
98745fc307
@ -7,7 +7,7 @@ export const ServicesTablePage = Loadable(
|
||||
export const ServiceMetricsPage = Loadable(
|
||||
() =>
|
||||
import(
|
||||
/* webpackChunkName: "ServiceMetricsPage" */ 'pages/MetricApplication'
|
||||
/* webpackChunkName: "ServiceMetricsPage" */ 'pages/MetricsApplication'
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -1,13 +1,7 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/metrics/getServiceOverview';
|
||||
|
||||
const getServiceOverview = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const getServiceOverview = async (props: Props): Promise<PayloadProps> => {
|
||||
const response = await axios.post(`/service/overview`, {
|
||||
start: `${props.start}`,
|
||||
end: `${props.end}`,
|
||||
@ -16,15 +10,7 @@ const getServiceOverview = async (
|
||||
tags: props.selectedTags,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export default getServiceOverview;
|
||||
|
@ -1,24 +1,12 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/metrics/getTopLevelOperations';
|
||||
|
||||
const getTopLevelOperations = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const getTopLevelOperations = async (): Promise<ServiceDataProps> => {
|
||||
const response = await axios.post(`/service/top_level_operations`);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data[props.service],
|
||||
return response.data;
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
|
||||
export type ServiceDataProps = {
|
||||
[serviceName: string]: string[];
|
||||
};
|
||||
|
||||
export default getTopLevelOperations;
|
||||
|
@ -1,13 +1,7 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/metrics/getTopOperations';
|
||||
|
||||
const getTopOperations = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const getTopOperations = async (props: Props): Promise<PayloadProps> => {
|
||||
const response = await axios.post(`/service/top_operations`, {
|
||||
start: `${props.start}`,
|
||||
end: `${props.end}`,
|
||||
@ -15,15 +9,7 @@ const getTopOperations = async (
|
||||
tags: props.selectedTags,
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export default getTopOperations;
|
||||
|
@ -1,3 +1,5 @@
|
||||
const SOMETHING_WENT_WRONG = 'Something went wrong';
|
||||
|
||||
const getVersion = 'version';
|
||||
|
||||
export { getVersion };
|
||||
export { getVersion, SOMETHING_WENT_WRONG };
|
||||
|
@ -26,6 +26,7 @@ function FullView({
|
||||
name,
|
||||
yAxisUnit,
|
||||
onDragSelect,
|
||||
isDependedDataLoaded = false,
|
||||
}: FullViewProps): JSX.Element {
|
||||
const { selectedTime: globalSelectedTime } = useSelector<
|
||||
AppState,
|
||||
@ -61,6 +62,7 @@ function FullView({
|
||||
},
|
||||
{
|
||||
queryKey,
|
||||
enabled: !isDependedDataLoaded,
|
||||
},
|
||||
);
|
||||
|
||||
@ -76,9 +78,7 @@ function FullView({
|
||||
[response],
|
||||
);
|
||||
|
||||
const isLoading = response.isLoading === true;
|
||||
|
||||
if (isLoading) {
|
||||
if (response.status === 'idle' || response.status === 'loading') {
|
||||
return <Spinner height="100%" size="large" tip="Loading..." />;
|
||||
}
|
||||
|
||||
@ -123,6 +123,7 @@ interface FullViewProps {
|
||||
name: string;
|
||||
yAxisUnit?: string;
|
||||
onDragSelect?: (start: number, end: number) => void;
|
||||
isDependedDataLoaded?: boolean;
|
||||
}
|
||||
|
||||
FullView.defaultProps = {
|
||||
@ -130,6 +131,7 @@ FullView.defaultProps = {
|
||||
onClickHandler: undefined,
|
||||
yAxisUnit: undefined,
|
||||
onDragSelect: undefined,
|
||||
isDependedDataLoaded: undefined,
|
||||
};
|
||||
|
||||
export default FullView;
|
||||
|
@ -1,5 +1,13 @@
|
||||
import { Typography } from 'antd';
|
||||
import getServiceOverview from 'api/metrics/getServiceOverview';
|
||||
import getTopLevelOperations, {
|
||||
ServiceDataProps,
|
||||
} from 'api/metrics/getTopLevelOperations';
|
||||
import getTopOperations from 'api/metrics/getTopOperations';
|
||||
import axios from 'axios';
|
||||
import { ActiveElement, Chart, ChartData, ChartEvent } from 'chart.js';
|
||||
import Graph from 'components/Graph';
|
||||
import Spinner from 'components/Spinner';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import ROUTES from 'constants/routes';
|
||||
import FullView from 'container/GridGraphLayout/Graph/FullView/index.metricsBuilder';
|
||||
@ -12,16 +20,22 @@ import {
|
||||
} from 'hooks/useResourceAttribute/utils';
|
||||
import convertToNanoSecondsToSecond from 'lib/convertToNanoSecondsToSecond';
|
||||
import { colors } from 'lib/getRandomColor';
|
||||
import getStep from 'lib/getStep';
|
||||
import history from 'lib/history';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useQueries, UseQueryResult } from 'react-query';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
import { UpdateTimeInterval } from 'store/actions';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { PayloadProps } from 'types/api/metrics/getServiceOverview';
|
||||
import { PayloadProps as PayloadPropsTopOpertions } from 'types/api/metrics/getTopOperations';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import MetricReducer from 'types/reducer/metrics';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { Tags } from 'types/reducer/trace';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { SOMETHING_WENT_WRONG } from '../../../constants/api';
|
||||
import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
|
||||
import {
|
||||
errorPercentage,
|
||||
@ -37,9 +51,17 @@ import {
|
||||
} from './util';
|
||||
|
||||
function Application(): JSX.Element {
|
||||
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
||||
(state) => state.globalTime,
|
||||
);
|
||||
const { servicename } = useParams<{ servicename?: string }>();
|
||||
const [selectedTimeStamp, setSelectedTimeStamp] = useState<number>(0);
|
||||
const { search } = useLocation();
|
||||
const { queries } = useResourceAttribute();
|
||||
const selectedTags = useMemo(
|
||||
() => (convertRawQueriesToTraceSelectedTags(queries) as Tags[]) || [],
|
||||
[queries],
|
||||
);
|
||||
|
||||
const handleSetTimeStamp = useCallback((selectTime: number) => {
|
||||
setSelectedTimeStamp(selectTime);
|
||||
@ -64,12 +86,53 @@ function Application(): JSX.Element {
|
||||
[handleSetTimeStamp],
|
||||
);
|
||||
|
||||
const { topOperations, serviceOverview, topLevelOperations } = useSelector<
|
||||
AppState,
|
||||
MetricReducer
|
||||
>((state) => state.metrics);
|
||||
const queryResult = useQueries<
|
||||
[
|
||||
UseQueryResult<PayloadProps>,
|
||||
UseQueryResult<PayloadPropsTopOpertions>,
|
||||
UseQueryResult<ServiceDataProps>,
|
||||
]
|
||||
>([
|
||||
{
|
||||
queryKey: [servicename, selectedTags, minTime, maxTime],
|
||||
queryFn: (): Promise<PayloadProps> =>
|
||||
getServiceOverview({
|
||||
service: servicename || '',
|
||||
start: minTime,
|
||||
end: maxTime,
|
||||
step: getStep({
|
||||
start: minTime,
|
||||
end: maxTime,
|
||||
inputFormat: 'ns',
|
||||
}),
|
||||
selectedTags,
|
||||
}),
|
||||
},
|
||||
{
|
||||
queryKey: [minTime, maxTime, servicename, selectedTags],
|
||||
queryFn: (): Promise<PayloadPropsTopOpertions> =>
|
||||
getTopOperations({
|
||||
service: servicename || '',
|
||||
start: minTime,
|
||||
end: maxTime,
|
||||
selectedTags,
|
||||
}),
|
||||
},
|
||||
{
|
||||
queryKey: [servicename, minTime, maxTime, selectedTags],
|
||||
queryFn: (): Promise<ServiceDataProps> => getTopLevelOperations(),
|
||||
},
|
||||
]);
|
||||
|
||||
const { queries } = useResourceAttribute();
|
||||
const serviceOverview = queryResult[0].data;
|
||||
const serviceOverviewError = queryResult[0].error;
|
||||
const serviceOverviewIsError = queryResult[0].isError;
|
||||
const serviceOverviewIsLoading = queryResult[0].isLoading;
|
||||
const topOperations = queryResult[1].data;
|
||||
const topLevelOperations = queryResult[2].data;
|
||||
const topLevelOperationsError = queryResult[2].error;
|
||||
const topLevelOperationsIsError = queryResult[2].isError;
|
||||
const topLevelOperationsIsLoading = queryResult[2].isLoading;
|
||||
|
||||
const selectedTraceTags: string = JSON.stringify(
|
||||
convertRawQueriesToTraceSelectedTags(queries) || [],
|
||||
@ -89,7 +152,9 @@ function Application(): JSX.Element {
|
||||
builder: operationPerSec({
|
||||
servicename,
|
||||
tagFilterItems,
|
||||
topLevelOperations,
|
||||
topLevelOperations: topLevelOperations
|
||||
? topLevelOperations[servicename || '']
|
||||
: [],
|
||||
}),
|
||||
clickhouse_sql: [],
|
||||
id: uuid(),
|
||||
@ -105,7 +170,9 @@ function Application(): JSX.Element {
|
||||
builder: errorPercentage({
|
||||
servicename,
|
||||
tagFilterItems,
|
||||
topLevelOperations,
|
||||
topLevelOperations: topLevelOperations
|
||||
? topLevelOperations[servicename || '']
|
||||
: [],
|
||||
}),
|
||||
clickhouse_sql: [],
|
||||
id: uuid(),
|
||||
@ -158,8 +225,12 @@ function Application(): JSX.Element {
|
||||
[],
|
||||
);
|
||||
|
||||
const dataSets = useMemo(
|
||||
() => [
|
||||
const dataSets = useMemo(() => {
|
||||
if (!serviceOverview) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
data: serviceOverview.map((e) =>
|
||||
parseFloat(convertToNanoSecondsToSecond(e.p99)),
|
||||
@ -178,19 +249,25 @@ function Application(): JSX.Element {
|
||||
),
|
||||
...generalChartDataProperties('p50 Latency', 2),
|
||||
},
|
||||
],
|
||||
[generalChartDataProperties, serviceOverview],
|
||||
);
|
||||
];
|
||||
}, [generalChartDataProperties, serviceOverview]);
|
||||
|
||||
const data = useMemo(
|
||||
() => ({
|
||||
const data = useMemo(() => {
|
||||
if (!serviceOverview) {
|
||||
return {
|
||||
datasets: [],
|
||||
labels: [],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
datasets: dataSets,
|
||||
labels: serviceOverview.map(
|
||||
(e) => new Date(parseFloat(convertToNanoSecondsToSecond(e.timestamp))),
|
||||
),
|
||||
}),
|
||||
[serviceOverview, dataSets],
|
||||
);
|
||||
};
|
||||
}, [serviceOverview, dataSets]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Row gutter={24}>
|
||||
@ -208,7 +285,19 @@ function Application(): JSX.Element {
|
||||
View Traces
|
||||
</Button>
|
||||
<Card>
|
||||
{serviceOverviewIsError ? (
|
||||
<Typography>
|
||||
{axios.isAxiosError(serviceOverviewError)
|
||||
? serviceOverviewError.response?.data
|
||||
: SOMETHING_WENT_WRONG}
|
||||
</Typography>
|
||||
) : (
|
||||
<>
|
||||
<GraphTitle>Latency</GraphTitle>
|
||||
{serviceOverviewIsLoading && (
|
||||
<Spinner size="large" tip="Loading..." height="40vh" />
|
||||
)}
|
||||
{!serviceOverviewIsLoading && (
|
||||
<GraphContainer>
|
||||
<Graph
|
||||
animate={false}
|
||||
@ -220,6 +309,9 @@ function Application(): JSX.Element {
|
||||
onDragSelect={onDragSelect}
|
||||
/>
|
||||
</GraphContainer>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
@ -237,6 +329,14 @@ function Application(): JSX.Element {
|
||||
View Traces
|
||||
</Button>
|
||||
<Card>
|
||||
{topLevelOperationsIsError ? (
|
||||
<Typography>
|
||||
{axios.isAxiosError(topLevelOperationsError)
|
||||
? topLevelOperationsError.response?.data
|
||||
: SOMETHING_WENT_WRONG}
|
||||
</Typography>
|
||||
) : (
|
||||
<>
|
||||
<GraphTitle>Rate (ops/s)</GraphTitle>
|
||||
<GraphContainer>
|
||||
<FullView
|
||||
@ -246,8 +346,11 @@ function Application(): JSX.Element {
|
||||
widget={operationPerSecWidget}
|
||||
yAxisUnit="ops"
|
||||
onDragSelect={onDragSelect}
|
||||
isDependedDataLoaded={topLevelOperationsIsLoading}
|
||||
/>
|
||||
</GraphContainer>
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
@ -265,6 +368,14 @@ function Application(): JSX.Element {
|
||||
</Button>
|
||||
|
||||
<Card>
|
||||
{topLevelOperationsIsError ? (
|
||||
<Typography>
|
||||
{axios.isAxiosError(topLevelOperationsError)
|
||||
? topLevelOperationsError.response?.data
|
||||
: SOMETHING_WENT_WRONG}
|
||||
</Typography>
|
||||
) : (
|
||||
<>
|
||||
<GraphTitle>Error Percentage</GraphTitle>
|
||||
<GraphContainer>
|
||||
<FullView
|
||||
@ -274,14 +385,17 @@ function Application(): JSX.Element {
|
||||
widget={errorPercentageWidget}
|
||||
yAxisUnit="%"
|
||||
onDragSelect={onDragSelect}
|
||||
isDependedDataLoaded={topLevelOperationsIsLoading}
|
||||
/>
|
||||
</GraphContainer>
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<Col span={12}>
|
||||
<Card>
|
||||
<TopOperationsTable data={topOperations} />
|
||||
<TopOperationsTable data={topOperations || []} />
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
@ -1,90 +0,0 @@
|
||||
import RouteTab from 'components/RouteTab';
|
||||
import ROUTES from 'constants/routes';
|
||||
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
||||
import history from 'lib/history';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { generatePath, useParams } from 'react-router-dom';
|
||||
import { useLocation } from 'react-use';
|
||||
|
||||
import DBCall from './Tabs/DBCall';
|
||||
import External from './Tabs/External';
|
||||
import Overview from './Tabs/Overview';
|
||||
|
||||
function OverViewTab(): JSX.Element {
|
||||
return <Overview />;
|
||||
}
|
||||
|
||||
function DbCallTab(): JSX.Element {
|
||||
return <DBCall />;
|
||||
}
|
||||
|
||||
function ExternalTab(): JSX.Element {
|
||||
return <External />;
|
||||
}
|
||||
|
||||
function ServiceMetrics(): JSX.Element {
|
||||
const { search } = useLocation();
|
||||
const { servicename } = useParams<{ servicename: string }>();
|
||||
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const tab = searchParams.get('tab');
|
||||
|
||||
const overMetrics = 'Overview Metrics';
|
||||
const dbCallMetrics = 'Database Calls';
|
||||
const externalMetrics = 'External Calls';
|
||||
|
||||
const getActiveKey = (): string => {
|
||||
switch (tab) {
|
||||
case null: {
|
||||
return overMetrics;
|
||||
}
|
||||
case dbCallMetrics: {
|
||||
return dbCallMetrics;
|
||||
}
|
||||
case externalMetrics: {
|
||||
return externalMetrics;
|
||||
}
|
||||
default: {
|
||||
return overMetrics;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const activeKey = getActiveKey();
|
||||
|
||||
const routes = useMemo(
|
||||
() => [
|
||||
{
|
||||
Component: OverViewTab,
|
||||
name: overMetrics,
|
||||
route: `${generatePath(ROUTES.SERVICE_METRICS, {
|
||||
servicename,
|
||||
})}?tab=${overMetrics}`,
|
||||
},
|
||||
{
|
||||
Component: DbCallTab,
|
||||
name: dbCallMetrics,
|
||||
route: `${generatePath(ROUTES.SERVICE_METRICS, {
|
||||
servicename,
|
||||
})}?tab=${dbCallMetrics}`,
|
||||
},
|
||||
{
|
||||
Component: ExternalTab,
|
||||
name: externalMetrics,
|
||||
route: `${generatePath(ROUTES.SERVICE_METRICS, {
|
||||
servicename,
|
||||
})}?tab=${externalMetrics}`,
|
||||
},
|
||||
],
|
||||
[servicename],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ResourceAttributesFilter />
|
||||
<RouteTab routes={routes} history={history} activeKey={activeKey} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(ServiceMetrics);
|
@ -1,76 +0,0 @@
|
||||
import { Typography } from 'antd';
|
||||
import Spinner from 'components/Spinner';
|
||||
import MetricsApplicationContainer from 'container/MetricsApplication';
|
||||
import useResourceAttribute from 'hooks/useResourceAttribute';
|
||||
import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { connect, useSelector } from 'react-redux';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { ThunkDispatch } from 'redux-thunk';
|
||||
import {
|
||||
GetInitialData,
|
||||
GetInitialDataProps,
|
||||
} from 'store/actions/metrics/getInitialData';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import MetricReducer from 'types/reducer/metrics';
|
||||
import { Tags } from 'types/reducer/trace';
|
||||
|
||||
function MetricsApplication({ getInitialData }: MetricsProps): JSX.Element {
|
||||
const { minTime, maxTime } = useSelector<AppState, GlobalReducer>(
|
||||
(state) => state.globalTime,
|
||||
);
|
||||
const { error, errorMessage, metricsApplicationLoading } = useSelector<
|
||||
AppState,
|
||||
MetricReducer
|
||||
>((state) => state.metrics);
|
||||
|
||||
const { servicename } = useParams<ServiceProps>();
|
||||
const { queries } = useResourceAttribute();
|
||||
|
||||
const selectedTags = useMemo(
|
||||
() => (convertRawQueriesToTraceSelectedTags(queries) as Tags[]) || [],
|
||||
[queries],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (servicename !== undefined) {
|
||||
getInitialData({
|
||||
serviceName: servicename,
|
||||
maxTime,
|
||||
minTime,
|
||||
selectedTags,
|
||||
});
|
||||
}
|
||||
}, [servicename, getInitialData, maxTime, minTime, selectedTags]);
|
||||
|
||||
if (metricsApplicationLoading) {
|
||||
return <Spinner tip="Loading..." />;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <Typography>{errorMessage}</Typography>;
|
||||
}
|
||||
|
||||
return <MetricsApplicationContainer />;
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
getInitialData: (props: GetInitialDataProps) => void;
|
||||
}
|
||||
|
||||
interface ServiceProps {
|
||||
servicename?: string;
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (
|
||||
dispatch: ThunkDispatch<unknown, unknown, AppActions>,
|
||||
): DispatchProps => ({
|
||||
getInitialData: bindActionCreators(GetInitialData, dispatch),
|
||||
});
|
||||
|
||||
type MetricsProps = DispatchProps;
|
||||
|
||||
export default connect(null, mapDispatchToProps)(MetricsApplication);
|
8
frontend/src/pages/MetricsApplication/config.ts
Normal file
8
frontend/src/pages/MetricsApplication/config.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { MetricsApplicationTab } from './types';
|
||||
|
||||
export const TAB_KEYS_VS_METRICS_APPLICATION_KEY = {
|
||||
[MetricsApplicationTab.DB_CALL_METRICS]: MetricsApplicationTab.DB_CALL_METRICS,
|
||||
[MetricsApplicationTab.EXTERNAL_METRICS]:
|
||||
MetricsApplicationTab.EXTERNAL_METRICS,
|
||||
[MetricsApplicationTab.OVER_METRICS]: MetricsApplicationTab.OVER_METRICS,
|
||||
};
|
54
frontend/src/pages/MetricsApplication/index.tsx
Normal file
54
frontend/src/pages/MetricsApplication/index.tsx
Normal file
@ -0,0 +1,54 @@
|
||||
import RouteTab from 'components/RouteTab';
|
||||
import ROUTES from 'constants/routes';
|
||||
import DBCall from 'container/MetricsApplication/Tabs/DBCall';
|
||||
import External from 'container/MetricsApplication/Tabs/External';
|
||||
import Overview from 'container/MetricsApplication/Tabs/Overview';
|
||||
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
||||
import history from 'lib/history';
|
||||
import { useMemo } from 'react';
|
||||
import { generatePath, useParams } from 'react-router-dom';
|
||||
|
||||
import { MetricsApplicationTab, TAB_KEY_VS_LABEL } from './types';
|
||||
import useMetricsApplicationTabKey from './useMetricsApplicationTabKey';
|
||||
|
||||
function MetricsApplication(): JSX.Element {
|
||||
const { servicename } = useParams<{ servicename: string }>();
|
||||
|
||||
const activeKey = useMetricsApplicationTabKey();
|
||||
|
||||
const routes = useMemo(
|
||||
() => [
|
||||
{
|
||||
Component: Overview,
|
||||
name: TAB_KEY_VS_LABEL[MetricsApplicationTab.OVER_METRICS],
|
||||
route: `${generatePath(ROUTES.SERVICE_METRICS, {
|
||||
servicename,
|
||||
})}?tab=${MetricsApplicationTab.OVER_METRICS}`,
|
||||
},
|
||||
{
|
||||
Component: DBCall,
|
||||
name: TAB_KEY_VS_LABEL[MetricsApplicationTab.DB_CALL_METRICS],
|
||||
route: `${generatePath(ROUTES.SERVICE_METRICS, {
|
||||
servicename,
|
||||
})}?tab=${MetricsApplicationTab.DB_CALL_METRICS}`,
|
||||
},
|
||||
{
|
||||
Component: External,
|
||||
name: TAB_KEY_VS_LABEL[MetricsApplicationTab.EXTERNAL_METRICS],
|
||||
route: `${generatePath(ROUTES.SERVICE_METRICS, {
|
||||
servicename,
|
||||
})}?tab=${MetricsApplicationTab.EXTERNAL_METRICS}`,
|
||||
},
|
||||
],
|
||||
[servicename],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ResourceAttributesFilter />
|
||||
<RouteTab routes={routes} history={history} activeKey={activeKey} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default MetricsApplication;
|
11
frontend/src/pages/MetricsApplication/types.ts
Normal file
11
frontend/src/pages/MetricsApplication/types.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export enum MetricsApplicationTab {
|
||||
OVER_METRICS = 'OVER_METRICS',
|
||||
DB_CALL_METRICS = 'DB_CALL_METRICS',
|
||||
EXTERNAL_METRICS = 'EXTERNAL_METRICS',
|
||||
}
|
||||
|
||||
export const TAB_KEY_VS_LABEL = {
|
||||
[MetricsApplicationTab.OVER_METRICS]: 'Overview',
|
||||
[MetricsApplicationTab.DB_CALL_METRICS]: 'DB Call Metrics',
|
||||
[MetricsApplicationTab.EXTERNAL_METRICS]: 'External Metrics',
|
||||
};
|
@ -0,0 +1,14 @@
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
|
||||
import { TAB_KEY_VS_LABEL } from './types';
|
||||
import { getMetricsApplicationKey } from './utils';
|
||||
|
||||
const useMetricsApplicationTabKey = (): string => {
|
||||
const urlParams = useUrlQuery();
|
||||
|
||||
const tab = urlParams.get('tab');
|
||||
|
||||
return TAB_KEY_VS_LABEL[getMetricsApplicationKey(tab)];
|
||||
};
|
||||
|
||||
export default useMetricsApplicationTabKey;
|
17
frontend/src/pages/MetricsApplication/utils.ts
Normal file
17
frontend/src/pages/MetricsApplication/utils.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { TAB_KEYS_VS_METRICS_APPLICATION_KEY } from './config';
|
||||
import { MetricsApplicationTab } from './types';
|
||||
|
||||
export const isMetricsApplicationTab = (
|
||||
tab: string,
|
||||
): tab is MetricsApplicationTab =>
|
||||
Object.values(MetricsApplicationTab).includes(tab as MetricsApplicationTab);
|
||||
|
||||
export const getMetricsApplicationKey = (
|
||||
tab: string | null,
|
||||
): MetricsApplicationTab => {
|
||||
if (tab && isMetricsApplicationTab(tab)) {
|
||||
return TAB_KEYS_VS_METRICS_APPLICATION_KEY[tab];
|
||||
}
|
||||
|
||||
return MetricsApplicationTab.OVER_METRICS;
|
||||
};
|
@ -1,137 +0,0 @@
|
||||
// import getDBOverView from 'api/metrics/getDBOverView';
|
||||
// import getExternalAverageDuration from 'api/metrics/getExternalAverageDuration';
|
||||
// import getExternalError from 'api/metrics/getExternalError';
|
||||
// import getExternalService from 'api/metrics/getExternalService';
|
||||
import getServiceOverview from 'api/metrics/getServiceOverview';
|
||||
import getTopLevelOperations from 'api/metrics/getTopLevelOperations';
|
||||
import getTopOperations from 'api/metrics/getTopOperations';
|
||||
import { AxiosError } from 'axios';
|
||||
import GetMinMax from 'lib/getMinMax';
|
||||
import getStep from 'lib/getStep';
|
||||
import { Dispatch } from 'redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { Props } from 'types/api/metrics/getDBOverview';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { Tags } from 'types/reducer/trace';
|
||||
|
||||
export const GetInitialData = (
|
||||
props: GetInitialDataProps,
|
||||
): ((
|
||||
dispatch: Dispatch<AppActions>,
|
||||
getState: () => AppState,
|
||||
) => void) => async (dispatch, getState): Promise<void> => {
|
||||
try {
|
||||
const { globalTime } = getState();
|
||||
|
||||
/**
|
||||
* @description This is because we keeping the store as source of truth
|
||||
*/
|
||||
if (
|
||||
props.maxTime !== globalTime.maxTime &&
|
||||
props.minTime !== globalTime.minTime
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: 'GET_INITIAL_APPLICATION_LOADING',
|
||||
});
|
||||
|
||||
const { maxTime, minTime } = GetMinMax(globalTime.selectedTime, [
|
||||
globalTime.minTime / 1000000,
|
||||
globalTime.maxTime / 1000000,
|
||||
]);
|
||||
|
||||
const [
|
||||
// getDBOverViewResponse,
|
||||
// getExternalAverageDurationResponse,
|
||||
// getExternalErrorResponse,
|
||||
// getExternalServiceResponse,
|
||||
getServiceOverviewResponse,
|
||||
getTopOperationsResponse,
|
||||
getTopLevelOperationsResponse,
|
||||
] = await Promise.all([
|
||||
// getDBOverView({
|
||||
// ...props,
|
||||
// }),
|
||||
// getExternalAverageDuration({
|
||||
// ...props,
|
||||
// }),
|
||||
// getExternalError({
|
||||
// ...props,
|
||||
// }),
|
||||
// getExternalService({
|
||||
// ...props,
|
||||
// }),
|
||||
getServiceOverview({
|
||||
end: maxTime,
|
||||
service: props.serviceName,
|
||||
start: minTime,
|
||||
step: getStep({ start: minTime, end: maxTime, inputFormat: 'ns' }),
|
||||
selectedTags: props.selectedTags,
|
||||
}),
|
||||
getTopOperations({
|
||||
end: maxTime,
|
||||
service: props.serviceName,
|
||||
start: minTime,
|
||||
selectedTags: props.selectedTags,
|
||||
}),
|
||||
getTopLevelOperations({
|
||||
service: props.serviceName,
|
||||
}),
|
||||
]);
|
||||
|
||||
if (
|
||||
// getDBOverViewResponse.statusCode === 200 &&
|
||||
// getExternalAverageDurationResponse.statusCode === 200 &&
|
||||
// getExternalErrorResponse.statusCode === 200 &&
|
||||
// getExternalServiceResponse.statusCode === 200 &&
|
||||
getServiceOverviewResponse.statusCode === 200 &&
|
||||
getTopOperationsResponse.statusCode === 200 &&
|
||||
getTopLevelOperationsResponse.statusCode === 200
|
||||
) {
|
||||
dispatch({
|
||||
type: 'GET_INTIAL_APPLICATION_DATA',
|
||||
payload: {
|
||||
// dbOverView: getDBOverViewResponse.payload,
|
||||
// externalAverageDuration: getExternalAverageDurationResponse.payload,
|
||||
// externalError: getExternalErrorResponse.payload,
|
||||
// externalService: getExternalServiceResponse.payload,
|
||||
serviceOverview: getServiceOverviewResponse.payload,
|
||||
topOperations: getTopOperationsResponse.payload,
|
||||
topLevelOperations: getTopLevelOperationsResponse.payload,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: 'GET_INITIAL_APPLICATION_ERROR',
|
||||
payload: {
|
||||
errorMessage:
|
||||
getTopOperationsResponse.error ||
|
||||
getServiceOverviewResponse.error ||
|
||||
getTopLevelOperationsResponse.error ||
|
||||
// getExternalServiceResponse.error ||
|
||||
// getExternalErrorResponse.error ||
|
||||
// getExternalAverageDurationResponse.error ||
|
||||
// getDBOverViewResponse.error ||
|
||||
'Something went wrong',
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
dispatch({
|
||||
type: 'GET_INITIAL_APPLICATION_ERROR',
|
||||
payload: {
|
||||
errorMessage: (error as AxiosError).toString() || 'Something went wrong',
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export interface GetInitialDataProps {
|
||||
serviceName: Props['service'];
|
||||
maxTime: GlobalReducer['maxTime'];
|
||||
minTime: GlobalReducer['minTime'];
|
||||
selectedTags: Tags[];
|
||||
}
|
@ -12,7 +12,7 @@ import {
|
||||
} from 'types/actions/logs';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
|
||||
const intitalState: GlobalReducer = {
|
||||
const initialState: GlobalReducer = {
|
||||
maxTime: Date.now() * 1000000,
|
||||
minTime: (Date.now() - 15 * 60 * 1000) * 1000000,
|
||||
loading: true,
|
||||
@ -24,7 +24,7 @@ const intitalState: GlobalReducer = {
|
||||
};
|
||||
|
||||
const globalTimeReducer = (
|
||||
state = intitalState,
|
||||
state = initialState,
|
||||
action: GlobalTimeAction,
|
||||
): GlobalReducer => {
|
||||
switch (action.type) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user