From 57c1b9702e9d50aebd6a279a7e03a953ed91b951 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Tue, 2 Jul 2024 11:45:57 +0200 Subject: [PATCH 1/3] 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 2/3] 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 3/3] 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 */