displayReprocessEventAction.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import {ExceptionValue, PlatformType} from 'app/types';
  2. import {EntryException, EntryType, Event} from 'app/types/event';
  3. import {Thread} from 'app/types/events';
  4. import {StacktraceType} from 'app/types/stacktrace';
  5. const NATIVE_PLATFORMS = ['cocoa', 'native'] as Array<PlatformType>;
  6. // Finds all frames in a given data blob and returns it's platforms
  7. function getPlatforms(exceptionValue: ExceptionValue | StacktraceType) {
  8. const frames = exceptionValue?.frames ?? [];
  9. const stacktraceFrames = (exceptionValue as ExceptionValue)?.stacktrace?.frames ?? [];
  10. if (!frames.length && !stacktraceFrames.length) {
  11. return [];
  12. }
  13. return [...frames, ...stacktraceFrames]
  14. .map(frame => frame.platform)
  15. .filter(platform => !!platform);
  16. }
  17. function getStackTracePlatforms(event: Event, exceptionEntry: EntryException) {
  18. // Fetch platforms in stack traces of an exception entry
  19. const exceptionEntryPlatforms = (exceptionEntry.data.values ?? []).flatMap(
  20. getPlatforms
  21. );
  22. // Fetch platforms in an exception entry
  23. const stackTraceEntry = (event.entries.find(
  24. entry => entry.type === EntryType.STACKTRACE
  25. )?.data ?? {}) as StacktraceType;
  26. // Fetch platforms in an exception entry
  27. const stackTraceEntryPlatforms = Object.keys(stackTraceEntry).flatMap(key =>
  28. getPlatforms(stackTraceEntry[key])
  29. );
  30. // Fetch platforms in an thread entry
  31. const threadEntry = (event.entries.find(entry => entry.type === EntryType.THREADS)?.data
  32. .values ?? []) as Array<Thread>;
  33. // Fetch platforms in a thread entry
  34. const threadEntryPlatforms = threadEntry.flatMap(({stacktrace}) =>
  35. getPlatforms(stacktrace)
  36. );
  37. return new Set([
  38. ...exceptionEntryPlatforms,
  39. ...stackTraceEntryPlatforms,
  40. ...threadEntryPlatforms,
  41. ]);
  42. }
  43. // Checks whether an event indicates that it has an apple crash report.
  44. function isNativeEvent(event: Event, exceptionEntry: EntryException) {
  45. const {platform} = event;
  46. if (platform && NATIVE_PLATFORMS.includes(platform)) {
  47. return true;
  48. }
  49. const stackTracePlatforms = getStackTracePlatforms(event, exceptionEntry);
  50. return NATIVE_PLATFORMS.some(nativePlatform => stackTracePlatforms.has(nativePlatform));
  51. }
  52. // Checks whether an event indicates that it has an associated minidump.
  53. function isMinidumpEvent(exceptionEntry: EntryException) {
  54. const {data} = exceptionEntry;
  55. return (data.values ?? []).some(value => value.mechanism?.type === 'minidump');
  56. }
  57. // Checks whether an event indicates that it has an apple crash report.
  58. function isAppleCrashReportEvent(exceptionEntry: EntryException) {
  59. const {data} = exceptionEntry;
  60. return (data.values ?? []).some(value => value.mechanism?.type === 'applecrashreport');
  61. }
  62. export function displayReprocessEventAction(orgFeatures: Array<string>, event?: Event) {
  63. if (!event || !orgFeatures.includes('reprocessing-v2')) {
  64. return false;
  65. }
  66. const {entries} = event;
  67. const exceptionEntry = entries.find(entry => entry.type === EntryType.EXCEPTION) as
  68. | EntryException
  69. | undefined;
  70. if (!exceptionEntry) {
  71. return false;
  72. }
  73. // We want to show the reprocessing button if the issue in question is native or contains native frames.
  74. // The logic is taken from the symbolication pipeline in Python, where it is used to determine whether reprocessing
  75. // payloads should be stored:
  76. // https://github.com/getsentry/sentry/blob/cb7baef414890336881d67b7a8433ee47198c701/src/sentry/lang/native/processing.py#L425-L426
  77. // It is still not ideal as one can always merge native and non-native events together into one issue,
  78. // but it's the best approximation we have.
  79. if (
  80. !isMinidumpEvent(exceptionEntry) &&
  81. !isAppleCrashReportEvent(exceptionEntry) &&
  82. !isNativeEvent(event, exceptionEntry)
  83. ) {
  84. return false;
  85. }
  86. return true;
  87. }