diff --git a/src/utils/error-report/ErrorData.ts b/src/utils/error-report/ErrorData.ts new file mode 100644 index 0000000000000000000000000000000000000000..ba1abdded66753878d048fcc5efdb760a3cbd646 --- /dev/null +++ b/src/utils/error-report/ErrorData.ts @@ -0,0 +1,11 @@ +export type ErrorData = { + url: string | null; + login: string | null; + email: string | null; + browser: string | null; + timestamp: string | null; + version: string | null; + comment: string | null; + stacktrace: string; + javaStacktrace: string | null; +}; diff --git a/src/utils/error-report/errorReporting.ts b/src/utils/error-report/errorReporting.ts new file mode 100644 index 0000000000000000000000000000000000000000..909c0ba213d45a316348dd63eb08852e63833280 --- /dev/null +++ b/src/utils/error-report/errorReporting.ts @@ -0,0 +1,33 @@ +/* eslint-disable no-console */ +import { ErrorData } from '@/utils/error-report/ErrorData'; +import { SerializedError } from '@reduxjs/toolkit'; + +export const handleError = (error: Error | SerializedError | undefined): void => { + let stacktrace = ''; + if (error !== undefined) { + stacktrace = error.stack !== undefined ? error.stack : ''; + } + + const errorData: ErrorData = { + url: null, // TODO + login: null, // TODO provide user login + browser: null, // TODO + comment: null, + email: null, // TODO + javaStacktrace: null, // TODO + stacktrace, + timestamp: null, // TODO + version: null, // TODO + }; + // eslint-disable-next-line no-console + console.log(errorData); +}; + +export const initializeErrorReporting = (): void => { + if (typeof window !== 'undefined') { + window.onerror = (msg, url, lineNo, columnNo, error): boolean => { + handleError(error); + return true; + }; + } +}; diff --git a/src/utils/error-report/getError.ts b/src/utils/error-report/getError.ts new file mode 100644 index 0000000000000000000000000000000000000000..b1da418173ac5d178e1f4fc4e5feee24a4af0ad2 --- /dev/null +++ b/src/utils/error-report/getError.ts @@ -0,0 +1,26 @@ +import { getErrorMessage } from '@/utils/getErrorMessage'; +import { SerializedError } from '@reduxjs/toolkit'; +import { getErrorName } from '@/utils/error-report/getErrorName'; +import { getErrorCode } from '@/utils/error-report/getErrorCode'; +import { getErrorStack } from '@/utils/error-report/getErrorStack'; + +type GetErrorMessageConfig = { + error: unknown; + message?: string; + prefix?: string; +}; + +export const getError = ({ error, message, prefix }: GetErrorMessageConfig): SerializedError => { + const errorMessage = getErrorMessage({ error, message, prefix }); + + const name = getErrorName(error); + const stack = getErrorStack(error); + const code = getErrorCode(error); + + return { + name, + message: errorMessage, + stack, + code, + }; +}; diff --git a/src/utils/error-report/getErrorCode.ts b/src/utils/error-report/getErrorCode.ts new file mode 100644 index 0000000000000000000000000000000000000000..30f63f620451aaa58e04cdb7370a20725dfafb32 --- /dev/null +++ b/src/utils/error-report/getErrorCode.ts @@ -0,0 +1,13 @@ +import axios from 'axios'; +import { + UNKNOWN_AXIOS_ERROR_CODE, + UNKNOWN_ERROR, +} from '../getErrorMessage/getErrorMessage.constants'; + +export const getErrorCode = (error: unknown): string => { + if (axios.isAxiosError(error)) { + const { code } = error; + return code || UNKNOWN_AXIOS_ERROR_CODE; + } + return UNKNOWN_ERROR; +}; diff --git a/src/utils/error-report/getErrorName.ts b/src/utils/error-report/getErrorName.ts new file mode 100644 index 0000000000000000000000000000000000000000..163a0d860c9f3a87809a3262d941b30a692dbca6 --- /dev/null +++ b/src/utils/error-report/getErrorName.ts @@ -0,0 +1,12 @@ +import axios from 'axios'; +import { UNKNOWN_ERROR } from '../getErrorMessage/getErrorMessage.constants'; + +export const getErrorName = (error: unknown): string => { + if (axios.isAxiosError(error)) { + return error.name; + } + if (error instanceof Error) { + return error.name; + } + return UNKNOWN_ERROR; +}; diff --git a/src/utils/error-report/getErrorStack.ts b/src/utils/error-report/getErrorStack.ts new file mode 100644 index 0000000000000000000000000000000000000000..e148696f16214a786cb7a48ee1862fa3743bbbe2 --- /dev/null +++ b/src/utils/error-report/getErrorStack.ts @@ -0,0 +1,14 @@ +import axios from 'axios'; +import { getErrorUrl } from '@/utils/error-report/getErrorUrl'; + +export const getErrorStack = (error: unknown): string => { + let stack = null; + if (axios.isAxiosError(error)) { + const url = getErrorUrl(error); + + stack = (url ? `(Request URL: ${url}) ` : '') + error.stack; + } else if (error instanceof Error) { + stack = error.stack; + } + return stack || 'No stack provided'; +}; diff --git a/src/utils/error-report/getErrorUrl.ts b/src/utils/error-report/getErrorUrl.ts new file mode 100644 index 0000000000000000000000000000000000000000..53ef46e9f4e5c4bf4bb9541f252594f357c8de8f --- /dev/null +++ b/src/utils/error-report/getErrorUrl.ts @@ -0,0 +1,12 @@ +import axios from 'axios'; + +export const getErrorUrl = (error: unknown): string | null => { + if (axios.isAxiosError(error)) { + if (error.request) { + if (error.request.responseURL) { + return error.request.responseURL; + } + } + } + return null; +}; diff --git a/src/utils/getErrorMessage/getErrorMessage.constants.ts b/src/utils/getErrorMessage/getErrorMessage.constants.ts index 00b84d7087cf177ecf1a129633867153ce228e48..d3cba2ab68e69f35a06edf0874ce57d3216472d7 100644 --- a/src/utils/getErrorMessage/getErrorMessage.constants.ts +++ b/src/utils/getErrorMessage/getErrorMessage.constants.ts @@ -1,4 +1,5 @@ export const UNKNOWN_ERROR = 'An unknown error occurred. Please try again later.'; +export const UNKNOWN_AXIOS_ERROR_CODE = 'UNKNOWN_AXIOS_ERROR'; export const HTTP_ERROR_MESSAGES = { 400: "The server couldn't understand your request. Please check your input and try again.",