diff --git a/packages/core/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java b/packages/core/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java index 48c3661a0..2f4560e5c 100644 --- a/packages/core/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java +++ b/packages/core/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java @@ -278,6 +278,12 @@ protected void getSentryAndroidOptions( if (rnOptions.hasKey("enableNdk")) { options.setEnableNdk(rnOptions.getBoolean("enableNdk")); } + if (rnOptions.hasKey("_experiments")) { + var experiments = rnOptions.getMap("_experiments"); + if (experiments.hasKey(("enableLogs"))) { + options.getLogs().setEnabled(experiments.getBoolean("enableLogs")); + } + } if (rnOptions.hasKey("spotlight")) { if (rnOptions.getType("spotlight") == ReadableType.Boolean) { options.setEnableSpotlight(rnOptions.getBoolean("spotlight")); diff --git a/packages/core/package.json b/packages/core/package.json index 9a87431ef..f4781d171 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -66,20 +66,20 @@ }, "dependencies": { "@sentry/babel-plugin-component-annotate": "3.4.0", - "@sentry/browser": "9.12.0", + "@sentry/browser": "9.18.0", "@sentry/cli": "2.43.0", - "@sentry/core": "9.12.0", - "@sentry/react": "9.12.0", - "@sentry/types": "9.12.0" + "@sentry/core": "9.18.0", + "@sentry/react": "9.18.0", + "@sentry/types": "9.18.0" }, "devDependencies": { "@babel/core": "^7.25.2", "@expo/metro-config": "0.19.5", "@mswjs/interceptors": "^0.25.15", "@react-native/babel-preset": "0.77.1", - "@sentry-internal/eslint-config-sdk": "9.12.0", - "@sentry-internal/eslint-plugin-sdk": "9.12.0", - "@sentry-internal/typescript": "9.12.0", + "@sentry-internal/eslint-config-sdk": "9.18.0", + "@sentry-internal/eslint-plugin-sdk": "9.18.0", + "@sentry-internal/typescript": "9.18.0", "@sentry/wizard": "4.9.0", "@testing-library/react-native": "^12.7.2", "@types/jest": "^29.5.13", diff --git a/packages/core/src/js/client.ts b/packages/core/src/js/client.ts index d6b2d4568..87c61951d 100644 --- a/packages/core/src/js/client.ts +++ b/packages/core/src/js/client.ts @@ -11,6 +11,7 @@ import type { UserFeedback, } from '@sentry/core'; import { + _INTERNAL_flushLogsBuffer, addAutoIpAddressToSession, addAutoIpAddressToUser, BaseClient, @@ -32,6 +33,8 @@ import { mergeOutcomes } from './utils/outcome'; import { ReactNativeLibraries } from './utils/rnlibraries'; import { NATIVE } from './wrapper'; +const DEFAULT_FLUSH_INTERVAL = 5000; + /** * The Sentry React Native SDK Client. * @@ -40,6 +43,7 @@ import { NATIVE } from './wrapper'; */ export class ReactNativeClient extends BaseClient { private _outcomesBuffer: Outcome[]; + private _logFlushIdleTimeout: ReturnType | undefined; /** * Creates a new React Native SDK instance. @@ -60,6 +64,22 @@ export class ReactNativeClient extends BaseClient { this.on('postprocessEvent', addAutoIpAddressToUser); this.on('beforeSendSession', addAutoIpAddressToSession); } + + if (options._experiments?.enableLogs) { + this.on('flush', () => { + _INTERNAL_flushLogsBuffer(this); + }); + + this.on('afterCaptureLog', () => { + if (this._logFlushIdleTimeout) { + clearTimeout(this._logFlushIdleTimeout); + } + + this._logFlushIdleTimeout = setTimeout(() => { + _INTERNAL_flushLogsBuffer(this); + }, DEFAULT_FLUSH_INTERVAL); + }); + } } /** diff --git a/packages/core/src/js/options.ts b/packages/core/src/js/options.ts index 6ecc232ff..a21d12b5b 100644 --- a/packages/core/src/js/options.ts +++ b/packages/core/src/js/options.ts @@ -7,9 +7,14 @@ import { Platform } from 'react-native'; import type { TouchEventBoundaryProps } from './touchevents'; import { getExpoConstants } from './utils/expomodules'; +import type { BrowserOptions } from '@sentry/react'; + type ProfilerProps = React.ComponentProps; type BrowserTransportOptions = Parameters[0]; +type BrowserExperiments = NonNullable; +type SharedExperimentsSubset = Pick; + export interface BaseReactNativeOptions { /** * Enables native transport + device info + offline caching. @@ -245,7 +250,7 @@ export interface BaseReactNativeOptions { /** * Options which are in beta, or otherwise not guaranteed to be stable. */ - _experiments?: { + _experiments?: SharedExperimentsSubset & { [key: string]: unknown; /** diff --git a/packages/core/src/js/wrapper.ts b/packages/core/src/js/wrapper.ts index 289af2992..e5493a2e1 100644 --- a/packages/core/src/js/wrapper.ts +++ b/packages/core/src/js/wrapper.ts @@ -183,7 +183,7 @@ export const NATIVE: SentryNativeWrapper = { typeof itemHeader.content_type === 'string' ? itemHeader.content_type : 'application/octet-stream'; bytesPayload = itemPayload; } else { - bytesContentType = 'application/json'; + bytesContentType = 'application/vnd.sentry.items.log+json'; bytesPayload = utf8ToBytes(JSON.stringify(itemPayload)); if (!hardCrashed) { hardCrashed = isHardCrash(itemPayload); diff --git a/samples/react-native/package.json b/samples/react-native/package.json index d618606ff..cbcaf9d09 100644 --- a/samples/react-native/package.json +++ b/samples/react-native/package.json @@ -27,7 +27,7 @@ "@react-navigation/native": "^7.0.14", "@react-navigation/native-stack": "^7.2.0", "@react-navigation/stack": "^7.1.1", - "@sentry/core": "9.12.0", + "@sentry/core": "9.18.0", "@sentry/react-native": "7.0.0-alpha.0", "@shopify/flash-list": "^1.7.3", "delay": "^6.0.0", diff --git a/samples/react-native/src/App.tsx b/samples/react-native/src/App.tsx index 6d0d4aa43..cdbd33ffc 100644 --- a/samples/react-native/src/App.tsx +++ b/samples/react-native/src/App.tsx @@ -77,6 +77,12 @@ Sentry.init({ didCallNativeInit, ); }, + _experiments: { + enableLogs: true, + beforeSendLog: (log) => { + return log; + }, + }, enableUserInteractionTracing: true, integrations(integrations) { integrations.push( @@ -149,8 +155,8 @@ Sentry.init({ // release: 'myapp@1.2.3+1', // dist: `1`, profilesSampleRate: 1.0, - replaysSessionSampleRate: 1.0, - replaysOnErrorSampleRate: 1.0, + replaysSessionSampleRate: 0.0, + replaysOnErrorSampleRate: 0.0, spotlight: true, // This should be disabled when manually initializing the native SDK // Note that options from JS are not passed to the native SDKs when initialized manually diff --git a/samples/react-native/src/Screens/ErrorsScreen.tsx b/samples/react-native/src/Screens/ErrorsScreen.tsx index c1e320924..d7f1f6716 100644 --- a/samples/react-native/src/Screens/ErrorsScreen.tsx +++ b/samples/react-native/src/Screens/ErrorsScreen.tsx @@ -20,6 +20,7 @@ import { FallbackRender } from '@sentry/react'; import NativeSampleModule from '../../tm/NativeSampleModule'; import NativePlatformSampleModule from '../../tm/NativePlatformSampleModule'; import { TimeToFullDisplay } from '../utils'; +import { logger } from '@sentry/browser'; const { AssetsModule, CppModule, CrashModule } = NativeModules; @@ -149,6 +150,18 @@ const ErrorsScreen = (_props: Props) => { } }} /> +