diff --git a/CHANGELOG.md b/CHANGELOG.md index 09622493a2..eeea71a8a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- Order breadcrumbs by the timestamp they carry rather than by when they were created in the current process, so breadcrumbs restored from disk or handed over by a hybrid SDK no longer sort as if they had just happened ([#6097](https://github.com/getsentry/sentry-java/pull/6097)) + ## 8.56.0 ### Behavioral Changes diff --git a/sentry/src/main/java/io/sentry/Breadcrumb.java b/sentry/src/main/java/io/sentry/Breadcrumb.java index fff6954ee5..9a91b1630d 100644 --- a/sentry/src/main/java/io/sentry/Breadcrumb.java +++ b/sentry/src/main/java/io/sentry/Breadcrumb.java @@ -26,7 +26,14 @@ public final class Breadcrumb implements JsonUnknown, JsonSerializable, Comparab /** A timestamp representing when the breadcrumb occurred as java.util.Date. */ private @Nullable Date timestamp; - private final @NotNull Long nanos; + /** + * The tick this breadcrumb was created at, used to order breadcrumbs that share a timestamp. + * + *
Null for a breadcrumb rebuilt from a serialized one. A tick is a reading of a counter whose
+ * origin is this process run, so a tick from an earlier run is a number from an unrelated origin
+ * rather than a position in this run's order.
+ */
+ private final @Nullable Long creationTick;
/** If a message is provided, its rendered as text and the whitespace is preserved. */
private @Nullable String message;
@@ -59,21 +66,33 @@ public final class Breadcrumb implements JsonUnknown, JsonSerializable, Comparab
*
* @param timestamp the timestamp
*/
- @SuppressWarnings("JavaUtilDate")
public Breadcrumb(final @NotNull Date timestamp) {
- this.nanos = System.nanoTime();
+ this(timestamp, System.nanoTime());
+ }
+
+ @SuppressWarnings("JavaUtilDate")
+ private Breadcrumb(final @NotNull Date timestamp, final @Nullable Long creationTick) {
+ this.creationTick = creationTick;
this.timestamp = timestamp;
this.timestampMs = null;
}
+ /**
+ * A breadcrumb rebuilt from a serialized one — read back from disk, or handed over by a hybrid
+ * SDK. It carries the timestamp it was serialized with and no creation tick.
+ */
+ static @NotNull Breadcrumb deserialized(final @NotNull Date timestamp) {
+ return new Breadcrumb(timestamp, null);
+ }
+
public Breadcrumb(final long timestamp) {
- this.nanos = System.nanoTime();
+ this.creationTick = System.nanoTime();
this.timestampMs = timestamp;
this.timestamp = null;
}
Breadcrumb(final @NotNull Breadcrumb breadcrumb) {
- this.nanos = System.nanoTime();
+ this.creationTick = breadcrumb.creationTick;
this.timestamp = breadcrumb.timestamp;
this.timestampMs = breadcrumb.timestampMs;
this.message = breadcrumb.message;
@@ -170,7 +189,7 @@ public static Breadcrumb fromMap(
}
}
- final Breadcrumb breadcrumb = new Breadcrumb(timestamp);
+ final Breadcrumb breadcrumb = Breadcrumb.deserialized(timestamp);
breadcrumb.message = message;
breadcrumb.type = type;
if (data != null) {
@@ -831,8 +850,21 @@ public void setUnknown(@Nullable Map