mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
106 lines
3.6 KiB
TypeScript
106 lines
3.6 KiB
TypeScript
import * as Sentry from '@sentry/react';
|
|
import keyBy from 'lodash/keyBy';
|
|
|
|
import type {EntrySpans, EventTransaction} from 'sentry/types';
|
|
import {
|
|
EntryType,
|
|
getIssueTypeFromOccurrenceType,
|
|
IssueCategory,
|
|
IssueType,
|
|
} from 'sentry/types';
|
|
|
|
import type {RawSpanType} from '../spans/types';
|
|
|
|
import type {TraceContextSpanProxy} from './spanEvidence';
|
|
|
|
export function getSpanInfoFromTransactionEvent(
|
|
event: Pick<
|
|
EventTransaction,
|
|
| 'entries'
|
|
| 'perfProblem'
|
|
| 'issueCategory'
|
|
| 'endTimestamp'
|
|
| 'contexts'
|
|
| 'occurrence'
|
|
>
|
|
) {
|
|
const perfEvidenceData = event.perfProblem ?? event?.occurrence?.evidenceData;
|
|
if (!perfEvidenceData) {
|
|
if (
|
|
event.issueCategory === IssueCategory.PERFORMANCE &&
|
|
event.endTimestamp > 1663560000 // (Sep 19, 2022 onward), Some events could have been missing evidence before EA
|
|
) {
|
|
Sentry.captureException(new Error('Span Evidence missing for performance issue.'));
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// Let's dive into the event to pick off the span evidence data by using the IDs we know
|
|
const spanEntry = event.entries.find((entry: EntrySpans | any): entry is EntrySpans => {
|
|
return entry.type === EntryType.SPANS;
|
|
});
|
|
|
|
const spans: Array<RawSpanType | TraceContextSpanProxy> = spanEntry?.data
|
|
? [...spanEntry.data]
|
|
: [];
|
|
|
|
if (event?.contexts?.trace?.span_id) {
|
|
// TODO: Fix this conditional and check if span_id is ever actually undefined.
|
|
spans.push(event.contexts.trace as TraceContextSpanProxy);
|
|
}
|
|
const spansById = keyBy(spans, 'span_id');
|
|
const parentSpanIDs = perfEvidenceData?.parentSpanIds ?? [];
|
|
const offendingSpanIDs = perfEvidenceData?.offenderSpanIds ?? [];
|
|
const causeSpanIDs = perfEvidenceData?.causeSpanIds ?? [];
|
|
return {
|
|
parentSpan: spansById[parentSpanIDs[0]],
|
|
offendingSpans: offendingSpanIDs.map(spanID => spansById[spanID]),
|
|
causeSpans: causeSpanIDs.map(spanID => spansById[spanID]),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Given an event for a performance issue, returns the `affectedSpanIds` and `focusedSpanIds`.
|
|
* Both of these subsets of spans are used to determine which spans are initially visible on the span tree on the issue details
|
|
* page. The main difference is that the former will be highlighted in red, these spans are intended to indicate the 'root cause' spans
|
|
* of the issue, with the latter being supplemental spans that are involved in the issue but not necessarily the cause of it.
|
|
*
|
|
* @param event
|
|
*/
|
|
export function getProblemSpansForSpanTree(event: EventTransaction): {
|
|
affectedSpanIds: string[];
|
|
focusedSpanIds: string[];
|
|
} {
|
|
const perfEvidenceData = event.perfProblem ?? event?.occurrence?.evidenceData;
|
|
|
|
const issueType =
|
|
event.perfProblem?.issueType ??
|
|
getIssueTypeFromOccurrenceType(event?.occurrence?.type);
|
|
const affectedSpanIds: string[] = [];
|
|
const focusedSpanIds: string[] = [];
|
|
|
|
// By default, offender spans will always be `affected spans`
|
|
const offenderSpanIds = perfEvidenceData?.offenderSpanIds ?? [];
|
|
affectedSpanIds.push(...offenderSpanIds);
|
|
|
|
if (issueType !== IssueType.PERFORMANCE_N_PLUS_ONE_API_CALLS) {
|
|
const parentSpanIds = perfEvidenceData?.parentSpanIds ?? [];
|
|
affectedSpanIds.push(...parentSpanIds);
|
|
}
|
|
|
|
if (issueType === IssueType.PERFORMANCE_CONSECUTIVE_DB_QUERIES) {
|
|
const consecutiveSpanIds = perfEvidenceData?.causeSpanIds ?? [];
|
|
|
|
if (consecutiveSpanIds.length < 11) {
|
|
focusedSpanIds.push(...consecutiveSpanIds);
|
|
}
|
|
}
|
|
|
|
if (issueType === IssueType.PERFORMANCE_N_PLUS_ONE_DB_QUERIES) {
|
|
const precedingSpans = perfEvidenceData?.causeSpanIds ?? [];
|
|
focusedSpanIds.push(...precedingSpans);
|
|
}
|
|
|
|
return {affectedSpanIds, focusedSpanIds};
|
|
}
|