-
-
Notifications
You must be signed in to change notification settings - Fork 362
Expand file tree
/
Copy pathreactnativeinfo.ts
More file actions
117 lines (104 loc) · 3.39 KB
/
Copy pathreactnativeinfo.ts
File metadata and controls
117 lines (104 loc) · 3.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import type { Context, Event, EventHint, Integration } from '@sentry/core';
import {
getExpoGoVersion,
getExpoSdkVersion,
getHermesVersion,
getReactNativeVersion,
isExpo,
isFabricEnabled,
isHermesEnabled,
isTurboModuleEnabled,
} from '../utils/environment';
import type { ReactNativeError } from './debugsymbolicator';
const INTEGRATION_NAME = 'ReactNativeInfo';
export interface ReactNativeContext extends Context {
js_engine?: string;
turbo_module: boolean;
fabric: boolean;
expo: boolean;
hermes_version?: string;
react_native_version?: string;
component_stack?: string;
hermes_debug_info?: boolean;
expo_go_version?: string;
expo_sdk_version?: string;
}
/** Loads React Native context at runtime */
export const reactNativeInfoIntegration = (): Integration => {
return {
name: INTEGRATION_NAME,
setupOnce: () => {
// noop
},
processEvent,
};
};
function processEvent(event: Event, hint: EventHint): Event {
const reactNativeError = hint?.originalException ? (hint?.originalException as ReactNativeError) : undefined;
const reactNativeContext: ReactNativeContext = {
turbo_module: isTurboModuleEnabled(),
fabric: isFabricEnabled(),
react_native_version: getReactNativeVersion(),
expo: isExpo(),
};
if (isHermesEnabled()) {
reactNativeContext.js_engine = 'hermes';
const hermesVersion = getHermesVersion();
if (hermesVersion) {
reactNativeContext.hermes_version = hermesVersion;
}
reactNativeContext.hermes_debug_info = !isEventWithHermesBytecodeFrames(event);
} else if (reactNativeError?.jsEngine) {
reactNativeContext.js_engine = reactNativeError.jsEngine;
}
if (reactNativeContext.js_engine === 'hermes') {
event.tags = {
hermes: 'true',
...event.tags,
};
}
if (reactNativeError?.componentStack) {
reactNativeContext.component_stack = reactNativeError.componentStack;
}
const expoGoVersion = getExpoGoVersion();
if (expoGoVersion) {
reactNativeContext.expo_go_version = expoGoVersion;
}
const expoSdkVersion = getExpoSdkVersion();
if (expoSdkVersion) {
reactNativeContext.expo_sdk_version = expoSdkVersion;
}
event.contexts = {
react_native_context: reactNativeContext,
...event.contexts,
};
return event;
}
/**
* Guess if the event contains frames with Hermes bytecode
* (thus Hermes bundle doesn't contain debug info)
* based on the event exception/threads frames.
*
* This function can be relied on only if Hermes is enabled!
*
* Hermes bytecode position is always line 1 and column 0-based number.
* If Hermes bundle has debug info, the bytecode frames pos are calculated
* back to the plain bundle source code positions and line will be > 1.
*
* Line 1 contains start time var, it's safe to assume it won't crash.
* The above only applies when Hermes is enabled.
*
* Javascript/Hermes bytecode frames have platform === undefined.
* Native (Java, ObjC, C++) frames have platform === 'android'/'ios'/'native'.
*/
function isEventWithHermesBytecodeFrames(event: Event): boolean {
for (const value of event.exception?.values || event.threads?.values || []) {
for (const frame of value.stacktrace?.frames || []) {
// platform === undefined we assume it's javascript (only native frames use the platform attribute)
if (frame.platform === undefined && frame.lineno === 1) {
return true;
}
}
}
return false;
}