diff --git a/CHANGELOG.md b/CHANGELOG.md index 24c72a32..0ed55d06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,24 @@ > [!IMPORTANT] -> If you are upgrading to the `3.x` versions of the SDK from `2.x` or lower, make sure you follow our +> If you are upgrading to the `4.x` versions of the SDK from `3.x` or lower, make sure you follow our > [migration guide](https://docs.sentry.io/platforms/javascript/guides/capacitor/migration/) first. ## Unreleased +#### Sentry Capacitor V4 + +Version 4 removes Session Replay and Profiling support. No additional breaking changes +are expected. If these features are enabled through other means, Sentry will not provide support for them. +All other SDK features, including error monitoring and performance monitoring, remain fully supported and +unchanged. + +### Break Changes + +- Remove Session Replay ([#1214](https://github.com/getsentry/sentry-capacitor/pull/1214)) +- Remove Profiling support ([#1217](https://github.com/getsentry/sentry-capacitor/pull/1217)) + ### Fixes - (Android): AGP 9.0 no longer supports `proguard-android.txt` ([#1196](https://github.com/getsentry/sentry-capacitor/pull/1196)) diff --git a/android/src/main/java/io/sentry/capacitor/SentryCapacitor.java b/android/src/main/java/io/sentry/capacitor/SentryCapacitor.java index 33f832f7..9ae2ab00 100644 --- a/android/src/main/java/io/sentry/capacitor/SentryCapacitor.java +++ b/android/src/main/java/io/sentry/capacitor/SentryCapacitor.java @@ -154,14 +154,6 @@ public void initNativeSdk(final PluginCall call) { } } - // In case some user enable Android Replay by accident, - // it will not work with JavaScript replay, so we enforce this to disable Android replay. - // If you are interested on being able to use native replay, please open a Github issue - // on the following repo: https://github.com/getsentry/sentry-capacitor. - var controller = options.getSessionReplay(); - controller.setSessionSampleRate(null); - controller.setOnErrorSampleRate(null); - options.getLogs().setEnabled(Boolean.TRUE.equals(capOptions.getBoolean("enableLogs", false))); logger.log(SentryLevel.INFO, String.format("Native Integrations '%s'", options.getIntegrations())); diff --git a/example/ionic-angular-v7/src/app/app.module.ts b/example/ionic-angular-v7/src/app/app.module.ts index 37ef33d6..b838e411 100644 --- a/example/ionic-angular-v7/src/app/app.module.ts +++ b/example/ionic-angular-v7/src/app/app.module.ts @@ -14,8 +14,7 @@ import { environment } from '../environments/environment'; // ATTENTION: Change the DSN below with your own to see the events in Sentry. Get one at sentry.io Sentry.init( { - dsn: - 'https://4079af8b316240ea9453eb0a23b715cc@o447951.ingest.sentry.io/5522756', + dsn: 'https://4079af8b316240ea9453eb0a23b715cc@o447951.ingest.sentry.io/5522756', // An array of strings or regexps that'll be used to ignore specific errors based on their type/message ignoreErrors: [/MiddleEarth_\d\d/, 'RangeError'], // To see what the Sentry SDK is doing; Helps when setting things up @@ -25,22 +24,18 @@ Sentry.init( // Use the tracing integration to see traces and add performance monitoring _experiments: { enableMetrics: true, - beforeSendMetric: (metric) => { + beforeSendMetric: metric => { return metric; }, }, integrations: [ Sentry.browserTracingIntegration(), - Sentry.replayIntegration({ - maskAllText: false, - blockAllMedia: true, - }), Sentry.spotlightIntegration({ - sidecarUrl: environment.spotlightSidecarUrl, + sidecarUrl: environment.spotlightSidecarUrl, }), ], enableLogs: true, - beforeSendLog: (log) => { + beforeSendLog: log => { return log; }, // A release identifier @@ -52,12 +47,6 @@ Sentry.init( // We recommend adjusting this value in production, or using tracesSampler // for finer control tracesSampleRate: 1.0, - // This sets the sample rate to be 10%. You may want this to be 100% while - // in development and sample at a lower rate in production - replaysSessionSampleRate: 0.1, - // If the entire session is not sampled, use the below sample rate to sample - // sessions when an error occurs. - replaysOnErrorSampleRate: 1.0, }, sentryAngularInit, ); @@ -75,6 +64,6 @@ Sentry.init( useValue: createErrorHandler(), }, ], - bootstrap: [AppComponent] + bootstrap: [AppComponent], }) -export class AppModule { } +export class AppModule {} diff --git a/example/ionic-angular-v8/src/app/app.module.ts b/example/ionic-angular-v8/src/app/app.module.ts index 35097f6e..b838e411 100644 --- a/example/ionic-angular-v8/src/app/app.module.ts +++ b/example/ionic-angular-v8/src/app/app.module.ts @@ -14,8 +14,7 @@ import { environment } from '../environments/environment'; // ATTENTION: Change the DSN below with your own to see the events in Sentry. Get one at sentry.io Sentry.init( { - dsn: - 'https://4079af8b316240ea9453eb0a23b715cc@o447951.ingest.sentry.io/5522756', + dsn: 'https://4079af8b316240ea9453eb0a23b715cc@o447951.ingest.sentry.io/5522756', // An array of strings or regexps that'll be used to ignore specific errors based on their type/message ignoreErrors: [/MiddleEarth_\d\d/, 'RangeError'], // To see what the Sentry SDK is doing; Helps when setting things up @@ -25,22 +24,18 @@ Sentry.init( // Use the tracing integration to see traces and add performance monitoring _experiments: { enableMetrics: true, - beforeSendMetric: (metric) => { + beforeSendMetric: metric => { return metric; }, }, integrations: [ Sentry.browserTracingIntegration(), - Sentry.replayIntegration({ - maskAllText: false, - blockAllMedia: true, - }), Sentry.spotlightIntegration({ sidecarUrl: environment.spotlightSidecarUrl, }), ], enableLogs: true, - beforeSendLog: (log) => { + beforeSendLog: log => { return log; }, // A release identifier @@ -52,11 +47,6 @@ Sentry.init( // We recommend adjusting this value in production, or using tracesSampler // for finer control tracesSampleRate: 1.0, - // This sets the sample rate to be 10%. You may want this to be 100% while - // in development and sample at a lower rate in production - replaysSessionSampleRate: 1.0, // If the entire session is not sampled, use the below sample rate to sample - // sessions when an error occurs. - replaysOnErrorSampleRate: 1.0, }, sentryAngularInit, ); @@ -74,6 +64,6 @@ Sentry.init( useValue: createErrorHandler(), }, ], - bootstrap: [AppComponent] + bootstrap: [AppComponent], }) -export class AppModule { } +export class AppModule {} diff --git a/example/ionic-vue3/src/main.ts b/example/ionic-vue3/src/main.ts index d4b02586..71a89e41 100644 --- a/example/ionic-vue3/src/main.ts +++ b/example/ionic-vue3/src/main.ts @@ -1,5 +1,5 @@ -import { createApp } from 'vue' -import App from './App.vue' +import { createApp } from 'vue'; +import App from './App.vue'; import router from './router'; import { IonicVue } from '@ionic/vue'; @@ -26,10 +26,7 @@ import { localConfig } from './config/local'; /* Theme variables */ import './theme/variables.css'; -const app = createApp(App) - .use(IonicVue) - .use(router); - +const app = createApp(App).use(IonicVue).use(router); Sentry.init({ dsn: 'https://7f35532db4f8aca7c7b6992d488b39c1@o447951.ingest.sentry.io/4505912397660160', @@ -38,42 +35,31 @@ Sentry.init({ tracingOptions: { timeout: 1000, trackComponents: true, - hooks: ["mount", "update", "unmount"] - } - }), - SentryVue.replayCanvasIntegration({ - maskAllText: false, - blockAllMedia: false, + hooks: ['mount', 'update', 'unmount'], + }, }), - ...(localConfig.spotlightSidecarUrl ? [Sentry.spotlightIntegration({ - sidecarUrl: localConfig.spotlightSidecarUrl, - })] : []), + ...(localConfig.spotlightSidecarUrl + ? [ + Sentry.spotlightIntegration({ + sidecarUrl: localConfig.spotlightSidecarUrl, + }), + ] + : []), ], tracePropagationTargets: ['localhost', /^https:\/\/yourserver\.io\/api/], - // Performance Monitoring - tracesSampleRate: 1.0, // Capture 100% of the transactions - // Session Replay - replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production. - replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur. + tracesSampleRate: 1.0, enableLogs: true, beforeSendLog: (log) => { return log; }, +}); - siblingOptions: { - vueOptions: { - app: app, - attachErrorHandler: false, - attachProps: false, - }, - }, -}, - // Forward the init method from @sentry/vue - SentryVue.init, -); - +SentryVue.init({ + app: app, + attachErrorHandler: false, + attachProps: false, +}); router.isReady().then(() => { app.mount('#app'); - app.mount('Hello') }); diff --git a/src/index.ts b/src/index.ts index f9bc7fb5..a8368c75 100644 --- a/src/index.ts +++ b/src/index.ts @@ -50,7 +50,7 @@ export { startIdleSpan, } from '@sentry/core'; -export { metrics, replayIntegration, browserTracingIntegration, registerSpanErrorInstrumentation, logger } from '@sentry/browser'; +export { metrics, browserTracingIntegration, registerSpanErrorInstrumentation, logger } from '@sentry/browser'; export { pauseAppHangTracking, resumeAppHangTracking } from './wrapper'; diff --git a/src/integrations/logEnricherIntegration.ts b/src/integrations/logEnricherIntegration.ts index 836e706c..498a2dae 100644 --- a/src/integrations/logEnricherIntegration.ts +++ b/src/integrations/logEnricherIntegration.ts @@ -13,7 +13,7 @@ export const logEnricherIntegration = (): Integration => { cacheLogContext().then( () => { client.on('beforeCaptureLog', (log: Log) => { - processLog(log, client); + processLog(log); }); }, reason => { @@ -69,7 +69,7 @@ async function cacheLogContext(): Promise { return Promise.resolve(); } -function processLog(log: Log, client: Client): void { +function processLog(log: Log): void { if (NativeCache === undefined) { return; } @@ -85,9 +85,6 @@ function processLog(log: Log, client: Client): void { setLogAttribute(logAttributes, 'os.version', NativeCache.version); setLogAttribute(logAttributes, 'sentry.release', NativeCache.release); - const replay = client.getIntegrationByName string | null }>('Replay'); - setLogAttribute(logAttributes, 'sentry.replay_id', replay?.getReplayId()); - // Set log.attributes to the variable log.attributes = logAttributes; } diff --git a/src/nativeOptions.ts b/src/nativeOptions.ts index 019adacb..99416380 100644 --- a/src/nativeOptions.ts +++ b/src/nativeOptions.ts @@ -35,8 +35,6 @@ export function FilterNativeOptions( maxBreadcrumbs: options.maxBreadcrumbs, // maxValueLength: Only available on the JavaScript Layer. release: options.release, - // replaysOnErrorSampleRate: Only handled on the JavaScript Layer. - // replaysSessionSampleRate: Only handled on the JavaScript Layer. sampleRate: options.sampleRate, sendClientReports: options.sendClientReports, sendDefaultPii: options.sendDefaultPii, diff --git a/src/options.ts b/src/options.ts index 12dffafe..8f1ed1b6 100644 --- a/src/options.ts +++ b/src/options.ts @@ -5,24 +5,7 @@ import type { NuxtOptions, VueOptions } from './siblingOptions'; // Direct reference of BrowserTransportOptions is not compatible with strict builds of latest versions of Typescript 5. type BrowserTransportOptions = Parameters[0]; -type CapacitorBrowserClientReplayOptions = { - /** - * The sample rate for session-long replays. - * 1.0 will record all sessions and 0 will record none. - * @deprecated This option will be dropped on Capacitor V4. - */ - replaysSessionSampleRate?: number; - /** - * The sample rate for sessions that has had an error occur. - * This is independent of `sessionSampleRate`. - * 1.0 will record all sessions and 0 will record none. - * @deprecated This option will be dropped on Capacitor V4. - */ - replaysOnErrorSampleRate?: number; -}; - -export interface BaseCapacitorOptions - extends CapacitorBrowserClientReplayOptions { +export interface BaseCapacitorOptions { /** * Enables crash reporting for native crashes. * Defaults to `true`. @@ -152,6 +135,9 @@ export interface CapacitorOptions | 'enableMetrics' | 'replaysOnErrorSampleRate' | 'replaysSessionSampleRate' + | 'profilesSampleRate' + | 'profileLifecycle' + | 'profileSessionSampleRate' >, BaseCapacitorOptions {} @@ -166,5 +152,8 @@ export interface CapacitorClientOptions | 'enableMetrics' | 'replaysOnErrorSampleRate' | 'replaysSessionSampleRate' + | 'profilesSampleRate' + | 'profileLifecycle' + | 'profileSessionSampleRate' >, BaseCapacitorOptions {} diff --git a/src/sdk.ts b/src/sdk.ts index 69670af8..e181607f 100644 --- a/src/sdk.ts +++ b/src/sdk.ts @@ -86,15 +86,6 @@ export function init( ? getDefaultIntegrations(sharedOptions) : passedOptions.defaultIntegrations; - if ( - browserOptions.replaysSessionSampleRate || - browserOptions.replaysOnErrorSampleRate - ) { - debug.warn( - 'Sentry Capacitor options "replaysSessionSampleRate" and "replaysOnErrorSampleRate" will be removed in Capacitor SDK v4.', - ); - } - /** * Mobile options are the options that are only used by the native SDK. */ diff --git a/test/integrations/logEnricherIntegration.test.ts b/test/integrations/logEnricherIntegration.test.ts index c51d9ff2..07792d8d 100644 --- a/test/integrations/logEnricherIntegration.test.ts +++ b/test/integrations/logEnricherIntegration.test.ts @@ -252,74 +252,6 @@ describe('LogEnricher Integration', () => { expect(mockOn).not.toHaveBeenCalled(); }); - it('should add replay_id when Replay integration is available', async () => { - NATIVE.fetchNativeLogAttributes.mockResolvedValue({ - contexts: { - device: { - brand: 'Apple', - }, - }, - }); - - const mockReplayIntegration = { - getReplayId: jest.fn(() => 'replay-id-123'), - }; - mockGetIntegrationByName.mockReturnValue(mockReplayIntegration); - - const integration = logEnricherIntegration(); - integration.setup!(mockClient); - - // Wait for cacheLogContext to complete - await new Promise(resolve => setTimeout(resolve, 0)); - - const log = CreateLog(); - - const beforeCaptureLogHandler = mockOn.mock.calls.find( - call => call[0] === 'beforeCaptureLog', - )?.[1]; - - if (beforeCaptureLogHandler) { - beforeCaptureLogHandler(log, mockClient); - } - - expect(mockGetIntegrationByName).toHaveBeenCalledWith('Replay'); - expect(log.attributes).toEqual({ - 'device.brand': 'Apple', - 'sentry.replay_id': 'replay-id-123', - }); - }); - - it('should not add replay_id when Replay integration is not available', async () => { - NATIVE.fetchNativeLogAttributes.mockResolvedValue({ - contexts: { - device: { - brand: 'Apple', - }, - }, - }); - - mockGetIntegrationByName.mockReturnValue(null); - - const integration = logEnricherIntegration(); - integration.setup!(mockClient); - - // Wait for cacheLogContext to complete - await new Promise(resolve => setTimeout(resolve, 0)); - - const log = CreateLog(); - - const beforeCaptureLogHandler = mockOn.mock.calls.find( - call => call[0] === 'beforeCaptureLog', - )?.[1]; - - if (beforeCaptureLogHandler) { - beforeCaptureLogHandler(log, mockClient); - } - - expect(mockGetIntegrationByName).toHaveBeenCalledWith('Replay'); - expect(log.attributes).not.toHaveProperty('sentry.replay_id'); - }); - it('should handle log without attributes', async () => { NATIVE.fetchNativeLogAttributes.mockResolvedValue({ contexts: { diff --git a/test/nativeOptions.test.ts b/test/nativeOptions.test.ts index 65fe7ae0..b861f192 100644 --- a/test/nativeOptions.test.ts +++ b/test/nativeOptions.test.ts @@ -77,8 +77,6 @@ describe('nativeOptions', () => { normalizeDepth: 100, normalizeMaxBreadth: 100, release: '1', - replaysOnErrorSampleRate: 1, - replaysSessionSampleRate: 1, sampleRate: 1, sendClientReports: true, sendDefaultPii: true,