@@ -8,106 +8,137 @@ import type {
8
8
} from 'sentry/types' ;
9
9
import { EntryType } from 'sentry/types' ;
10
10
11
- const NATIVE_PLATFORMS : PlatformKey [ ] = [ 'cocoa' , 'native' ] ;
11
+ /** All platforms that always use Debug Files. */
12
+ const DEBUG_FILE_PLATFORMS : Set < PlatformKey > = new Set ( [
13
+ 'objc' ,
14
+ 'cocoa' ,
15
+ 'swift' ,
16
+ 'native' ,
17
+ 'c' ,
18
+ ] ) ;
19
+ /** Other platforms that may use Debug Files. */
20
+ const MAYBE_DEBUG_FILE_PLATFORMS : Set < PlatformKey > = new Set ( [ 'csharp' , 'java' ] ) ;
21
+
22
+ /**
23
+ * Returns whether to display the "Reprocess Event" action.
24
+ *
25
+ * That is the case when we have a "reprocessable" event, which is an event that needs
26
+ * Debug Files for proper processing, as those Debug Files could have been uploaded *after*
27
+ * the Event was ingested.
28
+ */
29
+ export function displayReprocessEventAction (
30
+ orgFeatures : Array < string > ,
31
+ event ?: Event
32
+ ) : boolean {
33
+ if ( ! event || ! orgFeatures . includes ( 'reprocessing-v2' ) ) {
34
+ return false ;
35
+ }
12
36
13
- // Finds all frames in a given data blob and returns it's platforms
14
- function getPlatforms ( exceptionValue : ExceptionValue | StacktraceType | null ) {
15
- const frames = exceptionValue ?. frames ?? [ ] ;
16
- const stacktraceFrames = ( exceptionValue as ExceptionValue ) ?. stacktrace ?. frames ?? [ ] ;
37
+ const eventPlatforms = getEventPlatform ( event ) ;
38
+ // Check Events from platforms that always use Debug Files as a fast-path
39
+ if ( hasIntersection ( eventPlatforms , DEBUG_FILE_PLATFORMS ) ) {
40
+ return true ;
41
+ }
42
+
43
+ const hasDebugImages = ( event ?. entries ?? [ ] ) . some (
44
+ entry => entry . type === EntryType . DEBUGMETA && entry . data . images . length > 0
45
+ ) ;
17
46
18
- if ( ! frames . length && ! stacktraceFrames . length ) {
19
- return [ ] ;
47
+ // Otherwise, check alternative platforms if they actually have Debug Files
48
+ if ( hasIntersection ( eventPlatforms , MAYBE_DEBUG_FILE_PLATFORMS ) && hasDebugImages ) {
49
+ return true ;
20
50
}
21
51
22
- return [ ... frames , ... stacktraceFrames ]
23
- . map ( frame => frame . platform )
24
- . filter ( platform => ! ! platform ) ;
25
- }
52
+ // Finally, fall back to checking the `platform` of each frame
53
+ const exceptionEntry = event . entries . find (
54
+ entry => entry . type === EntryType . EXCEPTION
55
+ ) as EntryException | undefined ;
26
56
27
- function getStackTracePlatforms ( event : Event , exceptionEntry : EntryException ) {
28
- // Fetch platforms in stack traces of an exception entry
29
- const exceptionEntryPlatforms = ( exceptionEntry . data . values ?? [ ] ) . flatMap (
30
- getPlatforms
57
+ if ( ! exceptionEntry ) {
58
+ return false ;
59
+ }
60
+
61
+ return hasIntersection (
62
+ getStackTracePlatforms ( event , exceptionEntry ) ,
63
+ DEBUG_FILE_PLATFORMS
31
64
) ;
65
+ }
66
+
67
+ /**
68
+ * Returns whether the two Sets have intersecting elements.
69
+ */
70
+ function hasIntersection < T > ( set1 : Set < T > , set2 : Set < T > ) : boolean {
71
+ for ( const v of set1 ) {
72
+ if ( set2 . has ( v ) ) {
73
+ return true ;
74
+ }
75
+ }
76
+ return false ;
77
+ }
78
+
79
+ /**
80
+ * Returns the event platform as a Set.
81
+ */
82
+ function getEventPlatform ( event : Event ) : Set < PlatformKey > {
83
+ const platforms = new Set < PlatformKey > ( ) ;
84
+ addPlatforms ( platforms , [ event ] ) ;
85
+ return platforms ;
86
+ }
87
+
88
+ /**
89
+ * Returns a Set of all platforms found in the `event` and `exceptionEntry`.
90
+ */
91
+ function getStackTracePlatforms (
92
+ event : Event ,
93
+ exceptionEntry : EntryException
94
+ ) : Set < PlatformKey > {
95
+ const platforms = new Set < PlatformKey > ( ) ;
96
+
97
+ // Add platforms in stack traces of an exception entry
98
+ ( exceptionEntry . data . values ?? [ ] ) . forEach ( exc => addFramePlatforms ( platforms , exc ) ) ;
32
99
33
- // Fetch platforms in an exception entry
100
+ // Add platforms in a stack trace entry
34
101
const stackTraceEntry = ( event . entries . find (
35
102
entry => entry . type === EntryType . STACKTRACE
36
103
) ?. data ?? { } ) as StacktraceType ;
37
104
38
- // Fetch platforms in an exception entry
39
- const stackTraceEntryPlatforms = Object . keys ( stackTraceEntry ) . flatMap ( key =>
40
- getPlatforms ( stackTraceEntry [ key ] )
105
+ Object . keys ( stackTraceEntry ) . forEach ( key =>
106
+ addFramePlatforms ( platforms , stackTraceEntry [ key ] )
41
107
) ;
42
108
43
- // Fetch platforms in an thread entry
109
+ // Add platforms in a thread entry
44
110
const threadEntry = ( event . entries . find ( entry => entry . type === EntryType . THREADS ) ?. data
45
111
. values ?? [ ] ) as Array < Thread > ;
46
112
47
- // Fetch platforms in a thread entry
48
- const threadEntryPlatforms = threadEntry . flatMap ( ( { stacktrace} ) =>
49
- getPlatforms ( stacktrace )
50
- ) ;
113
+ threadEntry . forEach ( ( { stacktrace} ) => addFramePlatforms ( platforms , stacktrace ) ) ;
51
114
52
- return new Set ( [
53
- ...exceptionEntryPlatforms ,
54
- ...stackTraceEntryPlatforms ,
55
- ...threadEntryPlatforms ,
56
- ] ) ;
115
+ return platforms ;
57
116
}
58
117
59
- // Checks whether an event indicates that it is a native event.
60
- function isNativeEvent ( event : Event , exceptionEntry : EntryException ) {
61
- const { platform} = event ;
62
-
63
- if ( platform && NATIVE_PLATFORMS . includes ( platform ) ) {
64
- return true ;
65
- }
66
-
67
- const stackTracePlatforms = getStackTracePlatforms ( event , exceptionEntry ) ;
68
-
69
- return NATIVE_PLATFORMS . some ( nativePlatform => stackTracePlatforms . has ( nativePlatform ) ) ;
70
- }
71
-
72
- // Checks whether an event indicates that it has an associated minidump.
73
- function isMinidumpEvent ( exceptionEntry : EntryException ) {
74
- const { data} = exceptionEntry ;
75
- return ( data . values ?? [ ] ) . some ( value => value . mechanism ?. type === 'minidump' ) ;
76
- }
118
+ /**
119
+ * Adds all the platforms in the frames of `exceptionValue` to the `platforms` Set.
120
+ */
121
+ function addFramePlatforms (
122
+ platforms : Set < PlatformKey > ,
123
+ exceptionValue : ExceptionValue | StacktraceType | null
124
+ ) {
125
+ const frames = exceptionValue ?. frames ?? [ ] ;
126
+ const stacktraceFrames = ( exceptionValue as ExceptionValue ) ?. stacktrace ?. frames ?? [ ] ;
77
127
78
- // Checks whether an event indicates that it has an apple crash report.
79
- function isAppleCrashReportEvent ( exceptionEntry : EntryException ) {
80
- const { data} = exceptionEntry ;
81
- return ( data . values ?? [ ] ) . some ( value => value . mechanism ?. type === 'applecrashreport' ) ;
128
+ addPlatforms ( platforms , frames ) ;
129
+ addPlatforms ( platforms , stacktraceFrames ) ;
82
130
}
83
131
84
- export function displayReprocessEventAction ( orgFeatures : Array < string > , event ?: Event ) {
85
- if ( ! event || ! orgFeatures . includes ( 'reprocessing-v2' ) ) {
86
- return false ;
132
+ /**
133
+ * Adds all the `platform` properties found in `iter` to the `platforms` Set.
134
+ */
135
+ function addPlatforms (
136
+ platforms : Set < PlatformKey > ,
137
+ iter : Array < { platform ?: PlatformKey | null } >
138
+ ) {
139
+ for ( const o of iter ) {
140
+ if ( o . platform ) {
141
+ platforms . add ( o . platform ) ;
142
+ }
87
143
}
88
-
89
- const { entries} = event ;
90
- const exceptionEntry = entries . find ( entry => entry . type === EntryType . EXCEPTION ) as
91
- | EntryException
92
- | undefined ;
93
-
94
- if ( ! exceptionEntry ) {
95
- return false ;
96
- }
97
-
98
- // We want to show the reprocessing button if the issue in question is native or contains native frames.
99
- // The logic is taken from the symbolication pipeline in Python, where it is used to determine whether reprocessing
100
- // payloads should be stored:
101
- // https://github.com/getsentry/sentry/blob/cb7baef414890336881d67b7a8433ee47198c701/src/sentry/lang/native/processing.py#L425-L426
102
- // It is still not ideal as one can always merge native and non-native events together into one issue,
103
- // but it's the best approximation we have.
104
- if (
105
- ! isMinidumpEvent ( exceptionEntry ) &&
106
- ! isAppleCrashReportEvent ( exceptionEntry ) &&
107
- ! isNativeEvent ( event , exceptionEntry )
108
- ) {
109
- return false ;
110
- }
111
-
112
- return true ;
113
144
}
0 commit comments