From 3f30abe545d2d813f4aecc481bba9c01a5488953 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Thu, 9 Oct 2025 09:36:38 +0200 Subject: [PATCH 1/3] Avoid forking rootScopes for Reactor if current thread has NoOpScopes --- .../io/sentry/reactor/SentryReactorThreadLocalAccessor.java | 6 +++++- sentry/api/sentry.api | 1 + sentry/src/main/java/io/sentry/Sentry.java | 6 ++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/sentry-reactor/src/main/java/io/sentry/reactor/SentryReactorThreadLocalAccessor.java b/sentry-reactor/src/main/java/io/sentry/reactor/SentryReactorThreadLocalAccessor.java index 7ef4bb9bd1e..2dfb33f318d 100644 --- a/sentry-reactor/src/main/java/io/sentry/reactor/SentryReactorThreadLocalAccessor.java +++ b/sentry-reactor/src/main/java/io/sentry/reactor/SentryReactorThreadLocalAccessor.java @@ -16,7 +16,11 @@ public Object key() { @Override public IScopes getValue() { - return Sentry.getCurrentScopes(); + if (Sentry.hasScopes()) { + return Sentry.getCurrentScopes(); + } else { + return NoOpScopes.getInstance(); + } } @Override diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 4bfa96f1207..e6889ff1c53 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -2599,6 +2599,7 @@ public final class io/sentry/Sentry { public static fun getLastEventId ()Lio/sentry/protocol/SentryId; public static fun getSpan ()Lio/sentry/ISpan; public static fun getTraceparent ()Lio/sentry/SentryTraceHeader; + public static fun hasScopes ()Z public static fun init ()V public static fun init (Lio/sentry/OptionsContainer;Lio/sentry/Sentry$OptionsConfiguration;)V public static fun init (Lio/sentry/OptionsContainer;Lio/sentry/Sentry$OptionsConfiguration;Z)V diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index 4aee71715d7..582b75b97a9 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -112,6 +112,12 @@ private Sentry() {} return scopes; } + @ApiStatus.Internal + public static boolean hasScopes() { + final @Nullable IScopes scopes = getScopesStorage().get(); + return scopes != null && !scopes.isNoOp(); + } + private static @NotNull IScopesStorage getScopesStorage() { return scopesStorage; } From 062cfee8bb710432ab48a69239eaadcade085806 Mon Sep 17 00:00:00 2001 From: getsentry-bot Date: Thu, 9 Oct 2025 08:43:02 +0000 Subject: [PATCH 2/3] release: 8.23.1-alpha.1 --- CHANGELOG.md | 2 +- gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f51bfd5c11f..184a2653ad6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## Unreleased +## 8.23.1-alpha.1 ### Fixes diff --git a/gradle.properties b/gradle.properties index 5637a2f35c0..787d75c7221 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled android.useAndroidX=true # Release information -versionName=8.23.0 +versionName=8.23.1-alpha.1 # Override the SDK name on native crashes on Android sentryAndroidSdkName=sentry.native.android From 0792d93056588bfb49ceab21d3ef5e96e90ddf6f Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Tue, 11 Nov 2025 19:47:44 +0100 Subject: [PATCH 3/3] fix changelog; replace hasScopes with bool param on getCurrentScopes --- CHANGELOG.md | 4 ++- .../SentryReactorThreadLocalAccessor.java | 6 +--- sentry/api/sentry.api | 2 +- sentry/src/main/java/io/sentry/Sentry.java | 29 +++++++++++++------ 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a253a1c59bb..81a1624de68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 8.23.1-alpha.1 +## Unreleased ### Features @@ -29,6 +29,8 @@ - Fix profilerId propagation ([#4833](https://github.com/getsentry/sentry-java/pull/4833)) - Fix profiling init for Spring and Spring Boot w Agent auto-init ([#4815](https://github.com/getsentry/sentry-java/pull/4815)) - Copy active span on scope clone ([#4878](https://github.com/getsentry/sentry-java/pull/4878)) +- Avoid forking `rootScopes` for Reactor if current thread has NoOpScopes ([#4793](https://github.com/getsentry/sentry-java/pull/4793)) + - This reduces the SDKs overhead by avoiding unnecessary scope forks ### Improvements diff --git a/sentry-reactor/src/main/java/io/sentry/reactor/SentryReactorThreadLocalAccessor.java b/sentry-reactor/src/main/java/io/sentry/reactor/SentryReactorThreadLocalAccessor.java index 2dfb33f318d..d2b841abe70 100644 --- a/sentry-reactor/src/main/java/io/sentry/reactor/SentryReactorThreadLocalAccessor.java +++ b/sentry-reactor/src/main/java/io/sentry/reactor/SentryReactorThreadLocalAccessor.java @@ -16,11 +16,7 @@ public Object key() { @Override public IScopes getValue() { - if (Sentry.hasScopes()) { - return Sentry.getCurrentScopes(); - } else { - return NoOpScopes.getInstance(); - } + return Sentry.getCurrentScopes(false); } @Override diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index b2d1252a4f6..855818f186e 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -2631,11 +2631,11 @@ public final class io/sentry/Sentry { public static fun getBaggage ()Lio/sentry/BaggageHeader; public static fun getCurrentHub ()Lio/sentry/IHub; public static fun getCurrentScopes ()Lio/sentry/IScopes; + public static fun getCurrentScopes (Z)Lio/sentry/IScopes; public static fun getGlobalScope ()Lio/sentry/IScope; public static fun getLastEventId ()Lio/sentry/protocol/SentryId; public static fun getSpan ()Lio/sentry/ISpan; public static fun getTraceparent ()Lio/sentry/SentryTraceHeader; - public static fun hasScopes ()Z public static fun init ()V public static fun init (Lio/sentry/OptionsContainer;Lio/sentry/Sentry$OptionsConfiguration;)V public static fun init (Lio/sentry/OptionsContainer;Lio/sentry/Sentry$OptionsConfiguration;Z)V diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index f45f418b3db..f726c1a602c 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -97,26 +97,37 @@ private Sentry() {} return new HubScopesWrapper(getCurrentScopes()); } - @ApiStatus.Internal // exposed for the coroutines integration in SentryContext + @ApiStatus.Internal @SuppressWarnings("deprecation") public static @NotNull IScopes getCurrentScopes() { + return getCurrentScopes(true); + } + + /** + * Returns the current contexts scopes. + * + * @param ensureForked if true, forks root scopes in case there are no scopes for this context if + * false, returns NoOpScopes if there are no scopes for this context + * @return current scopes, a root scopes fork or NoopScopes + */ + @ApiStatus.Internal + @SuppressWarnings("deprecation") + public static @NotNull IScopes getCurrentScopes(final boolean ensureForked) { if (globalHubMode) { return rootScopes; } @Nullable IScopes scopes = getScopesStorage().get(); if (scopes == null || scopes.isNoOp()) { - scopes = rootScopes.forkedScopes("getCurrentScopes"); - getScopesStorage().set(scopes); + if (!ensureForked) { + return NoOpScopes.getInstance(); + } else { + scopes = rootScopes.forkedScopes("getCurrentScopes"); + getScopesStorage().set(scopes); + } } return scopes; } - @ApiStatus.Internal - public static boolean hasScopes() { - final @Nullable IScopes scopes = getScopesStorage().get(); - return scopes != null && !scopes.isNoOp(); - } - private static @NotNull IScopesStorage getScopesStorage() { return scopesStorage; }