Skip to content

Commit 5c627e6

Browse files
authored
Merge branch 'main' into feedback-ui-2
2 parents 776747f + 5060f2d commit 5c627e6

File tree

4 files changed

+323
-89
lines changed

4 files changed

+323
-89
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
### Fixes
1818

1919
- crashedLastRun now returns the correct value ([#4829](https://github.com/getsentry/sentry-react-native/pull/4829))
20+
- Use engine-specific promise rejection tracking ([#4826](https://github.com/getsentry/sentry-react-native/pull/4826))
2021
- Fixes Feedback Widget accessibility issue on iOS ([#4739](https://github.com/getsentry/sentry-react-native/pull/4739))
2122

2223
## 6.14.0

packages/core/src/js/integrations/reactnativeerrorhandlers.ts

Lines changed: 76 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import type { EventHint, Integration, SeverityLevel } from '@sentry/core';
2-
import { addExceptionMechanism, captureException, getClient, getCurrentScope, logger } from '@sentry/core';
3-
2+
import {
3+
addExceptionMechanism,
4+
addGlobalUnhandledRejectionInstrumentationHandler,
5+
captureException,
6+
getClient,
7+
getCurrentScope,
8+
logger,
9+
} from '@sentry/core';
10+
11+
import { isHermesEnabled, isWeb } from '../utils/environment';
412
import { createSyntheticError, isErrorLike } from '../utils/error';
513
import { RN_GLOBAL_OBJ } from '../utils/worldwide';
614
import { checkPromiseAndWarn, polyfillPromise, requireRejectionTracking } from './reactnativeerrorhandlersutils';
@@ -44,49 +52,83 @@ function setup(options: ReactNativeErrorHandlersOptions): void {
4452
* Setup unhandled promise rejection tracking
4553
*/
4654
function setupUnhandledRejectionsTracking(patchGlobalPromise: boolean): void {
47-
if (patchGlobalPromise) {
48-
polyfillPromise();
49-
}
55+
try {
56+
if (
57+
isHermesEnabled() &&
58+
RN_GLOBAL_OBJ.HermesInternal?.enablePromiseRejectionTracker &&
59+
RN_GLOBAL_OBJ?.HermesInternal?.hasPromise?.()
60+
) {
61+
logger.log('Using Hermes native promise rejection tracking');
62+
63+
RN_GLOBAL_OBJ.HermesInternal.enablePromiseRejectionTracker({
64+
allRejections: true,
65+
onUnhandled: promiseRejectionTrackingOptions.onUnhandled,
66+
onHandled: promiseRejectionTrackingOptions.onHandled,
67+
});
5068

51-
attachUnhandledRejectionHandler();
52-
checkPromiseAndWarn();
69+
logger.log('Unhandled promise rejections will be caught by Sentry.');
70+
} else if (isWeb()) {
71+
logger.log('Using Browser JS promise rejection tracking for React Native Web');
72+
73+
// Use Sentry's built-in global unhandled rejection handler
74+
addGlobalUnhandledRejectionInstrumentationHandler((error: unknown) => {
75+
captureException(error, {
76+
originalException: error,
77+
syntheticException: isErrorLike(error) ? undefined : createSyntheticError(),
78+
mechanism: { handled: false, type: 'onunhandledrejection' },
79+
});
80+
});
81+
} else if (patchGlobalPromise) {
82+
// For JSC and other environments, use the existing approach
83+
polyfillPromise();
84+
attachUnhandledRejectionHandler();
85+
checkPromiseAndWarn();
86+
} else {
87+
// For JSC and other environments, patching was disabled by user configuration
88+
logger.log('Unhandled promise rejections will not be caught by Sentry.');
89+
}
90+
} catch (e) {
91+
logger.warn(
92+
'Failed to set up promise rejection tracking. ' +
93+
'Unhandled promise rejections will not be caught by Sentry.' +
94+
'See https://docs.sentry.io/platforms/react-native/troubleshooting/ for more details.',
95+
);
96+
}
5397
}
5498

55-
function attachUnhandledRejectionHandler(): void {
56-
const tracking = requireRejectionTracking();
99+
const promiseRejectionTrackingOptions: PromiseRejectionTrackingOptions = {
100+
onUnhandled: (id, error: unknown, rejection = {}) => {
101+
if (__DEV__) {
102+
logger.warn(`Possible Unhandled Promise Rejection (id: ${id}):\n${rejection}`);
103+
}
57104

58-
const promiseRejectionTrackingOptions: PromiseRejectionTrackingOptions = {
59-
onUnhandled: (id, rejection = {}) => {
60-
// eslint-disable-next-line no-console
61-
console.warn(`Possible Unhandled Promise Rejection (id: ${id}):\n${rejection}`);
62-
},
63-
onHandled: id => {
64-
// eslint-disable-next-line no-console
65-
console.warn(
105+
// Marking the rejection as handled to avoid breaking crash rate calculations.
106+
// See: https://github.com/getsentry/sentry-react-native/issues/4141
107+
captureException(error, {
108+
data: { id },
109+
originalException: error,
110+
syntheticException: isErrorLike(error) ? undefined : createSyntheticError(),
111+
mechanism: { handled: true, type: 'onunhandledrejection' },
112+
});
113+
},
114+
onHandled: id => {
115+
if (__DEV__) {
116+
logger.warn(
66117
`Promise Rejection Handled (id: ${id})\n` +
67118
'This means you can ignore any previous messages of the form ' +
68119
`"Possible Unhandled Promise Rejection (id: ${id}):"`,
69120
);
70-
},
71-
};
121+
}
122+
},
123+
};
124+
125+
function attachUnhandledRejectionHandler(): void {
126+
const tracking = requireRejectionTracking();
72127

73128
tracking.enable({
74129
allRejections: true,
75-
onUnhandled: (id: string, error: unknown) => {
76-
if (__DEV__) {
77-
promiseRejectionTrackingOptions.onUnhandled(id, error);
78-
}
79-
80-
captureException(error, {
81-
data: { id },
82-
originalException: error,
83-
syntheticException: isErrorLike(error) ? undefined : createSyntheticError(),
84-
mechanism: { handled: true, type: 'onunhandledrejection' },
85-
});
86-
},
87-
onHandled: (id: string) => {
88-
promiseRejectionTrackingOptions.onHandled(id);
89-
},
130+
onUnhandled: promiseRejectionTrackingOptions.onUnhandled,
131+
onHandled: promiseRejectionTrackingOptions.onHandled,
90132
});
91133
}
92134

packages/core/src/js/utils/worldwide.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,20 @@ import { GLOBAL_OBJ } from '@sentry/core';
33
import type { ErrorUtils } from 'react-native/types';
44

55
import type { ExpoGlobalObject } from './expoglobalobject';
6+
export interface HermesPromiseRejectionTrackingOptions {
7+
allRejections: boolean;
8+
onUnhandled: (id: string, error: unknown) => void;
9+
onHandled: (id: string) => void;
10+
}
611

712
/** Internal Global object interface with common and Sentry specific properties */
813
export interface ReactNativeInternalGlobal extends InternalGlobal {
914
__sentry_rn_v4_registered?: boolean;
1015
__sentry_rn_v5_registered?: boolean;
1116
HermesInternal?: {
1217
getRuntimeProperties?: () => Record<string, string | undefined>;
18+
enablePromiseRejectionTracker?: (options: HermesPromiseRejectionTrackingOptions) => void;
19+
hasPromise?: () => boolean;
1320
};
1421
Promise: unknown;
1522
__turboModuleProxy: unknown;

0 commit comments

Comments
 (0)