Skip to content
Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
### Improvements

- Reduce boxing to improve performance ([#5523](https://github.com/getsentry/sentry-java/pull/5523), [#5527](https://github.com/getsentry/sentry-java/pull/5527), [#5551](https://github.com/getsentry/sentry-java/pull/5551))
- Replace `Date` with a unix timestamp in `SentryNanotimeDate` to improve performance ([#5550](https://github.com/getsentry/sentry-java/pull/5550))
- `SentryNanotimeDate` is now marked `@ApiStatus.Internal`. A new `(long unixDateMillis, long nanos)` constructor was added, where `unixDateMillis` is milliseconds since the epoch. The existing `(Date, long)` constructor is retained but deprecated.

### Dependencies

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.Future;
Expand Down Expand Up @@ -94,7 +93,7 @@ public final class ActivityLifecycleIntegration
private final @NotNull WeakHashMap<Activity, ISpan> ttfdSpanMap = new WeakHashMap<>();
private final @NotNull WeakHashMap<Activity, ActivityLifecycleSpanHelper> activitySpanHelpers =
new WeakHashMap<>();
private @NotNull SentryDate lastPausedTime = new SentryNanotimeDate(new Date(0), 0);
private @NotNull SentryDate lastPausedTime = new SentryNanotimeDate(0, 0);
private @Nullable Future<?> ttfdAutoCloseFuture = null;

// WeakHashMap isn't thread safe but ActivityLifecycleCallbacks is only called from the
Expand Down Expand Up @@ -729,7 +728,7 @@ public void onActivityDestroyed(final @NotNull Activity activity) {

private void clear() {
firstActivityCreated = false;
lastPausedTime = new SentryNanotimeDate(new Date(0), 0);
lastPausedTime = new SentryNanotimeDate(0, 0);
activitySpanHelpers.clear();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import io.sentry.android.core.internal.util.SentryFrameMetricsCollector;
import io.sentry.protocol.MeasurementValue;
import io.sentry.util.AutoClosableReentrantLock;
import java.util.Date;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;
Expand All @@ -33,7 +32,7 @@ public class SpanFrameMetricsCollector
// grow indefinitely in case of a long running span
private static final int MAX_FRAMES_COUNT = 3600;
private static final long ONE_SECOND_NANOS = TimeUnit.SECONDS.toNanos(1);
private static final SentryNanotimeDate EMPTY_NANO_TIME = new SentryNanotimeDate(new Date(0), 0);
private static final SentryNanotimeDate EMPTY_NANO_TIME = new SentryNanotimeDate(0, 0);

private final boolean enabled;
protected final @NotNull AutoClosableReentrantLock lock = new AutoClosableReentrantLock();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import io.sentry.protocol.SentryId
import io.sentry.protocol.TransactionNameSource
import io.sentry.test.DeferredExecutorService
import io.sentry.test.getProperty
import java.util.Date
import java.util.concurrent.Future
import java.util.concurrent.TimeUnit
import kotlin.test.AfterTest
Expand Down Expand Up @@ -936,7 +935,7 @@ class ActivityLifecycleIntegrationTest {
sut.register(fixture.scopes, fixture.options)
sut.setFirstActivityCreated(false)

val date = SentryNanotimeDate(Date(1), 0)
val date = SentryNanotimeDate(1, 0)
setAppStartTime(date)
fixture.options.dateProvider = SentryDateProvider { date }

Expand All @@ -961,7 +960,7 @@ class ActivityLifecycleIntegrationTest {
sut.register(fixture.scopes, fixture.options)
sut.setFirstActivityCreated(false)

val date = SentryNanotimeDate(Date(1), 0)
val date = SentryNanotimeDate(1, 0)
setAppStartTime(date)

val activity = mock<Activity>()
Expand All @@ -984,8 +983,8 @@ class ActivityLifecycleIntegrationTest {
sut.register(fixture.scopes, fixture.options)
sut.setFirstActivityCreated(false)

val date = SentryNanotimeDate(Date(1), 0)
val date2 = SentryNanotimeDate(Date(2), 2)
val date = SentryNanotimeDate(1, 0)
val date2 = SentryNanotimeDate(2, 2)
setAppStartTime(date)

val activity = mock<Activity>()
Expand All @@ -1011,7 +1010,7 @@ class ActivityLifecycleIntegrationTest {
val sut = fixture.getSut { it.tracesSampleRate = 1.0 }
sut.register(fixture.scopes, fixture.options)
sut.setFirstActivityCreated(true)
val date = SentryNanotimeDate(Date(1), 0)
val date = SentryNanotimeDate(1, 0)
setAppStartTime(date)

val activity = mock<Activity>()
Expand All @@ -1030,8 +1029,8 @@ class ActivityLifecycleIntegrationTest {
sut.setFirstActivityCreated(false)

// usually set by SentryPerformanceProvider
val date = SentryNanotimeDate(Date(1), 0)
val date2 = SentryNanotimeDate(Date(2), 2)
val date = SentryNanotimeDate(1, 0)
val date2 = SentryNanotimeDate(2, 2)

val activity = mock<Activity>()
// Activity onCreate date will be used
Expand All @@ -1056,7 +1055,7 @@ class ActivityLifecycleIntegrationTest {
sut.register(fixture.scopes, fixture.options)

// usually set by SentryPerformanceProvider
val date = SentryNanotimeDate(Date(1), 0)
val date = SentryNanotimeDate(1, 0)
setAppStartTime(date)

val activity = mock<Activity>()
Expand All @@ -1080,7 +1079,7 @@ class ActivityLifecycleIntegrationTest {
sut.register(fixture.scopes, fixture.options)

// usually set by SentryPerformanceProvider
val startDate = SentryNanotimeDate(Date(1), 0)
val startDate = SentryNanotimeDate(1, 0)
setAppStartTime(startDate)
val appStartMetrics = AppStartMetrics.getInstance()
appStartMetrics.appStartType = AppStartType.WARM
Expand Down Expand Up @@ -1113,9 +1112,9 @@ class ActivityLifecycleIntegrationTest {
it.isEnableStandaloneAppStartTracing = true
}
sut.register(fixture.scopes, fixture.options)
val firstFrameDate = SentryNanotimeDate(Date(1499), 0)
val firstFrameDate = SentryNanotimeDate(1499, 0)
fixture.options.dateProvider = SentryDateProvider { firstFrameDate }
setAppStartTime(SentryNanotimeDate(Date(1), 0))
setAppStartTime(SentryNanotimeDate(1, 0))

val activity = mock<Activity>()
sut.onActivityPreCreated(activity, fixture.bundle)
Expand Down Expand Up @@ -1168,8 +1167,8 @@ class ActivityLifecycleIntegrationTest {
it.isEnableStandaloneAppStartTracing = true
}
sut.register(fixture.scopes, fixture.options)
val appStartEndDate = SentryNanotimeDate(Date(499), 0)
setAppStartTime(SentryNanotimeDate(Date(1), 0), appStartEndDate)
val appStartEndDate = SentryNanotimeDate(499, 0)
setAppStartTime(SentryNanotimeDate(1, 0), appStartEndDate)

val activity = mock<Activity>()
sut.onActivityPreCreated(activity, fixture.bundle)
Expand Down Expand Up @@ -1230,9 +1229,9 @@ class ActivityLifecycleIntegrationTest {
AppStartMetrics.getInstance().appStartSentryTraceHeader =
SentryTraceHeader(storedTraceId, SpanId(), true).value
// headless start ended right before the activity opens
AppStartMetrics.getInstance().appStartEndTime = SentryNanotimeDate(Date(0), 0)
AppStartMetrics.getInstance().appStartEndTime = SentryNanotimeDate(0, 0)
sut.register(fixture.scopes, fixture.options)
setAppStartTime(date = SentryNanotimeDate(Date(1), 0))
setAppStartTime(date = SentryNanotimeDate(1, 0))

val activity = mock<Activity>()
sut.onActivityCreated(activity, fixture.bundle)
Expand All @@ -1254,9 +1253,9 @@ class ActivityLifecycleIntegrationTest {
AppStartMetrics.getInstance().appStartSentryTraceHeader =
SentryTraceHeader(storedTraceId, SpanId(), true).value
// headless start ended at epoch, but the activity opens more than a minute later
AppStartMetrics.getInstance().appStartEndTime = SentryNanotimeDate(Date(0), 0)
AppStartMetrics.getInstance().appStartEndTime = SentryNanotimeDate(0, 0)
sut.register(fixture.scopes, fixture.options)
setAppStartTime(date = SentryNanotimeDate(Date(TimeUnit.MINUTES.toMillis(2)), 0))
setAppStartTime(date = SentryNanotimeDate(TimeUnit.MINUTES.toMillis(2), 0))

val activity = mock<Activity>()
sut.onActivityCreated(activity, fixture.bundle)
Expand Down Expand Up @@ -1389,7 +1388,7 @@ class ActivityLifecycleIntegrationTest {

// usually done by SentryPerformanceProvider, if disabled it's done by
// SentryAndroid.init
val startDate = SentryNanotimeDate(Date(1), 0)
val startDate = SentryNanotimeDate(1, 0)
setAppStartTime(startDate)
AppStartMetrics.getInstance().appStartType = AppStartType.WARM

Expand All @@ -1415,7 +1414,7 @@ class ActivityLifecycleIntegrationTest {
sut.register(fixture.scopes, fixture.options)

// usually done by SentryPerformanceProvider
val startDate = SentryNanotimeDate(Date(1), 0)
val startDate = SentryNanotimeDate(1, 0)
setAppStartTime(startDate)
AppStartMetrics.getInstance().appStartType = AppStartType.WARM
AppStartMetrics.getInstance().sdkInitTimeSpan.setStoppedAt(1234)
Expand All @@ -1439,7 +1438,7 @@ class ActivityLifecycleIntegrationTest {
sut.register(fixture.scopes, fixture.options)

// usually done by SentryPerformanceProvider
val startDate = SentryNanotimeDate(Date(1), 0)
val startDate = SentryNanotimeDate(1, 0)
setAppStartTime(startDate)
AppStartMetrics.getInstance().appStartType = AppStartType.WARM

Expand Down Expand Up @@ -1474,7 +1473,7 @@ class ActivityLifecycleIntegrationTest {
sut.register(fixture.scopes, fixture.options)
sut.setFirstActivityCreated(true)

val date = SentryNanotimeDate(Date(1), 0)
val date = SentryNanotimeDate(1, 0)
setAppStartTime()

val activity = mock<Activity>()
Expand Down Expand Up @@ -1988,14 +1987,14 @@ class ActivityLifecycleIntegrationTest {
@Test
fun `When sentry is initialized mid activity lifecycle, last paused time should be used in favor of app start time`() {
val sut = fixture.getSut(importance = RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
val now = SentryNanotimeDate(Date(1234), 456)
val now = SentryNanotimeDate(1234, 456)

fixture.options.tracesSampleRate = 1.0
fixture.options.dateProvider = SentryDateProvider { now }
sut.register(fixture.scopes, fixture.options)

// usually done by SentryPerformanceProvider
val startDate = SentryNanotimeDate(Date(5678), 910)
val startDate = SentryNanotimeDate(5678, 910)
setAppStartTime(startDate)
AppStartMetrics.getInstance().appStartType = AppStartType.COLD

Expand All @@ -2019,7 +2018,7 @@ class ActivityLifecycleIntegrationTest {
fixture.options.tracesSampleRate = 1.0
sut.register(fixture.scopes, fixture.options)

val date = SentryNanotimeDate(Date(1), 0)
val date = SentryNanotimeDate(1, 0)
setAppStartTime(date)

assertTrue(sut.activitySpanHelpers.isEmpty())
Expand All @@ -2036,8 +2035,8 @@ class ActivityLifecycleIntegrationTest {
fun `Creates activity lifecycle spans`() {
val sut = fixture.getSut()
fixture.options.tracesSampleRate = 1.0
val appStartDate = SentryNanotimeDate(Date(1), 0)
val startDate = SentryNanotimeDate(Date(2), 0)
val appStartDate = SentryNanotimeDate(1, 0)
val startDate = SentryNanotimeDate(2, 0)
val appStartMetrics = AppStartMetrics.getInstance()
val activity = mock<Activity>()
fixture.options.dateProvider = SentryDateProvider { startDate }
Expand Down Expand Up @@ -2076,7 +2075,7 @@ class ActivityLifecycleIntegrationTest {
fun `Creates activity lifecycle spans even when no app start span is available`() {
val sut = fixture.getSut()
fixture.options.tracesSampleRate = 1.0
val startDate = SentryNanotimeDate(Date(2), 0)
val startDate = SentryNanotimeDate(2, 0)
val appStartMetrics = AppStartMetrics.getInstance()
val activity = mock<Activity>()
fixture.options.dateProvider = SentryDateProvider { startDate }
Expand Down Expand Up @@ -2134,8 +2133,8 @@ class ActivityLifecycleIntegrationTest {
fun `Creates activity lifecycle spans on API lower than 29`() {
val sut = fixture.getSut(apiVersion = Build.VERSION_CODES.P)
fixture.options.tracesSampleRate = 1.0
val appStartDate = SentryNanotimeDate(Date(1), 0)
val startDate = SentryNanotimeDate(Date(2), 0)
val appStartDate = SentryNanotimeDate(1, 0)
val startDate = SentryNanotimeDate(2, 0)
val appStartMetrics = AppStartMetrics.getInstance()
val activity = mock<Activity>()
fixture.options.dateProvider = SentryDateProvider { startDate }
Expand Down Expand Up @@ -2187,8 +2186,8 @@ class ActivityLifecycleIntegrationTest {
fun `Does not add activity lifecycle spans when firstActivityCreated is true`() {
val sut = fixture.getSut()
fixture.options.tracesSampleRate = 1.0
val appStartDate = SentryNanotimeDate(Date(1), 0)
val startDate = SentryNanotimeDate(Date(2), 0)
val appStartDate = SentryNanotimeDate(1, 0)
val startDate = SentryNanotimeDate(2, 0)
val appStartMetrics = AppStartMetrics.getInstance()
val activity = mock<Activity>()
fixture.options.dateProvider = SentryDateProvider { startDate }
Expand All @@ -2209,7 +2208,7 @@ class ActivityLifecycleIntegrationTest {
fun `When firstActivityCreated is false and app start span has stopped, restart app start to current date`() {
val sut = fixture.getSut()
fixture.options.tracesSampleRate = 1.0
val appStartDate = SentryNanotimeDate(Date(1), 0)
val appStartDate = SentryNanotimeDate(1, 0)
val appStartMetrics = AppStartMetrics.getInstance()
val activity = mock<Activity>()
setAppStartTime(appStartDate)
Expand Down Expand Up @@ -2290,7 +2289,7 @@ class ActivityLifecycleIntegrationTest {
}

private fun setAppStartTime(
date: SentryDate = SentryNanotimeDate(Date(1), 0),
date: SentryDate = SentryNanotimeDate(1, 0),
stopDate: SentryDate? = null,
) {
// set by SentryPerformanceProvider so forcing it here
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import android.net.Network
import android.net.NetworkCapabilities
import android.os.Build
import io.sentry.Breadcrumb
import io.sentry.DateUtils
import io.sentry.IScopes
import io.sentry.ISentryExecutorService
import io.sentry.SentryDateProvider
Expand Down Expand Up @@ -54,8 +53,9 @@ class NetworkBreadcrumbsIntegrationTest {
executorService = executor
isEnableNetworkEventBreadcrumbs = enableNetworkEventBreadcrumbs
dateProvider = SentryDateProvider {
val nowNanos = TimeUnit.MILLISECONDS.toNanos(nowMs ?: System.currentTimeMillis())
SentryNanotimeDate(DateUtils.nanosToDate(nowNanos), nowNanos)
val nowMillis = nowMs ?: System.currentTimeMillis()
val nowNanos = TimeUnit.MILLISECONDS.toNanos(nowMillis)
SentryNanotimeDate(nowMillis, nowNanos)
}
}
return NetworkBreadcrumbsIntegration(context, buildInfo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import io.sentry.SentryNanotimeDate
import io.sentry.SpanContext
import io.sentry.android.core.internal.util.SentryFrameMetricsCollector
import io.sentry.protocol.MeasurementValue
import java.util.Date
import java.util.UUID
import java.util.concurrent.TimeUnit
import kotlin.test.Test
Expand Down Expand Up @@ -50,11 +49,12 @@ class SpanFrameMetricsCollectorTest {
val span = mock<ISpan>()
val spanContext = SpanContext("op.fake")
whenever(span.spanContext).thenReturn(spanContext)
whenever(span.startDate).thenReturn(SentryNanotimeDate(Date(), startTimeStampNanos))
whenever(span.startDate)
.thenReturn(SentryNanotimeDate(System.currentTimeMillis(), startTimeStampNanos))
whenever(span.finishDate)
.thenReturn(
if (endTimeStampNanos != null) {
SentryNanotimeDate(Date(), endTimeStampNanos)
SentryNanotimeDate(System.currentTimeMillis(), endTimeStampNanos)
} else {
null
}
Expand All @@ -69,11 +69,12 @@ class SpanFrameMetricsCollectorTest {
val span = mock<ITransaction>()
val spanContext = SpanContext("op.fake")
whenever(span.spanContext).thenReturn(spanContext)
whenever(span.startDate).thenReturn(SentryNanotimeDate(Date(), startTimeStampNanos))
whenever(span.startDate)
.thenReturn(SentryNanotimeDate(System.currentTimeMillis(), startTimeStampNanos))
whenever(span.finishDate)
.thenReturn(
if (endTimeStampNanos != null) {
SentryNanotimeDate(Date(), endTimeStampNanos)
SentryNanotimeDate(System.currentTimeMillis(), endTimeStampNanos)
} else {
null
}
Expand Down Expand Up @@ -438,8 +439,8 @@ class SpanFrameMetricsCollectorTest {
@Test
fun `SentryNanoDate diff does nano precision`() {
// having this in here, as SpanFrameMetricsCollector relies on this behavior
val a = SentryNanotimeDate(Date(1234), 567)
val b = SentryNanotimeDate(Date(1234), 0)
val a = SentryNanotimeDate(1234, 567)
val b = SentryNanotimeDate(1234, 0)

assertEquals(567, a.diff(b))
}
Expand Down
Loading
Loading