Skip to content

Commit

Permalink
Merge 8276f08 into 5183da9
Browse files Browse the repository at this point in the history
  • Loading branch information
adinauer authored Oct 30, 2024
2 parents 5183da9 + 8276f08 commit d1647d3
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import io.sentry.protocol.User;
import io.sentry.util.HintUtils;
import io.sentry.util.Random;
import io.sentry.util.SentryRandom;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -180,7 +181,7 @@ private boolean sampleReplay(final @NotNull SentryEvent event) {

try {
// we have to sample here with the old sample rate, because it may change between app launches
final @NotNull Random random = this.random != null ? this.random : new Random();
final @NotNull Random random = this.random != null ? this.random : SentryRandom.current();
final double replayErrorSampleRateDouble = Double.parseDouble(replayErrorSampleRate);
if (replayErrorSampleRateDouble < random.nextDouble()) {
options
Expand Down
5 changes: 5 additions & 0 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -5829,6 +5829,11 @@ public final class io/sentry/util/SampleRateUtils {
public static fun isValidTracesSampleRate (Ljava/lang/Double;Z)Z
}

public final class io/sentry/util/SentryRandom {
public fun <init> ()V
public static fun current ()Lio/sentry/util/Random;
}

public final class io/sentry/util/StringUtils {
public static fun byteCountToString (J)Ljava/lang/String;
public static fun calculateStringHash (Ljava/lang/String;Lio/sentry/ILogger;)Ljava/lang/String;
Expand Down
5 changes: 2 additions & 3 deletions sentry/src/main/java/io/sentry/SentryClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import io.sentry.util.HintUtils;
import io.sentry.util.Objects;
import io.sentry.util.Random;
import io.sentry.util.SentryRandom;
import io.sentry.util.TracingUtils;
import java.io.Closeable;
import java.io.IOException;
Expand All @@ -40,7 +41,6 @@ public final class SentryClient implements ISentryClient, IMetricsClient {

private final @NotNull SentryOptions options;
private final @NotNull ITransport transport;
private final @Nullable Random random;
private final @NotNull SortBreadcrumbsByDate sortBreadcrumbsByDate = new SortBreadcrumbsByDate();
private final @NotNull IMetricsAggregator metricsAggregator;

Expand All @@ -66,8 +66,6 @@ public boolean isEnabled() {
options.isEnableMetrics()
? new MetricsAggregator(options, this)
: NoopMetricsAggregator.getInstance();

this.random = options.getSampleRate() == null ? null : new Random();
}

private boolean shouldApplyScopeData(
Expand Down Expand Up @@ -1183,6 +1181,7 @@ public boolean isHealthy() {
}

private boolean sample() {
final @Nullable Random random = options.getSampleRate() == null ? null : SentryRandom.current();
// https://docs.sentry.io/development/sdk-dev/features/#event-sampling
if (options.getSampleRate() != null && random != null) {
final double sampling = options.getSampleRate();
Expand Down
16 changes: 12 additions & 4 deletions sentry/src/main/java/io/sentry/TracesSampler.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.sentry.util.Objects;
import io.sentry.util.Random;
import io.sentry.util.SentryRandom;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
Expand All @@ -10,14 +11,14 @@ final class TracesSampler {
private static final @NotNull Double DEFAULT_TRACES_SAMPLE_RATE = 1.0;

private final @NotNull SentryOptions options;
private final @NotNull Random random;
private final @Nullable Random random;

public TracesSampler(final @NotNull SentryOptions options) {
this(Objects.requireNonNull(options, "options are required"), new Random());
this(Objects.requireNonNull(options, "options are required"), null);
}

@TestOnly
TracesSampler(final @NotNull SentryOptions options, final @NotNull Random random) {
TracesSampler(final @NotNull SentryOptions options, final @Nullable Random random) {
this.options = options;
this.random = random;
}
Expand Down Expand Up @@ -90,6 +91,13 @@ TracesSamplingDecision sample(final @NotNull SamplingContext samplingContext) {
}

private boolean sample(final @NotNull Double aDouble) {
return !(aDouble < random.nextDouble());
return !(aDouble < getRandom().nextDouble());
}

private Random getRandom() {
if (random == null) {
return SentryRandom.current();
}
return random;
}
}
20 changes: 20 additions & 0 deletions sentry/src/main/java/io/sentry/util/SentryRandom.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.sentry.util;

import org.jetbrains.annotations.NotNull;

public final class SentryRandom {

private static final SentryRandomThreadLocal instance = new SentryRandomThreadLocal();

public static @NotNull Random current() {
return instance.get();
}

private static class SentryRandomThreadLocal extends ThreadLocal<Random> {

@Override
protected Random initialValue() {
return new Random();
}
}
}
45 changes: 45 additions & 0 deletions sentry/src/test/java/io/sentry/util/SentryRandomTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.sentry.util

import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals

class SentryRandomTest {

@Test
fun `thread local creates a new instance per thread but keeps re-using it for the same thread`() {
val mainThreadRandom1 = SentryRandom.current()
val mainThreadRandom2 = SentryRandom.current()
assertEquals(mainThreadRandom1.toString(), mainThreadRandom2.toString())

var thread1Random1: Random? = null
var thread1Random2: Random? = null

val thread1 = Thread() {
thread1Random1 = SentryRandom.current()
thread1Random2 = SentryRandom.current()
}

var thread2Random1: Random? = null
var thread2Random2: Random? = null

val thread2 = Thread() {
thread2Random1 = SentryRandom.current()
thread2Random2 = SentryRandom.current()
}

thread1.start()
thread2.start()
thread1.join()
thread2.join()

assertEquals(thread1Random1.toString(), thread1Random2.toString())
assertNotEquals(mainThreadRandom1.toString(), thread1Random1.toString())

assertEquals(thread2Random1.toString(), thread2Random2.toString())
assertNotEquals(mainThreadRandom1.toString(), thread2Random1.toString())

val mainThreadRandom3 = SentryRandom.current()
assertEquals(mainThreadRandom1.toString(), mainThreadRandom3.toString())
}
}

0 comments on commit d1647d3

Please sign in to comment.