diff --git a/CHANGELOG.md b/CHANGELOG.md index 92a81f5a510..f309e7d252d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- Do not override user-defined `SentryOptions` ([#4262](https://github.com/getsentry/sentry-java/pull/4262)) + ## 8.5.0 ### Features diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java index 6465381a8ea..f70ea73b0fe 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java @@ -11,6 +11,7 @@ import io.sentry.ILogger; import io.sentry.ISentryLifecycleToken; import io.sentry.ITransactionProfiler; +import io.sentry.NoOpCompositePerformanceCollector; import io.sentry.NoOpConnectionStatusProvider; import io.sentry.NoOpContinuousProfiler; import io.sentry.NoOpTransactionProfiler; @@ -35,12 +36,16 @@ import io.sentry.cache.PersistingScopeObserver; import io.sentry.compose.gestures.ComposeGestureTargetLocator; import io.sentry.compose.viewhierarchy.ComposeViewHierarchyExporter; +import io.sentry.internal.debugmeta.NoOpDebugMetaLoader; import io.sentry.internal.gestures.GestureTargetLocator; +import io.sentry.internal.modules.NoOpModulesLoader; import io.sentry.internal.viewhierarchy.ViewHierarchyExporter; import io.sentry.transport.CurrentDateProvider; import io.sentry.transport.NoOpEnvelopeCache; +import io.sentry.transport.NoOpTransportGate; import io.sentry.util.LazyEvaluator; import io.sentry.util.Objects; +import io.sentry.util.thread.NoOpThreadChecker; import java.io.File; import java.util.ArrayList; import java.util.List; @@ -163,7 +168,9 @@ static void initializeIntegrationsAndProcessors( options.addEventProcessor(new ScreenshotEventProcessor(options, buildInfoProvider)); options.addEventProcessor(new ViewHierarchyEventProcessor(options)); options.addEventProcessor(new AnrV2EventProcessor(context, options, buildInfoProvider)); - options.setTransportGate(new AndroidTransportGate(options)); + if (options.getTransportGate() instanceof NoOpTransportGate) { + options.setTransportGate(new AndroidTransportGate(options)); + } // Check if the profiler was already instantiated in the app start. // We use the Android profiler, that uses a global start/stop api, so we need to preserve the @@ -185,8 +192,12 @@ static void initializeIntegrationsAndProcessors( appStartTransactionProfiler, appStartContinuousProfiler); - options.setModulesLoader(new AssetsModulesLoader(context, options.getLogger())); - options.setDebugMetaLoader(new AssetsDebugMetaLoader(context, options.getLogger())); + if (options.getModulesLoader() instanceof NoOpModulesLoader) { + options.setModulesLoader(new AssetsModulesLoader(context, options.getLogger())); + } + if (options.getDebugMetaLoader() instanceof NoOpDebugMetaLoader) { + options.setDebugMetaLoader(new AssetsDebugMetaLoader(context, options.getLogger())); + } final boolean isAndroidXScrollViewAvailable = loadClass.isClassAvailable("androidx.core.view.ScrollingView", options); @@ -218,7 +229,9 @@ static void initializeIntegrationsAndProcessors( options.setViewHierarchyExporters(viewHierarchyExporters); } - options.setThreadChecker(AndroidThreadChecker.getInstance()); + if (options.getThreadChecker() instanceof NoOpThreadChecker) { + options.setThreadChecker(AndroidThreadChecker.getInstance()); + } if (options.getPerformanceCollectors().isEmpty()) { options.addPerformanceCollector(new AndroidMemoryCollector()); options.addPerformanceCollector(new AndroidCpuCollector(options.getLogger())); @@ -232,7 +245,9 @@ static void initializeIntegrationsAndProcessors( "options.getFrameMetricsCollector is required"))); } } - options.setCompositePerformanceCollector(new DefaultCompositePerformanceCollector(options)); + if (options.getCompositePerformanceCollector() instanceof NoOpCompositePerformanceCollector) { + options.setCompositePerformanceCollector(new DefaultCompositePerformanceCollector(options)); + } } /** Setup the correct profiler (transaction or continuous) based on the options. */ diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt index 769510479f8..dfc88fa0e78 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt @@ -6,7 +6,9 @@ import android.os.Build import android.os.Bundle import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.sentry.CompositePerformanceCollector import io.sentry.DefaultCompositePerformanceCollector +import io.sentry.IConnectionStatusProvider import io.sentry.IContinuousProfiler import io.sentry.ILogger import io.sentry.ITransactionProfiler @@ -15,17 +17,24 @@ import io.sentry.NoOpContinuousProfiler import io.sentry.NoOpTransactionProfiler import io.sentry.SentryOptions import io.sentry.android.core.cache.AndroidEnvelopeCache +import io.sentry.android.core.internal.debugmeta.AssetsDebugMetaLoader import io.sentry.android.core.internal.gestures.AndroidViewGestureTargetLocator import io.sentry.android.core.internal.modules.AssetsModulesLoader +import io.sentry.android.core.internal.util.AndroidConnectionStatusProvider import io.sentry.android.core.internal.util.AndroidThreadChecker import io.sentry.android.core.performance.AppStartMetrics import io.sentry.android.fragment.FragmentLifecycleIntegration import io.sentry.android.replay.ReplayIntegration import io.sentry.android.timber.SentryTimberIntegration +import io.sentry.cache.IEnvelopeCache import io.sentry.cache.PersistingOptionsObserver import io.sentry.cache.PersistingScopeObserver import io.sentry.compose.gestures.ComposeGestureTargetLocator +import io.sentry.internal.debugmeta.IDebugMetaLoader +import io.sentry.internal.modules.IModulesLoader import io.sentry.test.ImmediateExecutorService +import io.sentry.transport.ITransportGate +import io.sentry.util.thread.IThreadChecker import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.eq @@ -840,4 +849,25 @@ class AndroidOptionsInitializerTest { fixture.sentryOptions.findPersistingScopeObserver()?.setTags(mapOf("key" to "value")) assertFalse(File(AndroidOptionsInitializer.getCacheDir(fixture.context), PersistingScopeObserver.SCOPE_CACHE).exists()) } + + @Test + fun `user options have precedence over defaults`() { + fixture.initSut(configureOptions = { + setTransportGate(mock()) + setEnvelopeDiskCache(mock()) + connectionStatusProvider = mock() + setModulesLoader(mock()) + setDebugMetaLoader(mock()) + threadChecker = mock() + compositePerformanceCollector = mock() + }) + + assertFalse { fixture.sentryOptions.transportGate is AndroidTransportGate } + assertFalse { fixture.sentryOptions.envelopeDiskCache is AndroidEnvelopeCache } + assertFalse { fixture.sentryOptions.connectionStatusProvider is AndroidConnectionStatusProvider } + assertFalse { fixture.sentryOptions.modulesLoader is AssetsModulesLoader } + assertFalse { fixture.sentryOptions.debugMetaLoader is AssetsDebugMetaLoader } + assertFalse { fixture.sentryOptions.threadChecker is AndroidThreadChecker } + assertFalse { fixture.sentryOptions.compositePerformanceCollector is DefaultCompositePerformanceCollector } + } }