mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-15 01:36:10 +08:00
parent
95311db543
commit
5424c7714f
7
frontend/public/locales/en-GB/errorDetails.json
Normal file
7
frontend/public/locales/en-GB/errorDetails.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"see_trace_graph": "See what happened before and after this error in a trace graph",
|
||||
"see_error_in_trace_graph": "See the error in trace graph",
|
||||
"stack_trace": "Stacktrace",
|
||||
"older": "Older",
|
||||
"newer": "Newer"
|
||||
}
|
@ -11,7 +11,8 @@
|
||||
"n_a": "N/A",
|
||||
"routes": {
|
||||
"general": "General",
|
||||
"alert_channels": "Alert Channels"
|
||||
"alert_channels": "Alert Channels",
|
||||
"all_errors": "All Errors"
|
||||
},
|
||||
"settings": {
|
||||
"total_retention_period": "Total Retention Period",
|
||||
|
7
frontend/public/locales/en/errorDetails.json
Normal file
7
frontend/public/locales/en/errorDetails.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"see_trace_graph": "See what happened before and after this error in a trace graph",
|
||||
"see_error_in_trace_graph": "See the error in trace graph",
|
||||
"stack_trace": "Stacktrace",
|
||||
"older": "Older",
|
||||
"newer": "Newer"
|
||||
}
|
@ -11,7 +11,8 @@
|
||||
"n_a": "N/A",
|
||||
"routes": {
|
||||
"general": "General",
|
||||
"alert_channels": "Alert Channels"
|
||||
"alert_channels": "Alert Channels",
|
||||
"all_errors": "All Errors"
|
||||
},
|
||||
"settings": {
|
||||
"total_retention_period": "Total Retention Period",
|
||||
|
@ -86,6 +86,14 @@ export const AllAlertChannels = Loadable(
|
||||
() => import(/* webpackChunkName: "All Channels" */ 'pages/AllAlertChannels'),
|
||||
);
|
||||
|
||||
export const AllErrors = Loadable(
|
||||
/* webpackChunkName: "All Errors" */ () => import('pages/AllErrors'),
|
||||
);
|
||||
|
||||
export const ErrorDetails = Loadable(
|
||||
() => import(/* webpackChunkName: "Error Details" */ 'pages/ErrorDetails'),
|
||||
);
|
||||
|
||||
export const StatusPage = Loadable(
|
||||
() => import(/* webpackChunkName: "All Status" */ 'pages/Status'),
|
||||
);
|
||||
|
@ -4,11 +4,13 @@ import { RouteProps } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
AllAlertChannels,
|
||||
AllErrors,
|
||||
CreateAlertChannelAlerts,
|
||||
CreateNewAlerts,
|
||||
DashboardPage,
|
||||
EditAlertChannelsAlerts,
|
||||
EditRulesPage,
|
||||
ErrorDetails,
|
||||
InstrumentationPage,
|
||||
ListAllALertsPage,
|
||||
NewDashboardPage,
|
||||
@ -114,6 +116,16 @@ const routes: AppRoutes[] = [
|
||||
exact: true,
|
||||
component: AllAlertChannels,
|
||||
},
|
||||
{
|
||||
path: ROUTES.ALL_ERROR,
|
||||
exact: true,
|
||||
component: AllErrors,
|
||||
},
|
||||
{
|
||||
path: ROUTES.ERROR_DETAIL,
|
||||
exact: true,
|
||||
component: ErrorDetails,
|
||||
},
|
||||
{
|
||||
path: ROUTES.VERSION,
|
||||
exact: true,
|
||||
|
30
frontend/src/api/errors/getAll.ts
Normal file
30
frontend/src/api/errors/getAll.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import createQueryParams from 'lib/createQueryParams';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/errors/getAll';
|
||||
|
||||
const getAll = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`/errors?${createQueryParams({
|
||||
start: props.start.toString(),
|
||||
end: props.end.toString(),
|
||||
})}`,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.message,
|
||||
payload: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default getAll;
|
32
frontend/src/api/errors/getByErrorTypeAndService.ts
Normal file
32
frontend/src/api/errors/getByErrorTypeAndService.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import createQueryParams from 'lib/createQueryParams';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/errors/getByErrorTypeAndService';
|
||||
|
||||
const getByErrorType = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`/errorWithType?${createQueryParams({
|
||||
start: props.start.toString(),
|
||||
end: props.end.toString(),
|
||||
serviceName: props.serviceName,
|
||||
errorType: props.errorType,
|
||||
})}`,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.message,
|
||||
payload: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default getByErrorType;
|
31
frontend/src/api/errors/getById.ts
Normal file
31
frontend/src/api/errors/getById.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
||||
import { AxiosError } from 'axios';
|
||||
import createQueryParams from 'lib/createQueryParams';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { PayloadProps, Props } from 'types/api/errors/getById';
|
||||
|
||||
const getById = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`/errorWithId?${createQueryParams({
|
||||
start: props.start.toString(),
|
||||
end: props.end.toString(),
|
||||
errorId: props.errorId,
|
||||
})}`,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.message,
|
||||
payload: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default getById;
|
@ -1,13 +1,13 @@
|
||||
import MEditor from '@monaco-editor/react';
|
||||
import React from 'react';
|
||||
|
||||
function Editor({ value }: EditorProps): JSX.Element {
|
||||
function Editor({ value, readOnly = false }: EditorProps): JSX.Element {
|
||||
return (
|
||||
<MEditor
|
||||
theme="vs-dark"
|
||||
defaultLanguage="yaml"
|
||||
value={value.current}
|
||||
options={{ fontSize: 16, automaticLayout: true }}
|
||||
options={{ fontSize: 16, automaticLayout: true, readOnly }}
|
||||
height="40vh"
|
||||
onChange={(newValue): void => {
|
||||
if (value.current && newValue) {
|
||||
@ -21,6 +21,11 @@ function Editor({ value }: EditorProps): JSX.Element {
|
||||
|
||||
interface EditorProps {
|
||||
value: React.MutableRefObject<string>;
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
Editor.defaultProps = {
|
||||
readOnly: false,
|
||||
};
|
||||
|
||||
export default Editor;
|
||||
|
@ -17,6 +17,8 @@ const ROUTES = {
|
||||
ALL_CHANNELS: '/settings/channels',
|
||||
CHANNELS_NEW: '/setting/channels/new',
|
||||
CHANNELS_EDIT: '/setting/channels/edit/:id',
|
||||
ALL_ERROR: '/errors',
|
||||
ERROR_DETAIL: '/errors/:serviceName/:errorType',
|
||||
VERSION: '/status',
|
||||
};
|
||||
|
||||
|
104
frontend/src/container/AllError/index.tsx
Normal file
104
frontend/src/container/AllError/index.tsx
Normal file
@ -0,0 +1,104 @@
|
||||
import { Table, Typography } from 'antd';
|
||||
import { ColumnsType } from 'antd/lib/table';
|
||||
import getAll from 'api/errors/getAll';
|
||||
import ROUTES from 'constants/routes';
|
||||
import dayjs from 'dayjs';
|
||||
import React from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { generatePath, Link } from 'react-router-dom';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { Exception } from 'types/api/errors/getAll';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
|
||||
function AllErrors(): JSX.Element {
|
||||
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
||||
(state) => state.globalTime,
|
||||
);
|
||||
|
||||
const { isLoading, data } = useQuery(['getAllError', [maxTime, minTime]], {
|
||||
queryFn: () =>
|
||||
getAll({
|
||||
end: maxTime,
|
||||
start: minTime,
|
||||
}),
|
||||
});
|
||||
|
||||
const getDateValue = (value: string): JSX.Element => {
|
||||
return (
|
||||
<Typography>{dayjs(value).format('DD/MM/YYYY HH:mm:ss A')}</Typography>
|
||||
);
|
||||
};
|
||||
|
||||
const columns: ColumnsType<Exception> = [
|
||||
{
|
||||
title: 'Exception Type',
|
||||
dataIndex: 'exceptionType',
|
||||
key: 'exceptionType',
|
||||
render: (value, record): JSX.Element => (
|
||||
<Link
|
||||
to={generatePath(ROUTES.ERROR_DETAIL, {
|
||||
serviceName: record.serviceName,
|
||||
errorType: record.exceptionType,
|
||||
})}
|
||||
>
|
||||
{value}
|
||||
</Link>
|
||||
),
|
||||
sorter: (a, b): number => a.exceptionType.length - b.exceptionType.length,
|
||||
},
|
||||
{
|
||||
title: 'Error Message',
|
||||
dataIndex: 'exceptionMessage',
|
||||
key: 'exceptionMessage',
|
||||
render: (value): JSX.Element => (
|
||||
<Typography.Paragraph
|
||||
ellipsis={{
|
||||
rows: 2,
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
</Typography.Paragraph>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Count',
|
||||
dataIndex: 'exceptionCount',
|
||||
key: 'exceptionCount',
|
||||
sorter: (a, b): number => a.exceptionCount - b.exceptionCount,
|
||||
},
|
||||
{
|
||||
title: 'Last Seen',
|
||||
dataIndex: 'lastSeen',
|
||||
key: 'lastSeen',
|
||||
render: getDateValue,
|
||||
sorter: (a, b): number =>
|
||||
dayjs(a.lastSeen).isBefore(dayjs(b.lastSeen)) === true ? 1 : 0,
|
||||
},
|
||||
{
|
||||
title: 'First Seen',
|
||||
dataIndex: 'firstSeen',
|
||||
key: 'firstSeen',
|
||||
render: getDateValue,
|
||||
sorter: (a, b): number =>
|
||||
dayjs(a.firstSeen).isBefore(dayjs(b.firstSeen)) === true ? 1 : 0,
|
||||
},
|
||||
{
|
||||
title: 'Application',
|
||||
dataIndex: 'serviceName',
|
||||
key: 'serviceName',
|
||||
sorter: (a, b): number => a.serviceName.length - b.serviceName.length,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Table
|
||||
tableLayout="fixed"
|
||||
dataSource={data?.payload as Exception[]}
|
||||
columns={columns}
|
||||
loading={isLoading || false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default AllErrors;
|
157
frontend/src/container/ErrorDetails/index.tsx
Normal file
157
frontend/src/container/ErrorDetails/index.tsx
Normal file
@ -0,0 +1,157 @@
|
||||
import { Button, Divider, notification, Space, Table, Typography } from 'antd';
|
||||
import Editor from 'components/Editor';
|
||||
import dayjs from 'dayjs';
|
||||
import history from 'lib/history';
|
||||
import React, { useMemo, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { PayloadProps as GetByErrorTypeAndServicePayload } from 'types/api/errors/getByErrorTypeAndService';
|
||||
import { PayloadProps } from 'types/api/errors/getById';
|
||||
|
||||
import { DashedContainer, EditorContainer, EventContainer } from './styles';
|
||||
|
||||
function ErrorDetails(props: ErrorDetailsProps): JSX.Element {
|
||||
const { idPayload } = props;
|
||||
const [isLoading, setLoading] = useState<boolean>(false);
|
||||
const { t } = useTranslation(['errorDetails', 'common']);
|
||||
|
||||
const { search } = useLocation();
|
||||
const params = new URLSearchParams(search);
|
||||
const queryErrorId = params.get('errorId');
|
||||
|
||||
const errorDetail = idPayload;
|
||||
|
||||
const stackTraceValue = useRef(errorDetail.excepionStacktrace);
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: 'Key',
|
||||
dataIndex: 'key',
|
||||
key: 'key',
|
||||
},
|
||||
{
|
||||
title: 'Value',
|
||||
dataIndex: 'value',
|
||||
key: 'value',
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
|
||||
const keyToExclude = useMemo(
|
||||
() => [
|
||||
'excepionStacktrace',
|
||||
'exceptionType',
|
||||
'errorId',
|
||||
'timestamp',
|
||||
'exceptionMessage',
|
||||
'newerErrorId',
|
||||
'olderErrorId',
|
||||
],
|
||||
[],
|
||||
);
|
||||
|
||||
const onClickErrorIdHandler = async (id: string): Promise<void> => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
if (id.length === 0) {
|
||||
notification.error({
|
||||
message: 'Error Id cannot be empty',
|
||||
});
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
history.push(`${history.location.pathname}?errorId=${id}`);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
notification.error({
|
||||
message: t('something_went_wrong'),
|
||||
});
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const timeStamp = dayjs(errorDetail.timestamp);
|
||||
|
||||
const data: { key: string; value: string }[] = Object.keys(errorDetail)
|
||||
.filter((e) => !keyToExclude.includes(e))
|
||||
.map((key) => ({
|
||||
key,
|
||||
value: errorDetail[key as keyof GetByErrorTypeAndServicePayload],
|
||||
}));
|
||||
|
||||
const onClickTraceHandler = (): void => {
|
||||
history.push(`/trace/${errorDetail.traceID}?spanId=${errorDetail.spanID}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography>{errorDetail.exceptionType}</Typography>
|
||||
<Typography>{errorDetail.exceptionMessage}</Typography>
|
||||
<Divider />
|
||||
|
||||
<EventContainer>
|
||||
<div>
|
||||
<Typography>Event {errorDetail.errorId}</Typography>
|
||||
<Typography>{timeStamp.format('MMM DD YYYY hh:mm:ss A')}</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<Space align="end" direction="horizontal">
|
||||
{/* <Button icon={<LeftOutlined />} /> */}
|
||||
<Button
|
||||
loading={isLoading}
|
||||
disabled={
|
||||
errorDetail.olderErrorId.length === 0 ||
|
||||
queryErrorId === errorDetail.olderErrorId
|
||||
}
|
||||
onClick={(): Promise<void> =>
|
||||
onClickErrorIdHandler(errorDetail.olderErrorId)
|
||||
}
|
||||
>
|
||||
{t('older')}
|
||||
</Button>
|
||||
<Button
|
||||
loading={isLoading}
|
||||
disabled={
|
||||
errorDetail.newerErrorId.length === 0 ||
|
||||
queryErrorId === errorDetail.newerErrorId
|
||||
}
|
||||
onClick={(): Promise<void> =>
|
||||
onClickErrorIdHandler(errorDetail.newerErrorId)
|
||||
}
|
||||
>
|
||||
{t('newer')}
|
||||
</Button>
|
||||
{/* <Button icon={<RightOutlined />} /> */}
|
||||
</Space>
|
||||
</div>
|
||||
</EventContainer>
|
||||
|
||||
<DashedContainer>
|
||||
<Typography>{t('see_trace_graph')}</Typography>
|
||||
<Button onClick={onClickTraceHandler} type="primary">
|
||||
{t('see_error_in_trace_graph')}
|
||||
</Button>
|
||||
</DashedContainer>
|
||||
|
||||
<Typography.Title level={4}>{t('stack_trace')}</Typography.Title>
|
||||
<Editor value={stackTraceValue} readOnly />
|
||||
|
||||
<EditorContainer>
|
||||
<Space direction="vertical">
|
||||
<Table tableLayout="fixed" columns={columns} dataSource={data} />
|
||||
</Space>
|
||||
</EditorContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface ErrorDetailsProps {
|
||||
idPayload: PayloadProps;
|
||||
}
|
||||
|
||||
export default ErrorDetails;
|
28
frontend/src/container/ErrorDetails/styles.ts
Normal file
28
frontend/src/container/ErrorDetails/styles.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { grey } from '@ant-design/colors';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const DashedContainer = styled.div`
|
||||
border: ${`1px dashed ${grey[0]}`};
|
||||
box-sizing: border-box;
|
||||
border-radius: 0.25rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 1rem;
|
||||
margin-top: 1.875rem;
|
||||
margin-bottom: 1.625rem;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
export const ButtonContainer = styled.div`
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
`;
|
||||
|
||||
export const EventContainer = styled.div`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
`;
|
||||
|
||||
export const EditorContainer = styled.div`
|
||||
margin-top: 1.5rem;
|
||||
`;
|
@ -11,6 +11,7 @@ const breadcrumbNameMap = {
|
||||
[ROUTES.INSTRUMENTATION]: 'Add instrumentation',
|
||||
[ROUTES.SETTINGS]: 'Settings',
|
||||
[ROUTES.DASHBOARD]: 'Dashboard',
|
||||
[ROUTES.ALL_ERROR]: 'Errors',
|
||||
[ROUTES.VERSION]: 'Status',
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@ import {
|
||||
AlignLeftOutlined,
|
||||
ApiOutlined,
|
||||
BarChartOutlined,
|
||||
BugOutlined,
|
||||
DashboardFilled,
|
||||
DeploymentUnitOutlined,
|
||||
LineChartOutlined,
|
||||
@ -31,6 +32,11 @@ const menus: SidebarMenu[] = [
|
||||
to: ROUTES.LIST_ALL_ALERT,
|
||||
name: 'Alerts',
|
||||
},
|
||||
{
|
||||
Icon: BugOutlined,
|
||||
to: ROUTES.ALL_ERROR,
|
||||
name: 'Errors',
|
||||
},
|
||||
{
|
||||
to: ROUTES.SERVICE_MAP,
|
||||
name: 'Service Map',
|
||||
|
26
frontend/src/pages/AllErrors/index.tsx
Normal file
26
frontend/src/pages/AllErrors/index.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import RouteTab from 'components/RouteTab';
|
||||
import ROUTES from 'constants/routes';
|
||||
import AllErrorsContainer from 'container/AllError';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
function AllErrors(): JSX.Element {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<RouteTab
|
||||
{...{
|
||||
routes: [
|
||||
{
|
||||
Component: AllErrorsContainer,
|
||||
name: t('routes.all_errors'),
|
||||
route: ROUTES.ALL_ERROR,
|
||||
},
|
||||
],
|
||||
activeKey: t('routes.all_errors'),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default AllErrors;
|
88
frontend/src/pages/ErrorDetails/index.tsx
Normal file
88
frontend/src/pages/ErrorDetails/index.tsx
Normal file
@ -0,0 +1,88 @@
|
||||
import { Typography } from 'antd';
|
||||
import getByErrorType from 'api/errors/getByErrorTypeAndService';
|
||||
import getById from 'api/errors/getById';
|
||||
import Spinner from 'components/Spinner';
|
||||
import ErrorDetailsContainer from 'container/ErrorDetails';
|
||||
import React from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { PayloadProps } from 'types/api/errors/getById';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
|
||||
function ErrorDetails(): JSX.Element {
|
||||
const { errorType, serviceName } = useParams<ErrorDetailsParams>();
|
||||
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
||||
(state) => state.globalTime,
|
||||
);
|
||||
const { search } = useLocation();
|
||||
const params = new URLSearchParams(search);
|
||||
|
||||
const errorId = params.get('errorId');
|
||||
|
||||
const { data, status } = useQuery(
|
||||
[
|
||||
'errorByType',
|
||||
errorType,
|
||||
'serviceName',
|
||||
serviceName,
|
||||
maxTime,
|
||||
minTime,
|
||||
errorId,
|
||||
],
|
||||
{
|
||||
queryFn: () =>
|
||||
getByErrorType({
|
||||
end: maxTime,
|
||||
errorType,
|
||||
serviceName,
|
||||
start: minTime,
|
||||
}),
|
||||
enabled: errorId === null,
|
||||
cacheTime: 5000,
|
||||
},
|
||||
);
|
||||
|
||||
const { status: ErrorIdStatus, data: errorIdPayload } = useQuery(
|
||||
[
|
||||
'errorByType',
|
||||
errorType,
|
||||
'serviceName',
|
||||
serviceName,
|
||||
maxTime,
|
||||
minTime,
|
||||
'errorId',
|
||||
errorId,
|
||||
],
|
||||
{
|
||||
queryFn: () =>
|
||||
getById({
|
||||
end: maxTime,
|
||||
errorId: errorId || data?.payload?.errorId || '',
|
||||
start: minTime,
|
||||
}),
|
||||
enabled: errorId !== null || status === 'success',
|
||||
cacheTime: 5000,
|
||||
},
|
||||
);
|
||||
|
||||
if (status === 'loading' || ErrorIdStatus === 'loading') {
|
||||
return <Spinner tip="Loading.." />;
|
||||
}
|
||||
|
||||
if (status === 'error' || ErrorIdStatus === 'error') {
|
||||
return <Typography>{data?.error || errorIdPayload?.error}</Typography>;
|
||||
}
|
||||
|
||||
return (
|
||||
<ErrorDetailsContainer idPayload={errorIdPayload?.payload as PayloadProps} />
|
||||
);
|
||||
}
|
||||
|
||||
export interface ErrorDetailsParams {
|
||||
errorType: string;
|
||||
serviceName: string;
|
||||
}
|
||||
|
||||
export default ErrorDetails;
|
17
frontend/src/types/api/errors/getAll.ts
Normal file
17
frontend/src/types/api/errors/getAll.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { GlobalTime } from 'types/actions/globalTime';
|
||||
|
||||
export interface Props {
|
||||
start: GlobalTime['minTime'];
|
||||
end: GlobalTime['maxTime'];
|
||||
}
|
||||
|
||||
export interface Exception {
|
||||
exceptionType: string;
|
||||
exceptionMessage: string;
|
||||
exceptionCount: number;
|
||||
lastSeen: string;
|
||||
firstSeen: string;
|
||||
serviceName: string;
|
||||
}
|
||||
|
||||
export type PayloadProps = Exception[];
|
22
frontend/src/types/api/errors/getByErrorTypeAndService.ts
Normal file
22
frontend/src/types/api/errors/getByErrorTypeAndService.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { GlobalTime } from 'types/actions/globalTime';
|
||||
|
||||
export interface Props {
|
||||
start: GlobalTime['minTime'];
|
||||
end: GlobalTime['maxTime'];
|
||||
serviceName: string;
|
||||
errorType: string;
|
||||
}
|
||||
|
||||
export interface PayloadProps {
|
||||
errorId: string;
|
||||
exceptionType: string;
|
||||
excepionStacktrace: string;
|
||||
exceptionEscaped: string;
|
||||
exceptionMessage: string;
|
||||
timestamp: string;
|
||||
spanID: string;
|
||||
traceID: string;
|
||||
serviceName: Props['serviceName'];
|
||||
newerErrorId: string;
|
||||
olderErrorId: string;
|
||||
}
|
11
frontend/src/types/api/errors/getById.ts
Normal file
11
frontend/src/types/api/errors/getById.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { GlobalTime } from 'types/actions/globalTime';
|
||||
|
||||
import { PayloadProps as Payload } from './getByErrorTypeAndService';
|
||||
|
||||
export type PayloadProps = Payload;
|
||||
|
||||
export type Props = {
|
||||
start: GlobalTime['minTime'];
|
||||
end: GlobalTime['minTime'];
|
||||
errorId: string;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user