Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

## Unreleased

### Features

- Add `anrProfilingSampleRate` option to profile ANRs on Android ([#6673](https://github.com/getsentry/sentry-react-native/pull/6673))

### Dependencies

- Bump Cocoa SDK from v9.26.1 to v9.27.0 ([#6670](https://github.com/getsentry/sentry-react-native/pull/6670))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,38 @@ class RNSentryStartTest {
assertEquals(5000L, options.ndkAppHangTimeoutIntervalMillis)
}

@Test
fun `when anrProfilingSampleRate is set, the ANR profiling sample rate is applied`() {
val rnOptions = JavaOnlyMap.of("anrProfilingSampleRate", 0.5)
val options = SentryAndroidOptions()

RNSentryStart.getSentryAndroidOptions(options, rnOptions, logger)

assertEquals(0.5, options.anrProfilingSampleRate!!, 0.0)
assertTrue("ANR profiling should be enabled", options.isAnrProfilingEnabled)
}

@Test
fun `when anrProfilingSampleRate is not set, it remains at default (disabled)`() {
val rnOptions = JavaOnlyMap()
val options = SentryAndroidOptions()

RNSentryStart.getSentryAndroidOptions(options, rnOptions, logger)

assertNull("ANR profiling sample rate should be null by default", options.anrProfilingSampleRate)
assertFalse("ANR profiling should be disabled by default", options.isAnrProfilingEnabled)
}

@Test
fun `when anrProfilingSampleRate is not a number, it is ignored`() {
val rnOptions = JavaOnlyMap.of("anrProfilingSampleRate", "invalid")
val options = SentryAndroidOptions()

RNSentryStart.getSentryAndroidOptions(options, rnOptions, logger)

assertNull("ANR profiling sample rate should remain null", options.anrProfilingSampleRate)
}

@Test
fun `network detail replay options are forwarded to the native replay options`() {
val mobileReplayOptions =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ static void getSentryAndroidOptions(
if (rnOptions.hasKey("enableAnrFingerprinting")) {
options.setEnableAnrFingerprinting(rnOptions.getBoolean("enableAnrFingerprinting"));
}
if (rnOptions.hasKey("anrProfilingSampleRate")
&& rnOptions.getType("anrProfilingSampleRate") == ReadableType.Number) {
options.setAnrProfilingSampleRate(rnOptions.getDouble("anrProfilingSampleRate"));
}
if (rnOptions.hasKey("enableNdkAppHangTracking")) {
options.setEnableNdkAppHangTracking(rnOptions.getBoolean("enableNdkAppHangTracking"));
}
Expand Down
15 changes: 15 additions & 0 deletions packages/core/src/js/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,21 @@ export interface BaseReactNativeOptions {
*/
enableAnrFingerprinting?: boolean;

/**
* Sample rate for profiling ANR (Application Not Responding) events.
*
* When set to a value greater than `0.0`, the SDK profiles the main thread while an ANR is
* happening and attaches the resulting profile to the ANR event. The value is the probability
* (`0.0`โ€“`1.0`) that any given ANR is profiled.
*
* Requires ANR detection, which is enabled by default. This is independent of UI/transaction
* profiling configured via `profilesSampleRate` and `_experiments.profilingOptions`.
*
* @default undefined (ANR profiling disabled)
* @platform android
*/
anrProfilingSampleRate?: number;

/**
* When enabled, all the threads are automatically attached to all logged events on Android
*
Expand Down
17 changes: 17 additions & 0 deletions packages/core/test/wrapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,23 @@ describe('Tests Native Wrapper', () => {
expect(debug.warn).toHaveBeenLastCalledWith('Note: Native Sentry SDK is disabled.');
});

test('forwards anrProfilingSampleRate to the Native SDK', async () => {
await NATIVE.initNativeSdk({
dsn: VALID_DSN,
enableNative: true,
autoInitializeNativeSdk: true,
anrProfilingSampleRate: 0.5,
devServerUrl: undefined,
defaultSidecarUrl: undefined,
mobileReplayOptions: undefined,
});

expect(RNSentry.initNativeSdk).toHaveBeenCalled();
// @ts-expect-error mock value
const initParameter = RNSentry.initNativeSdk.mock.calls[0][0];
expect(initParameter.anrProfilingSampleRate).toBe(0.5);
});

test('filter beforeSend when initializing Native SDK', async () => {
await NATIVE.initNativeSdk({
dsn: VALID_DSN,
Expand Down
Loading