From bb57a104668b6f3fb398f34a494c58a23c1e8f16 Mon Sep 17 00:00:00 2001 From: lcian Date: Tue, 23 Sep 2025 10:13:25 +0200 Subject: [PATCH 01/13] wip --- .../core/DefaultAndroidEventProcessor.java | 13 ++++- sentry/src/main/java/io/sentry/Scopes.java | 22 +++++-- .../java/io/sentry/SentryExecutorService.java | 58 +++++++++++++------ .../src/main/java/io/sentry/SentryValues.java | 6 +- .../backpressure/BackpressureMonitor.java | 9 ++- .../sentry/logger/LoggerBatchProcessor.java | 9 ++- .../transport/QueuedThreadPoolExecutor.java | 9 ++- 7 files changed, 97 insertions(+), 29 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java index 9409c29b0d8..c3749f9dc2f 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java @@ -37,6 +37,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -66,8 +67,16 @@ public DefaultAndroidEventProcessor( // noinspection Convert2MethodRef // some device info performs disk I/O, but it's result is cached, let's pre-cache it final @NotNull ExecutorService executorService = Executors.newSingleThreadExecutor(); - this.deviceInfoUtil = - executorService.submit(() -> DeviceInfoUtil.getInstance(this.context, options)); + try { + this.deviceInfoUtil = + executorService.submit(() -> DeviceInfoUtil.getInstance(this.context, options)); + } catch (RejectedExecutionException e) { + // Fall back to synchronous initialization if executor rejects the task + options + .getLogger() + .log(SentryLevel.DEBUG, "Device info pre-caching task rejected. Using synchronous initialization.", e); + this.deviceInfoUtil = null; + } executorService.shutdown(); } diff --git a/sentry/src/main/java/io/sentry/Scopes.java b/sentry/src/main/java/io/sentry/Scopes.java index 77b9b94731c..2e46b33c099 100644 --- a/sentry/src/main/java/io/sentry/Scopes.java +++ b/sentry/src/main/java/io/sentry/Scopes.java @@ -5,17 +5,17 @@ import io.sentry.hints.SessionStartHint; import io.sentry.logger.ILoggerApi; import io.sentry.logger.LoggerApi; -import io.sentry.protocol.Feedback; -import io.sentry.protocol.SentryId; -import io.sentry.protocol.SentryTransaction; -import io.sentry.protocol.User; +import io.sentry.protocol.*; import io.sentry.transport.RateLimiter; import io.sentry.util.HintUtils; import io.sentry.util.Objects; import io.sentry.util.SpanUtils; import io.sentry.util.TracingUtils; import java.io.Closeable; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -449,8 +449,18 @@ public void close(final boolean isRestarting) { getOptions().getConnectionStatusProvider().close(); final @NotNull ISentryExecutorService executorService = getOptions().getExecutorService(); if (isRestarting) { - executorService.submit( - () -> executorService.close(getOptions().getShutdownTimeoutMillis())); + try { + executorService.submit( + () -> executorService.close(getOptions().getShutdownTimeoutMillis())); + } catch (RejectedExecutionException e) { + getOptions() + .getLogger() + .log( + SentryLevel.DEBUG, + "Failed to submit executor service shutdown task during restart. Shutting down synchronously.", + e); + executorService.close(getOptions().getShutdownTimeoutMillis()); + } } else { executorService.close(getOptions().getShutdownTimeoutMillis()); } diff --git a/sentry/src/main/java/io/sentry/SentryExecutorService.java b/sentry/src/main/java/io/sentry/SentryExecutorService.java index 3fe262b5538..d226d8cbc80 100644 --- a/sentry/src/main/java/io/sentry/SentryExecutorService.java +++ b/sentry/src/main/java/io/sentry/SentryExecutorService.java @@ -56,9 +56,17 @@ public SentryExecutorService() { @Override public @NotNull Future submit(final @NotNull Runnable runnable) { if (executorService.getQueue().size() < MAX_QUEUE_SIZE) { - return executorService.submit(runnable); + try { + return executorService.submit(runnable); + } catch (RejectedExecutionException e) { + if (options != null) { + options + .getLogger() + .log(SentryLevel.WARNING, "Task " + runnable + " rejected from " + executorService, e); + } + return new CancelledFuture<>(); + } } - // TODO: maybe RejectedExecutionException? if (options != null) { options .getLogger() @@ -70,9 +78,17 @@ public SentryExecutorService() { @Override public @NotNull Future submit(final @NotNull Callable callable) { if (executorService.getQueue().size() < MAX_QUEUE_SIZE) { - return executorService.submit(callable); + try { + return executorService.submit(callable); + } catch (RejectedExecutionException e) { + if (options != null) { + options + .getLogger() + .log(SentryLevel.WARNING, "Task " + callable + " rejected from " + executorService, e); + } + return new CancelledFuture<>(); + } } - // TODO: maybe RejectedExecutionException? if (options != null) { options .getLogger() @@ -122,20 +138,28 @@ public boolean isClosed() { @SuppressWarnings({"FutureReturnValueIgnored"}) @Override public void prewarm() { - executorService.submit( - () -> { - try { - // schedule a bunch of dummy runnables in the future that will never execute to trigger - // queue growth and then purge the queue - for (int i = 0; i < INITIAL_QUEUE_SIZE; i++) { - final Future future = executorService.schedule(dummyRunnable, 365L, TimeUnit.DAYS); - future.cancel(true); + try { + executorService.submit( + () -> { + try { + // schedule a bunch of dummy runnables in the future that will never execute to trigger + // queue growth and then purge the queue + for (int i = 0; i < INITIAL_QUEUE_SIZE; i++) { + final Future future = executorService.schedule(dummyRunnable, 365L, TimeUnit.DAYS); + future.cancel(true); + } + executorService.purge(); + } catch (RejectedExecutionException ignored) { + // ignore } - executorService.purge(); - } catch (RejectedExecutionException ignored) { - // ignore - } - }); + }); + } catch (RejectedExecutionException e) { + if (options != null) { + options + .getLogger() + .log(SentryLevel.DEBUG, "Prewarm task rejected from " + executorService, e); + } + } } private static final class SentryExecutorServiceThreadFactory implements ThreadFactory { diff --git a/sentry/src/main/java/io/sentry/SentryValues.java b/sentry/src/main/java/io/sentry/SentryValues.java index 170b7bf85d5..cc3dcb6e977 100644 --- a/sentry/src/main/java/io/sentry/SentryValues.java +++ b/sentry/src/main/java/io/sentry/SentryValues.java @@ -1,6 +1,7 @@ package io.sentry; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -16,7 +17,10 @@ final class SentryValues { } public @NotNull List getValues() { - return values; + ArrayList result = new ArrayList<>(values.size()); + result.addAll(values); + //Collections.reverse(result); + return result; } public static final class JsonKeys { diff --git a/sentry/src/main/java/io/sentry/backpressure/BackpressureMonitor.java b/sentry/src/main/java/io/sentry/backpressure/BackpressureMonitor.java index 92fa3ce0a5c..b02e23cb61d 100644 --- a/sentry/src/main/java/io/sentry/backpressure/BackpressureMonitor.java +++ b/sentry/src/main/java/io/sentry/backpressure/BackpressureMonitor.java @@ -7,6 +7,7 @@ import io.sentry.SentryOptions; import io.sentry.util.AutoClosableReentrantLock; import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -79,7 +80,13 @@ private void reschedule(final int delay) { final @NotNull ISentryExecutorService executorService = sentryOptions.getExecutorService(); if (!executorService.isClosed()) { try (final @NotNull ISentryLifecycleToken ignored = lock.acquire()) { - latestScheduledRun = executorService.schedule(this, delay); + try { + latestScheduledRun = executorService.schedule(this, delay); + } catch (RejectedExecutionException e) { + sentryOptions + .getLogger() + .log(SentryLevel.DEBUG, "Backpressure monitor reschedule task rejected", e); + } } } } diff --git a/sentry/src/main/java/io/sentry/logger/LoggerBatchProcessor.java b/sentry/src/main/java/io/sentry/logger/LoggerBatchProcessor.java index 3d760263f38..d3b3b13c593 100644 --- a/sentry/src/main/java/io/sentry/logger/LoggerBatchProcessor.java +++ b/sentry/src/main/java/io/sentry/logger/LoggerBatchProcessor.java @@ -15,6 +15,7 @@ import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -76,7 +77,13 @@ private void maybeSchedule(boolean forceSchedule, boolean immediately) { || latestScheduledFlush.isCancelled()) { hasScheduled = true; final int flushAfterMs = immediately ? 0 : FLUSH_AFTER_MS; - scheduledFlush = executorService.schedule(new BatchRunnable(), flushAfterMs); + try { + scheduledFlush = executorService.schedule(new BatchRunnable(), flushAfterMs); + } catch (RejectedExecutionException e) { + options + .getLogger() + .log(SentryLevel.DEBUG, "Logger batch flush task rejected", e); + } } } } diff --git a/sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java b/sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java index f8d35a6888a..92accfe3a0d 100644 --- a/sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java +++ b/sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java @@ -8,6 +8,7 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; @@ -65,7 +66,13 @@ public QueuedThreadPoolExecutor( public Future submit(final @NotNull Runnable task) { if (isSchedulingAllowed()) { unfinishedTasksCount.increment(); - return super.submit(task); + try { + return super.submit(task); + } catch (RejectedExecutionException e) { + unfinishedTasksCount.decrement(); + logger.log(SentryLevel.WARNING, "Submit rejected by thread pool executor", e); + return new CancelledFuture<>(); + } } else { lastRejectTimestamp = dateProvider.now(); // if the thread pool is full, we don't cache it From 47cf358422f2e9d67e7b89837c3f79fb0a6cfedf Mon Sep 17 00:00:00 2001 From: lcian Date: Tue, 23 Sep 2025 10:15:11 +0200 Subject: [PATCH 02/13] wip --- sentry/src/main/java/io/sentry/SentryValues.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sentry/src/main/java/io/sentry/SentryValues.java b/sentry/src/main/java/io/sentry/SentryValues.java index cc3dcb6e977..170b7bf85d5 100644 --- a/sentry/src/main/java/io/sentry/SentryValues.java +++ b/sentry/src/main/java/io/sentry/SentryValues.java @@ -1,7 +1,6 @@ package io.sentry; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -17,10 +16,7 @@ final class SentryValues { } public @NotNull List getValues() { - ArrayList result = new ArrayList<>(values.size()); - result.addAll(values); - //Collections.reverse(result); - return result; + return values; } public static final class JsonKeys { From 0a0f99a01ac5646a0636fa6587d6cd37dfdb0577 Mon Sep 17 00:00:00 2001 From: lcian Date: Tue, 23 Sep 2025 10:27:52 +0200 Subject: [PATCH 03/13] improve --- .../io/sentry/android/core/DefaultAndroidEventProcessor.java | 4 +--- sentry/src/main/java/io/sentry/Scopes.java | 2 +- .../main/java/io/sentry/backpressure/BackpressureMonitor.java | 2 +- .../src/main/java/io/sentry/logger/LoggerBatchProcessor.java | 2 +- .../java/io/sentry/transport/QueuedThreadPoolExecutor.java | 2 +- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java index c3749f9dc2f..9adb194d6fa 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java @@ -71,11 +71,9 @@ public DefaultAndroidEventProcessor( this.deviceInfoUtil = executorService.submit(() -> DeviceInfoUtil.getInstance(this.context, options)); } catch (RejectedExecutionException e) { - // Fall back to synchronous initialization if executor rejects the task options .getLogger() - .log(SentryLevel.DEBUG, "Device info pre-caching task rejected. Using synchronous initialization.", e); - this.deviceInfoUtil = null; + .log(SentryLevel.WARNING, "Device info pre-caching task rejected.", e); } executorService.shutdown(); } diff --git a/sentry/src/main/java/io/sentry/Scopes.java b/sentry/src/main/java/io/sentry/Scopes.java index 2e46b33c099..4833759611f 100644 --- a/sentry/src/main/java/io/sentry/Scopes.java +++ b/sentry/src/main/java/io/sentry/Scopes.java @@ -456,7 +456,7 @@ public void close(final boolean isRestarting) { getOptions() .getLogger() .log( - SentryLevel.DEBUG, + SentryLevel.WARNING, "Failed to submit executor service shutdown task during restart. Shutting down synchronously.", e); executorService.close(getOptions().getShutdownTimeoutMillis()); diff --git a/sentry/src/main/java/io/sentry/backpressure/BackpressureMonitor.java b/sentry/src/main/java/io/sentry/backpressure/BackpressureMonitor.java index b02e23cb61d..fdbfea2a3a2 100644 --- a/sentry/src/main/java/io/sentry/backpressure/BackpressureMonitor.java +++ b/sentry/src/main/java/io/sentry/backpressure/BackpressureMonitor.java @@ -85,7 +85,7 @@ private void reschedule(final int delay) { } catch (RejectedExecutionException e) { sentryOptions .getLogger() - .log(SentryLevel.DEBUG, "Backpressure monitor reschedule task rejected", e); + .log(SentryLevel.WARNING, "Backpressure monitor reschedule task rejected", e); } } } diff --git a/sentry/src/main/java/io/sentry/logger/LoggerBatchProcessor.java b/sentry/src/main/java/io/sentry/logger/LoggerBatchProcessor.java index d3b3b13c593..18fc708f66d 100644 --- a/sentry/src/main/java/io/sentry/logger/LoggerBatchProcessor.java +++ b/sentry/src/main/java/io/sentry/logger/LoggerBatchProcessor.java @@ -82,7 +82,7 @@ private void maybeSchedule(boolean forceSchedule, boolean immediately) { } catch (RejectedExecutionException e) { options .getLogger() - .log(SentryLevel.DEBUG, "Logger batch flush task rejected", e); + .log(SentryLevel.WARNING, "Logs batch processor flush task rejected", e); } } } diff --git a/sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java b/sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java index 92accfe3a0d..8c101f78f4b 100644 --- a/sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java +++ b/sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java @@ -69,7 +69,7 @@ public Future submit(final @NotNull Runnable task) { try { return super.submit(task); } catch (RejectedExecutionException e) { - unfinishedTasksCount.decrement(); + lastRejectTimestamp = dateProvider.now(); logger.log(SentryLevel.WARNING, "Submit rejected by thread pool executor", e); return new CancelledFuture<>(); } From 514bc23d44a0a599d7d89105cf555c3654bf2f11 Mon Sep 17 00:00:00 2001 From: lcian Date: Tue, 23 Sep 2025 10:59:23 +0200 Subject: [PATCH 04/13] improve --- .../core/DefaultAndroidEventProcessor.java | 2 +- .../java/io/sentry/SentryExecutorService.java | 28 ++++--------------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java index 9adb194d6fa..b1bcf87390b 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java @@ -73,7 +73,7 @@ public DefaultAndroidEventProcessor( } catch (RejectedExecutionException e) { options .getLogger() - .log(SentryLevel.WARNING, "Device info pre-caching task rejected.", e); + .log(SentryLevel.WARNING, "Device info caching task rejected.", e); } executorService.shutdown(); } diff --git a/sentry/src/main/java/io/sentry/SentryExecutorService.java b/sentry/src/main/java/io/sentry/SentryExecutorService.java index d226d8cbc80..6c47210adfb 100644 --- a/sentry/src/main/java/io/sentry/SentryExecutorService.java +++ b/sentry/src/main/java/io/sentry/SentryExecutorService.java @@ -54,18 +54,9 @@ public SentryExecutorService() { } @Override - public @NotNull Future submit(final @NotNull Runnable runnable) { + public @NotNull Future submit(final @NotNull Runnable runnable) throws RejectedExecutionException { if (executorService.getQueue().size() < MAX_QUEUE_SIZE) { - try { - return executorService.submit(runnable); - } catch (RejectedExecutionException e) { - if (options != null) { - options - .getLogger() - .log(SentryLevel.WARNING, "Task " + runnable + " rejected from " + executorService, e); - } - return new CancelledFuture<>(); - } + return executorService.submit(runnable); } if (options != null) { options @@ -76,18 +67,9 @@ public SentryExecutorService() { } @Override - public @NotNull Future submit(final @NotNull Callable callable) { + public @NotNull Future submit(final @NotNull Callable callable) throws RejectedExecutionException { if (executorService.getQueue().size() < MAX_QUEUE_SIZE) { - try { - return executorService.submit(callable); - } catch (RejectedExecutionException e) { - if (options != null) { - options - .getLogger() - .log(SentryLevel.WARNING, "Task " + callable + " rejected from " + executorService, e); - } - return new CancelledFuture<>(); - } + return executorService.submit(callable); } if (options != null) { options @@ -98,7 +80,7 @@ public SentryExecutorService() { } @Override - public @NotNull Future schedule(final @NotNull Runnable runnable, final long delayMillis) { + public @NotNull Future schedule(final @NotNull Runnable runnable, final long delayMillis) throws RejectedExecutionException { if (executorService.getQueue().size() < MAX_QUEUE_SIZE) { return executorService.schedule(runnable, delayMillis, TimeUnit.MILLISECONDS); } From fefa6044605d7e7014874d6345ecdc2050b77077 Mon Sep 17 00:00:00 2001 From: lcian Date: Tue, 23 Sep 2025 11:23:42 +0200 Subject: [PATCH 05/13] improve --- .../core/DefaultAndroidEventProcessor.java | 22 +++++-------------- sentry/src/main/java/io/sentry/Scopes.java | 2 -- .../java/io/sentry/SentryExecutorService.java | 15 ++++++++----- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java index b1bcf87390b..5e070bde2f9 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java @@ -4,18 +4,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build; -import io.sentry.DateUtils; -import io.sentry.EventProcessor; -import io.sentry.Hint; -import io.sentry.IpAddressUtils; -import io.sentry.NoOpLogger; -import io.sentry.SentryAttributeType; -import io.sentry.SentryBaseEvent; -import io.sentry.SentryEvent; -import io.sentry.SentryLevel; -import io.sentry.SentryLogEvent; -import io.sentry.SentryLogEventAttributeValue; -import io.sentry.SentryReplayEvent; +import io.sentry.*; import io.sentry.android.core.internal.util.AndroidThreadChecker; import io.sentry.android.core.performance.AppStartMetrics; import io.sentry.android.core.performance.TimeSpan; @@ -66,15 +55,16 @@ public DefaultAndroidEventProcessor( // don't ref. to method reference, theres a bug on it // noinspection Convert2MethodRef // some device info performs disk I/O, but it's result is cached, let's pre-cache it + @Nullable Future deviceInfoUtil; final @NotNull ExecutorService executorService = Executors.newSingleThreadExecutor(); try { - this.deviceInfoUtil = + deviceInfoUtil = executorService.submit(() -> DeviceInfoUtil.getInstance(this.context, options)); } catch (RejectedExecutionException e) { - options - .getLogger() - .log(SentryLevel.WARNING, "Device info caching task rejected.", e); + deviceInfoUtil = null; + options.getLogger().log(SentryLevel.WARNING, "Device info caching task rejected.", e); } + this.deviceInfoUtil = deviceInfoUtil; executorService.shutdown(); } diff --git a/sentry/src/main/java/io/sentry/Scopes.java b/sentry/src/main/java/io/sentry/Scopes.java index 4833759611f..ce11b19f738 100644 --- a/sentry/src/main/java/io/sentry/Scopes.java +++ b/sentry/src/main/java/io/sentry/Scopes.java @@ -12,8 +12,6 @@ import io.sentry.util.SpanUtils; import io.sentry.util.TracingUtils; import java.io.Closeable; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry/src/main/java/io/sentry/SentryExecutorService.java b/sentry/src/main/java/io/sentry/SentryExecutorService.java index 6c47210adfb..49bfadebc84 100644 --- a/sentry/src/main/java/io/sentry/SentryExecutorService.java +++ b/sentry/src/main/java/io/sentry/SentryExecutorService.java @@ -54,7 +54,8 @@ public SentryExecutorService() { } @Override - public @NotNull Future submit(final @NotNull Runnable runnable) throws RejectedExecutionException { + public @NotNull Future submit(final @NotNull Runnable runnable) + throws RejectedExecutionException { if (executorService.getQueue().size() < MAX_QUEUE_SIZE) { return executorService.submit(runnable); } @@ -67,7 +68,8 @@ public SentryExecutorService() { } @Override - public @NotNull Future submit(final @NotNull Callable callable) throws RejectedExecutionException { + public @NotNull Future submit(final @NotNull Callable callable) + throws RejectedExecutionException { if (executorService.getQueue().size() < MAX_QUEUE_SIZE) { return executorService.submit(callable); } @@ -80,7 +82,8 @@ public SentryExecutorService() { } @Override - public @NotNull Future schedule(final @NotNull Runnable runnable, final long delayMillis) throws RejectedExecutionException { + public @NotNull Future schedule(final @NotNull Runnable runnable, final long delayMillis) + throws RejectedExecutionException { if (executorService.getQueue().size() < MAX_QUEUE_SIZE) { return executorService.schedule(runnable, delayMillis, TimeUnit.MILLISECONDS); } @@ -124,10 +127,12 @@ public void prewarm() { executorService.submit( () -> { try { - // schedule a bunch of dummy runnables in the future that will never execute to trigger + // schedule a bunch of dummy runnables in the future that will never execute to + // trigger // queue growth and then purge the queue for (int i = 0; i < INITIAL_QUEUE_SIZE; i++) { - final Future future = executorService.schedule(dummyRunnable, 365L, TimeUnit.DAYS); + final Future future = + executorService.schedule(dummyRunnable, 365L, TimeUnit.DAYS); future.cancel(true); } executorService.purge(); From ff7e95273cc63e1d9423335e4c527dd8395486d5 Mon Sep 17 00:00:00 2001 From: lcian Date: Tue, 23 Sep 2025 11:32:15 +0200 Subject: [PATCH 06/13] improve --- sentry/src/main/java/io/sentry/SentryExecutorService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sentry/src/main/java/io/sentry/SentryExecutorService.java b/sentry/src/main/java/io/sentry/SentryExecutorService.java index 49bfadebc84..e1f6631d02a 100644 --- a/sentry/src/main/java/io/sentry/SentryExecutorService.java +++ b/sentry/src/main/java/io/sentry/SentryExecutorService.java @@ -87,7 +87,6 @@ public SentryExecutorService() { if (executorService.getQueue().size() < MAX_QUEUE_SIZE) { return executorService.schedule(runnable, delayMillis, TimeUnit.MILLISECONDS); } - // TODO: maybe RejectedExecutionException? if (options != null) { options .getLogger() From 78abc13f5a814503ff29dc7a92768132f27acd25 Mon Sep 17 00:00:00 2001 From: lcian Date: Tue, 23 Sep 2025 11:33:50 +0200 Subject: [PATCH 07/13] improve --- sentry/src/main/java/io/sentry/SentryExecutorService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry/src/main/java/io/sentry/SentryExecutorService.java b/sentry/src/main/java/io/sentry/SentryExecutorService.java index e1f6631d02a..873e4744e3c 100644 --- a/sentry/src/main/java/io/sentry/SentryExecutorService.java +++ b/sentry/src/main/java/io/sentry/SentryExecutorService.java @@ -143,7 +143,7 @@ public void prewarm() { if (options != null) { options .getLogger() - .log(SentryLevel.DEBUG, "Prewarm task rejected from " + executorService, e); + .log(SentryLevel.WARNING, "Prewarm task rejected from " + executorService, e); } } } From ba456cbc1801f816cc1c33bb8a7ce2d77d8b4117 Mon Sep 17 00:00:00 2001 From: lcian Date: Tue, 23 Sep 2025 12:29:11 +0200 Subject: [PATCH 08/13] improve --- .../io/sentry/android/core/DefaultAndroidEventProcessor.java | 2 +- .../main/java/io/sentry/transport/QueuedThreadPoolExecutor.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java index 5e070bde2f9..e69060c0c38 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java @@ -37,7 +37,7 @@ final class DefaultAndroidEventProcessor implements EventProcessor { private final @NotNull BuildInfoProvider buildInfoProvider; private final @NotNull SentryAndroidOptions options; - private final @NotNull Future deviceInfoUtil; + private final @Nullable Future deviceInfoUtil; private final @NotNull LazyEvaluator deviceFamily = new LazyEvaluator<>(() -> ContextUtils.getFamily(NoOpLogger.getInstance())); diff --git a/sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java b/sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java index 8c101f78f4b..e5565a279fc 100644 --- a/sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java +++ b/sentry/src/main/java/io/sentry/transport/QueuedThreadPoolExecutor.java @@ -69,6 +69,7 @@ public Future submit(final @NotNull Runnable task) { try { return super.submit(task); } catch (RejectedExecutionException e) { + unfinishedTasksCount.decrement(); lastRejectTimestamp = dateProvider.now(); logger.log(SentryLevel.WARNING, "Submit rejected by thread pool executor", e); return new CancelledFuture<>(); From a3ab6618dcf7e6929351fbffb93dcbff5243d2dc Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Thu, 25 Sep 2025 10:12:32 +0200 Subject: [PATCH 09/13] handle null everywhere --- .../core/DefaultAndroidEventProcessor.java | 138 ++++++++++-------- 1 file changed, 79 insertions(+), 59 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java index e69060c0c38..376d09c92d2 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java @@ -19,6 +19,7 @@ import io.sentry.util.HintUtils; import io.sentry.util.LazyEvaluator; import io.sentry.util.Objects; + import java.util.Collections; import java.util.List; import java.util.Locale; @@ -27,29 +28,31 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionException; + import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; final class DefaultAndroidEventProcessor implements EventProcessor { - @TestOnly final Context context; + @TestOnly + final Context context; private final @NotNull BuildInfoProvider buildInfoProvider; private final @NotNull SentryAndroidOptions options; private final @Nullable Future deviceInfoUtil; private final @NotNull LazyEvaluator deviceFamily = - new LazyEvaluator<>(() -> ContextUtils.getFamily(NoOpLogger.getInstance())); + new LazyEvaluator<>(() -> ContextUtils.getFamily(NoOpLogger.getInstance())); public DefaultAndroidEventProcessor( - final @NotNull Context context, - final @NotNull BuildInfoProvider buildInfoProvider, - final @NotNull SentryAndroidOptions options) { + final @NotNull Context context, + final @NotNull BuildInfoProvider buildInfoProvider, + final @NotNull SentryAndroidOptions options) { this.context = - Objects.requireNonNull( - ContextUtils.getApplicationContext(context), "The application context is required."); + Objects.requireNonNull( + ContextUtils.getApplicationContext(context), "The application context is required."); this.buildInfoProvider = - Objects.requireNonNull(buildInfoProvider, "The BuildInfoProvider is required."); + Objects.requireNonNull(buildInfoProvider, "The BuildInfoProvider is required."); this.options = Objects.requireNonNull(options, "The options object is required."); // don't ref. to method reference, theres a bug on it @@ -59,7 +62,7 @@ public DefaultAndroidEventProcessor( final @NotNull ExecutorService executorService = Executors.newSingleThreadExecutor(); try { deviceInfoUtil = - executorService.submit(() -> DeviceInfoUtil.getInstance(this.context, options)); + executorService.submit(() -> DeviceInfoUtil.getInstance(this.context, options)); } catch (RejectedExecutionException e) { deviceInfoUtil = null; options.getLogger().log(SentryLevel.WARNING, "Device info caching task rejected.", e); @@ -118,7 +121,7 @@ private static void fixExceptionOrder(final @NotNull SentryEvent event) { if (frames != null) { for (final @NotNull SentryStackFrame frame : frames) { if ("com.android.internal.os.RuntimeInit$MethodAndArgsCaller" - .equals(frame.getModule())) { + .equals(frame.getModule())) { reverseExceptions = true; break; } @@ -134,25 +137,25 @@ private static void fixExceptionOrder(final @NotNull SentryEvent event) { } private void setCommons( - final @NotNull SentryBaseEvent event, - final boolean errorEvent, - final boolean applyScopeData) { + final @NotNull SentryBaseEvent event, + final boolean errorEvent, + final boolean applyScopeData) { mergeUser(event); setDevice(event, errorEvent, applyScopeData); setSideLoadedInfo(event); } private boolean shouldApplyScopeData( - final @NotNull SentryBaseEvent event, final @NotNull Hint hint) { + final @NotNull SentryBaseEvent event, final @NotNull Hint hint) { if (HintUtils.shouldApplyScopeData(hint)) { return true; } else { options - .getLogger() - .log( - SentryLevel.DEBUG, - "Event was cached so not applying data relevant to the current app execution/version: %s", - event.getEventId()); + .getLogger() + .log( + SentryLevel.DEBUG, + "Event was cached so not applying data relevant to the current app execution/version: %s", + event.getEventId()); return false; } } @@ -174,16 +177,20 @@ private void mergeUser(final @NotNull SentryBaseEvent event) { } private void setDevice( - final @NotNull SentryBaseEvent event, - final boolean errorEvent, - final boolean applyScopeData) { + final @NotNull SentryBaseEvent event, + final boolean errorEvent, + final boolean applyScopeData) { if (event.getContexts().getDevice() == null) { - try { - event + if (deviceInfoUtil != null) { + try { + event .getContexts() .setDevice(deviceInfoUtil.get().collectDeviceInformation(errorEvent, applyScopeData)); - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info", e); + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info", e); + } + } else { + options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info"); } mergeOS(event); } @@ -191,12 +198,17 @@ private void setDevice( private void mergeOS(final @NotNull SentryBaseEvent event) { final OperatingSystem currentOS = event.getContexts().getOperatingSystem(); - try { - final OperatingSystem androidOS = deviceInfoUtil.get().getOperatingSystem(); - // make Android OS the main OS using the 'os' key - event.getContexts().setOperatingSystem(androidOS); - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve os system", e); + + if (deviceInfoUtil != null) { + try { + final OperatingSystem androidOS = deviceInfoUtil.get().getOperatingSystem(); + // make Android OS the main OS using the 'os' key + event.getContexts().setOperatingSystem(androidOS); + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve os system", e); + } + } else { + options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info"); } if (currentOS != null) { @@ -214,14 +226,14 @@ private void mergeOS(final @NotNull SentryBaseEvent event) { private void setDevice(final @NotNull SentryLogEvent event) { try { event.setAttribute( - "device.brand", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.BRAND)); + "device.brand", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.BRAND)); event.setAttribute( - "device.model", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.MODEL)); + "device.model", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.MODEL)); event.setAttribute( - "device.family", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, deviceFamily.getValue())); + "device.family", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, deviceFamily.getValue())); } catch (Throwable e) { options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info", e); } @@ -230,10 +242,10 @@ private void setDevice(final @NotNull SentryLogEvent event) { private void setOs(final @NotNull SentryLogEvent event) { try { event.setAttribute( - "os.name", new SentryLogEventAttributeValue(SentryAttributeType.STRING, "Android")); + "os.name", new SentryLogEventAttributeValue(SentryAttributeType.STRING, "Android")); event.setAttribute( - "os.version", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.VERSION.RELEASE)); + "os.version", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.VERSION.RELEASE)); } catch (Throwable e) { options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve os system", e); } @@ -241,7 +253,7 @@ private void setOs(final @NotNull SentryLogEvent event) { // Data to be applied to events that was created in the running process private void processNonCachedEvent( - final @NotNull SentryBaseEvent event, final @NotNull Hint hint) { + final @NotNull SentryBaseEvent event, final @NotNull Hint hint) { App app = event.getContexts().getApp(); if (app == null) { app = new App(); @@ -273,18 +285,22 @@ private void setThreads(final @NotNull SentryEvent event, final @NotNull Hint hi private void setPackageInfo(final @NotNull SentryBaseEvent event, final @NotNull App app) { final PackageInfo packageInfo = - ContextUtils.getPackageInfo( - context, PackageManager.GET_PERMISSIONS, options.getLogger(), buildInfoProvider); + ContextUtils.getPackageInfo( + context, PackageManager.GET_PERMISSIONS, options.getLogger(), buildInfoProvider); if (packageInfo != null) { String versionCode = ContextUtils.getVersionCode(packageInfo, buildInfoProvider); setDist(event, versionCode); @Nullable DeviceInfoUtil deviceInfoUtil = null; - try { - deviceInfoUtil = this.deviceInfoUtil.get(); - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info", e); + if (this.deviceInfoUtil != null) { + try { + deviceInfoUtil = this.deviceInfoUtil.get(); + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info", e); + } + } else { + options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info"); } ContextUtils.setAppPackageInfo(packageInfo, buildInfoProvider, deviceInfoUtil, app); @@ -300,7 +316,7 @@ private void setDist(final @NotNull SentryBaseEvent event, final @NotNull String private void setAppExtras(final @NotNull App app, final @NotNull Hint hint) { app.setAppName(ContextUtils.getApplicationName(context)); final @NotNull TimeSpan appStartTimeSpan = - AppStartMetrics.getInstance().getAppStartTimeSpanWithFallback(options); + AppStartMetrics.getInstance().getAppStartTimeSpanWithFallback(options); if (appStartTimeSpan.hasStarted()) { app.setAppStartTime(DateUtils.toUtilDate(appStartTimeSpan.getStartTimestamp())); } @@ -328,22 +344,26 @@ private void setAppExtras(final @NotNull App app, final @NotNull Hint hint) { } private void setSideLoadedInfo(final @NotNull SentryBaseEvent event) { - try { - final ContextUtils.SideLoadedInfo sideLoadedInfo = deviceInfoUtil.get().getSideLoadedInfo(); - if (sideLoadedInfo != null) { - final @NotNull Map tags = sideLoadedInfo.asTags(); - for (Map.Entry entry : tags.entrySet()) { - event.setTag(entry.getKey(), entry.getValue()); + if (deviceInfoUtil != null) { + try { + final ContextUtils.SideLoadedInfo sideLoadedInfo = deviceInfoUtil.get().getSideLoadedInfo(); + if (sideLoadedInfo != null) { + final @NotNull Map tags = sideLoadedInfo.asTags(); + for (Map.Entry entry : tags.entrySet()) { + event.setTag(entry.getKey(), entry.getValue()); + } } + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Error getting side loaded info.", e); } - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Error getting side loaded info.", e); + } else { + options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info"); } } @Override public @NotNull SentryTransaction process( - final @NotNull SentryTransaction transaction, final @NotNull Hint hint) { + final @NotNull SentryTransaction transaction, final @NotNull Hint hint) { final boolean applyScopeData = shouldApplyScopeData(transaction, hint); if (applyScopeData) { @@ -357,7 +377,7 @@ private void setSideLoadedInfo(final @NotNull SentryBaseEvent event) { @Override public @NotNull SentryReplayEvent process( - final @NotNull SentryReplayEvent event, final @NotNull Hint hint) { + final @NotNull SentryReplayEvent event, final @NotNull Hint hint) { final boolean applyScopeData = shouldApplyScopeData(event, hint); if (applyScopeData) { processNonCachedEvent(event, hint); From 9cf54638c29fa3b8ef0cec58178156d042916914 Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Thu, 25 Sep 2025 08:15:40 +0000 Subject: [PATCH 10/13] Format code --- .../core/DefaultAndroidEventProcessor.java | 81 +++++++++---------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java index 376d09c92d2..1e37916aaee 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java @@ -19,7 +19,6 @@ import io.sentry.util.HintUtils; import io.sentry.util.LazyEvaluator; import io.sentry.util.Objects; - import java.util.Collections; import java.util.List; import java.util.Locale; @@ -28,31 +27,29 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionException; - import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; final class DefaultAndroidEventProcessor implements EventProcessor { - @TestOnly - final Context context; + @TestOnly final Context context; private final @NotNull BuildInfoProvider buildInfoProvider; private final @NotNull SentryAndroidOptions options; private final @Nullable Future deviceInfoUtil; private final @NotNull LazyEvaluator deviceFamily = - new LazyEvaluator<>(() -> ContextUtils.getFamily(NoOpLogger.getInstance())); + new LazyEvaluator<>(() -> ContextUtils.getFamily(NoOpLogger.getInstance())); public DefaultAndroidEventProcessor( - final @NotNull Context context, - final @NotNull BuildInfoProvider buildInfoProvider, - final @NotNull SentryAndroidOptions options) { + final @NotNull Context context, + final @NotNull BuildInfoProvider buildInfoProvider, + final @NotNull SentryAndroidOptions options) { this.context = - Objects.requireNonNull( - ContextUtils.getApplicationContext(context), "The application context is required."); + Objects.requireNonNull( + ContextUtils.getApplicationContext(context), "The application context is required."); this.buildInfoProvider = - Objects.requireNonNull(buildInfoProvider, "The BuildInfoProvider is required."); + Objects.requireNonNull(buildInfoProvider, "The BuildInfoProvider is required."); this.options = Objects.requireNonNull(options, "The options object is required."); // don't ref. to method reference, theres a bug on it @@ -62,7 +59,7 @@ public DefaultAndroidEventProcessor( final @NotNull ExecutorService executorService = Executors.newSingleThreadExecutor(); try { deviceInfoUtil = - executorService.submit(() -> DeviceInfoUtil.getInstance(this.context, options)); + executorService.submit(() -> DeviceInfoUtil.getInstance(this.context, options)); } catch (RejectedExecutionException e) { deviceInfoUtil = null; options.getLogger().log(SentryLevel.WARNING, "Device info caching task rejected.", e); @@ -121,7 +118,7 @@ private static void fixExceptionOrder(final @NotNull SentryEvent event) { if (frames != null) { for (final @NotNull SentryStackFrame frame : frames) { if ("com.android.internal.os.RuntimeInit$MethodAndArgsCaller" - .equals(frame.getModule())) { + .equals(frame.getModule())) { reverseExceptions = true; break; } @@ -137,25 +134,25 @@ private static void fixExceptionOrder(final @NotNull SentryEvent event) { } private void setCommons( - final @NotNull SentryBaseEvent event, - final boolean errorEvent, - final boolean applyScopeData) { + final @NotNull SentryBaseEvent event, + final boolean errorEvent, + final boolean applyScopeData) { mergeUser(event); setDevice(event, errorEvent, applyScopeData); setSideLoadedInfo(event); } private boolean shouldApplyScopeData( - final @NotNull SentryBaseEvent event, final @NotNull Hint hint) { + final @NotNull SentryBaseEvent event, final @NotNull Hint hint) { if (HintUtils.shouldApplyScopeData(hint)) { return true; } else { options - .getLogger() - .log( - SentryLevel.DEBUG, - "Event was cached so not applying data relevant to the current app execution/version: %s", - event.getEventId()); + .getLogger() + .log( + SentryLevel.DEBUG, + "Event was cached so not applying data relevant to the current app execution/version: %s", + event.getEventId()); return false; } } @@ -177,15 +174,15 @@ private void mergeUser(final @NotNull SentryBaseEvent event) { } private void setDevice( - final @NotNull SentryBaseEvent event, - final boolean errorEvent, - final boolean applyScopeData) { + final @NotNull SentryBaseEvent event, + final boolean errorEvent, + final boolean applyScopeData) { if (event.getContexts().getDevice() == null) { if (deviceInfoUtil != null) { try { event - .getContexts() - .setDevice(deviceInfoUtil.get().collectDeviceInformation(errorEvent, applyScopeData)); + .getContexts() + .setDevice(deviceInfoUtil.get().collectDeviceInformation(errorEvent, applyScopeData)); } catch (Throwable e) { options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info", e); } @@ -226,14 +223,14 @@ private void mergeOS(final @NotNull SentryBaseEvent event) { private void setDevice(final @NotNull SentryLogEvent event) { try { event.setAttribute( - "device.brand", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.BRAND)); + "device.brand", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.BRAND)); event.setAttribute( - "device.model", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.MODEL)); + "device.model", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.MODEL)); event.setAttribute( - "device.family", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, deviceFamily.getValue())); + "device.family", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, deviceFamily.getValue())); } catch (Throwable e) { options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info", e); } @@ -242,10 +239,10 @@ private void setDevice(final @NotNull SentryLogEvent event) { private void setOs(final @NotNull SentryLogEvent event) { try { event.setAttribute( - "os.name", new SentryLogEventAttributeValue(SentryAttributeType.STRING, "Android")); + "os.name", new SentryLogEventAttributeValue(SentryAttributeType.STRING, "Android")); event.setAttribute( - "os.version", - new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.VERSION.RELEASE)); + "os.version", + new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.VERSION.RELEASE)); } catch (Throwable e) { options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve os system", e); } @@ -253,7 +250,7 @@ private void setOs(final @NotNull SentryLogEvent event) { // Data to be applied to events that was created in the running process private void processNonCachedEvent( - final @NotNull SentryBaseEvent event, final @NotNull Hint hint) { + final @NotNull SentryBaseEvent event, final @NotNull Hint hint) { App app = event.getContexts().getApp(); if (app == null) { app = new App(); @@ -285,8 +282,8 @@ private void setThreads(final @NotNull SentryEvent event, final @NotNull Hint hi private void setPackageInfo(final @NotNull SentryBaseEvent event, final @NotNull App app) { final PackageInfo packageInfo = - ContextUtils.getPackageInfo( - context, PackageManager.GET_PERMISSIONS, options.getLogger(), buildInfoProvider); + ContextUtils.getPackageInfo( + context, PackageManager.GET_PERMISSIONS, options.getLogger(), buildInfoProvider); if (packageInfo != null) { String versionCode = ContextUtils.getVersionCode(packageInfo, buildInfoProvider); @@ -316,7 +313,7 @@ private void setDist(final @NotNull SentryBaseEvent event, final @NotNull String private void setAppExtras(final @NotNull App app, final @NotNull Hint hint) { app.setAppName(ContextUtils.getApplicationName(context)); final @NotNull TimeSpan appStartTimeSpan = - AppStartMetrics.getInstance().getAppStartTimeSpanWithFallback(options); + AppStartMetrics.getInstance().getAppStartTimeSpanWithFallback(options); if (appStartTimeSpan.hasStarted()) { app.setAppStartTime(DateUtils.toUtilDate(appStartTimeSpan.getStartTimestamp())); } @@ -363,7 +360,7 @@ private void setSideLoadedInfo(final @NotNull SentryBaseEvent event) { @Override public @NotNull SentryTransaction process( - final @NotNull SentryTransaction transaction, final @NotNull Hint hint) { + final @NotNull SentryTransaction transaction, final @NotNull Hint hint) { final boolean applyScopeData = shouldApplyScopeData(transaction, hint); if (applyScopeData) { @@ -377,7 +374,7 @@ private void setSideLoadedInfo(final @NotNull SentryBaseEvent event) { @Override public @NotNull SentryReplayEvent process( - final @NotNull SentryReplayEvent event, final @NotNull Hint hint) { + final @NotNull SentryReplayEvent event, final @NotNull Hint hint) { final boolean applyScopeData = shouldApplyScopeData(event, hint); if (applyScopeData) { processNonCachedEvent(event, hint); From 63f225ef51da1965844224666fae65ac19ce0ba7 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Thu, 25 Sep 2025 14:14:41 +0200 Subject: [PATCH 11/13] trigger CI From 520353f9358dcde448b9d5574d0371f32e94e499 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Thu, 25 Sep 2025 14:18:30 +0200 Subject: [PATCH 12/13] changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa094db937d..c27650927c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Improvements + +- Handle `RejectedExecutionException` everywhere ([#4747](https://github.com/getsentry/sentry-java/pull/4747)) + ## 8.22.0 ### Features From 053342dfa89de62ae527dc87b11025cce6b6d691 Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Fri, 26 Sep 2025 09:54:21 +0200 Subject: [PATCH 13/13] reset hasScheduled for logs batch processor --- sentry/src/main/java/io/sentry/logger/LoggerBatchProcessor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sentry/src/main/java/io/sentry/logger/LoggerBatchProcessor.java b/sentry/src/main/java/io/sentry/logger/LoggerBatchProcessor.java index 18fc708f66d..369f24f75de 100644 --- a/sentry/src/main/java/io/sentry/logger/LoggerBatchProcessor.java +++ b/sentry/src/main/java/io/sentry/logger/LoggerBatchProcessor.java @@ -80,6 +80,7 @@ private void maybeSchedule(boolean forceSchedule, boolean immediately) { try { scheduledFlush = executorService.schedule(new BatchRunnable(), flushAfterMs); } catch (RejectedExecutionException e) { + hasScheduled = false; options .getLogger() .log(SentryLevel.WARNING, "Logs batch processor flush task rejected", e);