useTraceTimelineEvents.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import {useMemo} from 'react';
  2. import type {Event} from 'sentry/types/event';
  3. import {DiscoverDatasets} from 'sentry/utils/discover/types';
  4. import {getTraceTimeRangeFromEvent} from 'sentry/utils/performance/quickTrace/utils';
  5. import {useApiQuery} from 'sentry/utils/queryClient';
  6. import useOrganization from 'sentry/utils/useOrganization';
  7. interface BaseEvent {
  8. id: string;
  9. 'issue.id': number;
  10. project: string;
  11. 'project.name': string;
  12. timestamp: string;
  13. title: string;
  14. transaction: string;
  15. }
  16. interface TimelineDiscoverEvent extends BaseEvent {}
  17. interface TimelineIssuePlatformEvent extends BaseEvent {
  18. 'event.type': string;
  19. 'stack.function': string[];
  20. }
  21. export type TimelineEvent = TimelineDiscoverEvent | TimelineIssuePlatformEvent;
  22. export interface TraceEventResponse {
  23. data: TimelineEvent[];
  24. meta: unknown;
  25. }
  26. interface UseTraceTimelineEventsOptions {
  27. event: Event;
  28. }
  29. export function useTraceTimelineEvents({event}: UseTraceTimelineEventsOptions): {
  30. endTimestamp: number;
  31. isError: boolean;
  32. isLoading: boolean;
  33. startTimestamp: number;
  34. traceEvents: TimelineEvent[];
  35. } {
  36. const organization = useOrganization();
  37. const {start, end} = getTraceTimeRangeFromEvent(event);
  38. const traceId = event.contexts?.trace?.trace_id ?? '';
  39. const enabled = !!traceId;
  40. const {
  41. data: issuePlatformData,
  42. isLoading: isLoadingIssuePlatform,
  43. isError: isErrorIssuePlatform,
  44. } = useApiQuery<TraceEventResponse>(
  45. [
  46. `/organizations/${organization.slug}/events/`,
  47. {
  48. query: {
  49. // Get performance issues
  50. dataset: DiscoverDatasets.ISSUE_PLATFORM,
  51. field: ['title', 'project', 'timestamp', 'issue.id', 'transaction'],
  52. per_page: 100,
  53. query: `trace:${traceId}`,
  54. referrer: 'api.issues.issue_events',
  55. sort: '-timestamp',
  56. start,
  57. end,
  58. },
  59. },
  60. ],
  61. {staleTime: Infinity, retry: false, enabled}
  62. );
  63. const {
  64. data: discoverData,
  65. isLoading: isLoadingDiscover,
  66. isError: isErrorDiscover,
  67. } = useApiQuery<{
  68. data: TimelineEvent[];
  69. meta: unknown;
  70. }>(
  71. [
  72. `/organizations/${organization.slug}/events/`,
  73. {
  74. query: {
  75. // Other events
  76. dataset: DiscoverDatasets.DISCOVER,
  77. field: [
  78. 'title',
  79. 'project',
  80. 'timestamp',
  81. 'issue.id',
  82. 'transaction',
  83. 'event.type',
  84. 'stack.function',
  85. ],
  86. per_page: 100,
  87. query: `trace:${traceId}`,
  88. referrer: 'api.issues.issue_events',
  89. sort: '-timestamp',
  90. start,
  91. end,
  92. },
  93. },
  94. ],
  95. {staleTime: Infinity, retry: false, enabled}
  96. );
  97. const eventData = useMemo(() => {
  98. if (
  99. isLoadingIssuePlatform ||
  100. isLoadingDiscover ||
  101. isErrorIssuePlatform ||
  102. isErrorDiscover
  103. ) {
  104. return {
  105. data: [],
  106. startTimestamp: 0,
  107. endTimestamp: 0,
  108. };
  109. }
  110. // Events is unsorted since they're grouped by date later
  111. const events = [...issuePlatformData.data, ...discoverData.data];
  112. // The current event might be missing when there is a large number of issues
  113. const hasCurrentEvent = events.some(e => e.id === event.id);
  114. if (!hasCurrentEvent) {
  115. events.push({
  116. id: event.id,
  117. 'issue.id': Number(event.groupID),
  118. project: event.projectID,
  119. // The project name for current event is not used
  120. 'project.name': '',
  121. timestamp: event.dateCreated!,
  122. title: event.title,
  123. transaction: '',
  124. });
  125. }
  126. const timestamps = events.map(e => new Date(e.timestamp).getTime());
  127. const startTimestamp = Math.min(...timestamps);
  128. const endTimestamp = Math.max(...timestamps);
  129. return {
  130. data: events,
  131. startTimestamp,
  132. endTimestamp,
  133. };
  134. }, [
  135. event,
  136. issuePlatformData,
  137. discoverData,
  138. isLoadingIssuePlatform,
  139. isLoadingDiscover,
  140. isErrorIssuePlatform,
  141. isErrorDiscover,
  142. ]);
  143. return {
  144. traceEvents: eventData.data,
  145. startTimestamp: eventData.startTimestamp,
  146. endTimestamp: eventData.endTimestamp,
  147. isLoading: isLoadingIssuePlatform || isLoadingDiscover,
  148. isError: isErrorIssuePlatform || isErrorDiscover,
  149. };
  150. }