Skip to content

Commit 40bfdac

Browse files
authored
add updateable threshold sampler (open-telemetry#2137)
1 parent 8e8ab53 commit 40bfdac

File tree

5 files changed

+179
-47
lines changed

5 files changed

+179
-47
lines changed

consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentFixedThresholdSampler.java

Lines changed: 3 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,9 @@
55

66
package io.opentelemetry.contrib.sampler.consistent56;
77

8-
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.calculateSamplingProbability;
98
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.calculateThreshold;
10-
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.checkThreshold;
11-
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getInvalidThreshold;
12-
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getMaxThreshold;
139

14-
import io.opentelemetry.api.common.Attributes;
15-
import io.opentelemetry.api.trace.SpanKind;
16-
import io.opentelemetry.context.Context;
17-
import io.opentelemetry.sdk.trace.data.LinkData;
18-
import java.util.List;
19-
20-
public class ConsistentFixedThresholdSampler extends ConsistentSampler {
10+
public class ConsistentFixedThresholdSampler extends ConsistentThresholdSampler {
2111

2212
private final long threshold;
2313
private final String description;
@@ -31,47 +21,13 @@ protected ConsistentFixedThresholdSampler(double samplingProbability) {
3121
this(calculateThreshold(samplingProbability));
3222
}
3323

34-
private static long getThreshold(long threshold) {
35-
checkThreshold(threshold);
36-
return threshold;
37-
}
38-
39-
private static String getThresholdDescription(long threshold) {
40-
String thresholdString;
41-
if (threshold == getMaxThreshold()) {
42-
thresholdString = "max";
43-
} else {
44-
thresholdString =
45-
ConsistentSamplingUtil.appendLast56BitHexEncodedWithoutTrailingZeros(
46-
new StringBuilder(), threshold)
47-
.toString();
48-
}
49-
50-
return "ConsistentFixedThresholdSampler{threshold="
51-
+ thresholdString
52-
+ ", sampling probability="
53-
+ calculateSamplingProbability(threshold)
54-
+ "}";
55-
}
56-
5724
@Override
5825
public String getDescription() {
5926
return description;
6027
}
6128

6229
@Override
63-
public SamplingIntent getSamplingIntent(
64-
Context parentContext,
65-
String name,
66-
SpanKind spanKind,
67-
Attributes attributes,
68-
List<LinkData> parentLinks) {
69-
70-
return () -> {
71-
if (threshold == getMaxThreshold()) {
72-
return getInvalidThreshold();
73-
}
74-
return threshold;
75-
};
30+
public long getThreshold() {
31+
return threshold;
7632
}
7733
}

consistent-sampling/src/main/java/io/opentelemetry/contrib/sampler/consistent56/ConsistentSampler.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ public static ConsistentSampler probabilityBased(double samplingProbability) {
5555
return new ConsistentFixedThresholdSampler(threshold);
5656
}
5757

58+
/**
59+
* Returns a {@link ConsistentSampler} that samples each span with a known probability, where the
60+
* probablity can be dynamically updated.
61+
*
62+
* @param samplingProbability the sampling probability
63+
* @return a sampler
64+
*/
65+
public static ConsistentSampler updateableProbabilityBased(double samplingProbability) {
66+
return new ConsistentVariableThresholdSampler(samplingProbability);
67+
}
68+
5869
/**
5970
* Returns a new {@link ConsistentSampler} that respects the sampling decision of the parent span
6071
* or falls-back to the given sampler if it is a root span.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.sampler.consistent56;
7+
8+
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.appendLast56BitHexEncodedWithoutTrailingZeros;
9+
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.calculateSamplingProbability;
10+
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.checkThreshold;
11+
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getInvalidThreshold;
12+
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getMaxThreshold;
13+
14+
import io.opentelemetry.api.common.Attributes;
15+
import io.opentelemetry.api.trace.SpanKind;
16+
import io.opentelemetry.context.Context;
17+
import io.opentelemetry.sdk.trace.data.LinkData;
18+
import java.util.List;
19+
20+
public abstract class ConsistentThresholdSampler extends ConsistentSampler {
21+
22+
protected abstract long getThreshold();
23+
24+
protected static long getThreshold(long threshold) {
25+
checkThreshold(threshold);
26+
return threshold;
27+
}
28+
29+
protected static String getThresholdDescription(long threshold) {
30+
String thresholdString;
31+
if (threshold == getMaxThreshold()) {
32+
thresholdString = "max";
33+
} else {
34+
thresholdString =
35+
appendLast56BitHexEncodedWithoutTrailingZeros(new StringBuilder(), threshold).toString();
36+
}
37+
38+
return "ConsistentFixedThresholdSampler{threshold="
39+
+ thresholdString
40+
+ ", sampling probability="
41+
+ calculateSamplingProbability(threshold)
42+
+ "}";
43+
}
44+
45+
@Override
46+
public SamplingIntent getSamplingIntent(
47+
Context parentContext,
48+
String name,
49+
SpanKind spanKind,
50+
Attributes attributes,
51+
List<LinkData> parentLinks) {
52+
53+
return () -> {
54+
if (getThreshold() == getMaxThreshold()) {
55+
return getInvalidThreshold();
56+
}
57+
return getThreshold();
58+
};
59+
}
60+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.sampler.consistent56;
7+
8+
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.calculateSamplingProbability;
9+
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.calculateThreshold;
10+
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.checkThreshold;
11+
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getMaxThreshold;
12+
13+
public class ConsistentVariableThresholdSampler extends ConsistentThresholdSampler {
14+
15+
private volatile long threshold;
16+
private volatile String description = "";
17+
18+
protected ConsistentVariableThresholdSampler(double samplingProbability) {
19+
setSamplingProbability(samplingProbability);
20+
}
21+
22+
@Override
23+
public String getDescription() {
24+
return description;
25+
}
26+
27+
@Override
28+
public long getThreshold() {
29+
return threshold;
30+
}
31+
32+
public void setSamplingProbability(double samplingProbability) {
33+
long threshold = calculateThreshold(samplingProbability);
34+
checkThreshold(threshold);
35+
this.threshold = threshold;
36+
37+
String thresholdString;
38+
if (threshold == getMaxThreshold()) {
39+
thresholdString = "max";
40+
} else {
41+
thresholdString =
42+
ConsistentSamplingUtil.appendLast56BitHexEncodedWithoutTrailingZeros(
43+
new StringBuilder(), threshold)
44+
.toString();
45+
}
46+
47+
// tiny eventual consistency where the description would be out of date with the threshold,
48+
// but this doesn't really matter
49+
this.description =
50+
"ConsistentVariableThresholdSampler{threshold="
51+
+ thresholdString
52+
+ ", sampling probability="
53+
+ calculateSamplingProbability(threshold)
54+
+ "}";
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.sampler.consistent56;
7+
8+
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.calculateThreshold;
9+
import static io.opentelemetry.contrib.sampler.consistent56.ConsistentSamplingUtil.getMaxThreshold;
10+
import static org.assertj.core.api.Assertions.assertThat;
11+
12+
import org.junit.jupiter.api.Test;
13+
14+
class ConsistentVariableThresholdSamplerTest {
15+
16+
@Test
17+
void testSetSamplingProbability() {
18+
double probability = 0.5;
19+
ConsistentVariableThresholdSampler sampler =
20+
new ConsistentVariableThresholdSampler(probability);
21+
testSetSamplingProbability(probability, sampler, /* updateProbability= */ false);
22+
testSetSamplingProbability(0.25, sampler, /* updateProbability= */ true);
23+
testSetSamplingProbability(0.0, sampler, /* updateProbability= */ true);
24+
testSetSamplingProbability(1.0, sampler, /* updateProbability= */ true);
25+
}
26+
27+
private static void testSetSamplingProbability(
28+
double probability, ConsistentVariableThresholdSampler sampler, boolean updateProbability) {
29+
long threshold = calculateThreshold(probability);
30+
String thresholdString =
31+
ConsistentSamplingUtil.appendLast56BitHexEncodedWithoutTrailingZeros(
32+
new StringBuilder(), threshold)
33+
.toString();
34+
if (threshold == getMaxThreshold()) {
35+
thresholdString = "max";
36+
}
37+
if (updateProbability) {
38+
sampler.setSamplingProbability(probability);
39+
}
40+
assertThat(sampler.getThreshold()).isEqualTo(threshold);
41+
assertThat(sampler.getDescription())
42+
.isEqualTo(
43+
"ConsistentVariableThresholdSampler{threshold="
44+
+ thresholdString
45+
+ ", sampling probability="
46+
+ probability
47+
+ "}");
48+
}
49+
}

0 commit comments

Comments
 (0)