displayReprocessEventAction.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import type {
  2. EntryException,
  3. Event,
  4. ExceptionValue,
  5. PlatformKey,
  6. StacktraceType,
  7. Thread,
  8. } from 'sentry/types';
  9. import {EntryType} from 'sentry/types/event';
  10. /** All platforms that always use Debug Files. */
  11. const DEBUG_FILE_PLATFORMS: Set<PlatformKey> = new Set([
  12. 'objc',
  13. 'cocoa',
  14. 'swift',
  15. 'native',
  16. 'c',
  17. ]);
  18. /** Other platforms that may use Debug Files. */
  19. const MAYBE_DEBUG_FILE_PLATFORMS: Set<PlatformKey> = new Set(['csharp', 'java']);
  20. /**
  21. * Returns whether to display the "Reprocess Event" action.
  22. *
  23. * That is the case when we have a "reprocessable" event, which is an event that needs
  24. * Debug Files for proper processing, as those Debug Files could have been uploaded *after*
  25. * the Event was ingested.
  26. */
  27. export function displayReprocessEventAction(event?: Event): boolean {
  28. if (!event) {
  29. return false;
  30. }
  31. const eventPlatforms = getEventPlatform(event);
  32. // Check Events from platforms that always use Debug Files as a fast-path
  33. if (hasIntersection(eventPlatforms, DEBUG_FILE_PLATFORMS)) {
  34. return true;
  35. }
  36. const hasDebugImages = (event?.entries ?? []).some(
  37. entry => entry.type === EntryType.DEBUGMETA && entry.data.images.length > 0
  38. );
  39. // Otherwise, check alternative platforms if they actually have Debug Files
  40. if (hasIntersection(eventPlatforms, MAYBE_DEBUG_FILE_PLATFORMS) && hasDebugImages) {
  41. return true;
  42. }
  43. // Finally, fall back to checking the `platform` of each frame
  44. const exceptionEntry = event.entries.find(
  45. entry => entry.type === EntryType.EXCEPTION
  46. ) as EntryException | undefined;
  47. if (!exceptionEntry) {
  48. return false;
  49. }
  50. return hasIntersection(
  51. getStackTracePlatforms(event, exceptionEntry),
  52. DEBUG_FILE_PLATFORMS
  53. );
  54. }
  55. /**
  56. * Returns whether the two Sets have intersecting elements.
  57. */
  58. function hasIntersection<T>(set1: Set<T>, set2: Set<T>): boolean {
  59. for (const v of set1) {
  60. if (set2.has(v)) {
  61. return true;
  62. }
  63. }
  64. return false;
  65. }
  66. /**
  67. * Returns the event platform as a Set.
  68. */
  69. function getEventPlatform(event: Event): Set<PlatformKey> {
  70. const platforms = new Set<PlatformKey>();
  71. addPlatforms(platforms, [event]);
  72. return platforms;
  73. }
  74. /**
  75. * Returns a Set of all platforms found in the `event` and `exceptionEntry`.
  76. */
  77. function getStackTracePlatforms(
  78. event: Event,
  79. exceptionEntry: EntryException
  80. ): Set<PlatformKey> {
  81. const platforms = new Set<PlatformKey>();
  82. // Add platforms in stack traces of an exception entry
  83. (exceptionEntry.data.values ?? []).forEach(exc => addFramePlatforms(platforms, exc));
  84. // Add platforms in a stack trace entry
  85. const stackTraceEntry = (event.entries.find(
  86. entry => entry.type === EntryType.STACKTRACE
  87. )?.data ?? {}) as StacktraceType;
  88. Object.keys(stackTraceEntry).forEach(key =>
  89. addFramePlatforms(platforms, stackTraceEntry[key])
  90. );
  91. // Add platforms in a thread entry
  92. const threadEntry = (event.entries.find(entry => entry.type === EntryType.THREADS)?.data
  93. .values ?? []) as Array<Thread>;
  94. threadEntry.forEach(({stacktrace}) => addFramePlatforms(platforms, stacktrace));
  95. return platforms;
  96. }
  97. /**
  98. * Adds all the platforms in the frames of `exceptionValue` to the `platforms` Set.
  99. */
  100. function addFramePlatforms(
  101. platforms: Set<PlatformKey>,
  102. exceptionValue: ExceptionValue | StacktraceType | null
  103. ) {
  104. const frames = exceptionValue?.frames ?? [];
  105. const stacktraceFrames = (exceptionValue as ExceptionValue)?.stacktrace?.frames ?? [];
  106. addPlatforms(platforms, frames);
  107. addPlatforms(platforms, stacktraceFrames);
  108. }
  109. /**
  110. * Adds all the `platform` properties found in `iter` to the `platforms` Set.
  111. */
  112. function addPlatforms(
  113. platforms: Set<PlatformKey>,
  114. iter: Array<{platform?: PlatformKey | null}>
  115. ) {
  116. for (const o of iter) {
  117. if (o.platform) {
  118. platforms.add(o.platform);
  119. }
  120. }
  121. }