From 57c1b9702e9d50aebd6a279a7e03a953ed91b951 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Tue, 2 Jul 2024 11:45:57 +0200 Subject: [PATCH 01/10] Support spans across batches --- .../main/java/io/sentry/opentelemetry/SentrySpanExporter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanExporter.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanExporter.java index 5e7c610cc0f..0e86f281bcc 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanExporter.java +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanExporter.java @@ -105,7 +105,8 @@ public CompletableResultCode export(Collection spans) { final @NotNull SentryInstantDate now = new SentryInstantDate(); final @NotNull List nonExpired = - remaining.stream().filter((span) -> isSpanTooOld(span, now)).collect(Collectors.toList()); + remaining.stream().filter((span) -> !isSpanTooOld(span, now)).collect(Collectors.toList()); + this.finishedSpans.addAll(nonExpired); // TODO From 2a3d0eb7df609b3c9b385387cb5dd9dde9099a08 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Tue, 2 Jul 2024 11:49:39 +0200 Subject: [PATCH 02/10] changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a179e82555a..ac39c1c7a85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ - `sentry-android-okhttp` has been removed in favor of `sentry-okhttp`, removing android dependency from the module ([#3510](https://github.com/getsentry/sentry-java/pull/3510)) +### Fixes + +- Support spans that are split into multiple batches ([#3539](https://github.com/getsentry/sentry-java/pull/3539)) + - When spans belonging to a single transaction were split into multiple batches for SpanExporter, we did not add all spans because the isSpanTooOld check wasn't inverted. + ## 8.0.0-alpha.2 ### Behavioural Changes From 0f180c4320f7db186fef3b4a7a3cadd81da7a1cf Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Tue, 2 Jul 2024 14:04:56 +0200 Subject: [PATCH 03/10] POC use correct options for multi init --- sentry/api/sentry.api | 8 +-- .../java/io/sentry/CombinedScopeView.java | 4 +- sentry/src/main/java/io/sentry/IScope.java | 2 +- sentry/src/main/java/io/sentry/NoOpScope.java | 4 +- sentry/src/main/java/io/sentry/Scope.java | 5 +- sentry/src/main/java/io/sentry/Sentry.java | 60 +++++++++++-------- 6 files changed, 49 insertions(+), 34 deletions(-) diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 68ad64144fa..4d4e5448897 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -278,7 +278,7 @@ public final class io/sentry/CombinedScopeView : io/sentry/IScope { public fun removeContexts (Ljava/lang/String;)V public fun removeExtra (Ljava/lang/String;)V public fun removeTag (Ljava/lang/String;)V - public fun replaceOptions (Lio/sentry/SentryOptions;)V + public fun replaceOptions (Lio/sentry/SentryOptions;)Z public fun setContexts (Ljava/lang/String;Ljava/lang/Boolean;)V public fun setContexts (Ljava/lang/String;Ljava/lang/Character;)V public fun setContexts (Ljava/lang/String;Ljava/lang/Number;)V @@ -767,7 +767,7 @@ public abstract interface class io/sentry/IScope { public abstract fun removeContexts (Ljava/lang/String;)V public abstract fun removeExtra (Ljava/lang/String;)V public abstract fun removeTag (Ljava/lang/String;)V - public abstract fun replaceOptions (Lio/sentry/SentryOptions;)V + public abstract fun replaceOptions (Lio/sentry/SentryOptions;)Z public abstract fun setContexts (Ljava/lang/String;Ljava/lang/Boolean;)V public abstract fun setContexts (Ljava/lang/String;Ljava/lang/Character;)V public abstract fun setContexts (Ljava/lang/String;Ljava/lang/Number;)V @@ -1444,7 +1444,7 @@ public final class io/sentry/NoOpScope : io/sentry/IScope { public fun removeContexts (Ljava/lang/String;)V public fun removeExtra (Ljava/lang/String;)V public fun removeTag (Ljava/lang/String;)V - public fun replaceOptions (Lio/sentry/SentryOptions;)V + public fun replaceOptions (Lio/sentry/SentryOptions;)Z public fun setContexts (Ljava/lang/String;Ljava/lang/Boolean;)V public fun setContexts (Ljava/lang/String;Ljava/lang/Character;)V public fun setContexts (Ljava/lang/String;Ljava/lang/Number;)V @@ -1916,7 +1916,7 @@ public final class io/sentry/Scope : io/sentry/IScope { public fun removeContexts (Ljava/lang/String;)V public fun removeExtra (Ljava/lang/String;)V public fun removeTag (Ljava/lang/String;)V - public fun replaceOptions (Lio/sentry/SentryOptions;)V + public fun replaceOptions (Lio/sentry/SentryOptions;)Z public fun setContexts (Ljava/lang/String;Ljava/lang/Boolean;)V public fun setContexts (Ljava/lang/String;Ljava/lang/Character;)V public fun setContexts (Ljava/lang/String;Ljava/lang/Number;)V diff --git a/sentry/src/main/java/io/sentry/CombinedScopeView.java b/sentry/src/main/java/io/sentry/CombinedScopeView.java index c22fd060bb3..b097685219a 100644 --- a/sentry/src/main/java/io/sentry/CombinedScopeView.java +++ b/sentry/src/main/java/io/sentry/CombinedScopeView.java @@ -481,7 +481,7 @@ public void setSpanContext( @ApiStatus.Internal @Override - public void replaceOptions(@NotNull SentryOptions options) { - globalScope.replaceOptions(options); + public boolean replaceOptions(@NotNull SentryOptions options) { + return globalScope.replaceOptions(options); } } diff --git a/sentry/src/main/java/io/sentry/IScope.java b/sentry/src/main/java/io/sentry/IScope.java index 6d6ddfb4ce2..e8c1369b2d2 100644 --- a/sentry/src/main/java/io/sentry/IScope.java +++ b/sentry/src/main/java/io/sentry/IScope.java @@ -401,5 +401,5 @@ void setSpanContext( final @NotNull String transactionName); @ApiStatus.Internal - void replaceOptions(final @NotNull SentryOptions options); + boolean replaceOptions(final @NotNull SentryOptions options); } diff --git a/sentry/src/main/java/io/sentry/NoOpScope.java b/sentry/src/main/java/io/sentry/NoOpScope.java index fd258fd7c67..5e2489c853b 100644 --- a/sentry/src/main/java/io/sentry/NoOpScope.java +++ b/sentry/src/main/java/io/sentry/NoOpScope.java @@ -282,5 +282,7 @@ public void setSpanContext( @NotNull Throwable throwable, @NotNull ISpan span, @NotNull String transactionName) {} @Override - public void replaceOptions(@NotNull SentryOptions options) {} + public boolean replaceOptions(@NotNull SentryOptions options) { + return false; + } } diff --git a/sentry/src/main/java/io/sentry/Scope.java b/sentry/src/main/java/io/sentry/Scope.java index 8b47bddf38d..47ea6b7bec7 100644 --- a/sentry/src/main/java/io/sentry/Scope.java +++ b/sentry/src/main/java/io/sentry/Scope.java @@ -1042,7 +1042,8 @@ public void setSpanContext( @ApiStatus.Internal @Override - public void replaceOptions(final @NotNull SentryOptions options) { + public boolean replaceOptions(final @NotNull SentryOptions options) { + // TODO [POTEL] implement some override mechanism if (!getClient().isEnabled()) { this.options = options; final Queue oldBreadcrumbs = breadcrumbs; @@ -1054,7 +1055,9 @@ public void replaceOptions(final @NotNull SentryOptions options) { */ addBreadcrumb(breadcrumb); } + return true; } + return false; } /** The IWithTransaction callback */ diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index 7206df9b376..852a0276e9f 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -272,43 +272,51 @@ private static synchronized void init( "Sentry has been already initialized. Previous configuration will be overwritten."); } - if (!initConfigurations(options)) { + if (!preInitConfigurations(options)) { return; } options.getLogger().log(SentryLevel.INFO, "GlobalHubMode: '%s'", String.valueOf(globalHubMode)); Sentry.globalHubMode = globalHubMode; - globalScope.replaceOptions(options); + final boolean didReplaceOptions = globalScope.replaceOptions(options); + + // since replaceOptions can noop, we retrieve the options to use from global scope + final @NotNull SentryOptions optionsToUse = globalScope.getOptions(); final IScopes scopes = getCurrentScopes(); - final IScope rootScope = new Scope(options); - final IScope rootIsolationScope = new Scope(options); + final IScope rootScope = new Scope(optionsToUse); + final IScope rootIsolationScope = new Scope(optionsToUse); rootScopes = new Scopes(rootScope, rootIsolationScope, globalScope, "Sentry.init"); getScopesStorage().set(rootScopes); - scopes.close(true); - globalScope.bindClient(new SentryClient(rootScopes.getOptions())); + if (didReplaceOptions) { + scopes.close(true); - // If the executorService passed in the init is the same that was previously closed, we have to - // set a new one - if (options.getExecutorService().isClosed()) { - options.setExecutorService(new SentryExecutorService()); - } + initConfigurations(optionsToUse); - // when integrations are registered on Scopes ctor and async integrations are fired, - // it might and actually happened that integrations called captureSomething - // and Scopes was still NoOp. - // Registering integrations here make sure that Scopes is already created. - for (final Integration integration : options.getIntegrations()) { - integration.register(ScopesAdapter.getInstance(), options); - } + globalScope.bindClient(new SentryClient(optionsToUse)); - notifyOptionsObservers(options); + // If the executorService passed in the init is the same that was previously closed, we have + // to + // set a new one + if (options.getExecutorService().isClosed()) { + options.setExecutorService(new SentryExecutorService()); + } + // when integrations are registered on Scopes ctor and async integrations are fired, + // it might and actually happened that integrations called captureSomething + // and Scopes was still NoOp. + // Registering integrations here make sure that Scopes is already created. + for (final Integration integration : options.getIntegrations()) { + integration.register(ScopesAdapter.getInstance(), options); + } + + notifyOptionsObservers(options); - finalizePreviousSession(options, ScopesAdapter.getInstance()); + finalizePreviousSession(options, ScopesAdapter.getInstance()); - handleAppStartProfilingConfig(options, options.getExecutorService()); + handleAppStartProfilingConfig(options, options.getExecutorService()); + } } @SuppressWarnings("FutureReturnValueIgnored") @@ -412,8 +420,7 @@ private static void notifyOptionsObservers(final @NotNull SentryOptions options) } } - @SuppressWarnings("FutureReturnValueIgnored") - private static boolean initConfigurations(final @NotNull SentryOptions options) { + private static boolean preInitConfigurations(final @NotNull SentryOptions options) { if (options.isEnableExternalConfiguration()) { options.merge(ExternalOptions.from(PropertiesProviderFactory.create(), options.getLogger())); } @@ -431,6 +438,11 @@ private static boolean initConfigurations(final @NotNull SentryOptions options) @SuppressWarnings("unused") final Dsn parsedDsn = new Dsn(dsn); + return true; + } + + @SuppressWarnings("FutureReturnValueIgnored") + private static void initConfigurations(final @NotNull SentryOptions options) { ILogger logger = options.getLogger(); if (options.isDebug() && logger instanceof NoOpLogger) { @@ -527,8 +539,6 @@ private static boolean initConfigurations(final @NotNull SentryOptions options) options.setBackpressureMonitor(new BackpressureMonitor(options, ScopesAdapter.getInstance())); options.getBackpressureMonitor().start(); } - - return true; } /** Close the SDK */ From 1169294ca13c304b89542bb9b4747c93ebbff4c8 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 2 Sep 2024 10:42:56 +0200 Subject: [PATCH 04/10] Add settings for controlling init priority --- .../jakarta/SentryAutoConfigurationTest.kt | 2 + .../boot/SentryAutoConfigurationTest.kt | 2 + sentry/api/sentry.api | 29 +++++- .../java/io/sentry/CombinedScopeView.java | 4 +- .../main/java/io/sentry/ExternalOptions.java | 10 ++ sentry/src/main/java/io/sentry/IScope.java | 2 +- .../src/main/java/io/sentry/InitPriority.java | 12 +++ sentry/src/main/java/io/sentry/NoOpScope.java | 4 +- sentry/src/main/java/io/sentry/Scope.java | 25 ++--- sentry/src/main/java/io/sentry/Sentry.java | 29 +++--- .../main/java/io/sentry/SentryOptions.java | 34 +++++++ .../main/java/io/sentry/util/InitUtil.java | 28 ++++++ .../java/io/sentry/ExternalOptionsTest.kt | 7 ++ .../test/java/io/sentry/SentryOptionsTest.kt | 2 + .../test/java/io/sentry/util/InitUtilTest.kt | 99 +++++++++++++++++++ 15 files changed, 252 insertions(+), 37 deletions(-) create mode 100644 sentry/src/main/java/io/sentry/InitPriority.java create mode 100644 sentry/src/main/java/io/sentry/util/InitUtil.java create mode 100644 sentry/src/test/java/io/sentry/util/InitUtilTest.kt diff --git a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt index 9805de6e216..d5331c8c520 100644 --- a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt +++ b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt @@ -172,6 +172,7 @@ class SentryAutoConfigurationTest { "sentry.send-modules=false", "sentry.ignored-checkins=slug1,slugB", "sentry.enable-backpressure-handling=false", + "sentry.force-init=true", "sentry.cron.default-checkin-margin=10", "sentry.cron.default-max-runtime=30", "sentry.cron.default-timezone=America/New_York", @@ -209,6 +210,7 @@ class SentryAutoConfigurationTest { assertThat(options.isSendModules).isEqualTo(false) assertThat(options.ignoredCheckIns).containsOnly("slug1", "slugB") assertThat(options.isEnableBackpressureHandling).isEqualTo(false) + assertThat(options.isForceInit).isEqualTo(true) assertThat(options.cron).isNotNull assertThat(options.cron!!.defaultCheckinMargin).isEqualTo(10L) assertThat(options.cron!!.defaultMaxRuntime).isEqualTo(30L) diff --git a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt index a65926c9342..6a44d074ce8 100644 --- a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt +++ b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt @@ -171,6 +171,7 @@ class SentryAutoConfigurationTest { "sentry.send-modules=false", "sentry.ignored-checkins=slug1,slugB", "sentry.enable-backpressure-handling=false", + "sentry.force-init=true", "sentry.cron.default-checkin-margin=10", "sentry.cron.default-max-runtime=30", "sentry.cron.default-timezone=America/New_York", @@ -208,6 +209,7 @@ class SentryAutoConfigurationTest { assertThat(options.isSendModules).isEqualTo(false) assertThat(options.ignoredCheckIns).containsOnly("slug1", "slugB") assertThat(options.isEnableBackpressureHandling).isEqualTo(false) + assertThat(options.isForceInit).isEqualTo(true) assertThat(options.cron).isNotNull assertThat(options.cron!!.defaultCheckinMargin).isEqualTo(10L) assertThat(options.cron!!.defaultMaxRuntime).isEqualTo(30L) diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 0f74a1bcbcf..f742eb4dbc2 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -275,7 +275,7 @@ public final class io/sentry/CombinedScopeView : io/sentry/IScope { public fun removeContexts (Ljava/lang/String;)V public fun removeExtra (Ljava/lang/String;)V public fun removeTag (Ljava/lang/String;)V - public fun replaceOptions (Lio/sentry/SentryOptions;)Z + public fun replaceOptions (Lio/sentry/SentryOptions;)V public fun setActiveSpan (Lio/sentry/ISpan;)V public fun setContexts (Ljava/lang/String;Ljava/lang/Boolean;)V public fun setContexts (Ljava/lang/String;Ljava/lang/Character;)V @@ -459,6 +459,7 @@ public final class io/sentry/ExternalOptions { public fun isEnableBackpressureHandling ()Ljava/lang/Boolean; public fun isEnablePrettySerializationOutput ()Ljava/lang/Boolean; public fun isEnabled ()Ljava/lang/Boolean; + public fun isForceInit ()Ljava/lang/Boolean; public fun isSendDefaultPii ()Ljava/lang/Boolean; public fun isSendModules ()Ljava/lang/Boolean; public fun setCron (Lio/sentry/SentryOptions$Cron;)V @@ -472,6 +473,7 @@ public final class io/sentry/ExternalOptions { public fun setEnableUncaughtExceptionHandler (Ljava/lang/Boolean;)V public fun setEnabled (Ljava/lang/Boolean;)V public fun setEnvironment (Ljava/lang/String;)V + public fun setForceInit (Ljava/lang/Boolean;)V public fun setIdleTimeout (Ljava/lang/Long;)V public fun setIgnoredCheckIns (Ljava/util/List;)V public fun setMaxRequestBodySize (Lio/sentry/SentryOptions$RequestSize;)V @@ -769,7 +771,7 @@ public abstract interface class io/sentry/IScope { public abstract fun removeContexts (Ljava/lang/String;)V public abstract fun removeExtra (Ljava/lang/String;)V public abstract fun removeTag (Ljava/lang/String;)V - public abstract fun replaceOptions (Lio/sentry/SentryOptions;)Z + public abstract fun replaceOptions (Lio/sentry/SentryOptions;)V public abstract fun setActiveSpan (Lio/sentry/ISpan;)V public abstract fun setContexts (Ljava/lang/String;Ljava/lang/Boolean;)V public abstract fun setContexts (Ljava/lang/String;Ljava/lang/Character;)V @@ -1028,6 +1030,16 @@ public abstract interface class io/sentry/ITransportFactory { public abstract fun create (Lio/sentry/SentryOptions;Lio/sentry/RequestDetails;)Lio/sentry/transport/ITransport; } +public final class io/sentry/InitPriority : java/lang/Enum { + public static final field HIGH Lio/sentry/InitPriority; + public static final field HIGHEST Lio/sentry/InitPriority; + public static final field LOW Lio/sentry/InitPriority; + public static final field LOWEST Lio/sentry/InitPriority; + public static final field MEDIUM Lio/sentry/InitPriority; + public static fun valueOf (Ljava/lang/String;)Lio/sentry/InitPriority; + public static fun values ()[Lio/sentry/InitPriority; +} + public final class io/sentry/Instrumenter : java/lang/Enum { public static final field OTEL Lio/sentry/Instrumenter; public static final field SENTRY Lio/sentry/Instrumenter; @@ -1449,7 +1461,7 @@ public final class io/sentry/NoOpScope : io/sentry/IScope { public fun removeContexts (Ljava/lang/String;)V public fun removeExtra (Ljava/lang/String;)V public fun removeTag (Ljava/lang/String;)V - public fun replaceOptions (Lio/sentry/SentryOptions;)Z + public fun replaceOptions (Lio/sentry/SentryOptions;)V public fun setActiveSpan (Lio/sentry/ISpan;)V public fun setContexts (Ljava/lang/String;Ljava/lang/Boolean;)V public fun setContexts (Ljava/lang/String;Ljava/lang/Character;)V @@ -1923,7 +1935,7 @@ public final class io/sentry/Scope : io/sentry/IScope { public fun removeContexts (Ljava/lang/String;)V public fun removeExtra (Ljava/lang/String;)V public fun removeTag (Ljava/lang/String;)V - public fun replaceOptions (Lio/sentry/SentryOptions;)Z + public fun replaceOptions (Lio/sentry/SentryOptions;)V public fun setActiveSpan (Lio/sentry/ISpan;)V public fun setContexts (Ljava/lang/String;Ljava/lang/Boolean;)V public fun setContexts (Ljava/lang/String;Ljava/lang/Character;)V @@ -2706,6 +2718,7 @@ public class io/sentry/SentryOptions { public fun getIgnoredSpanOrigins ()Ljava/util/List; public fun getInAppExcludes ()Ljava/util/List; public fun getInAppIncludes ()Ljava/util/List; + public fun getInitPriority ()Lio/sentry/InitPriority; public fun getInstrumenter ()Lio/sentry/Instrumenter; public fun getIntegrations ()Ljava/util/List; public fun getInternalTracesSampler ()Lio/sentry/TracesSampler; @@ -2775,6 +2788,7 @@ public class io/sentry/SentryOptions { public fun isEnableUserInteractionBreadcrumbs ()Z public fun isEnableUserInteractionTracing ()Z public fun isEnabled ()Z + public fun isForceInit ()Z public fun isPrintUncaughtStackTrace ()Z public fun isProfilingEnabled ()Z public fun isSendClientReports ()Z @@ -2828,10 +2842,12 @@ public class io/sentry/SentryOptions { public fun setEnvironment (Ljava/lang/String;)V public fun setExecutorService (Lio/sentry/ISentryExecutorService;)V public fun setFlushTimeoutMillis (J)V + public fun setForceInit (Z)V public fun setGestureTargetLocators (Ljava/util/List;)V public fun setIdleTimeout (Ljava/lang/Long;)V public fun setIgnoredCheckIns (Ljava/util/List;)V public fun setIgnoredSpanOrigins (Ljava/util/List;)V + public fun setInitPriority (Lio/sentry/InitPriority;)V public fun setInstrumenter (Lio/sentry/Instrumenter;)V public fun setLogger (Lio/sentry/ILogger;)V public fun setMainThreadChecker (Lio/sentry/util/thread/IMainThreadChecker;)V @@ -5548,6 +5564,11 @@ public final class io/sentry/util/HttpUtils { public static fun isSecurityCookie (Ljava/lang/String;Ljava/util/List;)Z } +public final class io/sentry/util/InitUtil { + public fun ()V + public static fun shouldInit (Lio/sentry/SentryOptions;Lio/sentry/SentryOptions;Z)Z +} + public final class io/sentry/util/IntegrationUtils { public fun ()V public static fun addIntegrationToSdkVersion (Ljava/lang/Class;)V diff --git a/sentry/src/main/java/io/sentry/CombinedScopeView.java b/sentry/src/main/java/io/sentry/CombinedScopeView.java index c6af43fd095..a4143fe2e62 100644 --- a/sentry/src/main/java/io/sentry/CombinedScopeView.java +++ b/sentry/src/main/java/io/sentry/CombinedScopeView.java @@ -486,7 +486,7 @@ public void setSpanContext( @ApiStatus.Internal @Override - public boolean replaceOptions(@NotNull SentryOptions options) { - return globalScope.replaceOptions(options); + public void replaceOptions(@NotNull SentryOptions options) { + globalScope.replaceOptions(options); } } diff --git a/sentry/src/main/java/io/sentry/ExternalOptions.java b/sentry/src/main/java/io/sentry/ExternalOptions.java index aa5aa439375..515ea6c08c1 100644 --- a/sentry/src/main/java/io/sentry/ExternalOptions.java +++ b/sentry/src/main/java/io/sentry/ExternalOptions.java @@ -51,6 +51,7 @@ public final class ExternalOptions { private @Nullable Boolean sendModules; private @Nullable Boolean sendDefaultPii; private @Nullable Boolean enableBackpressureHandling; + private @Nullable Boolean forceInit; private @Nullable SentryOptions.Cron cron; @@ -73,6 +74,7 @@ public final class ExternalOptions { options.setDebug(propertiesProvider.getBooleanProperty("debug")); options.setEnableDeduplication(propertiesProvider.getBooleanProperty("enable-deduplication")); options.setSendClientReports(propertiesProvider.getBooleanProperty("send-client-reports")); + options.setForceInit(propertiesProvider.getBooleanProperty("force-init")); final String maxRequestBodySize = propertiesProvider.getProperty("max-request-body-size"); if (maxRequestBodySize != null) { options.setMaxRequestBodySize( @@ -451,6 +453,14 @@ public void setEnableBackpressureHandling(final @Nullable Boolean enableBackpres return enableBackpressureHandling; } + public void setForceInit(final @Nullable Boolean forceInit) { + this.forceInit = forceInit; + } + + public @Nullable Boolean isForceInit() { + return forceInit; + } + @ApiStatus.Experimental public @Nullable SentryOptions.Cron getCron() { return cron; diff --git a/sentry/src/main/java/io/sentry/IScope.java b/sentry/src/main/java/io/sentry/IScope.java index d5b91adc0ea..4bafec185e0 100644 --- a/sentry/src/main/java/io/sentry/IScope.java +++ b/sentry/src/main/java/io/sentry/IScope.java @@ -404,5 +404,5 @@ void setSpanContext( final @NotNull String transactionName); @ApiStatus.Internal - boolean replaceOptions(final @NotNull SentryOptions options); + void replaceOptions(final @NotNull SentryOptions options); } diff --git a/sentry/src/main/java/io/sentry/InitPriority.java b/sentry/src/main/java/io/sentry/InitPriority.java new file mode 100644 index 00000000000..7548851c161 --- /dev/null +++ b/sentry/src/main/java/io/sentry/InitPriority.java @@ -0,0 +1,12 @@ +package io.sentry; + +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public enum InitPriority { + LOWEST, + LOW, + MEDIUM, + HIGH, + HIGHEST; +} diff --git a/sentry/src/main/java/io/sentry/NoOpScope.java b/sentry/src/main/java/io/sentry/NoOpScope.java index 005572fb0ec..af94bd6a8c7 100644 --- a/sentry/src/main/java/io/sentry/NoOpScope.java +++ b/sentry/src/main/java/io/sentry/NoOpScope.java @@ -285,7 +285,5 @@ public void setSpanContext( @NotNull Throwable throwable, @NotNull ISpan span, @NotNull String transactionName) {} @Override - public boolean replaceOptions(@NotNull SentryOptions options) { - return false; - } + public void replaceOptions(@NotNull SentryOptions options) {} } diff --git a/sentry/src/main/java/io/sentry/Scope.java b/sentry/src/main/java/io/sentry/Scope.java index 307ee3baa23..a213e6ae3c3 100644 --- a/sentry/src/main/java/io/sentry/Scope.java +++ b/sentry/src/main/java/io/sentry/Scope.java @@ -1054,22 +1054,17 @@ public void setSpanContext( @ApiStatus.Internal @Override - public boolean replaceOptions(final @NotNull SentryOptions options) { - // TODO [POTEL] implement some override mechanism - if (!getClient().isEnabled()) { - this.options = options; - final Queue oldBreadcrumbs = breadcrumbs; - breadcrumbs = createBreadcrumbsList(options.getMaxBreadcrumbs()); - for (Breadcrumb breadcrumb : oldBreadcrumbs) { - /* - this should trigger beforeBreadcrumb - and notify observers for breadcrumbs added before options where customized in Sentry.init - */ - addBreadcrumb(breadcrumb); - } - return true; + public void replaceOptions(final @NotNull SentryOptions options) { + this.options = options; + final Queue oldBreadcrumbs = breadcrumbs; + breadcrumbs = createBreadcrumbsList(options.getMaxBreadcrumbs()); + for (Breadcrumb breadcrumb : oldBreadcrumbs) { + /* + this should trigger beforeBreadcrumb + and notify observers for breadcrumbs added before options where customized in Sentry.init + */ + addBreadcrumb(breadcrumb); } - return false; } /** The IWithTransaction callback */ diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index 852a0276e9f..ea41ce9e147 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -17,6 +17,7 @@ import io.sentry.transport.NoOpEnvelopeCache; import io.sentry.util.DebugMetaPropertiesApplier; import io.sentry.util.FileUtils; +import io.sentry.util.InitUtil; import io.sentry.util.LoadClass; import io.sentry.util.Platform; import io.sentry.util.thread.IMainThreadChecker; @@ -278,24 +279,22 @@ private static synchronized void init( options.getLogger().log(SentryLevel.INFO, "GlobalHubMode: '%s'", String.valueOf(globalHubMode)); Sentry.globalHubMode = globalHubMode; - final boolean didReplaceOptions = globalScope.replaceOptions(options); + final boolean shouldInit = InitUtil.shouldInit(globalScope.getOptions(), options, isEnabled()); + if (shouldInit) { + globalScope.replaceOptions(options); - // since replaceOptions can noop, we retrieve the options to use from global scope - final @NotNull SentryOptions optionsToUse = globalScope.getOptions(); + final IScopes scopes = getCurrentScopes(); + final IScope rootScope = new Scope(options); + final IScope rootIsolationScope = new Scope(options); + rootScopes = new Scopes(rootScope, rootIsolationScope, globalScope, "Sentry.init"); - final IScopes scopes = getCurrentScopes(); - final IScope rootScope = new Scope(optionsToUse); - final IScope rootIsolationScope = new Scope(optionsToUse); - rootScopes = new Scopes(rootScope, rootIsolationScope, globalScope, "Sentry.init"); - - getScopesStorage().set(rootScopes); + getScopesStorage().set(rootScopes); - if (didReplaceOptions) { scopes.close(true); - initConfigurations(optionsToUse); + initConfigurations(options); - globalScope.bindClient(new SentryClient(optionsToUse)); + globalScope.bindClient(new SentryClient(options)); // If the executorService passed in the init is the same that was previously closed, we have // to @@ -316,6 +315,12 @@ private static synchronized void init( finalizePreviousSession(options, ScopesAdapter.getInstance()); handleAppStartProfilingConfig(options, options.getExecutorService()); + } else { + options + .getLogger() + .log( + SentryLevel.WARNING, + "This init call has been ignored due to priority being too low."); } } diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index 7e24e81dcec..fb82e49d074 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -489,6 +489,9 @@ public class SentryOptions { private @NotNull ScopeType defaultScopeType = ScopeType.ISOLATION; + private @NotNull InitPriority initPriority = InitPriority.MEDIUM; + private boolean forceInit = false; + /** * Adds an event processor * @@ -2440,6 +2443,33 @@ public void setDefaultScopeType(final @NotNull ScopeType scopeType) { return defaultScopeType; } + @ApiStatus.Internal + public void setInitPriority(final @NotNull InitPriority initPriority) { + this.initPriority = initPriority; + } + + @ApiStatus.Internal + public @NotNull InitPriority getInitPriority() { + return initPriority; + } + + /** + * If set to true a call to Sentry.init (or SentryAndroid.init) will go through and replace + * previous options if there are any. + * + *

By default the SDK will check whether a previous call to Sentry.init has higher priority + * than the current one and decide whether to actually perform the init and replace options. + * + * @param forceInit true = replace previous init and options + */ + public void setForceInit(final boolean forceInit) { + this.forceInit = forceInit; + } + + public boolean isForceInit() { + return forceInit; + } + /** The BeforeSend callback */ public interface BeforeSendCallback { @@ -2562,6 +2592,7 @@ public SentryOptions() { */ private SentryOptions(final boolean empty) { if (!empty) { + setInitPriority(InitPriority.LOWEST); setSpanFactory(new DefaultSpanFactory()); // SentryExecutorService should be initialized before any // SendCachedEventFireAndForgetIntegration @@ -2636,6 +2667,9 @@ public void merge(final @NotNull ExternalOptions options) { if (options.getSendClientReports() != null) { setSendClientReports(options.getSendClientReports()); } + if (options.isForceInit() != null) { + setForceInit(options.isForceInit()); + } final Map tags = new HashMap<>(options.getTags()); for (final Map.Entry tag : tags.entrySet()) { this.tags.put(tag.getKey(), tag.getValue()); diff --git a/sentry/src/main/java/io/sentry/util/InitUtil.java b/sentry/src/main/java/io/sentry/util/InitUtil.java new file mode 100644 index 00000000000..f651383a788 --- /dev/null +++ b/sentry/src/main/java/io/sentry/util/InitUtil.java @@ -0,0 +1,28 @@ +package io.sentry.util; + +import io.sentry.SentryOptions; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Internal +public final class InitUtil { + public static boolean shouldInit( + final @Nullable SentryOptions previousOptions, + final @NotNull SentryOptions newOptions, + final boolean isEnabled) { + if (!isEnabled) { + return true; + } + + if (previousOptions == null) { + return true; + } + + if (newOptions.isForceInit()) { + return true; + } + + return previousOptions.getInitPriority().ordinal() <= newOptions.getInitPriority().ordinal(); + } +} diff --git a/sentry/src/test/java/io/sentry/ExternalOptionsTest.kt b/sentry/src/test/java/io/sentry/ExternalOptionsTest.kt index fd5b363219d..8c525da45a6 100644 --- a/sentry/src/test/java/io/sentry/ExternalOptionsTest.kt +++ b/sentry/src/test/java/io/sentry/ExternalOptionsTest.kt @@ -293,6 +293,13 @@ class ExternalOptionsTest { } } + @Test + fun `creates options with forceInit set to true`() { + withPropertiesFile("force-init=true") { options -> + assertTrue(options.isForceInit == true) + } + } + private fun withPropertiesFile(textLines: List = emptyList(), logger: ILogger = mock(), fn: (ExternalOptions) -> Unit) { // create a sentry.properties file in temporary folder val temporaryFolder = TemporaryFolder() diff --git a/sentry/src/test/java/io/sentry/SentryOptionsTest.kt b/sentry/src/test/java/io/sentry/SentryOptionsTest.kt index c11eafdc5ae..a462279d46c 100644 --- a/sentry/src/test/java/io/sentry/SentryOptionsTest.kt +++ b/sentry/src/test/java/io/sentry/SentryOptionsTest.kt @@ -374,6 +374,7 @@ class SentryOptionsTest { externalOptions.isEnableBackpressureHandling = false externalOptions.maxRequestBodySize = SentryOptions.RequestSize.MEDIUM externalOptions.isSendDefaultPii = true + externalOptions.isForceInit = true externalOptions.cron = SentryOptions.Cron().apply { defaultCheckinMargin = 10L defaultMaxRuntime = 30L @@ -412,6 +413,7 @@ class SentryOptionsTest { assertFalse(options.isSendModules) assertEquals(listOf("slug1", "slug-B"), options.ignoredCheckIns) assertFalse(options.isEnableBackpressureHandling) + assertTrue(options.isForceInit) assertNotNull(options.cron) assertEquals(10L, options.cron?.defaultCheckinMargin) assertEquals(30L, options.cron?.defaultMaxRuntime) diff --git a/sentry/src/test/java/io/sentry/util/InitUtilTest.kt b/sentry/src/test/java/io/sentry/util/InitUtilTest.kt new file mode 100644 index 00000000000..12913bd2f75 --- /dev/null +++ b/sentry/src/test/java/io/sentry/util/InitUtilTest.kt @@ -0,0 +1,99 @@ +package io.sentry.util + +import io.sentry.InitPriority +import io.sentry.SentryOptions +import kotlin.test.Test +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class InitUtilTest { + + var previousOptions: SentryOptions? = null + var newOptions: SentryOptions? = null + var clientEnabled: Boolean = true + + @Test + fun `first init on empty options goes through`() { + givenPreviousOptions(SentryOptions.empty()) + givenNewOptions(SentryOptions().also { it.initPriority = InitPriority.LOWEST }) + givenClientDisabled() + + thenInitIsPerformed() + } + + @Test + fun `init with same priority goes through`() { + givenPreviousOptions(SentryOptions().also { it.initPriority = InitPriority.LOWEST }) + givenNewOptions(SentryOptions().also { it.initPriority = InitPriority.LOWEST }) + givenClientEnabled() + + thenInitIsPerformed() + } + + @Test + fun `init without previous options goes through`() { + givenPreviousOptions(null) + givenNewOptions(SentryOptions().also { it.initPriority = InitPriority.LOWEST }) + givenClientEnabled() + + thenInitIsPerformed() + } + + @Test + fun `init with lower priority is ignored if already initialized`() { + givenPreviousOptions(SentryOptions().also { it.initPriority = InitPriority.LOW }) + givenNewOptions(SentryOptions().also { it.initPriority = InitPriority.LOWEST }) + givenClientEnabled() + + thenInitIsIgnored() + } + + @Test + fun `init with lower priority goes through if not yet initialized`() { + givenPreviousOptions(SentryOptions().also { it.initPriority = InitPriority.LOW }) + givenNewOptions(SentryOptions().also { it.initPriority = InitPriority.LOWEST }) + givenClientDisabled() + + thenInitIsPerformed() + } + + @Test + fun `init with lower priority goes through with forceInit if already initialized`() { + givenPreviousOptions(SentryOptions().also { it.initPriority = InitPriority.LOW }) + givenNewOptions( + SentryOptions().also { + it.initPriority = InitPriority.LOWEST + it.isForceInit = true + } + ) + givenClientEnabled() + + thenInitIsPerformed() + } + + private fun givenPreviousOptions(options: SentryOptions?) { + previousOptions = options + } + + private fun givenNewOptions(options: SentryOptions?) { + newOptions = options + } + + private fun givenClientDisabled() { + clientEnabled = false + } + + private fun givenClientEnabled() { + clientEnabled = true + } + + private fun thenInitIsPerformed() { + val shouldInit = InitUtil.shouldInit(previousOptions, newOptions!!, clientEnabled) + assertTrue(shouldInit) + } + + private fun thenInitIsIgnored() { + val shouldInit = InitUtil.shouldInit(previousOptions, newOptions!!, clientEnabled) + assertFalse(shouldInit) + } +} From 32f4b13916d4e68bcfc734571a99eb1e69555ea2 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 2 Sep 2024 11:00:08 +0200 Subject: [PATCH 05/10] Set InitPriority for Android, Manifest option for forceInit --- .../core/AndroidOptionsInitializer.java | 5 ++++ .../android/core/ManifestMetadataReader.java | 4 +++ .../core/ManifestMetadataReaderTest.kt | 25 +++++++++++++++++++ 3 files changed, 34 insertions(+) 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 dd5c3c5254b..5f32db2ba26 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 @@ -9,6 +9,7 @@ import io.sentry.DefaultTransactionPerformanceCollector; import io.sentry.ILogger; import io.sentry.ITransactionProfiler; +import io.sentry.InitPriority; import io.sentry.NoOpConnectionStatusProvider; import io.sentry.ScopeType; import io.sentry.SendFireAndForgetEnvelopeSender; @@ -113,6 +114,10 @@ static void loadDefaultAndMetadataOptions( options.setCacheDirPath(getCacheDir(context).getAbsolutePath()); readDefaultOptionValues(options, context, buildInfoProvider); + + if (ManifestMetadataReader.isAutoInit(context, logger)) { + options.setInitPriority(InitPriority.LOW); + } } @TestOnly diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java b/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java index b51c4b22a85..2bf0f21ed77 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java @@ -104,6 +104,8 @@ final class ManifestMetadataReader { static final String ENABLE_METRICS = "io.sentry.enable-metrics"; + static final String FORCE_INIT = "io.sentry.force-init"; + /** ManifestMetadataReader ctor */ private ManifestMetadataReader() {} @@ -263,6 +265,8 @@ static void applyMetadata( options.setSendClientReports( readBool(metadata, logger, CLIENT_REPORTS_ENABLE, options.isSendClientReports())); + options.setForceInit(readBool(metadata, logger, FORCE_INIT, options.isForceInit())); + options.setCollectAdditionalContext( readBool( metadata, diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt index 4a8e57303e7..18853c4c4ed 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt @@ -1420,4 +1420,29 @@ class ManifestMetadataReaderTest { // Assert assertFalse(fixture.options.isEnableMetrics) } + + @Test + fun `applyMetadata reads forceInit flag to options`() { + // Arrange + val bundle = bundleOf(ManifestMetadataReader.FORCE_INIT to true) + val context = fixture.getContext(metaData = bundle) + + // Act + ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider) + + // Assert + assertTrue(fixture.options.isForceInit) + } + + @Test + fun `applyMetadata reads forceInit flag to options and keeps default if not found`() { + // Arrange + val context = fixture.getContext() + + // Act + ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider) + + // Assert + assertFalse(fixture.options.isForceInit) + } } From edd0f4f2d5c7c49937641ee4451aff728e18cba5 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 2 Sep 2024 11:13:42 +0200 Subject: [PATCH 06/10] Set init priority for backend integrations --- .../java/io/sentry/log4j2/SentryAppender.java | 42 +++++++++---------- .../io/sentry/logback/SentryAppender.java | 33 +++++++-------- ...ryAutoConfigurationCustomizerProvider.java | 2 + .../boot/jakarta/SentryAutoConfiguration.java | 2 + .../spring/boot/SentryAutoConfiguration.java | 2 + .../spring/jakarta/SentryHubRegistrar.java | 2 + .../io/sentry/spring/SentryHubRegistrar.java | 2 + 7 files changed, 47 insertions(+), 38 deletions(-) diff --git a/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java b/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java index 4ee07ab7b92..35b9d694192 100644 --- a/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java +++ b/sentry-log4j2/src/main/java/io/sentry/log4j2/SentryAppender.java @@ -9,6 +9,7 @@ import io.sentry.Hint; import io.sentry.IScopes; import io.sentry.ITransportFactory; +import io.sentry.InitPriority; import io.sentry.ScopesAdapter; import io.sentry.Sentry; import io.sentry.SentryEvent; @@ -116,28 +117,27 @@ public SentryAppender( @Override public void start() { - if (!Sentry.isEnabled()) { - try { - Sentry.init( - options -> { - options.setEnableExternalConfiguration(true); - options.setDsn(dsn); - if (debug != null) { - options.setDebug(debug); + try { + Sentry.init( + options -> { + options.setEnableExternalConfiguration(true); + options.setInitPriority(InitPriority.LOWEST); + options.setDsn(dsn); + if (debug != null) { + options.setDebug(debug); + } + options.setSentryClientName( + BuildConfig.SENTRY_LOG4J2_SDK_NAME + "/" + BuildConfig.VERSION_NAME); + options.setSdkVersion(createSdkVersion(options)); + if (contextTags != null) { + for (final String contextTag : contextTags) { + options.addContextTag(contextTag); } - options.setSentryClientName( - BuildConfig.SENTRY_LOG4J2_SDK_NAME + "/" + BuildConfig.VERSION_NAME); - options.setSdkVersion(createSdkVersion(options)); - if (contextTags != null) { - for (final String contextTag : contextTags) { - options.addContextTag(contextTag); - } - } - Optional.ofNullable(transportFactory).ifPresent(options::setTransportFactory); - }); - } catch (IllegalArgumentException e) { - LOGGER.warn("Failed to init Sentry during appender initialization: " + e.getMessage()); - } + } + Optional.ofNullable(transportFactory).ifPresent(options::setTransportFactory); + }); + } catch (IllegalArgumentException e) { + LOGGER.warn("Failed to init Sentry during appender initialization: " + e.getMessage()); } addPackageAndIntegrationInfo(); super.start(); diff --git a/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java b/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java index 56db0b4dbcc..77ce05f47f3 100644 --- a/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java +++ b/sentry-logback/src/main/java/io/sentry/logback/SentryAppender.java @@ -13,6 +13,7 @@ import io.sentry.DateUtils; import io.sentry.Hint; import io.sentry.ITransportFactory; +import io.sentry.InitPriority; import io.sentry.ScopesAdapter; import io.sentry.Sentry; import io.sentry.SentryEvent; @@ -49,24 +50,22 @@ public class SentryAppender extends UnsynchronizedAppenderBase { @Override public void start() { - // NOTE: logback.xml properties will only be applied if the SDK has not yet been initialized - if (!Sentry.isEnabled()) { - if (options.getDsn() == null || !options.getDsn().endsWith("_IS_UNDEFINED")) { - options.setEnableExternalConfiguration(true); - options.setSentryClientName( - BuildConfig.SENTRY_LOGBACK_SDK_NAME + "/" + BuildConfig.VERSION_NAME); - options.setSdkVersion(createSdkVersion(options)); - Optional.ofNullable(transportFactory).ifPresent(options::setTransportFactory); - try { - Sentry.init(options); - } catch (IllegalArgumentException e) { - addWarn("Failed to init Sentry during appender initialization: " + e.getMessage()); - } - } else { - options - .getLogger() - .log(SentryLevel.WARNING, "DSN is null. SentryAppender is not being initialized"); + if (options.getDsn() == null || !options.getDsn().endsWith("_IS_UNDEFINED")) { + options.setEnableExternalConfiguration(true); + options.setInitPriority(InitPriority.LOWEST); + options.setSentryClientName( + BuildConfig.SENTRY_LOGBACK_SDK_NAME + "/" + BuildConfig.VERSION_NAME); + options.setSdkVersion(createSdkVersion(options)); + Optional.ofNullable(transportFactory).ifPresent(options::setTransportFactory); + try { + Sentry.init(options); + } catch (IllegalArgumentException e) { + addWarn("Failed to init Sentry during appender initialization: " + e.getMessage()); } + } else if (!Sentry.isEnabled()) { + options + .getLogger() + .log(SentryLevel.WARNING, "DSN is null. SentryAppender is not being initialized"); } addPackageAndIntegrationInfo(); super.start(); diff --git a/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java index 019541e7e3a..581b0fd12ae 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java +++ b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java @@ -6,6 +6,7 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; +import io.sentry.InitPriority; import io.sentry.Sentry; import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryOptions; @@ -50,6 +51,7 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) { Sentry.init( options -> { options.setEnableExternalConfiguration(true); + options.setInitPriority(InitPriority.HIGH); options.setIgnoredSpanOrigins(SpanUtils.ignoredSpanOriginsForOpenTelemetry()); options.setSpanFactory(spanFactory); final @Nullable SdkVersion sdkVersion = createSdkVersion(options, versionInfoHolder); diff --git a/sentry-spring-boot-jakarta/src/main/java/io/sentry/spring/boot/jakarta/SentryAutoConfiguration.java b/sentry-spring-boot-jakarta/src/main/java/io/sentry/spring/boot/jakarta/SentryAutoConfiguration.java index f38682cf6dd..51ce2e4f785 100644 --- a/sentry-spring-boot-jakarta/src/main/java/io/sentry/spring/boot/jakarta/SentryAutoConfiguration.java +++ b/sentry-spring-boot-jakarta/src/main/java/io/sentry/spring/boot/jakarta/SentryAutoConfiguration.java @@ -5,6 +5,7 @@ import io.sentry.EventProcessor; import io.sentry.IScopes; import io.sentry.ITransportFactory; +import io.sentry.InitPriority; import io.sentry.Integration; import io.sentry.ScopesAdapter; import io.sentry.Sentry; @@ -133,6 +134,7 @@ static class HubConfiguration { options.setSentryClientName( BuildConfig.SENTRY_SPRING_BOOT_JAKARTA_SDK_NAME + "/" + BuildConfig.VERSION_NAME); options.setSdkVersion(createSdkVersion(options)); + options.setInitPriority(InitPriority.LOW); addPackageAndIntegrationInfo(); // Spring Boot sets ignored exceptions in runtime using reflection - where the generic // information is lost diff --git a/sentry-spring-boot/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java b/sentry-spring-boot/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java index 62f8e8457df..39eb420793c 100644 --- a/sentry-spring-boot/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java +++ b/sentry-spring-boot/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java @@ -5,6 +5,7 @@ import io.sentry.EventProcessor; import io.sentry.IScopes; import io.sentry.ITransportFactory; +import io.sentry.InitPriority; import io.sentry.Integration; import io.sentry.ScopesAdapter; import io.sentry.Sentry; @@ -131,6 +132,7 @@ static class HubConfiguration { options.setSentryClientName( BuildConfig.SENTRY_SPRING_BOOT_SDK_NAME + "/" + BuildConfig.VERSION_NAME); options.setSdkVersion(createSdkVersion(options)); + options.setInitPriority(InitPriority.LOW); addPackageAndIntegrationInfo(); // Spring Boot sets ignored exceptions in runtime using reflection - where the generic // information is lost diff --git a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/SentryHubRegistrar.java b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/SentryHubRegistrar.java index 9598f0c926a..638f6a63223 100644 --- a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/SentryHubRegistrar.java +++ b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/SentryHubRegistrar.java @@ -1,6 +1,7 @@ package io.sentry.spring.jakarta; import com.jakewharton.nopen.annotation.Open; +import io.sentry.InitPriority; import io.sentry.ScopesAdapter; import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryOptions; @@ -46,6 +47,7 @@ private void registerSentryOptions( builder.addPropertyValue("enableExternalConfiguration", true); builder.addPropertyValue("sentryClientName", BuildConfig.SENTRY_SPRING_JAKARTA_SDK_NAME); builder.addPropertyValue("sdkVersion", createSdkVersion()); + builder.addPropertyValue("initPriority", InitPriority.LOW); addPackageAndIntegrationInfo(); if (annotationAttributes.containsKey("sendDefaultPii")) { builder.addPropertyValue("sendDefaultPii", annotationAttributes.getBoolean("sendDefaultPii")); diff --git a/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java b/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java index 195a88e277c..c02955d11b7 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java +++ b/sentry-spring/src/main/java/io/sentry/spring/SentryHubRegistrar.java @@ -1,6 +1,7 @@ package io.sentry.spring; import com.jakewharton.nopen.annotation.Open; +import io.sentry.InitPriority; import io.sentry.ScopesAdapter; import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryOptions; @@ -46,6 +47,7 @@ private void registerSentryOptions( builder.addPropertyValue("enableExternalConfiguration", true); builder.addPropertyValue("sentryClientName", BuildConfig.SENTRY_SPRING_SDK_NAME); builder.addPropertyValue("sdkVersion", createSdkVersion()); + builder.addPropertyValue("initPriority", InitPriority.LOW); addPackageAndIntegrationInfo(); if (annotationAttributes.containsKey("sendDefaultPii")) { builder.addPropertyValue("sendDefaultPii", annotationAttributes.getBoolean("sendDefaultPii")); From ac5c1e1fe39c7b2d2b589cb8887bbdd9c7a1ef5f Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 2 Sep 2024 13:43:12 +0200 Subject: [PATCH 07/10] Add JUL --- .../src/main/java/io/sentry/jul/SentryHandler.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sentry-jul/src/main/java/io/sentry/jul/SentryHandler.java b/sentry-jul/src/main/java/io/sentry/jul/SentryHandler.java index c52b4706f2a..d6afd514e63 100644 --- a/sentry-jul/src/main/java/io/sentry/jul/SentryHandler.java +++ b/sentry-jul/src/main/java/io/sentry/jul/SentryHandler.java @@ -6,6 +6,7 @@ import com.jakewharton.nopen.annotation.Open; import io.sentry.Breadcrumb; import io.sentry.Hint; +import io.sentry.InitPriority; import io.sentry.ScopesAdapter; import io.sentry.Sentry; import io.sentry.SentryEvent; @@ -69,11 +70,10 @@ public SentryHandler(final @NotNull SentryOptions options) { if (configureFromLogManager) { retrieveProperties(); } - if (!Sentry.isEnabled()) { - options.setEnableExternalConfiguration(true); - options.setSdkVersion(createSdkVersion(options)); - Sentry.init(options); - } + options.setEnableExternalConfiguration(true); + options.setInitPriority(InitPriority.LOWEST); + options.setSdkVersion(createSdkVersion(options)); + Sentry.init(options); addPackageAndIntegrationInfo(); } From 93c8ce855237b3f73457b86030ea080b5acfa5e3 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 16 Sep 2024 13:59:06 +0200 Subject: [PATCH 08/10] revert merge mistake --- .../io/sentry/android/core/AndroidOptionsInitializer.java | 5 ----- 1 file changed, 5 deletions(-) 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 5f32db2ba26..dd5c3c5254b 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 @@ -9,7 +9,6 @@ import io.sentry.DefaultTransactionPerformanceCollector; import io.sentry.ILogger; import io.sentry.ITransactionProfiler; -import io.sentry.InitPriority; import io.sentry.NoOpConnectionStatusProvider; import io.sentry.ScopeType; import io.sentry.SendFireAndForgetEnvelopeSender; @@ -114,10 +113,6 @@ static void loadDefaultAndMetadataOptions( options.setCacheDirPath(getCacheDir(context).getAbsolutePath()); readDefaultOptionValues(options, context, buildInfoProvider); - - if (ManifestMetadataReader.isAutoInit(context, logger)) { - options.setInitPriority(InitPriority.LOW); - } } @TestOnly From d2bd58e1fe5b47efdfcacd40947aadb956fcbc2c Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 16 Sep 2024 14:26:06 +0200 Subject: [PATCH 09/10] fix changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b859654f3d1..5c6f3a0bf0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ - Add init priority settings ([#3674](https://github.com/getsentry/sentry-java/pull/3674)) - You may now set `forceInit=true` (`force-init` for `.properties` files) to ensure a call to Sentry.init / SentryAndroid.init takes effect -- Add force init option to Android Manifest +- Add force init option to Android Manifest ([#3675](https://github.com/getsentry/sentry-java/pull/3675)) - Use `` to ensure Sentry Android auto init is not easily overwritten ### Fixes From aeec682aa64e5b3268d911bb0c2bc638e393947a Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 16 Sep 2024 14:31:56 +0200 Subject: [PATCH 10/10] move already initialized log message --- sentry/src/main/java/io/sentry/Sentry.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index 7807bced45a..1482d391f4f 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -272,13 +272,6 @@ private static synchronized void init( "You are running Android. Please, use SentryAndroid.init. " + options.getClass().getName()); } - if (isEnabled()) { - options - .getLogger() - .log( - SentryLevel.WARNING, - "Sentry has been already initialized. Previous configuration will be overwritten."); - } if (!preInitConfigurations(options)) { return; @@ -288,6 +281,13 @@ private static synchronized void init( Sentry.globalHubMode = globalHubMode; final boolean shouldInit = InitUtil.shouldInit(globalScope.getOptions(), options, isEnabled()); if (shouldInit) { + if (isEnabled()) { + options + .getLogger() + .log( + SentryLevel.WARNING, + "Sentry has been already initialized. Previous configuration will be overwritten."); + } globalScope.replaceOptions(options); final IScopes scopes = getCurrentScopes();