diff --git a/CHANGELOG.md b/CHANGELOG.md index 1348e68f114..84e85b5dac8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Behavioral Changes - Measure HTTP rate-limit backoff on a monotonic clock instead of the wall clock, so that a device time change no longer lifts or extends an active rate limit ([#6030](https://github.com/getsentry/sentry-java/pull/6030)) +- Measure check-in durations on the monotonic clock, so a cron job that spans device sleep reports the time a user would measure instead of the time the CPU was awake ([#6032](https://github.com/getsentry/sentry-java/pull/6032)) ### Fixes diff --git a/sentry-spring-7/src/main/java/io/sentry/spring7/checkin/SentryCheckInAdvice.java b/sentry-spring-7/src/main/java/io/sentry/spring7/checkin/SentryCheckInAdvice.java index d2c164b9a6e..d6730602de2 100644 --- a/sentry-spring-7/src/main/java/io/sentry/spring7/checkin/SentryCheckInAdvice.java +++ b/sentry-spring-7/src/main/java/io/sentry/spring7/checkin/SentryCheckInAdvice.java @@ -9,6 +9,7 @@ import io.sentry.ScopesAdapter; import io.sentry.SentryLevel; import io.sentry.protocol.SentryId; +import io.sentry.time.Stopwatch; import io.sentry.util.Objects; import io.sentry.util.TracingUtils; import java.lang.reflect.Method; @@ -91,7 +92,8 @@ public Object invoke(final @NotNull MethodInvocation invocation) throws Throwabl TracingUtils.startNewTrace(scopes); @Nullable SentryId checkInId = null; - final long startTime = System.nanoTime(); + final @NotNull Stopwatch stopwatch = + Stopwatch.started(scopes.getOptions().getMonotonicClock()); boolean didError = false; try { @@ -105,7 +107,7 @@ public Object invoke(final @NotNull MethodInvocation invocation) throws Throwabl } finally { final @NotNull CheckInStatus status = didError ? CheckInStatus.ERROR : CheckInStatus.OK; CheckIn checkIn = new CheckIn(checkInId, monitorSlug, status); - checkIn.setDuration(DateUtils.nanosToSeconds(System.nanoTime() - startTime)); + checkIn.setDuration(DateUtils.nanosToSeconds(stopwatch.elapsedNanos())); scopes.captureCheckIn(checkIn); } } diff --git a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/checkin/SentryCheckInAdvice.java b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/checkin/SentryCheckInAdvice.java index fa64ac0e3e4..8507f1d42f6 100644 --- a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/checkin/SentryCheckInAdvice.java +++ b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/checkin/SentryCheckInAdvice.java @@ -9,6 +9,7 @@ import io.sentry.ScopesAdapter; import io.sentry.SentryLevel; import io.sentry.protocol.SentryId; +import io.sentry.time.Stopwatch; import io.sentry.util.Objects; import io.sentry.util.TracingUtils; import java.lang.reflect.Method; @@ -91,7 +92,8 @@ public Object invoke(final @NotNull MethodInvocation invocation) throws Throwabl TracingUtils.startNewTrace(scopes); @Nullable SentryId checkInId = null; - final long startTime = System.nanoTime(); + final @NotNull Stopwatch stopwatch = + Stopwatch.started(scopes.getOptions().getMonotonicClock()); boolean didError = false; try { @@ -105,7 +107,7 @@ public Object invoke(final @NotNull MethodInvocation invocation) throws Throwabl } finally { final @NotNull CheckInStatus status = didError ? CheckInStatus.ERROR : CheckInStatus.OK; CheckIn checkIn = new CheckIn(checkInId, monitorSlug, status); - checkIn.setDuration(DateUtils.nanosToSeconds(System.nanoTime() - startTime)); + checkIn.setDuration(DateUtils.nanosToSeconds(stopwatch.elapsedNanos())); scopes.captureCheckIn(checkIn); } } diff --git a/sentry-spring/src/main/java/io/sentry/spring/checkin/SentryCheckInAdvice.java b/sentry-spring/src/main/java/io/sentry/spring/checkin/SentryCheckInAdvice.java index a96e9e29808..ebbc55d40f0 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/checkin/SentryCheckInAdvice.java +++ b/sentry-spring/src/main/java/io/sentry/spring/checkin/SentryCheckInAdvice.java @@ -9,6 +9,7 @@ import io.sentry.ScopesAdapter; import io.sentry.SentryLevel; import io.sentry.protocol.SentryId; +import io.sentry.time.Stopwatch; import io.sentry.util.Objects; import io.sentry.util.TracingUtils; import java.lang.reflect.Method; @@ -94,7 +95,8 @@ public Object invoke(final @NotNull MethodInvocation invocation) throws Throwabl TracingUtils.startNewTrace(scopes); @Nullable SentryId checkInId = null; - final long startTime = System.nanoTime(); + final @NotNull Stopwatch stopwatch = + Stopwatch.started(scopes.getOptions().getMonotonicClock()); boolean didError = false; try { @@ -108,7 +110,7 @@ public Object invoke(final @NotNull MethodInvocation invocation) throws Throwabl } finally { final @NotNull CheckInStatus status = didError ? CheckInStatus.ERROR : CheckInStatus.OK; CheckIn checkIn = new CheckIn(checkInId, monitorSlug, status); - checkIn.setDuration(DateUtils.nanosToSeconds(System.nanoTime() - startTime)); + checkIn.setDuration(DateUtils.nanosToSeconds(stopwatch.elapsedNanos())); scopes.captureCheckIn(checkIn); } } diff --git a/sentry/src/main/java/io/sentry/util/CheckInUtils.java b/sentry/src/main/java/io/sentry/util/CheckInUtils.java index 3deea093142..67a1c89ab76 100644 --- a/sentry/src/main/java/io/sentry/util/CheckInUtils.java +++ b/sentry/src/main/java/io/sentry/util/CheckInUtils.java @@ -9,6 +9,7 @@ import io.sentry.MonitorConfig; import io.sentry.Sentry; import io.sentry.protocol.SentryId; +import io.sentry.time.Stopwatch; import java.util.List; import java.util.concurrent.Callable; import org.jetbrains.annotations.ApiStatus; @@ -37,7 +38,8 @@ public static U withCheckIn( try (final @NotNull ISentryLifecycleToken ignored = Sentry.forkedScopes("CheckInUtils").makeCurrent()) { final @NotNull IScopes scopes = Sentry.getCurrentScopes(); - final long startTime = System.nanoTime(); + final @NotNull Stopwatch stopwatch = + Stopwatch.started(scopes.getOptions().getMonotonicClock()); boolean didError = false; TracingUtils.startNewTrace(scopes); @@ -61,7 +63,7 @@ public static U withCheckIn( if (environment != null) { checkIn.setEnvironment(environment); } - checkIn.setDuration(DateUtils.nanosToSeconds(System.nanoTime() - startTime)); + checkIn.setDuration(DateUtils.nanosToSeconds(stopwatch.elapsedNanos())); scopes.captureCheckIn(checkIn); } } diff --git a/sentry/src/test/java/io/sentry/util/CheckInUtilsTest.kt b/sentry/src/test/java/io/sentry/util/CheckInUtilsTest.kt index d4831c829e4..03a3e1bf69e 100644 --- a/sentry/src/test/java/io/sentry/util/CheckInUtilsTest.kt +++ b/sentry/src/test/java/io/sentry/util/CheckInUtilsTest.kt @@ -143,6 +143,7 @@ class CheckInUtilsTest { sentry.`when` { Sentry.forkedScopes(any()) }.then { scopes.forkedScopes("test") } whenever(scopes.forkedScopes(any())).thenReturn(scopes) whenever(scopes.makeCurrent()).thenReturn(lifecycleToken) + whenever(scopes.options).thenReturn(SentryOptions()) try { CheckInUtils.withCheckIn("monitor-1") { throw RuntimeException("thrown on purpose") }