Skip to content
Merged
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@

## Unreleased

### Features

- Expose `enableNetworkBreadcrumbs` (iOS) to disable native HTTP request breadcrumbs ([#6764](https://github.com/getsentry/sentry-react-native/pull/6764))
- Expose `enableNetworkEventBreadcrumbs` (Android) to disable native network connectivity breadcrumbs ([#6764](https://github.com/getsentry/sentry-react-native/pull/6764))

### Fixes

- Declare optional peer dependencies so imports resolve under strict and Plug'n'Play package managers ([#6729](https://github.com/getsentry/sentry-react-native/pull/6729))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ static void getSentryAndroidOptions(
options.setNdkAppHangTimeoutIntervalMillis(
rnOptions.getInt("ndkAppHangTimeoutIntervalMillis"));
}
if (rnOptions.hasKey("enableNetworkEventBreadcrumbs")) {
options.setEnableNetworkEventBreadcrumbs(
rnOptions.getBoolean("enableNetworkEventBreadcrumbs"));
}
Comment thread
antonis marked this conversation as resolved.
Comment thread
antonis marked this conversation as resolved.
if (rnOptions.hasKey("spotlight")) {
if (rnOptions.getType("spotlight") == ReadableType.Boolean) {
options.setEnableSpotlight(rnOptions.getBoolean("spotlight"));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package io.sentry.react;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import com.facebook.react.bridge.ReadableMap;
import io.sentry.ILogger;
import io.sentry.android.core.SentryAndroidOptions;
import org.junit.Test;

/**
* Coverage for the native option mapping in {@link RNSentryStart#getSentryAndroidOptions} โ€” that RN
* options forwarded from JS are applied onto {@link SentryAndroidOptions}.
*/
public class RNSentryStartTest {

private static SentryAndroidOptions optionsFrom(ReadableMap rnOptions) {
final SentryAndroidOptions options = new SentryAndroidOptions();
RNSentryStart.getSentryAndroidOptions(options, rnOptions, mock(ILogger.class));
return options;
}

@Test
public void enableNetworkEventBreadcrumbsForwardsTrue() {
final ReadableMap rnOptions = mock(ReadableMap.class);
when(rnOptions.hasKey("enableNetworkEventBreadcrumbs")).thenReturn(true);
when(rnOptions.getBoolean("enableNetworkEventBreadcrumbs")).thenReturn(true);

assertTrue(optionsFrom(rnOptions).isEnableNetworkEventBreadcrumbs());
}

@Test
public void enableNetworkEventBreadcrumbsForwardsFalse() {
final ReadableMap rnOptions = mock(ReadableMap.class);
when(rnOptions.hasKey("enableNetworkEventBreadcrumbs")).thenReturn(true);
when(rnOptions.getBoolean("enableNetworkEventBreadcrumbs")).thenReturn(false);

assertFalse(optionsFrom(rnOptions).isEnableNetworkEventBreadcrumbs());
}

@Test
public void enableNetworkEventBreadcrumbsPreservesNativeDefaultWhenUnset() {
final ReadableMap rnOptions = mock(ReadableMap.class);

// Native default is true; omitting the RN option must not change it.
assertTrue(optionsFrom(rnOptions).isEnableNetworkEventBreadcrumbs());
}
}
2 changes: 2 additions & 0 deletions packages/core/etc/sentry-react-native.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ export interface BaseReactNativeOptions {
enableNdk?: boolean;
enableNdkAppHangTracking?: boolean;
enableNdkScopeSync?: boolean;
enableNetworkBreadcrumbs?: boolean;
enableNetworkEventBreadcrumbs?: boolean;
enableStallTracking?: boolean;
enableTombstone?: boolean;
// @internal
Expand Down
27 changes: 27 additions & 0 deletions packages/core/src/js/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,33 @@ export interface BaseReactNativeOptions {
*/
ndkAppHangTimeoutIntervalMillis?: number;

/**
* When enabled, the native iOS SDK records a breadcrumb for every network request.
*
* The JS SDK already records breadcrumbs for `fetch`/`XHR` requests, so the native
* network breadcrumbs are largely duplicates (deduplicated on a best-effort basis when
* merged into JS events). Disable this to stop the native layer from adding its own HTTP
* breadcrumbs and reduce breadcrumb noise.
*
* @default true
* @platform ios
*/
enableNetworkBreadcrumbs?: boolean;

/**
* When enabled, the native Android SDK records breadcrumbs for network connectivity
* changes (network available/lost, capability changes such as WiFi <-> cellular, and
* bandwidth/VPN state).
*
* These track the device's network state, not individual HTTP requests, so they are
* distinct from the `fetch`/`XHR` breadcrumbs the JS SDK records. Disable this to stop
* the native layer from adding connectivity breadcrumbs and reduce breadcrumb noise.
*
* @default true
* @platform android
*/
enableNetworkEventBreadcrumbs?: boolean;

/**
* Use this feature to enable the Sentry MetricKit integration.
*
Expand Down
34 changes: 34 additions & 0 deletions packages/core/test/wrapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,40 @@ describe('Tests Native Wrapper', () => {
expect(initParameter.anrProfilingSampleRate).toBe(0.5);
});

test('forwards enableNetworkBreadcrumbs to the Native SDK', async () => {
await NATIVE.initNativeSdk({
dsn: VALID_DSN,
enableNative: true,
autoInitializeNativeSdk: true,
enableNetworkBreadcrumbs: false,
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.enableNetworkBreadcrumbs).toBe(false);
});

test('forwards enableNetworkEventBreadcrumbs to the Native SDK', async () => {
await NATIVE.initNativeSdk({
dsn: VALID_DSN,
enableNative: true,
autoInitializeNativeSdk: true,
enableNetworkEventBreadcrumbs: false,
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.enableNetworkEventBreadcrumbs).toBe(false);
});

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