Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Faster ID generation #3818

Merged
merged 36 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
22029c1
lazy uuid generation for SentryId and SpanId
lbloder Oct 7, 2024
f947f82
add changelog
lbloder Oct 7, 2024
debd140
Merge branch '8.x.x' into feat/lazy-span-id-v8
adinauer Oct 9, 2024
e6df0ad
add tests for lazy init, rework SentryId to cache string result
lbloder Oct 11, 2024
8a93fec
Merge branch '8.x.x' into feat/lazy-span-id-v8
lbloder Oct 11, 2024
fe8ccb0
Merge branch '8.x.x' into feat/lazy-span-id-v8
lbloder Oct 15, 2024
28b5bde
Merge branch '8.x.x' into feat/lazy-span-id-v8
lbloder Oct 18, 2024
f2fba85
fix changelog
lbloder Oct 18, 2024
3e1a32c
Merge branch '8.x.x' into feat/lazy-span-id-v8
lbloder Oct 21, 2024
c7ab294
Update sentry/src/main/java/io/sentry/protocol/SentryId.java
lbloder Oct 22, 2024
f1e66b2
Update sentry/src/main/java/io/sentry/protocol/SentryId.java
lbloder Oct 22, 2024
76b23c8
Update sentry/src/main/java/io/sentry/protocol/SentryId.java
lbloder Oct 22, 2024
8599535
Update sentry/src/main/java/io/sentry/protocol/SentryId.java
lbloder Oct 22, 2024
3bae1d7
Update sentry/src/main/java/io/sentry/protocol/SentryId.java
lbloder Oct 22, 2024
edba0c7
Format code
getsentry-bot Oct 22, 2024
c18a74d
Add object comparison to SpanFrameMetricsCollector only check for tim…
lbloder Oct 22, 2024
35b17db
Merge branch 'feat/lazy-span-id-v8' of github.com:getsentry/sentry-ja…
lbloder Oct 22, 2024
a50d881
add proposed SentryUUID class
lbloder Oct 22, 2024
149d59c
[WIP] use SentryUUID instead of UUID.random().toString
lbloder Oct 22, 2024
6418a33
Format code
getsentry-bot Oct 23, 2024
5314e83
split SentryUUID internals into separate classes for easier attribution
lbloder Oct 29, 2024
58a00c4
Merge branch '8.x.x' into feat/lazy-span-id-v8
lbloder Oct 29, 2024
097738b
add changelog
lbloder Oct 29, 2024
3518fce
Merge branch 'feat/lazy-span-id-v8' into feat/fast-id-generation
lbloder Oct 29, 2024
d11c3cc
fix tests
lbloder Oct 29, 2024
1ea4212
Merge branch '8.x.x' into feat/fast-id-generation
lbloder Oct 29, 2024
81a3bdb
fix SpanId.EMPTY_ID
lbloder Oct 29, 2024
5d00ae5
Merge branch '8.x.x' into feat/fast-id-generation
lbloder Nov 4, 2024
fac412e
test normalized is never called in no-arg constructor, only called on…
lbloder Nov 8, 2024
9f360d1
Merge branch '8.x.x' into feat/fast-id-generation
lbloder Nov 8, 2024
30b2602
fix test
lbloder Nov 8, 2024
05540a3
Format code
getsentry-bot Nov 8, 2024
143c26e
use new Random Generator
lbloder Nov 8, 2024
57d0a9b
Merge branch 'feat/fast-id-generation' of github.com:getsentry/sentry…
lbloder Nov 8, 2024
45c3cbe
fix Sentry Empty ID, replace dashes if 36 char uuid String is passed …
lbloder Nov 8, 2024
5c2c580
fix Tests for SpanId, add tests for SentryUUID and UUIDStringUtils
lbloder Nov 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Add `globalHubMode` to options ([#3805](https://github.com/getsentry/sentry-java/pull/3805))
- `globalHubMode` used to only be a param on `Sentry.init`. To make it easier to be used in e.g. Desktop environments, we now additionally added it as an option on SentryOptions that can also be set via `sentry.properties`.
- If both the param on `Sentry.init` and the option are set, the option will win. By default the option is set to `null` meaning whatever is passed to `Sentry.init` takes effect.
- Lazy uuid generation for SentryId and SpanId ([#3770](https://github.com/getsentry/sentry-java/pull/3770))

## 8.0.0-beta.1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.sentry.MemoryCollectionData;
import io.sentry.PerformanceCollectionData;
import io.sentry.SentryLevel;
import io.sentry.SentryUUID;
import io.sentry.android.core.internal.util.SentryFrameMetricsCollector;
import io.sentry.profilemeasurements.ProfileMeasurement;
import io.sentry.profilemeasurements.ProfileMeasurementValue;
Expand All @@ -24,7 +25,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -137,7 +137,7 @@ public AndroidProfiler(
if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.LOLLIPOP) return null;

// We create a file with a uuid name, so no need to check if it already exists
traceFile = new File(traceFilesDir, UUID.randomUUID() + ".trace");
traceFile = new File(traceFilesDir, SentryUUID.generateSentryId() + ".trace");

measurementsMap.clear();
screenFrameRateMeasurements.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

import android.content.Context;
import io.sentry.ISentryLifecycleToken;
import io.sentry.SentryUUID;
import io.sentry.util.AutoClosableReentrantLock;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.charset.Charset;
import java.util.UUID;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
Expand Down Expand Up @@ -65,7 +65,7 @@ public static String id(final @NotNull Context context) throws RuntimeException
static @NotNull String writeInstallationFile(final @NotNull File installation)
throws IOException {
try (final OutputStream out = new FileOutputStream(installation)) {
final String id = UUID.randomUUID().toString();
final String id = SentryUUID.generateSentryId();
out.write(id.getBytes(UTF_8));
out.flush();
return id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,19 @@ public class SpanFrameMetricsCollector
private final @NotNull SortedSet<ISpan> runningSpans =
new TreeSet<>(
(o1, o2) -> {
if (o1 == o2) {
return 0;
}
int timeDiff = o1.getStartDate().compareTo(o2.getStartDate());
if (timeDiff != 0) {
return timeDiff;
} else {
// TreeSet uses compareTo to check for duplicates, so ensure that
// two non-equal spans with the same start date are not considered equal
return o1.getSpanContext()
.getSpanId()
.toString()
.compareTo(o2.getSpanContext().getSpanId().toString());
}
// TreeSet uses compareTo to check for duplicates, so ensure that
// two non-equal spans with the same start date are not considered equal
return o1.getSpanContext()
.getSpanId()
.toString()
.compareTo(o2.getSpanContext().getSpanId().toString());
});

// all collected frames, sorted by frame end time
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
import io.sentry.ILogger;
import io.sentry.SentryLevel;
import io.sentry.SentryOptions;
import io.sentry.SentryUUID;
import io.sentry.android.core.BuildInfoProvider;
import io.sentry.android.core.ContextUtils;
import io.sentry.util.Objects;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -262,7 +262,7 @@ public void onActivityDestroyed(@NotNull Activity activity) {}
if (!isAvailable) {
return null;
}
final String uid = UUID.randomUUID().toString();
final String uid = SentryUUID.generateSentryId();
listenerMap.put(uid, listener);
trackCurrentWindow();
return uid;
Expand Down
20 changes: 20 additions & 0 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -3265,6 +3265,11 @@ public final class io/sentry/SentryTracer : io/sentry/ITransaction {
public fun updateEndDate (Lio/sentry/SentryDate;)Z
}

public final class io/sentry/SentryUUID {
public static fun generateSentryId ()Ljava/lang/String;
public static fun generateSpanId ()Ljava/lang/String;
}

public final class io/sentry/SentryWrapper {
public fun <init> ()V
public static fun wrapCallable (Ljava/util/concurrent/Callable;)Ljava/util/concurrent/Callable;
Expand Down Expand Up @@ -6151,6 +6156,7 @@ public final class io/sentry/util/SpanUtils {
}

public final class io/sentry/util/StringUtils {
public static final field PROPER_NIL_UUID Ljava/lang/String;
public static fun byteCountToString (J)Ljava/lang/String;
public static fun calculateStringHash (Ljava/lang/String;Lio/sentry/ILogger;)Ljava/lang/String;
public static fun camelCase (Ljava/lang/String;)Ljava/lang/String;
Expand Down Expand Up @@ -6179,6 +6185,20 @@ public final class io/sentry/util/TracingUtils$TracingHeaders {
public fun getSentryTraceHeader ()Lio/sentry/SentryTraceHeader;
}

public final class io/sentry/util/UUIDGenerator {
public fun <init> ()V
public static fun randomHalfLengthUUID ()J
public static fun randomUUID ()Ljava/util/UUID;
}

public final class io/sentry/util/UUIDStringUtils {
public fun <init> ()V
public static fun toSentryIdString (JJ)Ljava/lang/String;
public static fun toSentryIdString (Ljava/util/UUID;)Ljava/lang/String;
public static fun toSentrySpanIdString (J)Ljava/lang/String;
public static fun toSentrySpanIdString (Ljava/util/UUID;)Ljava/lang/String;
}

public final class io/sentry/util/UrlUtils {
public static final field SENSITIVE_DATA_SUBSTITUTE Ljava/lang/String;
public fun <init> ()V
Expand Down
3 changes: 1 addition & 2 deletions sentry/src/main/java/io/sentry/ProfilingTraceData.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import org.jetbrains.annotations.ApiStatus;
Expand Down Expand Up @@ -154,7 +153,7 @@ public ProfilingTraceData(
// Stacktrace context
this.transactionId = transactionId;
this.traceId = traceId;
this.profileId = UUID.randomUUID().toString();
this.profileId = SentryUUID.generateSentryId();
this.environment = environment != null ? environment : DEFAULT_ENVIRONMENT;
this.truncationReason = truncationReason;
if (!isTruncationReasonValid()) {
Expand Down
23 changes: 23 additions & 0 deletions sentry/src/main/java/io/sentry/SentryUUID.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.sentry;

import io.sentry.util.UUIDGenerator;
import io.sentry.util.UUIDStringUtils;

/**
* SentryUUID is a utility class for generating Sentry-specific ID Strings. It provides methods for
* generating Sentry IDs and Sentry Span IDs.
*/
public final class SentryUUID {

private SentryUUID() {
// A private constructor prevents callers from accidentally instantiating FastUUID objects
}

public static String generateSentryId() {
return UUIDStringUtils.toSentryIdString(UUIDGenerator.randomUUID());
}

public static String generateSpanId() {
return UUIDStringUtils.toSentrySpanIdString(UUIDGenerator.randomHalfLengthUUID());
}
}
28 changes: 13 additions & 15 deletions sentry/src/main/java/io/sentry/SpanId.java
Original file line number Diff line number Diff line change
@@ -1,52 +1,50 @@
package io.sentry;

import io.sentry.util.Objects;
import io.sentry.util.StringUtils;
import static io.sentry.util.StringUtils.PROPER_NIL_UUID;

import io.sentry.util.LazyEvaluator;
import java.io.IOException;
import java.util.UUID;
import java.util.Objects;
import org.jetbrains.annotations.NotNull;

public final class SpanId implements JsonSerializable {
public static final SpanId EMPTY_ID = new SpanId(new UUID(0, 0));
public static final SpanId EMPTY_ID = new SpanId(PROPER_NIL_UUID.replace("-", ""));

private final @NotNull String value;
private final @NotNull LazyEvaluator<String> lazyValue;

public SpanId(final @NotNull String value) {
this.value = Objects.requireNonNull(value, "value is required");
Objects.requireNonNull(value, "value is required");
this.lazyValue = new LazyEvaluator<>(() -> value);
}

public SpanId() {
this(UUID.randomUUID());
}

private SpanId(final @NotNull UUID uuid) {
this(StringUtils.normalizeUUID(uuid.toString()).replace("-", "").substring(0, 16));
this.lazyValue = new LazyEvaluator<>(SentryUUID::generateSpanId);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SpanId spanId = (SpanId) o;
return value.equals(spanId.value);
return lazyValue.getValue().equals(spanId.lazyValue.getValue());
}

@Override
public int hashCode() {
return value.hashCode();
return lazyValue.getValue().hashCode();
}

@Override
public String toString() {
return this.value;
return lazyValue.getValue();
}

// JsonElementSerializer

@Override
public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger)
throws IOException {
writer.value(value);
writer.value(lazyValue.getValue());
}

// JsonElementDeserializer
Expand Down
4 changes: 2 additions & 2 deletions sentry/src/main/java/io/sentry/cache/EnvelopeCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import io.sentry.SentryItemType;
import io.sentry.SentryLevel;
import io.sentry.SentryOptions;
import io.sentry.SentryUUID;
import io.sentry.Session;
import io.sentry.UncaughtExceptionHandlerIntegration;
import io.sentry.hints.AbnormalExit;
Expand Down Expand Up @@ -45,7 +46,6 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.WeakHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -368,7 +368,7 @@ public void discard(final @NotNull SentryEnvelope envelope) {
if (fileNameMap.containsKey(envelope)) {
fileName = fileNameMap.get(envelope);
} else {
fileName = UUID.randomUUID() + SUFFIX_ENVELOPE_FILE;
fileName = SentryUUID.generateSentryId() + SUFFIX_ENVELOPE_FILE;
fileNameMap.put(envelope, fileName);
}

Expand Down
50 changes: 22 additions & 28 deletions sentry/src/main/java/io/sentry/protocol/SentryId.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,69 +5,63 @@
import io.sentry.JsonSerializable;
import io.sentry.ObjectReader;
import io.sentry.ObjectWriter;
import io.sentry.SentryUUID;
import io.sentry.util.LazyEvaluator;
import io.sentry.util.StringUtils;
import java.io.IOException;
import java.util.UUID;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public final class SentryId implements JsonSerializable {
private final @NotNull UUID uuid;

public static final SentryId EMPTY_ID = new SentryId(new UUID(0, 0));
public static final SentryId EMPTY_ID = new SentryId(StringUtils.PROPER_NIL_UUID);

private final @NotNull LazyEvaluator<String> lazyStringValue;

public SentryId() {
this((UUID) null);
}

public SentryId(@Nullable UUID uuid) {
if (uuid == null) {
uuid = UUID.randomUUID();
if (uuid != null) {
this.lazyStringValue = new LazyEvaluator<>(() -> normalize(uuid.toString()));
} else {
this.lazyStringValue = new LazyEvaluator<>(SentryUUID::generateSentryId);
}
this.uuid = uuid;
}

public SentryId(final @NotNull String sentryIdString) {
this.uuid = fromStringSentryId(StringUtils.normalizeUUID(sentryIdString));
final @NotNull String normalized = StringUtils.normalizeUUID(sentryIdString);
if (normalized.length() != 32 && normalized.length() != 36) {
throw new IllegalArgumentException(
"String representation of SentryId has either 32 (UUID no dashes) "
+ "or 36 characters long (completed UUID). Received: "
+ sentryIdString);
}
this.lazyStringValue = new LazyEvaluator<>(() -> normalize(normalized));
}

@Override
public String toString() {
return StringUtils.normalizeUUID(uuid.toString()).replace("-", "");
return lazyStringValue.getValue();
}

@Override
public boolean equals(final @Nullable Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SentryId sentryId = (SentryId) o;
return uuid.compareTo(sentryId.uuid) == 0;
return lazyStringValue.getValue().equals(sentryId.lazyStringValue.getValue());
}

@Override
public int hashCode() {
return uuid.hashCode();
return lazyStringValue.getValue().hashCode();
}

private @NotNull UUID fromStringSentryId(@NotNull String sentryIdString) {
if (sentryIdString.length() == 32) {
// expected format, SentryId is a UUID without dashes
sentryIdString =
new StringBuilder(sentryIdString)
.insert(8, "-")
.insert(13, "-")
.insert(18, "-")
.insert(23, "-")
.toString();
}
if (sentryIdString.length() != 36) {
throw new IllegalArgumentException(
"String representation of SentryId has either 32 (UUID no dashes) "
+ "or 36 characters long (completed UUID). Received: "
+ sentryIdString);
}

return UUID.fromString(sentryIdString);
private @NotNull String normalize(@NotNull String uuidString) {
return StringUtils.normalizeUUID(uuidString).replace("-", "");
}

// JsonSerializable
Expand Down
2 changes: 1 addition & 1 deletion sentry/src/main/java/io/sentry/util/StringUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public final class StringUtils {

private static final Charset UTF_8 = Charset.forName("UTF-8");

public static final String PROPER_NIL_UUID = "00000000-0000-0000-0000-000000000000";
private static final String CORRUPTED_NIL_UUID = "0000-0000";
private static final String PROPER_NIL_UUID = "00000000-0000-0000-0000-000000000000";
private static final @NotNull Pattern PATTERN_WORD_SNAKE_CASE = Pattern.compile("[\\W_]+");

private StringUtils() {}
Expand Down
Loading
Loading