From b2883e5fe6478ffd0543f509c936ec222abbe577 Mon Sep 17 00:00:00 2001 From: Otmar Ertl Date: Tue, 3 Oct 2023 21:07:41 +0200 Subject: [PATCH 01/12] consistent sampler prototypes using 56 bits of randomness following https://github.com/open-telemetry/oteps/pull/235 --- consistent-sampling/build.gradle.kts | 1 + .../ConsistentAlwaysOffSampler.java | 26 ++ .../ConsistentAlwaysOnSampler.java | 28 ++ .../ConsistentComposedAndSampler.java | 57 ++++ .../ConsistentComposedOrSampler.java | 63 ++++ .../ConsistentFixedThresholdSampler.java | 33 ++ .../ConsistentParentBasedSampler.java | 52 +++ .../ConsistentRateLimitingSampler.java | 157 +++++++++ .../consistent2/ConsistentSampler.java | 319 ++++++++++++++++++ .../consistent2/ConsistentSamplingUtil.java | 116 +++++++ .../sampler/consistent2/OtelTraceState.java | 281 +++++++++++++++ .../consistent2/RandomValueGenerator.java | 24 ++ .../consistent2/RandomValueGenerators.java | 25 ++ .../ConsistentFixedThresholdSamplerTest.java | 100 ++++++ .../ConsistentRateLimitingSamplerTest.java | 214 ++++++++++++ .../consistent2/ConsistentSamplerTest.java | 261 ++++++++++++++ .../ConsistentSamplingUtilTest.java | 77 +++++ .../consistent2/OtelTraceStateTest.java | 75 ++++ 18 files changed, 1909 insertions(+) create mode 100644 consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOffSampler.java create mode 100644 consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOnSampler.java create mode 100644 consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentComposedAndSampler.java create mode 100644 consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentComposedOrSampler.java create mode 100644 consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSampler.java create mode 100644 consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentParentBasedSampler.java create mode 100644 consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSampler.java create mode 100644 consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java create mode 100644 consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java create mode 100644 consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceState.java create mode 100644 consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGenerator.java create mode 100644 consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGenerators.java create mode 100644 consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSamplerTest.java create mode 100644 consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSamplerTest.java create mode 100644 consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplerTest.java create mode 100644 consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java create mode 100644 consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceStateTest.java diff --git a/consistent-sampling/build.gradle.kts b/consistent-sampling/build.gradle.kts index 65f9fc25e..cfd04d697 100644 --- a/consistent-sampling/build.gradle.kts +++ b/consistent-sampling/build.gradle.kts @@ -5,6 +5,7 @@ plugins { description = "Sampler and exporter implementations for consistent sampling" otelJava.moduleName.set("io.opentelemetry.contrib.sampler.consistent") +otelJava.moduleName.set("io.opentelemetry.contrib.sampler.consistent2") dependencies { api("io.opentelemetry:opentelemetry-sdk-trace") diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOffSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOffSampler.java new file mode 100644 index 000000000..6f6f3a033 --- /dev/null +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOffSampler.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import javax.annotation.concurrent.Immutable; + +@Immutable +final class ConsistentAlwaysOffSampler extends ConsistentSampler { + + ConsistentAlwaysOffSampler(RandomValueGenerator randomValueGenerator) { + super(randomValueGenerator); + } + + @Override + protected long getThreshold(long parentThreshold, boolean isRoot) { + return 0; + } + + @Override + public String getDescription() { + return "ConsistentAlwaysOffSampler"; + } +} diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOnSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOnSampler.java new file mode 100644 index 000000000..43e359a34 --- /dev/null +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOnSampler.java @@ -0,0 +1,28 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxThreshold; + +import javax.annotation.concurrent.Immutable; + +@Immutable +final class ConsistentAlwaysOnSampler extends ConsistentSampler { + + ConsistentAlwaysOnSampler(RandomValueGenerator randomValueGenerator) { + super(randomValueGenerator); + } + + @Override + protected long getThreshold(long parentThreshold, boolean isRoot) { + return getMaxThreshold(); + } + + @Override + public String getDescription() { + return "ConsistentAlwaysOnSampler"; + } +} diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentComposedAndSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentComposedAndSampler.java new file mode 100644 index 000000000..2c6e608e6 --- /dev/null +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentComposedAndSampler.java @@ -0,0 +1,57 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidThreshold; +import static java.util.Objects.requireNonNull; + +import javax.annotation.concurrent.Immutable; + +/** + * A consistent sampler composed of two consistent samplers. + * + *

This sampler samples if both samplers would sample. + */ +@Immutable +final class ConsistentComposedAndSampler extends ConsistentSampler { + + private final ConsistentSampler sampler1; + private final ConsistentSampler sampler2; + private final String description; + + ConsistentComposedAndSampler( + ConsistentSampler sampler1, + ConsistentSampler sampler2, + RandomValueGenerator randomValueGenerator) { + super(randomValueGenerator); + this.sampler1 = requireNonNull(sampler1); + this.sampler2 = requireNonNull(sampler2); + this.description = + "ConsistentComposedAndSampler{" + + "sampler1=" + + sampler1.getDescription() + + ",sampler2=" + + sampler2.getDescription() + + '}'; + } + + @Override + protected long getThreshold(long parentThreshold, boolean isRoot) { + long threshold1 = sampler1.getThreshold(parentThreshold, isRoot); + long threshold2 = sampler2.getThreshold(parentThreshold, isRoot); + if (isValidThreshold(threshold1) && isValidThreshold(threshold2)) { + return Math.min(threshold1, threshold2); + } else { + return getInvalidThreshold(); + } + } + + @Override + public String getDescription() { + return description; + } +} diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentComposedOrSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentComposedOrSampler.java new file mode 100644 index 000000000..497ccb878 --- /dev/null +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentComposedOrSampler.java @@ -0,0 +1,63 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidThreshold; +import static java.util.Objects.requireNonNull; + +import javax.annotation.concurrent.Immutable; + +/** + * A consistent sampler composed of two consistent samplers. + * + *

This sampler samples if any of the two samplers would sample. + */ +@Immutable +final class ConsistentComposedOrSampler extends ConsistentSampler { + + private final ConsistentSampler sampler1; + private final ConsistentSampler sampler2; + private final String description; + + ConsistentComposedOrSampler( + ConsistentSampler sampler1, + ConsistentSampler sampler2, + RandomValueGenerator randomValueGenerator) { + super(randomValueGenerator); + this.sampler1 = requireNonNull(sampler1); + this.sampler2 = requireNonNull(sampler2); + this.description = + "ConsistentComposedOrSampler{" + + "sampler1=" + + sampler1.getDescription() + + ",sampler2=" + + sampler2.getDescription() + + '}'; + } + + @Override + protected long getThreshold(long parentThreshold, boolean isRoot) { + long threshold1 = sampler1.getThreshold(parentThreshold, isRoot); + long threshold2 = sampler2.getThreshold(parentThreshold, isRoot); + if (isValidThreshold(threshold1)) { + if (isValidThreshold(threshold2)) { + return Math.max(threshold1, threshold2); + } + return threshold1; + } else { + if (isValidThreshold(threshold2)) { + return threshold2; + } + return getInvalidThreshold(); + } + } + + @Override + public String getDescription() { + return description; + } +} diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSampler.java new file mode 100644 index 000000000..e832b647d --- /dev/null +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSampler.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.checkThreshold; + +public class ConsistentFixedThresholdSampler extends ConsistentSampler { + + private final long threshold; + private final String description; + + protected ConsistentFixedThresholdSampler( + long threshold, RandomValueGenerator randomValueGenerator) { + super(randomValueGenerator); + checkThreshold(threshold); + this.threshold = threshold; + this.description = + "ConsistentFixedThresholdSampler{threshold=" + Long.toHexString(threshold) + "}"; + } + + @Override + public String getDescription() { + return description; + } + + @Override + protected long getThreshold(long parentThreshold, boolean isRoot) { + return threshold; + } +} diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentParentBasedSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentParentBasedSampler.java new file mode 100644 index 000000000..12c5d412b --- /dev/null +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentParentBasedSampler.java @@ -0,0 +1,52 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; +import static java.util.Objects.requireNonNull; + +import javax.annotation.concurrent.Immutable; + +/** + * A consistent sampler that makes the same sampling decision as the parent. For root spans the + * sampling decision is delegated to the root sampler. + */ +@Immutable +final class ConsistentParentBasedSampler extends ConsistentSampler { + + private final ConsistentSampler rootSampler; + + private final String description; + + /** + * Constructs a new consistent parent based sampler using the given root sampler and the given + * thread-safe random generator. + * + * @param rootSampler the root sampler + * @param randomValueGenerator the function to use for generating the r-value + */ + ConsistentParentBasedSampler( + ConsistentSampler rootSampler, RandomValueGenerator randomValueGenerator) { + super(randomValueGenerator); + this.rootSampler = requireNonNull(rootSampler); + this.description = + "ConsistentParentBasedSampler{rootSampler=" + rootSampler.getDescription() + '}'; + } + + @Override + protected long getThreshold(long parentThreshold, boolean isRoot) { + if (isRoot) { + return rootSampler.getThreshold(getInvalidThreshold(), isRoot); + } else { + return parentThreshold; + } + } + + @Override + public String getDescription() { + return description; + } +} diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSampler.java new file mode 100644 index 000000000..154b22103 --- /dev/null +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSampler.java @@ -0,0 +1,157 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxThreshold; +import static java.util.Objects.requireNonNull; + +import io.opentelemetry.sdk.trace.samplers.Sampler; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.LongSupplier; +import javax.annotation.concurrent.Immutable; + +/** + * This consistent {@link Sampler} adjusts the sampling probability dynamically to limit the rate of + * sampled spans. + * + *

This sampler uses exponential smoothing to estimate on irregular data (compare Wright, David + * J. "Forecasting data published at irregular time intervals using an extension of Holt's method." + * Management science 32.4 (1986): 499-510.) to estimate the average waiting time between spans + * which further allows to estimate the current rate of spans. In the paper, Eq. 2 defines the + * weighted average of a sequence of data + * + *

{@code ..., X(n-2), X(n-1), X(n)} + * + *

at irregular times + * + *

{@code ..., t(n-2), t(n-1), t(n)} + * + *

as + * + *

{@code E(X(n)) := A(n) * V(n)}. + * + *

{@code A(n)} and {@code V(n)} are computed recursively using Eq. 5 and Eq. 6 given by + * + *

{@code A(n) = b(n) * A(n-1) + X(n)} and {@code V(n) = V(n-1) / (b(n) + V(n-1))} + * + *

where + * + *

{@code b(n) := (1 - a)^(t(n) - t(n-1)) = exp((t(n) - t(n-1)) * ln(1 - a))}. + * + *

Introducing + * + *

{@code C(n) := 1 / V(n)} + * + *

the recursion can be rewritten as + * + *

{@code A(n) = b(n) * A(n-1) + X(n)} and {@code C(n) = b(n) * C(n-1) + 1}. + * + *

+ * + *

Since we want to estimate the average waiting time, our data is given by + * + *

{@code X(n) := t(n) - t(n-1)}. + * + *

+ * + *

The following correspondence is used for the implementation: + * + *

+ */ +final class ConsistentRateLimitingSampler extends ConsistentSampler { + + @Immutable + private static final class State { + private final double effectiveWindowCount; + private final double effectiveWindowNanos; + private final long lastNanoTime; + + public State(double effectiveWindowCount, double effectiveWindowNanos, long lastNanoTime) { + this.effectiveWindowCount = effectiveWindowCount; + this.effectiveWindowNanos = effectiveWindowNanos; + this.lastNanoTime = lastNanoTime; + } + } + + private final String description; + private final LongSupplier nanoTimeSupplier; + private final double inverseAdaptationTimeNanos; + private final double targetSpansPerNanosecondLimit; + private final AtomicReference state; + + /** + * Constructor. + * + * @param targetSpansPerSecondLimit the desired spans per second limit + * @param adaptationTimeSeconds the typical time to adapt to a new load (time constant used for + * exponential smoothing) + * @param randomValueGenerator the function to use for generating the r-value + * @param nanoTimeSupplier a supplier for the current nano time + */ + ConsistentRateLimitingSampler( + double targetSpansPerSecondLimit, + double adaptationTimeSeconds, + RandomValueGenerator randomValueGenerator, + LongSupplier nanoTimeSupplier) { + super(randomValueGenerator); + + if (targetSpansPerSecondLimit < 0.0) { + throw new IllegalArgumentException("Limit for sampled spans per second must be nonnegative!"); + } + if (adaptationTimeSeconds < 0.0) { + throw new IllegalArgumentException("Adaptation rate must be nonnegative!"); + } + this.description = + String.format( + "ConsistentRateLimitingSampler{%.6f, %.6f}", + targetSpansPerSecondLimit, adaptationTimeSeconds); + this.nanoTimeSupplier = requireNonNull(nanoTimeSupplier); + + this.inverseAdaptationTimeNanos = 1e-9 / adaptationTimeSeconds; + this.targetSpansPerNanosecondLimit = 1e-9 * targetSpansPerSecondLimit; + + this.state = new AtomicReference<>(new State(0, 0, nanoTimeSupplier.getAsLong())); + } + + private State updateState(State oldState, long currentNanoTime) { + if (currentNanoTime <= oldState.lastNanoTime) { + return new State( + oldState.effectiveWindowCount + 1, oldState.effectiveWindowNanos, oldState.lastNanoTime); + } + long nanoTimeDelta = currentNanoTime - oldState.lastNanoTime; + double decayFactor = Math.exp(-nanoTimeDelta * inverseAdaptationTimeNanos); + double currentEffectiveWindowCount = oldState.effectiveWindowCount * decayFactor + 1; + double currentEffectiveWindowNanos = + oldState.effectiveWindowNanos * decayFactor + nanoTimeDelta; + return new State(currentEffectiveWindowCount, currentEffectiveWindowNanos, currentNanoTime); + } + + @Override + protected long getThreshold(long parentThreshold, boolean isRoot) { + long currentNanoTime = nanoTimeSupplier.getAsLong(); + State currentState = state.updateAndGet(s -> updateState(s, currentNanoTime)); + + double samplingProbability = + (currentState.effectiveWindowNanos * targetSpansPerNanosecondLimit) + / currentState.effectiveWindowCount; + + if (samplingProbability >= 1.) { + return getMaxThreshold(); + } else { + return ConsistentSamplingUtil.calculateThreshold(samplingProbability); + } + } + + @Override + public String getDescription() { + return description; + } +} diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java new file mode 100644 index 000000000..5e1283e8f --- /dev/null +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java @@ -0,0 +1,319 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidRandomValue; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxThreshold; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidThreshold; +import static java.util.Objects.requireNonNull; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.trace.data.LinkData; +import io.opentelemetry.sdk.trace.samplers.Sampler; +import io.opentelemetry.sdk.trace.samplers.SamplingDecision; +import io.opentelemetry.sdk.trace.samplers.SamplingResult; +import java.util.List; +import java.util.function.LongSupplier; + +/** Abstract base class for consistent samplers. */ +public abstract class ConsistentSampler implements Sampler { + + /** + * Returns a {@link ConsistentSampler} that samples all spans. + * + * @return a sampler + */ + public static ConsistentSampler alwaysOn() { + return alwaysOn(RandomValueGenerators.getDefault()); + } + + /** + * Returns a {@link ConsistentSampler} that samples all spans. + * + * @param randomValueGenerator the function to use for generating the random value + * @return a sampler + */ + public static ConsistentSampler alwaysOn(RandomValueGenerator randomValueGenerator) { + return new ConsistentAlwaysOnSampler(randomValueGenerator); + } + + /** + * Returns a {@link ConsistentSampler} that does not sample any span. + * + * @return a sampler + */ + public static ConsistentSampler alwaysOff() { + return alwaysOff(RandomValueGenerators.getDefault()); + } + + /** + * Returns a {@link ConsistentSampler} that does not sample any span. + * + * @param randomValueGenerator the function to use for generating the random value + * @return a sampler + */ + public static ConsistentSampler alwaysOff(RandomValueGenerator randomValueGenerator) { + return new ConsistentAlwaysOffSampler(randomValueGenerator); + } + + /** + * Returns a {@link ConsistentSampler} that samples each span with a fixed probability. + * + * @param samplingProbability the sampling probability + * @return a sampler + */ + public static ConsistentSampler probabilityBased(double samplingProbability) { + return probabilityBased(samplingProbability, RandomValueGenerators.getDefault()); + } + + /** + * Returns a {@link ConsistentSampler} that samples each span with a fixed probability. + * + * @param samplingProbability the sampling probability + * @param randomValueGenerator the function to use for generating the r-value + * @return a sampler + */ + public static ConsistentSampler probabilityBased( + double samplingProbability, RandomValueGenerator randomValueGenerator) { + long threshold = ConsistentSamplingUtil.calculateThreshold(samplingProbability); + return new ConsistentFixedThresholdSampler(threshold, randomValueGenerator); + } + + /** + * Returns a new {@link ConsistentSampler} that respects the sampling decision of the parent span + * or falls-back to the given sampler if it is a root span. + * + * @param rootSampler the root sampler + */ + public static ConsistentSampler parentBased(ConsistentSampler rootSampler) { + return parentBased(rootSampler, RandomValueGenerators.getDefault()); + } + + /** + * Returns a new {@link ConsistentSampler} that respects the sampling decision of the parent span + * or falls-back to the given sampler if it is a root span. + * + * @param rootSampler the root sampler + * @param randomValueGenerator the function to use for generating the random value + */ + public static ConsistentSampler parentBased( + ConsistentSampler rootSampler, RandomValueGenerator randomValueGenerator) { + return new ConsistentParentBasedSampler(rootSampler, randomValueGenerator); + } + + /** + * Returns a new {@link ConsistentSampler} that attempts to adjust the sampling probability + * dynamically to meet the target span rate. + * + * @param targetSpansPerSecondLimit the desired spans per second limit + * @param adaptationTimeSeconds the typical time to adapt to a new load (time constant used for + * exponential smoothing) + */ + public static ConsistentSampler rateLimited( + double targetSpansPerSecondLimit, double adaptationTimeSeconds) { + return rateLimited( + targetSpansPerSecondLimit, adaptationTimeSeconds, RandomValueGenerators.getDefault()); + } + + /** + * Returns a new {@link ConsistentSampler} that attempts to adjust the sampling probability + * dynamically to meet the target span rate. + * + * @param targetSpansPerSecondLimit the desired spans per second limit + * @param adaptationTimeSeconds the typical time to adapt to a new load (time constant used for + * exponential smoothing) + * @param randomValueGenerator the function to use for generating the random value + */ + public static ConsistentSampler rateLimited( + double targetSpansPerSecondLimit, + double adaptationTimeSeconds, + RandomValueGenerator randomValueGenerator) { + return rateLimited( + targetSpansPerSecondLimit, adaptationTimeSeconds, randomValueGenerator, System::nanoTime); + } + + /** + * Returns a new {@link ConsistentSampler} that attempts to adjust the sampling probability + * dynamically to meet the target span rate. + * + * @param targetSpansPerSecondLimit the desired spans per second limit + * @param adaptationTimeSeconds the typical time to adapt to a new load (time constant used for + * exponential smoothing) + * @param randomValueGenerator the function to use for generating the random value + * @param nanoTimeSupplier a supplier for the current nano time + */ + static ConsistentSampler rateLimited( + double targetSpansPerSecondLimit, + double adaptationTimeSeconds, + RandomValueGenerator randomValueGenerator, + LongSupplier nanoTimeSupplier) { + return new ConsistentRateLimitingSampler( + targetSpansPerSecondLimit, adaptationTimeSeconds, randomValueGenerator, nanoTimeSupplier); + } + + /** + * Returns a {@link ConsistentSampler} that samples a span if both this and the other given + * consistent sampler would sample the span. + * + *

If the other consistent sampler is the same as this, this consistent sampler will be + * returned. + * + *

The returned sampler takes care of setting the trace state correctly, which would not happen + * if the {@link #shouldSample(Context, String, String, SpanKind, Attributes, List)} method was + * called for each sampler individually. Also, the combined sampler is more efficient than + * evaluating the two samplers individually and combining both results afterwards. + * + * @param otherConsistentSampler the other consistent sampler + * @return the composed consistent sampler + */ + public ConsistentSampler and(ConsistentSampler otherConsistentSampler) { + if (otherConsistentSampler == this) { + return this; + } + return new ConsistentComposedAndSampler( + this, otherConsistentSampler, RandomValueGenerators.getDefault()); + } + + /** + * Returns a {@link ConsistentSampler} that samples a span if either this or the other given + * consistent sampler would sample the span. + * + *

If the other consistent sampler is the same as this, this consistent sampler will be + * returned. + * + *

The returned sampler takes care of setting the trace state correctly, which would not happen + * if the {@link #shouldSample(Context, String, String, SpanKind, Attributes, List)} method was + * called for each sampler individually. Also, the combined sampler is more efficient than + * evaluating the two samplers individually and combining both results afterwards. + * + * @param otherConsistentSampler the other consistent sampler + * @return the composed consistent sampler + */ + public ConsistentSampler or(ConsistentSampler otherConsistentSampler) { + if (otherConsistentSampler == this) { + return this; + } + return new ConsistentComposedOrSampler( + this, otherConsistentSampler, RandomValueGenerators.getDefault()); + } + + private final RandomValueGenerator randomValueGenerator; + + protected ConsistentSampler(RandomValueGenerator randomValueGenerator) { + this.randomValueGenerator = requireNonNull(randomValueGenerator); + } + + @Override + public final SamplingResult shouldSample( + Context parentContext, + String traceId, + String name, + SpanKind spanKind, + Attributes attributes, + List parentLinks) { + + Span parentSpan = Span.fromContext(parentContext); + SpanContext parentSpanContext = parentSpan.getSpanContext(); + boolean isRoot = !parentSpanContext.isValid(); + boolean isParentSampled = parentSpanContext.isSampled(); + + boolean isRandomTraceIdFlagSet = false; // TODO in future get the random trace ID flag, compare + // https://www.w3.org/TR/trace-context-2/#random-trace-id-flag + + TraceState parentTraceState = parentSpanContext.getTraceState(); + String otelTraceStateString = parentTraceState.get(OtelTraceState.TRACE_STATE_KEY); + OtelTraceState otelTraceState = OtelTraceState.parse(otelTraceStateString); + + long randomValue; + if (otelTraceState.hasValidRandomValue()) { + randomValue = otelTraceState.getRandomValue(); + } else if (isRandomTraceIdFlagSet) { + randomValue = OtelTraceState.parseHex(traceId, 18, 14, getInvalidRandomValue()); + } else { + randomValue = randomValueGenerator.generate(traceId); + otelTraceState.invalidateThreshold(); + otelTraceState.setRandomValue(randomValue); + } + + long parentThreshold; + if (otelTraceState.hasValidThreshold()) { + long threshold = otelTraceState.getThreshold(); + if (((randomValue < threshold) == isParentSampled) || threshold == 0) { + parentThreshold = threshold; + } else { + parentThreshold = getInvalidThreshold(); + } + } else if (isParentSampled) { + parentThreshold = getMaxThreshold(); + } else { + parentThreshold = 0; + } + + // determine new threshold that is used for the sampling decision + long threshold = getThreshold(parentThreshold, isRoot); + + // determine sampling decision + boolean isSampled; + if (isValidThreshold(threshold)) { + isSampled = (randomValue < threshold); + if (0 < threshold && threshold < getMaxThreshold()) { + otelTraceState.setThreshold(threshold); + } else { + otelTraceState.invalidateThreshold(); + } + } else { + isSampled = isParentSampled; + otelTraceState.invalidateThreshold(); + } + + SamplingDecision samplingDecision = + isSampled ? SamplingDecision.RECORD_AND_SAMPLE : SamplingDecision.DROP; + + String newOtTraceState = otelTraceState.serialize(); + + return new SamplingResult() { + + @Override + public SamplingDecision getDecision() { + return samplingDecision; + } + + @Override + public Attributes getAttributes() { + return Attributes.empty(); + } + + @Override + public TraceState getUpdatedTraceState(TraceState parentTraceState) { + return parentTraceState.toBuilder() + .put(OtelTraceState.TRACE_STATE_KEY, newOtTraceState) + .build(); + } + }; + } + + /** + * Returns the threshold that is used for the sampling decision. + * + *

NOTE: In future, further information like span attributes could be also added as arguments + * such that the sampling probability could be made dependent on those extra arguments. However, + * in any case the returned threshold value must not depend directly or indirectly on the random + * value. In particular this means that the parent sampled flag must not be used for the + * calculation of the threshold as the sampled flag depends itself on the random value. + * + * @param parentThreshold is the threshold (if known) that was used for a consistent sampling + * decision by the parent + * @param isRoot is true for the root span + * @return this Builder + */ + protected abstract long getThreshold(long parentThreshold, boolean isRoot); +} diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java new file mode 100644 index 000000000..420dff456 --- /dev/null +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java @@ -0,0 +1,116 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +public final class ConsistentSamplingUtil { + + private static final int RANDOM_VALUE_BITS = 56; + private static final long MAX_THRESHOLD = 1L << RANDOM_VALUE_BITS; + private static final long MAX_RANDOM_VALUE = MAX_THRESHOLD - 1; + private static final long INVALID_THRESHOLD = -1; + private static final long INVALID_RANDOM_VALUE = -1; + + private ConsistentSamplingUtil() {} + + /** + * Returns for a given threshold the corresponding sampling probability. + * + *

The returned value does not always exactly match the applied sampling probability, since + * some least significant binary digits may not be represented by double-precision floating point + * numbers. + * + * @param threshold the threshold + * @return the sampling probability + */ + public static double calculateSamplingProbability(long threshold) { + checkThreshold(threshold); + return threshold * 0x1p-56; + } + + /** + * Returns the closest sampling threshold that can be used to realize sampling with the given + * probability. + * + * @param samplingProbability the sampling probability + * @return the threshold + */ + public static long calculateThreshold(double samplingProbability) { + checkProbability(samplingProbability); + return Math.round(samplingProbability * 0x1p56); + } + + /** + * Calculates the adjusted count from a given threshold. + * + *

Returns 1, if the threshold is invalid. + * + *

Returns {@link Double#POSITIVE_INFINITY}, if the threshold is 0. + * + * @param threshold the threshold + * @return the adjusted count + */ + public static double calculateAdjustedCount(long threshold) { + if (isValidThreshold(threshold)) { + return 0x1p56 / threshold; + } else { + return 1.; + } + } + + /** + * Returns an invalid random value. + * + *

{@code isValidRandomValue(getInvalidRandomValue())} will always return true. + * + * @return an invalid random value + */ + public static long getInvalidRandomValue() { + return INVALID_RANDOM_VALUE; + } + + /** + * Returns an invalid threshold. + * + *

{@code isValidThreshold(getInvalidThreshold())} will always return true. + * + * @return an invalid threshold value + */ + public static long getInvalidThreshold() { + return INVALID_THRESHOLD; + } + + public static long getMaxRandomValue() { + return MAX_RANDOM_VALUE; + } + + public static long getMaxThreshold() { + return MAX_THRESHOLD; + } + + public static boolean isValidRandomValue(long randomValue) { + return 0 <= randomValue && randomValue <= getMaxRandomValue(); + } + + public static boolean isValidThreshold(long threshold) { + return 0 <= threshold && threshold <= getMaxThreshold(); + } + + public static boolean isValidProbability(double probability) { + return 0 <= probability && probability <= 1; + } + + static void checkThreshold(long threshold) { + if (!isValidThreshold(threshold)) { + throw new IllegalArgumentException("The threshold must be in the range [0,2^56]!"); + } + } + + static void checkProbability(double probability) { + if (!isValidProbability(probability)) { + throw new IllegalArgumentException("The probability must be in the range [0,1]!"); + } + } +} diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceState.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceState.java new file mode 100644 index 000000000..57bbc42fe --- /dev/null +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceState.java @@ -0,0 +1,281 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidRandomValue; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxThreshold; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidRandomValue; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidThreshold; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nullable; + +final class OtelTraceState { + + public static final String TRACE_STATE_KEY = "ot"; + + private static final String SUBKEY_RANDOM_VALUE = "rv"; + private static final String SUBKEY_THRESHOLD = "th"; + private static final int TRACE_STATE_SIZE_LIMIT = 256; + + private long randomValue; // valid in the interval [0, MAX_RANDOM_VALUE] + private long threshold; // valid in the interval [0, MAX_THRESHOLD] + + private final List otherKeyValuePairs; + + private OtelTraceState(long randomValue, long threshold, List otherKeyValuePairs) { + this.randomValue = randomValue; + this.threshold = threshold; + this.otherKeyValuePairs = otherKeyValuePairs; + } + + private OtelTraceState() { + this(getInvalidRandomValue(), getInvalidThreshold(), Collections.emptyList()); + } + + public long getRandomValue() { + return randomValue; + } + + public long getThreshold() { + return threshold; + } + + public boolean hasValidRandomValue() { + return isValidRandomValue(randomValue); + } + + public boolean hasValidThreshold() { + return isValidThreshold(threshold); + } + + public void invalidateRandomValue() { + randomValue = getInvalidRandomValue(); + } + + public void invalidateThreshold() { + threshold = getInvalidThreshold(); + } + + /** + * Sets a new th-value. + * + *

If the given th-value is invalid, the current th-value is invalidated. + * + * @param threshold the new th-value + */ + public void setThreshold(long threshold) { + if (isValidThreshold(threshold)) { + this.threshold = threshold; + } else { + invalidateThreshold(); + } + } + + /** + * Sets a new rv-value. + * + *

If the given rv-value is invalid, the current rv-value is invalidated. + * + * @param randomValue the new rv-value + */ + public void setRandomValue(long randomValue) { + if (isValidRandomValue(randomValue)) { + this.randomValue = randomValue; + } else { + invalidateRandomValue(); + } + } + + /** + * Returns a string representing this state. + * + * @return a string + */ + public String serialize() { + StringBuilder sb = new StringBuilder(); + if (hasValidThreshold() && threshold < getMaxThreshold()) { + sb.append(SUBKEY_THRESHOLD).append(':'); + appendThreshold(sb, threshold); + } + if (hasValidRandomValue()) { + if (sb.length() > 0) { + sb.append(';'); + } + sb.append(SUBKEY_RANDOM_VALUE).append(':'); + appendRandomValue(sb, randomValue); + } + for (String pair : otherKeyValuePairs) { + int ex = sb.length(); + if (ex != 0) { + ex += 1; + } + if (ex + pair.length() > TRACE_STATE_SIZE_LIMIT) { + break; + } + if (sb.length() > 0) { + sb.append(';'); + } + sb.append(pair); + } + return sb.toString(); + } + + private static boolean isValueByte(char c) { + return isLowerCaseAlphaNum(c) || isUpperCaseAlpha(c) || c == '.' || c == '_' || c == '-'; + } + + private static boolean isLowerCaseAlphaNum(char c) { + return isLowerCaseAlpha(c) || isDigit(c); + } + + private static boolean isDigit(char c) { + return c >= '0' && c <= '9'; + } + + private static boolean isLowerCaseAlpha(char c) { + return c >= 'a' && c <= 'z'; + } + + private static boolean isUpperCaseAlpha(char c) { + return c >= 'A' && c <= 'Z'; + } + + private static final char[] HEX_DIGITS = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + @CanIgnoreReturnValue + static StringBuilder appendRandomValue(StringBuilder sb, long l) { + for (int i = 52; i >= 0; i -= 4) { + sb.append(HEX_DIGITS[(int) ((l >>> i) & 0xf)]); + } + return sb; + } + + @CanIgnoreReturnValue + static StringBuilder appendThreshold(StringBuilder sb, long l) { + int numTrailingBits = Long.numberOfTrailingZeros(l | 0x80000000000000L); + for (int i = 52; i >= numTrailingBits - 3; i -= 4) { + sb.append(HEX_DIGITS[(int) ((l >>> i) & 0xf)]); + } + return sb; + } + + private static long parseRandomValue(String s, int startIncl, int endIncl) { + int len = endIncl - startIncl; + if (len != 14) { + return getInvalidRandomValue(); + } + return parseHex(s, startIncl, len, getInvalidRandomValue()); + } + + private static long parseThreshold(String s, int startIncl, int endIncl) { + int len = endIncl - startIncl; + if (len > 14) { + return getInvalidThreshold(); + } + return parseHex(s, startIncl, len, getInvalidThreshold()); + } + + static long parseHex(String s, int startIncl, int len, long invalidReturnValue) { + long r = 0; + for (int i = 0; i < len; ++i) { + long c = s.charAt(startIncl + i); + long x; + if (c >= '0' && c <= '9') { + x = c - '0'; + } else if (c >= 'a' && c <= 'f') { + x = c - 'a' + 10; + } else { + return invalidReturnValue; + } + r |= x << (52 - (i << 2)); + } + return r; + } + + /** + * Parses the trace state from a given string. + * + *

If the string cannot be successfully parsed, a new empty {@code OtelTraceState2} is + * returned. + * + * @param ts the string + * @return the parsed trace state or an empty trace state in case of parsing errors + */ + public static OtelTraceState parse(@Nullable String ts) { + List otherKeyValuePairs = null; + long threshold = getInvalidThreshold(); + long randomValue = getInvalidRandomValue(); + + if (ts == null || ts.isEmpty()) { + return new OtelTraceState(); + } + + if (ts.length() > TRACE_STATE_SIZE_LIMIT) { + return new OtelTraceState(); + } + + int startPos = 0; + int len = ts.length(); + + while (true) { + int colonPos = startPos; + for (; colonPos < len; colonPos++) { + char c = ts.charAt(colonPos); + if (!isLowerCaseAlpha(c) && (!isDigit(c) || colonPos == startPos)) { + break; + } + } + if (colonPos == startPos || colonPos == len || ts.charAt(colonPos) != ':') { + return new OtelTraceState(); + } + + int separatorPos = colonPos + 1; + while (separatorPos < len && isValueByte(ts.charAt(separatorPos))) { + separatorPos++; + } + + if (colonPos - startPos == SUBKEY_THRESHOLD.length() + && ts.startsWith(SUBKEY_THRESHOLD, startPos)) { + threshold = parseThreshold(ts, colonPos + 1, separatorPos); + } else if (colonPos - startPos == SUBKEY_RANDOM_VALUE.length() + && ts.startsWith(SUBKEY_RANDOM_VALUE, startPos)) { + randomValue = parseRandomValue(ts, colonPos + 1, separatorPos); + } else { + if (otherKeyValuePairs == null) { + otherKeyValuePairs = new ArrayList<>(); + } + otherKeyValuePairs.add(ts.substring(startPos, separatorPos)); + } + + if (separatorPos < len && ts.charAt(separatorPos) != ';') { + return new OtelTraceState(); + } + + if (separatorPos == len) { + break; + } + + startPos = separatorPos + 1; + + // test for a trailing ; + if (startPos == len) { + return new OtelTraceState(); + } + } + + return new OtelTraceState( + randomValue, + threshold, + (otherKeyValuePairs != null) ? otherKeyValuePairs : Collections.emptyList()); + } +} diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGenerator.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGenerator.java new file mode 100644 index 000000000..4aa4c4460 --- /dev/null +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGenerator.java @@ -0,0 +1,24 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +/** + * A function for generating random values. + * + *

The distribution of random values generated by this function must be uniform over the range + * [0,2^56-1] + */ +@FunctionalInterface +public interface RandomValueGenerator { + + /** + * Returns a 56-bit uniformly distributed random value. + * + * @param traceId the trace ID + * @return the random value + */ + long generate(String traceId); +} diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGenerators.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGenerators.java new file mode 100644 index 000000000..97f56bc5a --- /dev/null +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGenerators.java @@ -0,0 +1,25 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxRandomValue; + +import java.util.concurrent.ThreadLocalRandom; + +final class RandomValueGenerators { + + private static final RandomValueGenerator DEFAULT = createDefault(); + + static RandomValueGenerator getDefault() { + return DEFAULT; + } + + private static RandomValueGenerator createDefault() { + return s -> ThreadLocalRandom.current().nextLong() & getMaxRandomValue(); + } + + private RandomValueGenerators() {} +} diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSamplerTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSamplerTest.java new file mode 100644 index 000000000..df450cb2e --- /dev/null +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSamplerTest.java @@ -0,0 +1,100 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.calculateThreshold; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxRandomValue; +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.trace.data.LinkData; +import io.opentelemetry.sdk.trace.samplers.Sampler; +import io.opentelemetry.sdk.trace.samplers.SamplingDecision; +import io.opentelemetry.sdk.trace.samplers.SamplingResult; +import java.util.Collections; +import java.util.List; +import java.util.SplittableRandom; +import org.hipparchus.stat.inference.AlternativeHypothesis; +import org.hipparchus.stat.inference.BinomialTest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class ConsistentFixedThresholdSamplerTest { + + private Context parentContext; + private String traceId; + private String name; + private SpanKind spanKind; + private Attributes attributes; + private List parentLinks; + + @BeforeEach + public void init() { + + parentContext = Context.root(); + traceId = "0123456789abcdef0123456789abcdef"; + name = "name"; + spanKind = SpanKind.SERVER; + attributes = Attributes.empty(); + parentLinks = Collections.emptyList(); + } + + private void test(SplittableRandom rng, double samplingProbability) { + int numSpans = 10000; + + Sampler sampler = + ConsistentSampler.probabilityBased( + samplingProbability, s -> rng.nextLong() & getMaxRandomValue()); + + int numSampled = 0; + for (long i = 0; i < numSpans; ++i) { + SamplingResult samplingResult = + sampler.shouldSample(parentContext, traceId, name, spanKind, attributes, parentLinks); + if (samplingResult.getDecision() == SamplingDecision.RECORD_AND_SAMPLE) { + String traceStateString = + samplingResult + .getUpdatedTraceState(TraceState.getDefault()) + .get(OtelTraceState.TRACE_STATE_KEY); + OtelTraceState traceState = OtelTraceState.parse(traceStateString); + assertThat(traceState.hasValidRandomValue()).isTrue(); + if (samplingProbability == 1.) { + assertThat(traceState.hasValidThreshold()).isFalse(); + } else { + assertThat(traceState.hasValidThreshold()).isTrue(); + assertThat(traceState.getThreshold()).isEqualTo(calculateThreshold(samplingProbability)); + } + + numSampled += 1; + } + } + + assertThat( + new BinomialTest() + .binomialTest( + numSpans, numSampled, samplingProbability, AlternativeHypothesis.TWO_SIDED)) + .isGreaterThan(0.005); + } + + @Test + public void test() { + + // fix seed to get reproducible results + SplittableRandom random = new SplittableRandom(0); + + test(random, 1.); + test(random, 0.5); + test(random, 0.25); + test(random, 0.125); + test(random, 0.0); + test(random, 0.45); + test(random, 0.2); + test(random, 0.13); + test(random, 0.05); + } +} diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSamplerTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSamplerTest.java new file mode 100644 index 000000000..c18f5f570 --- /dev/null +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSamplerTest.java @@ -0,0 +1,214 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxRandomValue; +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.trace.data.LinkData; +import io.opentelemetry.sdk.trace.samplers.SamplingDecision; +import io.opentelemetry.sdk.trace.samplers.SamplingResult; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.SplittableRandom; +import java.util.concurrent.TimeUnit; +import java.util.function.LongSupplier; +import org.assertj.core.data.Percentage; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class ConsistentRateLimitingSamplerTest { + + private long[] nanoTime; + private LongSupplier nanoTimeSupplier; + private Context parentContext; + private String traceId; + private String name; + private SpanKind spanKind; + private Attributes attributes; + private List parentLinks; + + private static RandomValueGenerator randomValueGenerator() { + SplittableRandom random = new SplittableRandom(0L); + return s -> random.nextLong() & getMaxRandomValue(); + } + + @BeforeEach + void init() { + nanoTime = new long[] {0L}; + nanoTimeSupplier = () -> nanoTime[0]; + parentContext = Context.root(); + traceId = "0123456789abcdef0123456789abcdef"; + name = "name"; + spanKind = SpanKind.SERVER; + attributes = Attributes.empty(); + parentLinks = Collections.emptyList(); + } + + private void advanceTime(long nanosIncrement) { + nanoTime[0] += nanosIncrement; + } + + private long getCurrentTimeNanos() { + return nanoTime[0]; + } + + @Test + void testConstantRate() { + + double targetSpansPerSecondLimit = 1000; + double adaptationTimeSeconds = 5; + + ConsistentSampler sampler = + ConsistentSampler.rateLimited( + targetSpansPerSecondLimit, + adaptationTimeSeconds, + randomValueGenerator(), + nanoTimeSupplier); + + long nanosBetweenSpans = TimeUnit.MICROSECONDS.toNanos(100); + int numSpans = 1000000; + + List spanSampledNanos = new ArrayList<>(); + + for (int i = 0; i < numSpans; ++i) { + advanceTime(nanosBetweenSpans); + SamplingResult samplingResult = + sampler.shouldSample(parentContext, traceId, name, spanKind, attributes, parentLinks); + if (SamplingDecision.RECORD_AND_SAMPLE.equals(samplingResult.getDecision())) { + spanSampledNanos.add(getCurrentTimeNanos()); + } + } + + long numSampledSpansInLast5Seconds = + spanSampledNanos.stream() + .filter(x -> x > TimeUnit.SECONDS.toNanos(95) && x <= TimeUnit.SECONDS.toNanos(100)) + .count(); + + assertThat(numSampledSpansInLast5Seconds / 5.) + .isCloseTo(targetSpansPerSecondLimit, Percentage.withPercentage(5)); + } + + @Test + void testRateIncrease() { + + double targetSpansPerSecondLimit = 1000; + double adaptationTimeSeconds = 5; + + ConsistentSampler sampler = + ConsistentSampler.rateLimited( + targetSpansPerSecondLimit, + adaptationTimeSeconds, + randomValueGenerator(), + nanoTimeSupplier); + + long nanosBetweenSpans1 = TimeUnit.MICROSECONDS.toNanos(100); + long nanosBetweenSpans2 = TimeUnit.MICROSECONDS.toNanos(10); + int numSpans1 = 500000; + int numSpans2 = 5000000; + + List spanSampledNanos = new ArrayList<>(); + + for (int i = 0; i < numSpans1; ++i) { + advanceTime(nanosBetweenSpans1); + SamplingResult samplingResult = + sampler.shouldSample(parentContext, traceId, name, spanKind, attributes, parentLinks); + if (SamplingDecision.RECORD_AND_SAMPLE.equals(samplingResult.getDecision())) { + spanSampledNanos.add(getCurrentTimeNanos()); + } + } + for (int i = 0; i < numSpans2; ++i) { + advanceTime(nanosBetweenSpans2); + SamplingResult samplingResult = + sampler.shouldSample(parentContext, traceId, name, spanKind, attributes, parentLinks); + if (SamplingDecision.RECORD_AND_SAMPLE.equals(samplingResult.getDecision())) { + spanSampledNanos.add(getCurrentTimeNanos()); + } + } + + long numSampledSpansWithin5SecondsBeforeChange = + spanSampledNanos.stream() + .filter(x -> x > TimeUnit.SECONDS.toNanos(45) && x <= TimeUnit.SECONDS.toNanos(50)) + .count(); + long numSampledSpansWithin5SecondsAfterChange = + spanSampledNanos.stream() + .filter(x -> x > TimeUnit.SECONDS.toNanos(50) && x <= TimeUnit.SECONDS.toNanos(55)) + .count(); + long numSampledSpansInLast5Seconds = + spanSampledNanos.stream() + .filter(x -> x > TimeUnit.SECONDS.toNanos(95) && x <= TimeUnit.SECONDS.toNanos(100)) + .count(); + + assertThat(numSampledSpansWithin5SecondsBeforeChange / 5.) + .isCloseTo(targetSpansPerSecondLimit, Percentage.withPercentage(5)); + assertThat(numSampledSpansWithin5SecondsAfterChange / 5.) + .isGreaterThan(2. * targetSpansPerSecondLimit); + assertThat(numSampledSpansInLast5Seconds / 5.) + .isCloseTo(targetSpansPerSecondLimit, Percentage.withPercentage(5)); + } + + @Test + void testRateDecrease() { + + double targetSpansPerSecondLimit = 1000; + double adaptationTimeSeconds = 5; + + ConsistentSampler sampler = + ConsistentSampler.rateLimited( + targetSpansPerSecondLimit, + adaptationTimeSeconds, + randomValueGenerator(), + nanoTimeSupplier); + + long nanosBetweenSpans1 = TimeUnit.MICROSECONDS.toNanos(10); + long nanosBetweenSpans2 = TimeUnit.MICROSECONDS.toNanos(100); + int numSpans1 = 5000000; + int numSpans2 = 500000; + + List spanSampledNanos = new ArrayList<>(); + + for (int i = 0; i < numSpans1; ++i) { + advanceTime(nanosBetweenSpans1); + SamplingResult samplingResult = + sampler.shouldSample(parentContext, traceId, name, spanKind, attributes, parentLinks); + if (SamplingDecision.RECORD_AND_SAMPLE.equals(samplingResult.getDecision())) { + spanSampledNanos.add(getCurrentTimeNanos()); + } + } + for (int i = 0; i < numSpans2; ++i) { + advanceTime(nanosBetweenSpans2); + SamplingResult samplingResult = + sampler.shouldSample(parentContext, traceId, name, spanKind, attributes, parentLinks); + if (SamplingDecision.RECORD_AND_SAMPLE.equals(samplingResult.getDecision())) { + spanSampledNanos.add(getCurrentTimeNanos()); + } + } + + long numSampledSpansWithin5SecondsBeforeChange = + spanSampledNanos.stream() + .filter(x -> x > TimeUnit.SECONDS.toNanos(45) && x <= TimeUnit.SECONDS.toNanos(50)) + .count(); + long numSampledSpansWithin5SecondsAfterChange = + spanSampledNanos.stream() + .filter(x -> x > TimeUnit.SECONDS.toNanos(50) && x <= TimeUnit.SECONDS.toNanos(55)) + .count(); + long numSampledSpansInLast5Seconds = + spanSampledNanos.stream() + .filter(x -> x > TimeUnit.SECONDS.toNanos(95) && x <= TimeUnit.SECONDS.toNanos(100)) + .count(); + + assertThat(numSampledSpansWithin5SecondsBeforeChange / 5.) + .isCloseTo(targetSpansPerSecondLimit, Percentage.withPercentage(5)); + assertThat(numSampledSpansWithin5SecondsAfterChange / 5.) + .isLessThan(0.5 * targetSpansPerSecondLimit); + assertThat(numSampledSpansInLast5Seconds / 5.) + .isCloseTo(targetSpansPerSecondLimit, Percentage.withPercentage(5)); + } +} diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplerTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplerTest.java new file mode 100644 index 000000000..da4fde503 --- /dev/null +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplerTest.java @@ -0,0 +1,261 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxRandomValue; +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.TraceFlags; +import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.trace.data.LinkData; +import io.opentelemetry.sdk.trace.samplers.SamplingDecision; +import io.opentelemetry.sdk.trace.samplers.SamplingResult; +import java.util.Collections; +import java.util.List; +import java.util.OptionalLong; +import java.util.SplittableRandom; +import org.junit.jupiter.api.Test; + +class ConsistentSamplerTest { + + private static class Input { + private static final String traceId = "00112233445566778800000000000000"; + private static final String spanId = "0123456789abcdef"; + private static final String name = "name"; + private static final SpanKind spanKind = SpanKind.SERVER; + private static final Attributes attributes = Attributes.empty(); + private static final List parentLinks = Collections.emptyList(); + private boolean parentSampled = true; + + private OptionalLong parentThreshold = OptionalLong.empty(); + private OptionalLong parentRandomValue = OptionalLong.empty(); + + private final SplittableRandom random = new SplittableRandom(0L); + + public void setParentSampled(boolean parentSampled) { + this.parentSampled = parentSampled; + } + + public void setParentThreshold(long parentThreshold) { + assertThat(parentThreshold).isBetween(0L, 0xffffffffffffffL); + this.parentThreshold = OptionalLong.of(parentThreshold); + } + + public void setParentRandomValue(long parentRandomValue) { + assertThat(parentRandomValue).isBetween(0L, 0xffffffffffffffL); + this.parentRandomValue = OptionalLong.of(parentRandomValue); + } + + public Context getParentContext() { + return createParentContext( + traceId, spanId, parentThreshold, parentRandomValue, parentSampled); + } + + public static String getTraceId() { + return traceId; + } + + public static String getName() { + return name; + } + + public static SpanKind getSpanKind() { + return spanKind; + } + + public static Attributes getAttributes() { + return attributes; + } + + public static List getParentLinks() { + return parentLinks; + } + + public RandomValueGenerator getRandomValueGenerator() { + return s -> random.nextLong() & getMaxRandomValue(); + } + } + + private static class Output { + + private final SamplingResult samplingResult; + private final Context parentContext; + + Output(SamplingResult samplingResult, Context parentContext) { + this.samplingResult = samplingResult; + this.parentContext = parentContext; + } + + boolean getSampledFlag() { + return SamplingDecision.RECORD_AND_SAMPLE.equals(samplingResult.getDecision()); + } + + OptionalLong getThreshold() { + Span parentSpan = Span.fromContext(parentContext); + OtelTraceState otelTraceState = + OtelTraceState.parse( + samplingResult + .getUpdatedTraceState(parentSpan.getSpanContext().getTraceState()) + .get(OtelTraceState.TRACE_STATE_KEY)); + return otelTraceState.hasValidThreshold() + ? OptionalLong.of(otelTraceState.getThreshold()) + : OptionalLong.empty(); + } + + OptionalLong getRandomValue() { + Span parentSpan = Span.fromContext(parentContext); + OtelTraceState otelTraceState = + OtelTraceState.parse( + samplingResult + .getUpdatedTraceState(parentSpan.getSpanContext().getTraceState()) + .get(OtelTraceState.TRACE_STATE_KEY)); + return otelTraceState.hasValidRandomValue() + ? OptionalLong.of(otelTraceState.getRandomValue()) + : OptionalLong.empty(); + } + } + + private static TraceState createTraceState(OptionalLong threshold, OptionalLong randomValue) { + OtelTraceState state = OtelTraceState.parse(""); + threshold.ifPresent(x -> state.setThreshold(x)); + randomValue.ifPresent(x -> state.setRandomValue(x)); + return TraceState.builder().put(OtelTraceState.TRACE_STATE_KEY, state.serialize()).build(); + } + + private static Context createParentContext( + String traceId, + String spanId, + OptionalLong threshold, + OptionalLong randomValue, + boolean sampled) { + TraceState parentTraceState = createTraceState(threshold, randomValue); + TraceFlags traceFlags = sampled ? TraceFlags.getSampled() : TraceFlags.getDefault(); + SpanContext parentSpanContext = + SpanContext.create(traceId, spanId, traceFlags, parentTraceState); + Span parentSpan = Span.wrap(parentSpanContext); + return parentSpan.storeInContext(Context.root()); + } + + private static Output sample(Input input, ConsistentSampler sampler) { + + Context parentContext = input.getParentContext(); + SamplingResult samplingResult = + sampler.shouldSample( + parentContext, + Input.getTraceId(), + Input.getName(), + Input.getSpanKind(), + Input.getAttributes(), + Input.getParentLinks()); + return new Output(samplingResult, parentContext); + } + + @Test + void testMaxThresholdWithoutParentRandomValue() { + + Input input = new Input(); + + ConsistentSampler sampler = ConsistentSampler.alwaysOn(input.getRandomValueGenerator()); + + Output output = sample(input, sampler); + + assertThat(output.samplingResult.getDecision()).isEqualTo(SamplingDecision.RECORD_AND_SAMPLE); + assertThat(output.getThreshold()).isEmpty(); + assertThat(output.getRandomValue()).hasValue(0x20a8397b1dcdafL); + assertThat(output.getSampledFlag()).isTrue(); + } + + @Test + void testMaxThresholdWithParentRandomValue() { + + long parentRandomValue = 0x7f99aa40c02744L; + + Input input = new Input(); + input.setParentRandomValue(parentRandomValue); + + ConsistentSampler sampler = ConsistentSampler.alwaysOn(input.getRandomValueGenerator()); + + Output output = sample(input, sampler); + + assertThat(output.samplingResult.getDecision()).isEqualTo(SamplingDecision.RECORD_AND_SAMPLE); + assertThat(output.getThreshold()).isEmpty(); + assertThat(output.getRandomValue()).hasValue(parentRandomValue); + assertThat(output.getSampledFlag()).isTrue(); + } + + @Test + void testMinThreshold() { + + Input input = new Input(); + + ConsistentSampler sampler = + new ConsistentFixedThresholdSampler(0L, input.getRandomValueGenerator()); + + Output output = sample(input, sampler); + + assertThat(output.samplingResult.getDecision()).isEqualTo(SamplingDecision.DROP); + assertThat(output.getThreshold()).isEmpty(); + assertThat(output.getRandomValue()).hasValue(0x20a8397b1dcdafL); + assertThat(output.getSampledFlag()).isFalse(); + } + + @Test + void testHalfThresholdNotSampled() { + + Input input = new Input(); + input.setParentRandomValue(0x8000000000000L); + + ConsistentSampler sampler = + new ConsistentFixedThresholdSampler(0x8000000000000L, input.getRandomValueGenerator()); + + Output output = sample(input, sampler); + + assertThat(output.samplingResult.getDecision()).isEqualTo(SamplingDecision.DROP); + assertThat(output.getThreshold()).hasValue(0x8000000000000L); + assertThat(output.getRandomValue()).hasValue(0x8000000000000L); + assertThat(output.getSampledFlag()).isFalse(); + } + + @Test + void testHalfThresholdSampled() { + + Input input = new Input(); + input.setParentRandomValue(0x7ffffffffffffL); + + ConsistentSampler sampler = + new ConsistentFixedThresholdSampler(0x8000000000000L, input.getRandomValueGenerator()); + + Output output = sample(input, sampler); + + assertThat(output.samplingResult.getDecision()).isEqualTo(SamplingDecision.RECORD_AND_SAMPLE); + assertThat(output.getThreshold()).hasValue(0x8000000000000L); + assertThat(output.getRandomValue()).hasValue(0x7ffffffffffffL); + assertThat(output.getSampledFlag()).isTrue(); + } + + @Test + void testParentExtraordinarySampledButChildNotSampled() { + + Input input = new Input(); + input.setParentThreshold(0L); + input.setParentSampled(true); + + ConsistentSampler sampler = + new ConsistentFixedThresholdSampler(0x0L, input.getRandomValueGenerator()); + Output output = sample(input, sampler); + + assertThat(output.samplingResult.getDecision()).isEqualTo(SamplingDecision.DROP); + + assertThat(output.getThreshold()).isEmpty(); + assertThat(output.getRandomValue()).isNotEmpty(); + assertThat(output.getSampledFlag()).isFalse(); + } +} diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java new file mode 100644 index 000000000..0ee69ae66 --- /dev/null +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java @@ -0,0 +1,77 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.calculateAdjustedCount; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.calculateSamplingProbability; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.calculateThreshold; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidRandomValue; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidRandomValue; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidThreshold; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +import org.junit.jupiter.api.Test; + +public class ConsistentSamplingUtilTest { + + @Test + void testCalculateSamplingProbability() { + assertThat(calculateSamplingProbability(0L)).isEqualTo(0.); + assertThat(calculateSamplingProbability(0x40000000000000L)).isEqualTo(0.25); + assertThat(calculateSamplingProbability(0x80000000000000L)).isEqualTo(0.5); + assertThat(calculateSamplingProbability(0x100000000000000L)).isEqualTo(1.); + assertThatIllegalArgumentException().isThrownBy(() -> calculateSamplingProbability(-1)); + assertThatIllegalArgumentException() + .isThrownBy(() -> calculateSamplingProbability(0x100000000000001L)); + } + + @Test + void testCalculateThreshold() { + assertThat(calculateThreshold(0.)).isEqualTo(0L); + assertThat(calculateThreshold(0.25)).isEqualTo(0x40000000000000L); + assertThat(calculateThreshold(0.5)).isEqualTo(0x80000000000000L); + assertThat(calculateThreshold(1.)).isEqualTo(0x100000000000000L); + assertThatIllegalArgumentException().isThrownBy(() -> calculateThreshold(Math.nextDown(0.))); + assertThatIllegalArgumentException().isThrownBy(() -> calculateThreshold(Math.nextUp(1.))); + assertThatIllegalArgumentException() + .isThrownBy(() -> calculateThreshold(Double.POSITIVE_INFINITY)); + assertThatIllegalArgumentException() + .isThrownBy(() -> calculateThreshold(Double.NEGATIVE_INFINITY)); + assertThatIllegalArgumentException().isThrownBy(() -> calculateThreshold(Double.NaN)); + } + + @Test + void testGetInvalidRandomValue() { + assertThat(isValidRandomValue(getInvalidRandomValue())).isFalse(); + } + + @Test + void testGetInvalidThreshold() { + assertThat(isValidThreshold(getInvalidThreshold())).isFalse(); + } + + @Test + void testGetMaxThreshold() { + assertThat(ConsistentSamplingUtil.getMaxThreshold()).isEqualTo(0x100000000000000L); + } + + @Test + void testGetMaxRandomValue() { + assertThat(ConsistentSamplingUtil.getMaxRandomValue()).isEqualTo(0xFFFFFFFFFFFFFFL); + } + + @Test + void testCalculateAdjustedCount() { + assertThat(calculateAdjustedCount(0L)).isEqualTo(Double.POSITIVE_INFINITY); + assertThat(calculateAdjustedCount(0x40000000000000L)).isEqualTo(4.); + assertThat(calculateAdjustedCount(0x80000000000000L)).isEqualTo(2.); + assertThat(calculateAdjustedCount(0x100000000000000L)).isEqualTo(1.); + assertThat(calculateAdjustedCount(-1)).isEqualTo(1.); + assertThat(calculateAdjustedCount(0x100000000000001L)).isEqualTo(1.); + } +} diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceStateTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceStateTest.java new file mode 100644 index 000000000..827604eb6 --- /dev/null +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceStateTest.java @@ -0,0 +1,75 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; + +public class OtelTraceStateTest { + + private static String getXString(int len) { + return Stream.generate(() -> "X").limit(len).collect(Collectors.joining()); + } + + @Test + public void test() { + + assertEquals("", OtelTraceState.parse("").serialize()); + assertEquals("", OtelTraceState.parse("").serialize()); + + assertEquals("", OtelTraceState.parse("a").serialize()); + assertEquals("", OtelTraceState.parse("#").serialize()); + assertEquals("", OtelTraceState.parse(" ").serialize()); + + assertEquals("rv:1234567890abcd", OtelTraceState.parse("rv:1234567890abcd").serialize()); + assertEquals("rv:01020304050607", OtelTraceState.parse("rv:01020304050607").serialize()); + assertEquals("", OtelTraceState.parse("rv:1234567890abcde").serialize()); + + assertEquals("th:1234567890abcd", OtelTraceState.parse("th:1234567890abcd").serialize()); + assertEquals("th:01020304050607", OtelTraceState.parse("th:01020304050607").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:10000000000000").serialize()); + assertEquals("th:12345", OtelTraceState.parse("th:1234500000000").serialize()); + assertEquals("th:0", OtelTraceState.parse("th:0").serialize()); // TODO + assertEquals("", OtelTraceState.parse("th:100000000000000").serialize()); + assertEquals("", OtelTraceState.parse("th:1234567890abcde").serialize()); + + assertEquals( + "th:1234567890abcd;rv:1234567890abcd;a:" + getXString(214) + ";x:3", + OtelTraceState.parse("a:" + getXString(214) + ";rv:1234567890abcd;th:1234567890abcd;x:3") + .serialize()); + assertEquals( + "", + OtelTraceState.parse("a:" + getXString(215) + ";rv:1234567890abcd;th:1234567890abcd;x:3") + .serialize()); + + assertEquals("", OtelTraceState.parse("th:x").serialize()); + assertEquals("", OtelTraceState.parse("th:100000000000000").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:10000000000000").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:1000000000000").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:100000000000").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:10000000000").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:1000000000").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:100000000").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:10000000").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:1000000").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:100000").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:10000").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:1000").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:100").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:10").serialize()); + assertEquals("th:1", OtelTraceState.parse("th:1").serialize()); + + assertEquals("th:10000000000001", OtelTraceState.parse("th:10000000000001").serialize()); + assertEquals("th:1000000000001", OtelTraceState.parse("th:10000000000010").serialize()); + assertEquals("", OtelTraceState.parse("rv:x").serialize()); + assertEquals("", OtelTraceState.parse("rv:100000000000000").serialize()); + assertEquals("rv:10000000000000", OtelTraceState.parse("rv:10000000000000").serialize()); + assertEquals("", OtelTraceState.parse("rv:1000000000000").serialize()); + } +} From 1c41d25a5637b27d2ca5f367b20921fee297bf5d Mon Sep 17 00:00:00 2001 From: Otmar Ertl Date: Sun, 8 Oct 2023 13:57:44 +0200 Subject: [PATCH 02/12] fixed javadoc --- .../contrib/sampler/consistent2/ConsistentSampler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java index 5e1283e8f..8edd0e74e 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java @@ -313,7 +313,7 @@ public TraceState getUpdatedTraceState(TraceState parentTraceState) { * @param parentThreshold is the threshold (if known) that was used for a consistent sampling * decision by the parent * @param isRoot is true for the root span - * @return this Builder + * @return the threshold to be used for the sampling decision */ protected abstract long getThreshold(long parentThreshold, boolean isRoot); } From ccfda5b102ea54c675fed06f7495de24b1cc22a8 Mon Sep 17 00:00:00 2001 From: Otmar Ertl Date: Sun, 8 Oct 2023 16:25:52 +0200 Subject: [PATCH 03/12] fixed javadoc --- .../contrib/sampler/consistent2/ConsistentSampler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java index 8edd0e74e..36d4411d2 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java @@ -184,8 +184,8 @@ public ConsistentSampler and(ConsistentSampler otherConsistentSampler) { } /** - * Returns a {@link ConsistentSampler} that samples a span if either this or the other given - * consistent sampler would sample the span. + * Returns a {@link ConsistentSampler} that samples a span if this or the other given consistent + * sampler would sample the span. * *

If the other consistent sampler is the same as this, this consistent sampler will be * returned. From 9492eb4325483010af27f0301c0f1a5cfee4b805 Mon Sep 17 00:00:00 2001 From: Otmar Ertl Date: Sun, 8 Oct 2023 16:41:43 +0200 Subject: [PATCH 04/12] fixed adjusted count for zero threshold --- .../sampler/consistent2/ConsistentSamplingUtil.java | 9 +++++++-- .../sampler/consistent2/ConsistentSamplingUtilTest.java | 8 ++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java index 420dff456..50f990066 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java @@ -47,14 +47,19 @@ public static long calculateThreshold(double samplingProbability) { * *

Returns 1, if the threshold is invalid. * - *

Returns {@link Double#POSITIVE_INFINITY}, if the threshold is 0. + *

Returns 0, if the threshold is 0. A span with zero threshold is only sampled due to a + * non-probabilistic sampling decision and therefore does not contribute to the adjusted count. * * @param threshold the threshold * @return the adjusted count */ public static double calculateAdjustedCount(long threshold) { if (isValidThreshold(threshold)) { - return 0x1p56 / threshold; + if (threshold > 0) { + return 0x1p56 / threshold; + } else { + return 0; + } } else { return 1.; } diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java index 0ee69ae66..635917255 100644 --- a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java @@ -67,11 +67,11 @@ void testGetMaxRandomValue() { @Test void testCalculateAdjustedCount() { - assertThat(calculateAdjustedCount(0L)).isEqualTo(Double.POSITIVE_INFINITY); + assertThat(calculateAdjustedCount(0L)).isZero(); assertThat(calculateAdjustedCount(0x40000000000000L)).isEqualTo(4.); assertThat(calculateAdjustedCount(0x80000000000000L)).isEqualTo(2.); - assertThat(calculateAdjustedCount(0x100000000000000L)).isEqualTo(1.); - assertThat(calculateAdjustedCount(-1)).isEqualTo(1.); - assertThat(calculateAdjustedCount(0x100000000000001L)).isEqualTo(1.); + assertThat(calculateAdjustedCount(0x100000000000000L)).isOne(); + assertThat(calculateAdjustedCount(-1)).isOne(); + assertThat(calculateAdjustedCount(0x100000000000001L)).isOne(); } } From 7b1adf020ff6807063935e8af51fd7c979ace2b6 Mon Sep 17 00:00:00 2001 From: Otmar Ertl Date: Sun, 8 Oct 2023 16:42:14 +0200 Subject: [PATCH 05/12] ConsistentAlwaysOffSamplerTest --- .../ConsistentAlwaysOffSamplerTest.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOffSamplerTest.java diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOffSamplerTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOffSamplerTest.java new file mode 100644 index 000000000..476b3c6a7 --- /dev/null +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOffSamplerTest.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxThreshold; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +public class ConsistentAlwaysOffSamplerTest { + + @Test + void testDescription() { + assertThat(ConsistentSampler.alwaysOff().getDescription()) + .isEqualTo("ConsistentAlwaysOffSampler"); + } + + @Test + void testThreshold() { + assertThat(ConsistentSampler.alwaysOff().getThreshold(getInvalidThreshold(), false)).isZero(); + assertThat(ConsistentSampler.alwaysOff().getThreshold(getInvalidThreshold(), true)).isZero(); + assertThat(ConsistentSampler.alwaysOff().getThreshold(getMaxThreshold(), false)).isZero(); + assertThat(ConsistentSampler.alwaysOff().getThreshold(getMaxThreshold(), true)).isZero(); + assertThat(ConsistentSampler.alwaysOff().getThreshold(0, false)).isZero(); + assertThat(ConsistentSampler.alwaysOff().getThreshold(0, true)).isZero(); + } +} From 4bd4820be7a0e0aea3514b08a516900b39f81f59 Mon Sep 17 00:00:00 2001 From: Otmar Ertl Date: Sun, 8 Oct 2023 16:42:24 +0200 Subject: [PATCH 06/12] ConsistentAlwaysOnSamplerTest --- .../ConsistentAlwaysOnSamplerTest.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOnSamplerTest.java diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOnSamplerTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOnSamplerTest.java new file mode 100644 index 000000000..2150e5732 --- /dev/null +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOnSamplerTest.java @@ -0,0 +1,35 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxThreshold; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +public class ConsistentAlwaysOnSamplerTest { + + @Test + void testDescription() { + assertThat(ConsistentSampler.alwaysOn().getDescription()) + .isEqualTo("ConsistentAlwaysOnSampler"); + } + + @Test + void testThreshold() { + assertThat(ConsistentSampler.alwaysOn().getThreshold(getInvalidThreshold(), false)) + .isEqualTo(getMaxThreshold()); + assertThat(ConsistentSampler.alwaysOn().getThreshold(getInvalidThreshold(), true)) + .isEqualTo(getMaxThreshold()); + assertThat(ConsistentSampler.alwaysOn().getThreshold(getMaxThreshold(), false)) + .isEqualTo(getMaxThreshold()); + assertThat(ConsistentSampler.alwaysOn().getThreshold(getMaxThreshold(), true)) + .isEqualTo(getMaxThreshold()); + assertThat(ConsistentSampler.alwaysOn().getThreshold(0, false)).isEqualTo(getMaxThreshold()); + assertThat(ConsistentSampler.alwaysOn().getThreshold(0, true)).isEqualTo(getMaxThreshold()); + } +} From 9e7f3b2e86f5a6476ef29c2f74c8f60f7985aa90 Mon Sep 17 00:00:00 2001 From: Otmar Ertl Date: Sun, 8 Oct 2023 16:50:12 +0200 Subject: [PATCH 07/12] RandomValueGeneratorsTest --- .../RandomValueGeneratorsTest.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGeneratorsTest.java diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGeneratorsTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGeneratorsTest.java new file mode 100644 index 000000000..a82bc33d1 --- /dev/null +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGeneratorsTest.java @@ -0,0 +1,22 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.contrib.sampler.consistent2; + +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxRandomValue; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +public class RandomValueGeneratorsTest { + @Test + void testRandomRange() { + int attempts = 10000; + for (int i = 0; i < attempts; ++i) { + assertThat(RandomValueGenerators.getDefault().generate("")) + .isBetween(0L, getMaxRandomValue()); + } + } +} From 5a3e4f76771a023da0854ccf57a1498b0c69a2a7 Mon Sep 17 00:00:00 2001 From: Otmar Ertl Date: Sun, 8 Oct 2023 16:51:25 +0200 Subject: [PATCH 08/12] moved hex encoding to ConsistentSamplingUtil --- .../consistent2/ConsistentSamplingUtil.java | 26 +++++++++++++ .../sampler/consistent2/OtelTraceState.java | 28 ++------------ .../ConsistentSamplingUtilTest.java | 37 +++++++++++++++++++ 3 files changed, 67 insertions(+), 24 deletions(-) diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java index 50f990066..18d47fe15 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java @@ -5,6 +5,8 @@ package io.opentelemetry.contrib.sampler.consistent2; +import com.google.errorprone.annotations.CanIgnoreReturnValue; + public final class ConsistentSamplingUtil { private static final int RANDOM_VALUE_BITS = 56; @@ -118,4 +120,28 @@ static void checkProbability(double probability) { throw new IllegalArgumentException("The probability must be in the range [0,1]!"); } } + + private static final char[] HEX_DIGITS = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + @CanIgnoreReturnValue + static StringBuilder appendLast56BitHexEncoded(StringBuilder sb, long l) { + return appendLast56BitHexEncodedHelper(sb, l, 0); + } + + @CanIgnoreReturnValue + static StringBuilder appendLast56BitHexEncodedWithoutTrailingZeros(StringBuilder sb, long l) { + int numTrailingBits = Long.numberOfTrailingZeros(l | 0x80000000000000L); + return appendLast56BitHexEncodedHelper(sb, l, numTrailingBits); + } + + @CanIgnoreReturnValue + private static StringBuilder appendLast56BitHexEncodedHelper( + StringBuilder sb, long l, int numTrailingZeroBits) { + for (int i = 52; i >= numTrailingZeroBits - 3; i -= 4) { + sb.append(HEX_DIGITS[(int) ((l >>> i) & 0xf)]); + } + return sb; + } } diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceState.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceState.java index 57bbc42fe..fde88854a 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceState.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceState.java @@ -5,13 +5,14 @@ package io.opentelemetry.contrib.sampler.consistent2; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.appendLast56BitHexEncoded; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.appendLast56BitHexEncodedWithoutTrailingZeros; import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidRandomValue; import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxThreshold; import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidRandomValue; import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidThreshold; -import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -103,14 +104,14 @@ public String serialize() { StringBuilder sb = new StringBuilder(); if (hasValidThreshold() && threshold < getMaxThreshold()) { sb.append(SUBKEY_THRESHOLD).append(':'); - appendThreshold(sb, threshold); + appendLast56BitHexEncodedWithoutTrailingZeros(sb, threshold); } if (hasValidRandomValue()) { if (sb.length() > 0) { sb.append(';'); } sb.append(SUBKEY_RANDOM_VALUE).append(':'); - appendRandomValue(sb, randomValue); + appendLast56BitHexEncoded(sb, randomValue); } for (String pair : otherKeyValuePairs) { int ex = sb.length(); @@ -148,27 +149,6 @@ private static boolean isUpperCaseAlpha(char c) { return c >= 'A' && c <= 'Z'; } - private static final char[] HEX_DIGITS = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; - - @CanIgnoreReturnValue - static StringBuilder appendRandomValue(StringBuilder sb, long l) { - for (int i = 52; i >= 0; i -= 4) { - sb.append(HEX_DIGITS[(int) ((l >>> i) & 0xf)]); - } - return sb; - } - - @CanIgnoreReturnValue - static StringBuilder appendThreshold(StringBuilder sb, long l) { - int numTrailingBits = Long.numberOfTrailingZeros(l | 0x80000000000000L); - for (int i = 52; i >= numTrailingBits - 3; i -= 4) { - sb.append(HEX_DIGITS[(int) ((l >>> i) & 0xf)]); - } - return sb; - } - private static long parseRandomValue(String s, int startIncl, int endIncl) { int len = endIncl - startIncl; if (len != 14) { diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java index 635917255..555564670 100644 --- a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java @@ -74,4 +74,41 @@ void testCalculateAdjustedCount() { assertThat(calculateAdjustedCount(-1)).isOne(); assertThat(calculateAdjustedCount(0x100000000000001L)).isOne(); } + + @Test + void testAppendLast56BitHexEncoded() { + assertThat( + ConsistentSamplingUtil.appendLast56BitHexEncoded(new StringBuilder(), 0x3a436f7842456L)) + .hasToString("03a436f7842456"); + assertThat( + ConsistentSamplingUtil.appendLast56BitHexEncoded( + new StringBuilder(), 0x3a436f7842456abL)) + .hasToString("a436f7842456ab"); + assertThat(ConsistentSamplingUtil.appendLast56BitHexEncoded(new StringBuilder(), 0L)) + .hasToString("00000000000000"); + } + + @Test + void testAppendLast56BitHexEncodedWithoutTrailingZeros() { + assertThat( + ConsistentSamplingUtil.appendLast56BitHexEncodedWithoutTrailingZeros( + new StringBuilder(), 0x3a436f7842456L)) + .hasToString("03a436f7842456"); + assertThat( + ConsistentSamplingUtil.appendLast56BitHexEncodedWithoutTrailingZeros( + new StringBuilder(), 0x3a436f7842456abL)) + .hasToString("a436f7842456ab"); + assertThat( + ConsistentSamplingUtil.appendLast56BitHexEncodedWithoutTrailingZeros( + new StringBuilder(), 0x80000000000000L)) + .hasToString("8"); + assertThat( + ConsistentSamplingUtil.appendLast56BitHexEncodedWithoutTrailingZeros( + new StringBuilder(), 0x11000000000000L)) + .hasToString("11"); + assertThat( + ConsistentSamplingUtil.appendLast56BitHexEncodedWithoutTrailingZeros( + new StringBuilder(), 0L)) + .hasToString("0"); + } } From a0c1adf165c520856d5208d5556aa15960cd9acd Mon Sep 17 00:00:00 2001 From: Otmar Ertl Date: Sun, 8 Oct 2023 16:52:19 +0200 Subject: [PATCH 09/12] better sampler descriptions --- .../ConsistentFixedThresholdSampler.java | 18 +++++++++- .../ConsistentRateLimitingSampler.java | 14 +++++--- .../ConsistentFixedThresholdSamplerTest.java | 36 +++++++++++++------ .../ConsistentRateLimitingSamplerTest.java | 17 +++++++++ 4 files changed, 68 insertions(+), 17 deletions(-) diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSampler.java index e832b647d..52df84e03 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSampler.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSampler.java @@ -5,6 +5,7 @@ package io.opentelemetry.contrib.sampler.consistent2; +import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.calculateSamplingProbability; import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.checkThreshold; public class ConsistentFixedThresholdSampler extends ConsistentSampler { @@ -17,8 +18,23 @@ protected ConsistentFixedThresholdSampler( super(randomValueGenerator); checkThreshold(threshold); this.threshold = threshold; + + String thresholdString; + if (threshold == ConsistentSamplingUtil.getMaxThreshold()) { + thresholdString = "max"; + } else { + thresholdString = + ConsistentSamplingUtil.appendLast56BitHexEncodedWithoutTrailingZeros( + new StringBuilder(), threshold) + .toString(); + } + this.description = - "ConsistentFixedThresholdSampler{threshold=" + Long.toHexString(threshold) + "}"; + "ConsistentFixedThresholdSampler{threshold=" + + thresholdString + + ", sampling probability=" + + calculateSamplingProbability(threshold) + + "}"; } @Override diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSampler.java index 154b22103..2ad925b36 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSampler.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSampler.java @@ -68,6 +68,8 @@ */ final class ConsistentRateLimitingSampler extends ConsistentSampler { + private static final double NANOS_IN_SECONDS = 1e-9; + @Immutable private static final class State { private final double effectiveWindowCount; @@ -110,13 +112,15 @@ public State(double effectiveWindowCount, double effectiveWindowNanos, long last throw new IllegalArgumentException("Adaptation rate must be nonnegative!"); } this.description = - String.format( - "ConsistentRateLimitingSampler{%.6f, %.6f}", - targetSpansPerSecondLimit, adaptationTimeSeconds); + "ConsistentRateLimitingSampler{targetSpansPerSecondLimit=" + + targetSpansPerSecondLimit + + ", adaptationTimeSeconds=" + + adaptationTimeSeconds + + "}"; this.nanoTimeSupplier = requireNonNull(nanoTimeSupplier); - this.inverseAdaptationTimeNanos = 1e-9 / adaptationTimeSeconds; - this.targetSpansPerNanosecondLimit = 1e-9 * targetSpansPerSecondLimit; + this.inverseAdaptationTimeNanos = NANOS_IN_SECONDS / adaptationTimeSeconds; + this.targetSpansPerNanosecondLimit = NANOS_IN_SECONDS * targetSpansPerSecondLimit; this.state = new AtomicReference<>(new State(0, 0, nanoTimeSupplier.getAsLong())); } diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSamplerTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSamplerTest.java index df450cb2e..e92b23416 100644 --- a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSamplerTest.java +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSamplerTest.java @@ -45,7 +45,7 @@ public void init() { parentLinks = Collections.emptyList(); } - private void test(SplittableRandom rng, double samplingProbability) { + private void testSampling(SplittableRandom rng, double samplingProbability) { int numSpans = 10000; Sampler sampler = @@ -82,19 +82,33 @@ private void test(SplittableRandom rng, double samplingProbability) { } @Test - public void test() { + public void testSampling() { // fix seed to get reproducible results SplittableRandom random = new SplittableRandom(0); - test(random, 1.); - test(random, 0.5); - test(random, 0.25); - test(random, 0.125); - test(random, 0.0); - test(random, 0.45); - test(random, 0.2); - test(random, 0.13); - test(random, 0.05); + testSampling(random, 1.); + testSampling(random, 0.5); + testSampling(random, 0.25); + testSampling(random, 0.125); + testSampling(random, 0.0); + testSampling(random, 0.45); + testSampling(random, 0.2); + testSampling(random, 0.13); + testSampling(random, 0.05); + } + + @Test + public void testDescription() { + assertThat(ConsistentSampler.probabilityBased(1.0).getDescription()) + .isEqualTo("ConsistentFixedThresholdSampler{threshold=max, sampling probability=1.0}"); + assertThat(ConsistentSampler.probabilityBased(0.5).getDescription()) + .isEqualTo("ConsistentFixedThresholdSampler{threshold=8, sampling probability=0.5}"); + assertThat(ConsistentSampler.probabilityBased(0.25).getDescription()) + .isEqualTo("ConsistentFixedThresholdSampler{threshold=4, sampling probability=0.25}"); + assertThat(ConsistentSampler.probabilityBased(1e-300).getDescription()) + .isEqualTo("ConsistentFixedThresholdSampler{threshold=0, sampling probability=0.0}"); + assertThat(ConsistentSampler.probabilityBased(0).getDescription()) + .isEqualTo("ConsistentFixedThresholdSampler{threshold=0, sampling probability=0.0}"); } } diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSamplerTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSamplerTest.java index c18f5f570..e6f8b8deb 100644 --- a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSamplerTest.java +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSamplerTest.java @@ -211,4 +211,21 @@ void testRateDecrease() { assertThat(numSampledSpansInLast5Seconds / 5.) .isCloseTo(targetSpansPerSecondLimit, Percentage.withPercentage(5)); } + + @Test + void testDescription() { + + double targetSpansPerSecondLimit = 123.456; + double adaptationTimeSeconds = 7.89; + ConsistentSampler sampler = + ConsistentSampler.rateLimited(targetSpansPerSecondLimit, adaptationTimeSeconds); + + assertThat(sampler.getDescription()) + .isEqualTo( + "ConsistentRateLimitingSampler{targetSpansPerSecondLimit=" + + targetSpansPerSecondLimit + + ", adaptationTimeSeconds=" + + adaptationTimeSeconds + + "}"); + } } From 2e7cf7282e1f29fda401eb3ac7b2caa447b83be0 Mon Sep 17 00:00:00 2001 From: Otmar Ertl Date: Sun, 8 Oct 2023 17:22:20 +0200 Subject: [PATCH 10/12] renamed consistent2 -> consistent56 --- consistent-sampling/build.gradle.kts | 2 +- .../ConsistentAlwaysOffSampler.java | 2 +- .../ConsistentAlwaysOnSampler.java | 4 +- .../ConsistentComposedAndSampler.java | 9 ++-- .../ConsistentComposedOrSampler.java | 12 +++-- .../ConsistentFixedThresholdSampler.java | 6 +-- .../ConsistentParentBasedSampler.java | 5 +-- .../ConsistentRateLimitingSampler.java | 5 +-- .../ConsistentSampler.java | 10 ++--- .../ConsistentSamplingUtil.java | 2 +- .../OtelTraceState.java | 45 +++++++++---------- .../RandomValueGenerator.java | 2 +- .../RandomValueGenerators.java | 4 +- .../ConsistentAlwaysOffSamplerTest.java | 6 +-- .../ConsistentAlwaysOnSamplerTest.java | 6 +-- .../ConsistentFixedThresholdSamplerTest.java | 6 +-- .../ConsistentRateLimitingSamplerTest.java | 4 +- .../ConsistentSamplerTest.java | 4 +- .../ConsistentSamplingUtilTest.java | 16 +++---- .../OtelTraceStateTest.java | 2 +- .../RandomValueGeneratorsTest.java | 4 +- 21 files changed, 73 insertions(+), 83 deletions(-) rename consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentAlwaysOffSampler.java (90%) rename consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentAlwaysOnSampler.java (77%) rename consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentComposedAndSampler.java (79%) rename consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentComposedOrSampler.java (77%) rename consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentFixedThresholdSampler.java (81%) rename consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentParentBasedSampler.java (85%) rename consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentRateLimitingSampler.java (96%) rename consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentSampler.java (96%) rename consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentSamplingUtil.java (98%) rename consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/OtelTraceState.java (78%) rename consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/RandomValueGenerator.java (89%) rename consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/RandomValueGenerators.java (75%) rename consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentAlwaysOffSamplerTest.java (78%) rename consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentAlwaysOnSamplerTest.java (81%) rename consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentFixedThresholdSamplerTest.java (93%) rename consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentRateLimitingSamplerTest.java (98%) rename consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentSamplerTest.java (98%) rename consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/ConsistentSamplingUtilTest.java (84%) rename consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/OtelTraceStateTest.java (98%) rename consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/{consistent2 => consistent56}/RandomValueGeneratorsTest.java (74%) diff --git a/consistent-sampling/build.gradle.kts b/consistent-sampling/build.gradle.kts index cfd04d697..bedabc341 100644 --- a/consistent-sampling/build.gradle.kts +++ b/consistent-sampling/build.gradle.kts @@ -5,7 +5,7 @@ plugins { description = "Sampler and exporter implementations for consistent sampling" otelJava.moduleName.set("io.opentelemetry.contrib.sampler.consistent") -otelJava.moduleName.set("io.opentelemetry.contrib.sampler.consistent2") +otelJava.moduleName.set("io.opentelemetry.contrib.sampler.consistent56") dependencies { api("io.opentelemetry:opentelemetry-sdk-trace") diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOffSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentAlwaysOffSampler.java similarity index 90% rename from consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOffSampler.java rename to consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentAlwaysOffSampler.java index 6f6f3a033..2b95c19ce 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOffSampler.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentAlwaysOffSampler.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; import javax.annotation.concurrent.Immutable; diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOnSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentAlwaysOnSampler.java similarity index 77% rename from consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOnSampler.java rename to consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentAlwaysOnSampler.java index 43e359a34..93db59560 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOnSampler.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentAlwaysOnSampler.java @@ -3,9 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxThreshold; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getMaxThreshold; import javax.annotation.concurrent.Immutable; diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentComposedAndSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentComposedAndSampler.java similarity index 79% rename from consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentComposedAndSampler.java rename to consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentComposedAndSampler.java index 2c6e608e6..de22a7056 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentComposedAndSampler.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentComposedAndSampler.java @@ -3,10 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidThreshold; import static java.util.Objects.requireNonNull; import javax.annotation.concurrent.Immutable; @@ -43,10 +41,11 @@ final class ConsistentComposedAndSampler extends ConsistentSampler { protected long getThreshold(long parentThreshold, boolean isRoot) { long threshold1 = sampler1.getThreshold(parentThreshold, isRoot); long threshold2 = sampler2.getThreshold(parentThreshold, isRoot); - if (isValidThreshold(threshold1) && isValidThreshold(threshold2)) { + if (ConsistentSamplingUtil.isValidThreshold(threshold1) + && ConsistentSamplingUtil.isValidThreshold(threshold2)) { return Math.min(threshold1, threshold2); } else { - return getInvalidThreshold(); + return ConsistentSamplingUtil.getInvalidThreshold(); } } diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentComposedOrSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentComposedOrSampler.java similarity index 77% rename from consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentComposedOrSampler.java rename to consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentComposedOrSampler.java index 497ccb878..542cc65bc 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentComposedOrSampler.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentComposedOrSampler.java @@ -3,10 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidThreshold; import static java.util.Objects.requireNonNull; import javax.annotation.concurrent.Immutable; @@ -43,16 +41,16 @@ final class ConsistentComposedOrSampler extends ConsistentSampler { protected long getThreshold(long parentThreshold, boolean isRoot) { long threshold1 = sampler1.getThreshold(parentThreshold, isRoot); long threshold2 = sampler2.getThreshold(parentThreshold, isRoot); - if (isValidThreshold(threshold1)) { - if (isValidThreshold(threshold2)) { + if (ConsistentSamplingUtil.isValidThreshold(threshold1)) { + if (ConsistentSamplingUtil.isValidThreshold(threshold2)) { return Math.max(threshold1, threshold2); } return threshold1; } else { - if (isValidThreshold(threshold2)) { + if (ConsistentSamplingUtil.isValidThreshold(threshold2)) { return threshold2; } - return getInvalidThreshold(); + return ConsistentSamplingUtil.getInvalidThreshold(); } } diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentFixedThresholdSampler.java similarity index 81% rename from consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSampler.java rename to consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentFixedThresholdSampler.java index 52df84e03..dd160f387 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSampler.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentFixedThresholdSampler.java @@ -3,10 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.calculateSamplingProbability; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.checkThreshold; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.calculateSamplingProbability; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.checkThreshold; public class ConsistentFixedThresholdSampler extends ConsistentSampler { diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentParentBasedSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentParentBasedSampler.java similarity index 85% rename from consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentParentBasedSampler.java rename to consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentParentBasedSampler.java index 12c5d412b..9d40793d9 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentParentBasedSampler.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentParentBasedSampler.java @@ -3,9 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; import static java.util.Objects.requireNonNull; import javax.annotation.concurrent.Immutable; @@ -39,7 +38,7 @@ final class ConsistentParentBasedSampler extends ConsistentSampler { @Override protected long getThreshold(long parentThreshold, boolean isRoot) { if (isRoot) { - return rootSampler.getThreshold(getInvalidThreshold(), isRoot); + return rootSampler.getThreshold(ConsistentSamplingUtil.getInvalidThreshold(), isRoot); } else { return parentThreshold; } diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentRateLimitingSampler.java similarity index 96% rename from consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSampler.java rename to consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentRateLimitingSampler.java index 2ad925b36..3e741df8d 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSampler.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentRateLimitingSampler.java @@ -3,9 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxThreshold; import static java.util.Objects.requireNonNull; import io.opentelemetry.sdk.trace.samplers.Sampler; @@ -148,7 +147,7 @@ protected long getThreshold(long parentThreshold, boolean isRoot) { / currentState.effectiveWindowCount; if (samplingProbability >= 1.) { - return getMaxThreshold(); + return ConsistentSamplingUtil.getMaxThreshold(); } else { return ConsistentSamplingUtil.calculateThreshold(samplingProbability); } diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentSampler.java similarity index 96% rename from consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java rename to consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentSampler.java index 36d4411d2..005c22d90 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSampler.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentSampler.java @@ -3,12 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidRandomValue; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxThreshold; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidThreshold; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getInvalidRandomValue; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getInvalidThreshold; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getMaxThreshold; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.isValidThreshold; import static java.util.Objects.requireNonNull; import io.opentelemetry.api.common.Attributes; diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentSamplingUtil.java similarity index 98% rename from consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java rename to consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentSamplingUtil.java index 18d47fe15..80a6bffd2 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtil.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentSamplingUtil.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; import com.google.errorprone.annotations.CanIgnoreReturnValue; diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceState.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/OtelTraceState.java similarity index 78% rename from consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceState.java rename to consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/OtelTraceState.java index fde88854a..e546b184b 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceState.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/OtelTraceState.java @@ -3,15 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; - -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.appendLast56BitHexEncoded; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.appendLast56BitHexEncodedWithoutTrailingZeros; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidRandomValue; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxThreshold; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidRandomValue; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidThreshold; +package io.opentelemetry.contrib.sampler.consistent56; import java.util.ArrayList; import java.util.Collections; @@ -38,7 +30,10 @@ private OtelTraceState(long randomValue, long threshold, List otherKeyVa } private OtelTraceState() { - this(getInvalidRandomValue(), getInvalidThreshold(), Collections.emptyList()); + this( + ConsistentSamplingUtil.getInvalidRandomValue(), + ConsistentSamplingUtil.getInvalidThreshold(), + Collections.emptyList()); } public long getRandomValue() { @@ -50,19 +45,19 @@ public long getThreshold() { } public boolean hasValidRandomValue() { - return isValidRandomValue(randomValue); + return ConsistentSamplingUtil.isValidRandomValue(randomValue); } public boolean hasValidThreshold() { - return isValidThreshold(threshold); + return ConsistentSamplingUtil.isValidThreshold(threshold); } public void invalidateRandomValue() { - randomValue = getInvalidRandomValue(); + randomValue = ConsistentSamplingUtil.getInvalidRandomValue(); } public void invalidateThreshold() { - threshold = getInvalidThreshold(); + threshold = ConsistentSamplingUtil.getInvalidThreshold(); } /** @@ -73,7 +68,7 @@ public void invalidateThreshold() { * @param threshold the new th-value */ public void setThreshold(long threshold) { - if (isValidThreshold(threshold)) { + if (ConsistentSamplingUtil.isValidThreshold(threshold)) { this.threshold = threshold; } else { invalidateThreshold(); @@ -88,7 +83,7 @@ public void setThreshold(long threshold) { * @param randomValue the new rv-value */ public void setRandomValue(long randomValue) { - if (isValidRandomValue(randomValue)) { + if (ConsistentSamplingUtil.isValidRandomValue(randomValue)) { this.randomValue = randomValue; } else { invalidateRandomValue(); @@ -102,16 +97,16 @@ public void setRandomValue(long randomValue) { */ public String serialize() { StringBuilder sb = new StringBuilder(); - if (hasValidThreshold() && threshold < getMaxThreshold()) { + if (hasValidThreshold() && threshold < ConsistentSamplingUtil.getMaxThreshold()) { sb.append(SUBKEY_THRESHOLD).append(':'); - appendLast56BitHexEncodedWithoutTrailingZeros(sb, threshold); + ConsistentSamplingUtil.appendLast56BitHexEncodedWithoutTrailingZeros(sb, threshold); } if (hasValidRandomValue()) { if (sb.length() > 0) { sb.append(';'); } sb.append(SUBKEY_RANDOM_VALUE).append(':'); - appendLast56BitHexEncoded(sb, randomValue); + ConsistentSamplingUtil.appendLast56BitHexEncoded(sb, randomValue); } for (String pair : otherKeyValuePairs) { int ex = sb.length(); @@ -152,17 +147,17 @@ private static boolean isUpperCaseAlpha(char c) { private static long parseRandomValue(String s, int startIncl, int endIncl) { int len = endIncl - startIncl; if (len != 14) { - return getInvalidRandomValue(); + return ConsistentSamplingUtil.getInvalidRandomValue(); } - return parseHex(s, startIncl, len, getInvalidRandomValue()); + return parseHex(s, startIncl, len, ConsistentSamplingUtil.getInvalidRandomValue()); } private static long parseThreshold(String s, int startIncl, int endIncl) { int len = endIncl - startIncl; if (len > 14) { - return getInvalidThreshold(); + return ConsistentSamplingUtil.getInvalidThreshold(); } - return parseHex(s, startIncl, len, getInvalidThreshold()); + return parseHex(s, startIncl, len, ConsistentSamplingUtil.getInvalidThreshold()); } static long parseHex(String s, int startIncl, int len, long invalidReturnValue) { @@ -193,8 +188,8 @@ static long parseHex(String s, int startIncl, int len, long invalidReturnValue) */ public static OtelTraceState parse(@Nullable String ts) { List otherKeyValuePairs = null; - long threshold = getInvalidThreshold(); - long randomValue = getInvalidRandomValue(); + long threshold = ConsistentSamplingUtil.getInvalidThreshold(); + long randomValue = ConsistentSamplingUtil.getInvalidRandomValue(); if (ts == null || ts.isEmpty()) { return new OtelTraceState(); diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGenerator.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/RandomValueGenerator.java similarity index 89% rename from consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGenerator.java rename to consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/RandomValueGenerator.java index 4aa4c4460..39ba47b03 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGenerator.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/RandomValueGenerator.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; /** * A function for generating random values. diff --git a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGenerators.java b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/RandomValueGenerators.java similarity index 75% rename from consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGenerators.java rename to consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/RandomValueGenerators.java index 97f56bc5a..fcd0f6f5f 100644 --- a/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGenerators.java +++ b/consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/RandomValueGenerators.java @@ -3,9 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxRandomValue; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getMaxRandomValue; import java.util.concurrent.ThreadLocalRandom; diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOffSamplerTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentAlwaysOffSamplerTest.java similarity index 78% rename from consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOffSamplerTest.java rename to consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentAlwaysOffSamplerTest.java index 476b3c6a7..60f97ac23 100644 --- a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOffSamplerTest.java +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentAlwaysOffSamplerTest.java @@ -3,10 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxThreshold; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getInvalidThreshold; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getMaxThreshold; import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.Test; diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOnSamplerTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentAlwaysOnSamplerTest.java similarity index 81% rename from consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOnSamplerTest.java rename to consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentAlwaysOnSamplerTest.java index 2150e5732..96943be5e 100644 --- a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentAlwaysOnSamplerTest.java +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentAlwaysOnSamplerTest.java @@ -3,10 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxThreshold; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getInvalidThreshold; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getMaxThreshold; import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.Test; diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSamplerTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentFixedThresholdSamplerTest.java similarity index 93% rename from consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSamplerTest.java rename to consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentFixedThresholdSamplerTest.java index e92b23416..340f6641f 100644 --- a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentFixedThresholdSamplerTest.java +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentFixedThresholdSamplerTest.java @@ -3,10 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.calculateThreshold; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxRandomValue; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.calculateThreshold; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getMaxRandomValue; import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.common.Attributes; diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSamplerTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentRateLimitingSamplerTest.java similarity index 98% rename from consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSamplerTest.java rename to consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentRateLimitingSamplerTest.java index e6f8b8deb..24c70e4e5 100644 --- a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentRateLimitingSamplerTest.java +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentRateLimitingSamplerTest.java @@ -3,9 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxRandomValue; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getMaxRandomValue; import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.common.Attributes; diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplerTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentSamplerTest.java similarity index 98% rename from consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplerTest.java rename to consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentSamplerTest.java index da4fde503..e36868a56 100644 --- a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplerTest.java +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentSamplerTest.java @@ -3,9 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxRandomValue; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getMaxRandomValue; import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.common.Attributes; diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentSamplingUtilTest.java similarity index 84% rename from consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java rename to consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentSamplingUtilTest.java index 555564670..944ace75b 100644 --- a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/ConsistentSamplingUtilTest.java +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentSamplingUtilTest.java @@ -3,15 +3,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.calculateAdjustedCount; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.calculateSamplingProbability; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.calculateThreshold; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidRandomValue; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getInvalidThreshold; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidRandomValue; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.isValidThreshold; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.calculateAdjustedCount; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.calculateSamplingProbability; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.calculateThreshold; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getInvalidRandomValue; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getInvalidThreshold; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.isValidRandomValue; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.isValidThreshold; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceStateTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/OtelTraceStateTest.java similarity index 98% rename from consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceStateTest.java rename to consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/OtelTraceStateTest.java index 827604eb6..a131e9b78 100644 --- a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/OtelTraceStateTest.java +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/OtelTraceStateTest.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGeneratorsTest.java b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/RandomValueGeneratorsTest.java similarity index 74% rename from consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGeneratorsTest.java rename to consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/RandomValueGeneratorsTest.java index a82bc33d1..ab7d378b6 100644 --- a/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent2/RandomValueGeneratorsTest.java +++ b/consistent-sampling/src/test/java/io/opentelemetry/contrib/sampler/consistent56/RandomValueGeneratorsTest.java @@ -3,9 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.contrib.sampler.consistent2; +package io.opentelemetry.contrib.sampler.consistent56; -import static io.opentelemetry.contrib.sampler.consistent2.ConsistentSamplingUtil.getMaxRandomValue; +import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getMaxRandomValue; import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.Test; From 50472fb565282a924800b462665f135a39c0edf0 Mon Sep 17 00:00:00 2001 From: Otmar Ertl Date: Sun, 8 Oct 2023 17:24:54 +0200 Subject: [PATCH 11/12] hipparchus 3.0 --- consistent-sampling/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/consistent-sampling/build.gradle.kts b/consistent-sampling/build.gradle.kts index bedabc341..63b9b895f 100644 --- a/consistent-sampling/build.gradle.kts +++ b/consistent-sampling/build.gradle.kts @@ -10,6 +10,6 @@ otelJava.moduleName.set("io.opentelemetry.contrib.sampler.consistent56") dependencies { api("io.opentelemetry:opentelemetry-sdk-trace") api("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") - testImplementation("org.hipparchus:hipparchus-core:2.3") - testImplementation("org.hipparchus:hipparchus-stat:2.3") + testImplementation("org.hipparchus:hipparchus-core:3.0") + testImplementation("org.hipparchus:hipparchus-stat:3.0") } From 0b66642a194cfda063ca7102ac874297e6cd4887 Mon Sep 17 00:00:00 2001 From: Otmar Ertl Date: Mon, 16 Oct 2023 15:21:46 +0200 Subject: [PATCH 12/12] update otelJava.moduleName.set --- consistent-sampling/build.gradle.kts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/consistent-sampling/build.gradle.kts b/consistent-sampling/build.gradle.kts index 63b9b895f..06b330c2f 100644 --- a/consistent-sampling/build.gradle.kts +++ b/consistent-sampling/build.gradle.kts @@ -4,8 +4,7 @@ plugins { } description = "Sampler and exporter implementations for consistent sampling" -otelJava.moduleName.set("io.opentelemetry.contrib.sampler.consistent") -otelJava.moduleName.set("io.opentelemetry.contrib.sampler.consistent56") +otelJava.moduleName.set("io.opentelemetry.contrib.sampler") dependencies { api("io.opentelemetry:opentelemetry-sdk-trace")