Files
mcb-platform-monorepo/packages/sentry/model/utils/addons.ts
T
2025-11-25 09:43:22 +03:00

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 };