From a6ccfaac929c0292b32c47ff90516c4cc75884fd Mon Sep 17 00:00:00 2001 From: lucas Date: Mon, 10 Nov 2025 16:13:44 +0000 Subject: [PATCH 1/7] loggerOrigin implementation --- packages/core/src/js/options.ts | 10 ++++++++ packages/core/src/js/wrapper.ts | 6 ++++- packages/core/test/wrapper.test.ts | 38 ++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/packages/core/src/js/options.ts b/packages/core/src/js/options.ts index feadc58ad0..11a8df1bbd 100644 --- a/packages/core/src/js/options.ts +++ b/packages/core/src/js/options.ts @@ -316,6 +316,16 @@ export interface BaseReactNativeOptions { * @default false */ propagateTraceparent?: boolean; + + /** + * Controls the origin of the logger to be logged, it takes effect when `enableLogger` is set to true. + * 'all' will log all origins. + * 'JS' will log only enable Logger to capture JavaScript logs. + * 'Native' will log only Native Logs.. + * + * @default 'all' + */ + loggerOrigin?: 'all' | 'js' | 'native'; } export type SentryReplayQuality = 'low' | 'medium' | 'high'; diff --git a/packages/core/src/js/wrapper.ts b/packages/core/src/js/wrapper.ts index 716aac0a1c..445117137e 100644 --- a/packages/core/src/js/wrapper.ts +++ b/packages/core/src/js/wrapper.ts @@ -228,6 +228,10 @@ export const NATIVE: SentryNativeWrapper = { enableNative: true, autoInitializeNativeSdk: true, ...originalOptions, + // Keeps original behavior of enableLogs by not setting it when not defined. + ...(originalOptions.enableLogs !== undefined + ? { enableLogs: originalOptions.enableLogs && originalOptions.loggerOrigin !== 'js' } + : {}), }; if (!options.enableNative) { @@ -273,7 +277,7 @@ export const NATIVE: SentryNativeWrapper = { // filter out all the options that would crash native. /* eslint-disable @typescript-eslint/unbound-method,@typescript-eslint/no-unused-vars */ - const { beforeSend, beforeBreadcrumb, beforeSendTransaction, integrations, ignoreErrors, ...filteredOptions } = + const { beforeSend, beforeBreadcrumb, beforeSendTransaction, integrations, ignoreErrors, loggerOrigin, ...filteredOptions } = options; /* eslint-enable @typescript-eslint/unbound-method,@typescript-eslint/no-unused-vars */ const nativeIsReady = await RNSentry.initNativeSdk(filteredOptions); diff --git a/packages/core/test/wrapper.test.ts b/packages/core/test/wrapper.test.ts index cf7f7cc818..bc27f18dd6 100644 --- a/packages/core/test/wrapper.test.ts +++ b/packages/core/test/wrapper.test.ts @@ -312,6 +312,44 @@ describe('Tests Native Wrapper', () => { expect(initParameter.ignoreErrorsStr).toBeUndefined(); expect(initParameter.ignoreErrorsRegex).toBeUndefined(); }); + + test('does not set enableLogs when option is undefined', async () => { + await NATIVE.initNativeSdk({ + dsn: 'test', + enableNative: true, + autoInitializeNativeSdk: true, + devServerUrl: undefined, + defaultSidecarUrl: undefined, + mobileReplayOptions: undefined, + }); + + expect(RNSentry.initNativeSdk).toHaveBeenCalled(); + const initParameter = (RNSentry.initNativeSdk as jest.MockedFunction).mock.calls[0][0]; + expect(initParameter.enableLogs).toBeUndefined(); + }); + + it.each([ + ['without loggerOrigin', undefined, true], + ['with loggerOrigin set to Native', 'native' as const, true], + ['with loggerOrigin set to all', 'all' as const, true], + ['with loggerOrigin set to JS', 'js' as const, false], + ])('handles enableLogs %s', async (_description, loggerOrigin, expectedEnableLogs) => { + await NATIVE.initNativeSdk({ + dsn: 'test', + enableNative: true, + autoInitializeNativeSdk: true, + enableLogs: true, + ...(loggerOrigin !== undefined ? { loggerOrigin } : {}), + devServerUrl: undefined, + defaultSidecarUrl: undefined, + mobileReplayOptions: undefined, + }); + + expect(RNSentry.initNativeSdk).toHaveBeenCalled(); + const initParameter = (RNSentry.initNativeSdk as jest.MockedFunction).mock.calls[0][0]; + expect(initParameter.enableLogs).toBe(expectedEnableLogs); + expect(initParameter.loggerOrigin).toBeUndefined(); + }); }); describe('sendEnvelope', () => { From 6809b5601605e37ffa8be93d4f02f57ff58392ab Mon Sep 17 00:00:00 2001 From: lucas Date: Mon, 10 Nov 2025 17:35:48 +0000 Subject: [PATCH 2/7] JS tests --- packages/core/src/js/client.ts | 2 +- packages/core/src/js/integrations/default.ts | 2 +- packages/core/test/client.test.ts | 49 ++++++++++++ .../test/integrations/defaultLogs.test.ts | 76 +++++++++++++++++++ 4 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 packages/core/test/integrations/defaultLogs.test.ts diff --git a/packages/core/src/js/client.ts b/packages/core/src/js/client.ts index b263689735..6aee412584 100644 --- a/packages/core/src/js/client.ts +++ b/packages/core/src/js/client.ts @@ -72,7 +72,7 @@ export class ReactNativeClient extends Client { this.on('beforeSendSession', addAutoIpAddressToSession); } - if (options.enableLogs) { + if (options.enableLogs && options.loggerOrigin !== 'native') { this.on('flush', () => { _INTERNAL_flushLogsBuffer(this); }); diff --git a/packages/core/src/js/integrations/default.ts b/packages/core/src/js/integrations/default.ts index 06255435ab..5c208a542a 100644 --- a/packages/core/src/js/integrations/default.ts +++ b/packages/core/src/js/integrations/default.ts @@ -85,7 +85,7 @@ export function getDefaultIntegrations(options: ReactNativeClientOptions): Integ if (options.enableNative) { integrations.push(deviceContextIntegration()); integrations.push(modulesLoaderIntegration()); - if (options.enableLogs) { + if (options.enableLogs && options.loggerOrigin !== 'native') { integrations.push(logEnricherIntegration()); integrations.push(consoleLoggingIntegration()); } diff --git a/packages/core/test/client.test.ts b/packages/core/test/client.test.ts index f495b0476d..e724cfcc44 100644 --- a/packages/core/test/client.test.ts +++ b/packages/core/test/client.test.ts @@ -7,6 +7,7 @@ import type { Transport, TransportMakeRequestResponse, } from '@sentry/core'; +import * as SentryCore from '@sentry/core'; import { addAutoIpAddressToSession, addAutoIpAddressToUser, @@ -852,8 +853,56 @@ describe('Tests ReactNativeClient', () => { ); }); }); + + describe('logger initialization', () => { + afterEach(() => { + jest.useRealTimers(); + jest.restoreAllMocks(); + }); + + test('does not flush logs when enableLogs is false', () => { + jest.useFakeTimers(); + const flushLogsSpy = jest.spyOn(SentryCore, '_INTERNAL_flushLogsBuffer').mockImplementation(jest.fn()); + + const { client } = createClientWithSpy({ enableLogs: false }); + + client.emit('afterCaptureLog', { message: 'test', attributes: {} } as unknown); + jest.advanceTimersByTime(5000); + + expect(flushLogsSpy).not.toHaveBeenCalled(); + }); + + test('does not flush logs when loggerOrigin is native', () => { + jest.useFakeTimers(); + const flushLogsSpy = jest.spyOn(SentryCore, '_INTERNAL_flushLogsBuffer').mockImplementation(jest.fn()); + + const { client } = createClientWithSpy({ enableLogs: true, loggerOrigin: 'native' }); + + client.emit('afterCaptureLog', { message: 'test', attributes: {} } as unknown); + jest.advanceTimersByTime(5000); + + expect(flushLogsSpy).not.toHaveBeenCalled(); + }); + + it.each([ + ['all' as const], + ['js' as const], + ])('flushes logs when loggerOrigin is %s', loggerOrigin => { + jest.useFakeTimers(); + const flushLogsSpy = jest.spyOn(SentryCore, '_INTERNAL_flushLogsBuffer').mockImplementation(jest.fn()); + + const { client } = createClientWithSpy({ enableLogs: true, loggerOrigin }); + + client.emit('afterCaptureLog', { message: 'test', attributes: {} } as unknown); + jest.advanceTimersByTime(5000); + + expect(flushLogsSpy).toHaveBeenCalledTimes(1); + expect(flushLogsSpy).toHaveBeenLastCalledWith(client); + }); + }); }); + function mockedOptions(options: Partial): ReactNativeClientOptions { return { integrations: [], diff --git a/packages/core/test/integrations/defaultLogs.test.ts b/packages/core/test/integrations/defaultLogs.test.ts new file mode 100644 index 0000000000..8496352aac --- /dev/null +++ b/packages/core/test/integrations/defaultLogs.test.ts @@ -0,0 +1,76 @@ +import { consoleLoggingIntegration } from '@sentry/browser'; +import type { Integration } from '@sentry/core'; +import { getDefaultIntegrations } from '../../src/js/integrations/default'; +import { logEnricherIntegration } from '../../src/js/integrations/logEnricherIntegration'; +import type { ReactNativeClientOptions } from '../../src/js/options'; +import { notWeb } from '../../src/js/utils/environment'; + +jest.mock('../../src/js/utils/environment', () => { + const actual = jest.requireActual('../../src/js/utils/environment'); + return { + ...actual, + notWeb: jest.fn(() => true), + }; +}); + +const logEnricherIntegrationName = logEnricherIntegration().name; +const consoleLoggingIntegrationName = consoleLoggingIntegration().name; + +describe('getDefaultIntegrations - logging integrations', () => { + beforeEach(() => { + (notWeb as jest.Mock).mockReturnValue(true); + }); + + const createOptions = (overrides: Partial): ReactNativeClientOptions => { + return { + dsn: 'https://example.com/1', + enableNative: true, + ...overrides, + } as ReactNativeClientOptions; + }; + + const getIntegrationNames = (options: ReactNativeClientOptions): string[] => { + const integrations = getDefaultIntegrations(options); + return integrations.map((integration: Integration) => integration.name); + }; + + it('does not add logging integrations when enableLogs is falsy', () => { + const names = getIntegrationNames(createOptions({ enableLogs: false })); + + expect(names).not.toContain(logEnricherIntegrationName); + expect(names).not.toContain(consoleLoggingIntegrationName); + }); + + it('adds logging integrations when enableLogs is true and loggerOrigin is not native', () => { + const names = getIntegrationNames(createOptions({ enableLogs: true })); + + expect(names).toContain(logEnricherIntegrationName); + expect(names).toContain(consoleLoggingIntegrationName); + }); + + it('does not add logging integrations when loggerOrigin is native', () => { + const names = getIntegrationNames( + createOptions({ enableLogs: true, loggerOrigin: 'native' as unknown as ReactNativeClientOptions['loggerOrigin'] }), + ); + + expect(names).not.toContain(logEnricherIntegrationName); + expect(names).not.toContain(consoleLoggingIntegrationName); + }); + + it.each([ + ['all', true], + ['js', true], + ['native', false], + ])('handles loggerOrigin %s correctly', (loggerOrigin, shouldInclude) => { + const names = getIntegrationNames( + createOptions({ + enableLogs: true, + loggerOrigin: loggerOrigin as unknown as ReactNativeClientOptions['loggerOrigin'], + }), + ); + + expect(names.includes(logEnricherIntegrationName)).toBe(shouldInclude); + expect(names.includes(consoleLoggingIntegrationName)).toBe(shouldInclude); + }); +}); + From ac657fc7a16e08d62f1b0c637144c03a64171c5e Mon Sep 17 00:00:00 2001 From: lucas Date: Mon, 10 Nov 2025 19:06:12 +0000 Subject: [PATCH 3/7] fix JS disabled also disabling native, lint fixes, test fixes --- packages/core/android/libs/replay-stubs.jar | Bin 1198 -> 1198 bytes packages/core/src/js/client.ts | 12 +++++++++++- packages/core/src/js/wrapper.ts | 11 +++++++++-- packages/core/test/client.test.ts | 6 +----- .../test/integrations/defaultLogs.test.ts | 6 ++++-- samples/react-native/src/App.tsx | 1 + 6 files changed, 26 insertions(+), 10 deletions(-) diff --git a/packages/core/android/libs/replay-stubs.jar b/packages/core/android/libs/replay-stubs.jar index ea82bc337b09f7af3f59ddcaf8794bdc1c276798..93e2fd8c8f548399f69baef2134d00f6f14f6431 100644 GIT binary patch delta 150 zcmZ3-xsH=Jz?+#xgn@yBgJDWZ)#ApVhH(N7KW@HAMH~Auy3CO_79L)A0b(6iA^}uvBvniO~ R%xnwR_?g)SOk1&(008WgCrAJQ diff --git a/packages/core/src/js/client.ts b/packages/core/src/js/client.ts index 6aee412584..99f1aa815f 100644 --- a/packages/core/src/js/client.ts +++ b/packages/core/src/js/client.ts @@ -64,6 +64,13 @@ export class ReactNativeClient extends Client { // We default this to true, as it is the safer scenario options.parentSpanIsAlwaysRootSpan = options.parentSpanIsAlwaysRootSpan === undefined ? true : options.parentSpanIsAlwaysRootSpan; + + const originalEnableLogs = options.enableLogs; + if (options.enableLogs && options.loggerOrigin === 'native') { + debug.log('disabling Sentry logs on JavaScript due to rule set by loggerOrigin'); + options.enableLogs = false; + } + super(options); this._outcomesBuffer = []; @@ -72,7 +79,7 @@ export class ReactNativeClient extends Client { this.on('beforeSendSession', addAutoIpAddressToSession); } - if (options.enableLogs && options.loggerOrigin !== 'native') { + if (options.enableLogs) { this.on('flush', () => { _INTERNAL_flushLogsBuffer(this); }); @@ -87,6 +94,9 @@ export class ReactNativeClient extends Client { }, DEFAULT_FLUSH_INTERVAL); }); } + + // Restore original settings for enabling Native options. + options.enableLogs = originalEnableLogs; } /** diff --git a/packages/core/src/js/wrapper.ts b/packages/core/src/js/wrapper.ts index 445117137e..fc3bc2685d 100644 --- a/packages/core/src/js/wrapper.ts +++ b/packages/core/src/js/wrapper.ts @@ -277,8 +277,15 @@ export const NATIVE: SentryNativeWrapper = { // filter out all the options that would crash native. /* eslint-disable @typescript-eslint/unbound-method,@typescript-eslint/no-unused-vars */ - const { beforeSend, beforeBreadcrumb, beforeSendTransaction, integrations, ignoreErrors, loggerOrigin, ...filteredOptions } = - options; + const { + beforeSend, + beforeBreadcrumb, + beforeSendTransaction, + integrations, + ignoreErrors, + loggerOrigin, + ...filteredOptions + } = options; /* eslint-enable @typescript-eslint/unbound-method,@typescript-eslint/no-unused-vars */ const nativeIsReady = await RNSentry.initNativeSdk(filteredOptions); diff --git a/packages/core/test/client.test.ts b/packages/core/test/client.test.ts index e724cfcc44..b72821e6d0 100644 --- a/packages/core/test/client.test.ts +++ b/packages/core/test/client.test.ts @@ -884,10 +884,7 @@ describe('Tests ReactNativeClient', () => { expect(flushLogsSpy).not.toHaveBeenCalled(); }); - it.each([ - ['all' as const], - ['js' as const], - ])('flushes logs when loggerOrigin is %s', loggerOrigin => { + it.each([['all' as const], ['js' as const]])('flushes logs when loggerOrigin is %s', loggerOrigin => { jest.useFakeTimers(); const flushLogsSpy = jest.spyOn(SentryCore, '_INTERNAL_flushLogsBuffer').mockImplementation(jest.fn()); @@ -902,7 +899,6 @@ describe('Tests ReactNativeClient', () => { }); }); - function mockedOptions(options: Partial): ReactNativeClientOptions { return { integrations: [], diff --git a/packages/core/test/integrations/defaultLogs.test.ts b/packages/core/test/integrations/defaultLogs.test.ts index 8496352aac..63b97bb93d 100644 --- a/packages/core/test/integrations/defaultLogs.test.ts +++ b/packages/core/test/integrations/defaultLogs.test.ts @@ -50,7 +50,10 @@ describe('getDefaultIntegrations - logging integrations', () => { it('does not add logging integrations when loggerOrigin is native', () => { const names = getIntegrationNames( - createOptions({ enableLogs: true, loggerOrigin: 'native' as unknown as ReactNativeClientOptions['loggerOrigin'] }), + createOptions({ + enableLogs: true, + loggerOrigin: 'native' as unknown as ReactNativeClientOptions['loggerOrigin'], + }), ); expect(names).not.toContain(logEnricherIntegrationName); @@ -73,4 +76,3 @@ describe('getDefaultIntegrations - logging integrations', () => { expect(names.includes(consoleLoggingIntegrationName)).toBe(shouldInclude); }); }); - diff --git a/samples/react-native/src/App.tsx b/samples/react-native/src/App.tsx index c9a24aea6f..a293b9dc17 100644 --- a/samples/react-native/src/App.tsx +++ b/samples/react-native/src/App.tsx @@ -67,6 +67,7 @@ Sentry.init({ _experiments: { enableUnhandledCPPExceptionsV2: true, }, + loggerOrigin: 'all', enableLogs: true, beforeSendLog: (log) => { return log; From 7c4d332910ba095a32c45640b214da2e5af4ec4c Mon Sep 17 00:00:00 2001 From: lucas Date: Mon, 10 Nov 2025 19:28:29 +0000 Subject: [PATCH 4/7] rename feat to logsOrigin --- CHANGELOG.md | 7 +++++++ packages/core/src/js/client.ts | 4 ++-- packages/core/src/js/integrations/default.ts | 2 +- packages/core/src/js/options.ts | 8 ++++---- packages/core/src/js/wrapper.ts | 4 ++-- packages/core/test/client.test.ts | 8 ++++---- .../core/test/integrations/defaultLogs.test.ts | 10 +++++----- packages/core/test/wrapper.test.ts | 14 +++++++------- samples/react-native/src/App.tsx | 2 +- 9 files changed, 33 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8e4e0ca67..ebefe54096 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,13 @@ ## Unreleased +### Features + +- added `logsOrigin` to Sentry Options ([#5354](https://github.com/getsentry/sentry-react-native/pull/5354)) + Now you can choose which logs will be captured: 'native' for only Logs that comes from the Native code, 'js' for logs that only comes from the JavaScript layer, or 'all' for both layers. This will only have any impact if `enableLogs` is set to `true`. + By default it is set to `all` so it behaves the same before this change. + + ### Fixes - Android SDK not being disabled when `options.enabled` is set to `false` ([#5334](https://github.com/getsentry/sentry-react-native/pull/5334)) diff --git a/packages/core/src/js/client.ts b/packages/core/src/js/client.ts index 99f1aa815f..2a80ca3077 100644 --- a/packages/core/src/js/client.ts +++ b/packages/core/src/js/client.ts @@ -66,8 +66,8 @@ export class ReactNativeClient extends Client { options.parentSpanIsAlwaysRootSpan === undefined ? true : options.parentSpanIsAlwaysRootSpan; const originalEnableLogs = options.enableLogs; - if (options.enableLogs && options.loggerOrigin === 'native') { - debug.log('disabling Sentry logs on JavaScript due to rule set by loggerOrigin'); + if (options.enableLogs && options.logsOrigin === 'native') { + debug.log('disabling Sentry logs on JavaScript due to rule set by logsOrigin'); options.enableLogs = false; } diff --git a/packages/core/src/js/integrations/default.ts b/packages/core/src/js/integrations/default.ts index 5c208a542a..19009ab26b 100644 --- a/packages/core/src/js/integrations/default.ts +++ b/packages/core/src/js/integrations/default.ts @@ -85,7 +85,7 @@ export function getDefaultIntegrations(options: ReactNativeClientOptions): Integ if (options.enableNative) { integrations.push(deviceContextIntegration()); integrations.push(modulesLoaderIntegration()); - if (options.enableLogs && options.loggerOrigin !== 'native') { + if (options.enableLogs && options.logsOrigin !== 'native') { integrations.push(logEnricherIntegration()); integrations.push(consoleLoggingIntegration()); } diff --git a/packages/core/src/js/options.ts b/packages/core/src/js/options.ts index 11a8df1bbd..cfcd6a0c3f 100644 --- a/packages/core/src/js/options.ts +++ b/packages/core/src/js/options.ts @@ -318,14 +318,14 @@ export interface BaseReactNativeOptions { propagateTraceparent?: boolean; /** - * Controls the origin of the logger to be logged, it takes effect when `enableLogger` is set to true. + * Controls which log origin is captured when `enableLogs` is set to true. * 'all' will log all origins. - * 'JS' will log only enable Logger to capture JavaScript logs. - * 'Native' will log only Native Logs.. + * 'js' will capture only JavaScript logs. + * 'native' will capture only native logs. * * @default 'all' */ - loggerOrigin?: 'all' | 'js' | 'native'; + logsOrigin?: 'all' | 'js' | 'native'; } export type SentryReplayQuality = 'low' | 'medium' | 'high'; diff --git a/packages/core/src/js/wrapper.ts b/packages/core/src/js/wrapper.ts index fc3bc2685d..d84e61a632 100644 --- a/packages/core/src/js/wrapper.ts +++ b/packages/core/src/js/wrapper.ts @@ -230,7 +230,7 @@ export const NATIVE: SentryNativeWrapper = { ...originalOptions, // Keeps original behavior of enableLogs by not setting it when not defined. ...(originalOptions.enableLogs !== undefined - ? { enableLogs: originalOptions.enableLogs && originalOptions.loggerOrigin !== 'js' } + ? { enableLogs: originalOptions.enableLogs && originalOptions.logsOrigin !== 'js' } : {}), }; @@ -283,7 +283,7 @@ export const NATIVE: SentryNativeWrapper = { beforeSendTransaction, integrations, ignoreErrors, - loggerOrigin, + logsOrigin, ...filteredOptions } = options; /* eslint-enable @typescript-eslint/unbound-method,@typescript-eslint/no-unused-vars */ diff --git a/packages/core/test/client.test.ts b/packages/core/test/client.test.ts index b72821e6d0..39385826cf 100644 --- a/packages/core/test/client.test.ts +++ b/packages/core/test/client.test.ts @@ -872,11 +872,11 @@ describe('Tests ReactNativeClient', () => { expect(flushLogsSpy).not.toHaveBeenCalled(); }); - test('does not flush logs when loggerOrigin is native', () => { + test('does not flush logs when logsOrigin is native', () => { jest.useFakeTimers(); const flushLogsSpy = jest.spyOn(SentryCore, '_INTERNAL_flushLogsBuffer').mockImplementation(jest.fn()); - const { client } = createClientWithSpy({ enableLogs: true, loggerOrigin: 'native' }); + const { client } = createClientWithSpy({ enableLogs: true, logsOrigin: 'native' }); client.emit('afterCaptureLog', { message: 'test', attributes: {} } as unknown); jest.advanceTimersByTime(5000); @@ -884,11 +884,11 @@ describe('Tests ReactNativeClient', () => { expect(flushLogsSpy).not.toHaveBeenCalled(); }); - it.each([['all' as const], ['js' as const]])('flushes logs when loggerOrigin is %s', loggerOrigin => { + it.each([['all' as const], ['js' as const]])('flushes logs when logsOrigin is %s', logOrlogsOriginigin => { jest.useFakeTimers(); const flushLogsSpy = jest.spyOn(SentryCore, '_INTERNAL_flushLogsBuffer').mockImplementation(jest.fn()); - const { client } = createClientWithSpy({ enableLogs: true, loggerOrigin }); + const { client } = createClientWithSpy({ enableLogs: true, logsOrigin: logOrlogsOriginigin }); client.emit('afterCaptureLog', { message: 'test', attributes: {} } as unknown); jest.advanceTimersByTime(5000); diff --git a/packages/core/test/integrations/defaultLogs.test.ts b/packages/core/test/integrations/defaultLogs.test.ts index 63b97bb93d..ba460e266a 100644 --- a/packages/core/test/integrations/defaultLogs.test.ts +++ b/packages/core/test/integrations/defaultLogs.test.ts @@ -41,18 +41,18 @@ describe('getDefaultIntegrations - logging integrations', () => { expect(names).not.toContain(consoleLoggingIntegrationName); }); - it('adds logging integrations when enableLogs is true and loggerOrigin is not native', () => { + it('adds logging integrations when enableLogs is true and logsOrigin is not native', () => { const names = getIntegrationNames(createOptions({ enableLogs: true })); expect(names).toContain(logEnricherIntegrationName); expect(names).toContain(consoleLoggingIntegrationName); }); - it('does not add logging integrations when loggerOrigin is native', () => { + it('does not add logging integrations when logsOrigin is native', () => { const names = getIntegrationNames( createOptions({ enableLogs: true, - loggerOrigin: 'native' as unknown as ReactNativeClientOptions['loggerOrigin'], + logsOrigin: 'native' as unknown as ReactNativeClientOptions['logsOrigin'], }), ); @@ -64,11 +64,11 @@ describe('getDefaultIntegrations - logging integrations', () => { ['all', true], ['js', true], ['native', false], - ])('handles loggerOrigin %s correctly', (loggerOrigin, shouldInclude) => { + ])('handles logsOrigin %s correctly', (logsOrigin, shouldInclude) => { const names = getIntegrationNames( createOptions({ enableLogs: true, - loggerOrigin: loggerOrigin as unknown as ReactNativeClientOptions['loggerOrigin'], + logsOrigin: logsOrigin as unknown as ReactNativeClientOptions['logsOrigin'], }), ); diff --git a/packages/core/test/wrapper.test.ts b/packages/core/test/wrapper.test.ts index bc27f18dd6..e15f98e7df 100644 --- a/packages/core/test/wrapper.test.ts +++ b/packages/core/test/wrapper.test.ts @@ -329,17 +329,17 @@ describe('Tests Native Wrapper', () => { }); it.each([ - ['without loggerOrigin', undefined, true], - ['with loggerOrigin set to Native', 'native' as const, true], - ['with loggerOrigin set to all', 'all' as const, true], - ['with loggerOrigin set to JS', 'js' as const, false], - ])('handles enableLogs %s', async (_description, loggerOrigin, expectedEnableLogs) => { + ['without logsOrigin', undefined, true], + ['with logsOrigin set to Native', 'native' as const, true], + ['with logsOrigin set to all', 'all' as const, true], + ['with logsOrigin set to JS', 'js' as const, false], + ])('handles enableLogs %s', async (_description, logsOrigin, expectedEnableLogs) => { await NATIVE.initNativeSdk({ dsn: 'test', enableNative: true, autoInitializeNativeSdk: true, enableLogs: true, - ...(loggerOrigin !== undefined ? { loggerOrigin } : {}), + ...(logsOrigin !== undefined ? { logsOrigin } : {}), devServerUrl: undefined, defaultSidecarUrl: undefined, mobileReplayOptions: undefined, @@ -348,7 +348,7 @@ describe('Tests Native Wrapper', () => { expect(RNSentry.initNativeSdk).toHaveBeenCalled(); const initParameter = (RNSentry.initNativeSdk as jest.MockedFunction).mock.calls[0][0]; expect(initParameter.enableLogs).toBe(expectedEnableLogs); - expect(initParameter.loggerOrigin).toBeUndefined(); + expect(initParameter.logsOrigin).toBeUndefined(); }); }); diff --git a/samples/react-native/src/App.tsx b/samples/react-native/src/App.tsx index a293b9dc17..8974c90206 100644 --- a/samples/react-native/src/App.tsx +++ b/samples/react-native/src/App.tsx @@ -67,7 +67,7 @@ Sentry.init({ _experiments: { enableUnhandledCPPExceptionsV2: true, }, - loggerOrigin: 'all', + logsOrigin: 'all', enableLogs: true, beforeSendLog: (log) => { return log; From 2d46d9d06c000dc93f435d5b65caf183a03c87c9 Mon Sep 17 00:00:00 2001 From: LucasZF Date: Tue, 11 Nov 2025 11:16:01 +0000 Subject: [PATCH 5/7] Update CHANGELOG.md Co-authored-by: Antonis Lilis --- CHANGELOG.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21d777c51b..2615d16733 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,9 @@ ### Features -- added `logsOrigin` to Sentry Options ([#5354](https://github.com/getsentry/sentry-react-native/pull/5354)) - Now you can choose which logs will be captured: 'native' for only Logs that comes from the Native code, 'js' for logs that only comes from the JavaScript layer, or 'all' for both layers. This will only have any impact if `enableLogs` is set to `true`. - By default it is set to `all` so it behaves the same before this change. - +- Added `logsOrigin` to Sentry Options ([#5354](https://github.com/getsentry/sentry-react-native/pull/5354)) + - You can now choose which logs are captured: 'native' for logs from native code only, 'js' for logs from the JavaScript layer only, or 'all' for both layers. + - Takes effect only if `enableLogs` is `true` and defaults to 'all', preserving previous behavior. ### Fixes From 62fc88aa8f0e8275f831b8a16e7de34aa8874b40 Mon Sep 17 00:00:00 2001 From: lucas Date: Tue, 11 Nov 2025 11:23:18 +0000 Subject: [PATCH 6/7] restore replay-stubs from main, added comments to client.ts --- packages/core/android/libs/replay-stubs.jar | Bin 1198 -> 1198 bytes packages/core/src/js/client.ts | 2 ++ 2 files changed, 2 insertions(+) diff --git a/packages/core/android/libs/replay-stubs.jar b/packages/core/android/libs/replay-stubs.jar index 93e2fd8c8f548399f69baef2134d00f6f14f6431..ea82bc337b09f7af3f59ddcaf8794bdc1c276798 100644 GIT binary patch delta 150 zcmZ3-xsH=Jz?+#xgn@yBgP}P#Vj`~^v*muHiDq7E7W<8&8GwKZL;wLZ5NGD=GczDG z0F_K!rp^qaF6c8~C=8#>#ApVhH(N7KW@HAMH~Auy3CO_79L)A0b(6iA^}uvBvniO~ R%xnwR_?g)SOk1&(008WgCrAJQ delta 150 zcmZ3-xsH=Jz?+#xgn@yBgJDWZ) { options.parentSpanIsAlwaysRootSpan = options.parentSpanIsAlwaysRootSpan === undefined ? true : options.parentSpanIsAlwaysRootSpan; + // enableLogs must be disabled before calling super() to avoid logs being captured. + // This makes a copy of the user defined value, so we can restore it later for the native usaege. const originalEnableLogs = options.enableLogs; if (options.enableLogs && options.logsOrigin === 'native') { debug.log('disabling Sentry logs on JavaScript due to rule set by logsOrigin'); From 1d3a918ea0513d9ba95c836f995322488b2342be Mon Sep 17 00:00:00 2001 From: lucas Date: Tue, 11 Nov 2025 11:26:19 +0000 Subject: [PATCH 7/7] changelog sync --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96ce6ad7ad..26feed3877 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ > make sure you follow our [migration guide](https://docs.sentry.io/platforms/react-native/migration/) first. -## 7.6.0 +## Unreleased ### Features @@ -14,6 +14,9 @@ - You can now choose which logs are captured: 'native' for logs from native code only, 'js' for logs from the JavaScript layer only, or 'all' for both layers. - Takes effect only if `enableLogs` is `true` and defaults to 'all', preserving previous behavior. +## 7.6.0 + + ### Fixes - Android SDK not being disabled when `options.enabled` is set to `false` ([#5334](https://github.com/getsentry/sentry-react-native/pull/5334))