123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- import {useMemo} from 'react';
- import type {Event} from 'sentry/types/event';
- import {DiscoverDatasets} from 'sentry/utils/discover/types';
- import {getTraceTimeRangeFromEvent} from 'sentry/utils/performance/quickTrace/utils';
- import {useApiQuery} from 'sentry/utils/queryClient';
- import useOrganization from 'sentry/utils/useOrganization';
- interface BaseEvent {
- id: string;
- 'issue.id': number;
- message: string;
- project: string;
- 'project.name': string;
- timestamp: string;
- title: string;
- transaction: string;
- }
- interface TimelineDiscoverEvent extends BaseEvent {}
- interface TimelineIssuePlatformEvent extends BaseEvent {
- 'event.type': string;
- 'stack.function': string[];
- }
- export type TimelineEvent = TimelineDiscoverEvent | TimelineIssuePlatformEvent;
- export interface TraceEventResponse {
- data: TimelineEvent[];
- meta: unknown;
- }
- interface UseTraceTimelineEventsOptions {
- event: Event;
- }
- export function useTraceTimelineEvents({event}: UseTraceTimelineEventsOptions): {
- endTimestamp: number;
- isError: boolean;
- isLoading: boolean;
- oneOtherIssueEvent: TimelineEvent | undefined;
- startTimestamp: number;
- traceEvents: TimelineEvent[];
- } {
- const organization = useOrganization();
- // If the org has global views, we want to look across all projects,
- // otherwise, just look at the current project.
- const hasGlobalViews = organization.features.includes('global-views');
- const project = hasGlobalViews ? -1 : event.projectID;
- const {start, end} = getTraceTimeRangeFromEvent(event);
- const traceId = event.contexts?.trace?.trace_id ?? '';
- const enabled = !!traceId;
- const {
- data: issuePlatformData,
- isLoading: isLoadingIssuePlatform,
- isError: isErrorIssuePlatform,
- } = useApiQuery<TraceEventResponse>(
- [
- `/organizations/${organization.slug}/events/`,
- {
- query: {
- // Get performance issues
- dataset: DiscoverDatasets.ISSUE_PLATFORM,
- field: ['message', 'title', 'project', 'timestamp', 'issue.id', 'transaction'],
- per_page: 100,
- query: `trace:${traceId}`,
- referrer: 'api.issues.issue_events',
- sort: '-timestamp',
- start,
- end,
- project: project,
- },
- },
- ],
- {staleTime: Infinity, retry: false, enabled}
- );
- const {
- data: discoverData,
- isLoading: isLoadingDiscover,
- isError: isErrorDiscover,
- } = useApiQuery<{
- data: TimelineEvent[];
- meta: unknown;
- }>(
- [
- `/organizations/${organization.slug}/events/`,
- {
- query: {
- // Other events
- dataset: DiscoverDatasets.DISCOVER,
- field: [
- 'message',
- 'title',
- 'project',
- 'timestamp',
- 'issue.id',
- 'transaction',
- 'event.type',
- 'stack.function',
- ],
- per_page: 100,
- query: `trace:${traceId}`,
- referrer: 'api.issues.issue_events',
- sort: '-timestamp',
- start,
- end,
- project: project,
- },
- },
- ],
- {staleTime: Infinity, retry: false, enabled}
- );
- const eventData = useMemo(() => {
- if (
- isLoadingIssuePlatform ||
- isLoadingDiscover ||
- isErrorIssuePlatform ||
- isErrorDiscover
- ) {
- return {
- data: [],
- startTimestamp: 0,
- endTimestamp: 0,
- };
- }
- // Events is unsorted since they're grouped by date later
- const events = [...issuePlatformData.data, ...discoverData.data];
- const oneOtherIssueEvent = getOneOtherIssueEvent(event, events);
- // The current event might be missing when there is a large number of issues
- const hasCurrentEvent = events.some(e => e.id === event.id);
- if (!hasCurrentEvent) {
- events.push({
- id: event.id,
- 'issue.id': Number(event.groupID),
- message: event.message,
- project: event.projectID,
- // The project name for current event is not used
- 'project.name': '',
- timestamp: event.dateCreated!,
- title: event.title,
- transaction: '',
- });
- }
- const timestamps = events.map(e => new Date(e.timestamp).getTime());
- const startTimestamp = Math.min(...timestamps);
- const endTimestamp = Math.max(...timestamps);
- return {
- data: events,
- startTimestamp,
- endTimestamp,
- oneOtherIssueEvent,
- };
- }, [
- event,
- issuePlatformData,
- discoverData,
- isLoadingIssuePlatform,
- isLoadingDiscover,
- isErrorIssuePlatform,
- isErrorDiscover,
- ]);
- return {
- traceEvents: eventData.data,
- startTimestamp: eventData.startTimestamp,
- endTimestamp: eventData.endTimestamp,
- isLoading: isLoadingIssuePlatform || isLoadingDiscover,
- isError: isErrorIssuePlatform || isErrorDiscover,
- oneOtherIssueEvent: eventData.oneOtherIssueEvent,
- };
- }
- function getOneOtherIssueEvent(
- event: Event,
- allTraceEvents: TimelineEvent[]
- ): TimelineEvent | undefined {
- const groupId = event.groupID;
- if (!groupId) {
- return undefined;
- }
- const otherIssues = allTraceEvents.filter(
- (_event, index, self) =>
- _event['issue.id'] !== undefined &&
- // Exclude the current issue
- _event['issue.id'] !== Number(groupId) &&
- self.findIndex(e => e['issue.id'] === _event['issue.id']) === index
- );
- return otherIssues.length === 1 ? otherIssues[0] : undefined;
- }
|