Files
2024-02-15 17:01:50 +00:00

193 lines
4.5 KiB
TypeScript

import {t} from 'sentry/locale';
import type {Crumb, RawCrumb} from 'sentry/types/breadcrumbs';
import {BreadcrumbLevelType, BreadcrumbType} from 'sentry/types/breadcrumbs';
import type {Event} from 'sentry/types/event';
import {EntryType} from 'sentry/types/event';
import {defined} from 'sentry/utils';
export function convertCrumbType(breadcrumb: RawCrumb): RawCrumb {
if (breadcrumb.type === BreadcrumbType.EXCEPTION) {
return {
...breadcrumb,
type: BreadcrumbType.ERROR,
};
}
// special case for 'ui.' and `sentry.` category breadcrumbs
// TODO: find a better way to customize UI around non-schema data
if (breadcrumb.type === BreadcrumbType.DEFAULT && defined(breadcrumb?.category)) {
const [category, subcategory] = breadcrumb.category.split('.');
if (category === 'ui') {
return {
...breadcrumb,
type: BreadcrumbType.UI,
};
}
if (category === 'console') {
return {
...breadcrumb,
type: BreadcrumbType.DEBUG,
};
}
if (category === 'navigation') {
return {
...breadcrumb,
type: BreadcrumbType.NAVIGATION,
};
}
if (
category === 'sentry' &&
(subcategory === 'transaction' || subcategory === 'event')
) {
return {
...breadcrumb,
type: BreadcrumbType.TRANSACTION,
};
}
}
if (!Object.values(BreadcrumbType).includes(breadcrumb.type)) {
return {
...breadcrumb,
type: BreadcrumbType.DEFAULT,
};
}
return breadcrumb;
}
export function getCrumbDescriptionAndColor(
type: BreadcrumbType
): Pick<Crumb, 'color' | 'description'> {
switch (type) {
case BreadcrumbType.USER:
case BreadcrumbType.UI:
return {
color: 'purple300',
description: t('User Action'),
};
case BreadcrumbType.NAVIGATION:
return {
color: 'green300',
description: t('Navigation'),
};
case BreadcrumbType.DEBUG:
return {
color: 'purple300',
description: t('Debug'),
};
case BreadcrumbType.INFO:
return {
color: 'blue300',
description: t('Info'),
};
case BreadcrumbType.ERROR:
return {
color: 'red300',
description: t('Error'),
};
case BreadcrumbType.HTTP:
return {
color: 'green300',
description: t('HTTP request'),
};
case BreadcrumbType.WARNING:
return {
color: 'yellow300',
description: t('Warning'),
};
case BreadcrumbType.QUERY:
return {
color: 'blue300',
description: t('Query'),
};
case BreadcrumbType.SYSTEM:
return {
color: 'pink300',
description: t('System'),
};
case BreadcrumbType.SESSION:
return {
color: 'pink300',
description: t('Session'),
};
case BreadcrumbType.TRANSACTION:
return {
color: 'pink300',
description: t('Transaction'),
};
default:
return {
color: 'gray300',
description: t('Default'),
};
}
}
export function transformCrumbs(breadcrumbs: Array<RawCrumb>): Crumb[] {
return breadcrumbs.map((breadcrumb, index) => {
const convertedCrumbType = convertCrumbType(breadcrumb);
const {color, description} = getCrumbDescriptionAndColor(convertedCrumbType.type);
return {
...convertedCrumbType,
id: index,
color,
description,
level: convertedCrumbType.level ?? BreadcrumbLevelType.UNDEFINED,
};
});
}
function moduleToCategory(module: string | null | undefined) {
if (!module) {
return undefined;
}
const match = module.match(/^.*\/(.*?)(:\d+)/);
if (!match) {
return module.split(/./)[0];
}
return match[1];
}
export function getVirtualCrumb(event: Event): RawCrumb | undefined {
const exception = event.entries.find(entry => entry.type === EntryType.EXCEPTION);
if (!exception && !event.message) {
return undefined;
}
const timestamp = event.dateCreated;
if (exception) {
const {type, value, module: mdl} = exception.data.values[0];
return {
type: BreadcrumbType.ERROR,
level: BreadcrumbLevelType.ERROR,
category: moduleToCategory(mdl) || 'exception',
data: {
type,
value,
},
timestamp,
};
}
const levelTag = (event.tags || []).find(tag => tag.key === 'level');
return {
type: BreadcrumbType.INFO,
level: (levelTag?.value as BreadcrumbLevelType) || BreadcrumbLevelType.UNDEFINED,
category: 'message',
message: event.message,
timestamp,
};
}