107 lines
4.2 KiB
TypeScript
107 lines
4.2 KiB
TypeScript
import { getClient } from '@sentry/react';
|
|
import type { ErrorEvent, Event, Breadcrumb, BreadcrumbHint } from '@sentry/types';
|
|
|
|
import { TAGS } from './constants';
|
|
import { clearData, isExcludedPath } from './helpers';
|
|
|
|
/**
|
|
* Функция вызывается перед добавлением breadcrumb в Sentry. Позволяет фильтровать и модифицировать breadcrumbs.
|
|
*
|
|
* @param breadcrumb - Объект breadcrumb, который будет отправлен в Sentry.
|
|
* @param hint - Объект, содержащий дополнительную информацию о событии.
|
|
* @returns Модифицированный breadcrumb, или null, если breadcrumb не должен быть отправлен.
|
|
*/
|
|
const beforeBreadcrumb = (breadcrumb: Breadcrumb, hint: BreadcrumbHint | undefined, isSendingAllowed: boolean) => {
|
|
// Не отправляем breadcrumbs, если страница в исключениях или отправка запрещена.
|
|
if (isExcludedPath() || !isSendingAllowed) {
|
|
return null;
|
|
}
|
|
|
|
const augmentedData = { ...breadcrumb.data };
|
|
|
|
// По 400+ кодам ответов в нетворке дополняем payload, response и traceId в объект Breadcrumb
|
|
if (breadcrumb.category === 'xhr' && augmentedData?.status_code >= 400) {
|
|
const payload = clearData(hint?.input);
|
|
const traceId = hint?.xhr instanceof XMLHttpRequest ? hint.xhr.getResponseHeader(TAGS.traceIdHeader) : undefined;
|
|
|
|
if (traceId) {
|
|
augmentedData[TAGS.traceIdHeader] = traceId;
|
|
}
|
|
|
|
if (payload) {
|
|
augmentedData.payload = payload;
|
|
}
|
|
|
|
const response = clearData(hint?.xhr?.responseText);
|
|
|
|
if (response) {
|
|
augmentedData.response = response;
|
|
}
|
|
|
|
return { ...breadcrumb, data: augmentedData };
|
|
} else if (breadcrumb.category === 'navigation') {
|
|
// убираем хэш-часть урлов редиректов, т.к. в ней может быть токен
|
|
if (typeof augmentedData.from === 'string') {
|
|
augmentedData.from = augmentedData.from.replace(/#.*/, '');
|
|
}
|
|
|
|
if (typeof augmentedData.to === 'string') {
|
|
augmentedData.to = augmentedData.to.replace(/#.*/, '');
|
|
}
|
|
|
|
return { ...breadcrumb, data: augmentedData };
|
|
}
|
|
|
|
return breadcrumb;
|
|
};
|
|
|
|
/**
|
|
* Функция вызывается перед отправкой события в Sentry. Позволяет фильтровать и модифицировать события.
|
|
*
|
|
* @param event - Объект события, который будет отправлен в Sentry.
|
|
* @returns Модифицированный event, или null, если событие не должно быть отправлено.
|
|
*/
|
|
const beforeSend = (event: ErrorEvent, isSendingAllowed: boolean): Event | PromiseLike<Event | null> | null => {
|
|
const { breadcrumbs, contexts, exception: eventException, tags } = event;
|
|
const exception = eventException?.values?.[0];
|
|
|
|
if (
|
|
// Выключаем логирование для случаев:
|
|
// страница из исключений
|
|
isExcludedPath() ||
|
|
// стоит флаг запрета отправки событий
|
|
!isSendingAllowed
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
const mechanismType = exception?.mechanism?.type;
|
|
|
|
if (mechanismType === 'http.client') {
|
|
const errData = breadcrumbs?.[breadcrumbs.length - 1]?.data;
|
|
|
|
const traceId = contexts?.response?.headers?.[TAGS.traceIdHeader];
|
|
|
|
// Добавляем тег с traceId от бэкенда, если получили его в заголовках
|
|
if (traceId) {
|
|
return { ...event, tags: { ...tags, [TAGS.traceIdHeader]: traceId } };
|
|
}
|
|
|
|
try {
|
|
const traceIdResp = errData?.response ? JSON.parse(errData?.response)?.errorInfo?.traceId : null;
|
|
|
|
// Добавляем тег с traceId от бэкенда, если получили его в теле ответа
|
|
return traceIdResp ? { ...event, tags: { ...tags, [TAGS.traceIdHeader]: traceIdResp } } : event;
|
|
} catch {
|
|
return event;
|
|
}
|
|
}
|
|
|
|
return event;
|
|
};
|
|
|
|
/** Отключение клиента Sentry. */
|
|
const clientShutdown = () => getClient()?.close(0);
|
|
|
|
export { beforeBreadcrumb, beforeSend, clientShutdown };
|