Skip to content

Commit a0126d7

Browse files
committed
Expose aggregation configuration and wire in exemplar sampler
- Expose classes for aggregation configuration that are visible in exemplar sampler - Create default exemplar sampler that samples w/ traces - Expand metric benchmarks to include exemplar + no-exemplar to check overhead.
1 parent bcb0335 commit a0126d7

16 files changed

+286
-64
lines changed

sdk/metrics/build.gradle.kts

+2
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,6 @@ dependencies {
2323
testImplementation(project(":sdk:metrics-testing"))
2424
testImplementation(project(":sdk:testing"))
2525
testImplementation("com.google.guava:guava")
26+
27+
jmh(project(":sdk:trace"))
2628
}

sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/MetricsBenchmarks.java

+16
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
import io.opentelemetry.api.common.Attributes;
99
import io.opentelemetry.api.metrics.Meter;
10+
import io.opentelemetry.api.trace.Span;
11+
import io.opentelemetry.api.trace.Tracer;
1012
import java.util.concurrent.TimeUnit;
1113
import org.openjdk.jmh.annotations.Benchmark;
1214
import org.openjdk.jmh.annotations.BenchmarkMode;
@@ -18,6 +20,7 @@
1820
import org.openjdk.jmh.annotations.Scope;
1921
import org.openjdk.jmh.annotations.Setup;
2022
import org.openjdk.jmh.annotations.State;
23+
import org.openjdk.jmh.annotations.TearDown;
2124
import org.openjdk.jmh.annotations.Threads;
2225
import org.openjdk.jmh.annotations.Warmup;
2326
import org.openjdk.jmh.infra.ThreadParams;
@@ -37,16 +40,29 @@ public static class ThreadState {
3740
@Param MetricsTestOperationBuilder opBuilder;
3841

3942
MetricsTestOperationBuilder.Operation op;
43+
Span span;
44+
io.opentelemetry.context.Scope contextScope;
4045
final Attributes sharedLabelSet = Attributes.builder().put("KEY", "VALUE").build();
4146
Attributes threadUniqueLabelSet;
4247

4348
@Setup
49+
@SuppressWarnings("MustBeClosedChecker")
4450
public void setup(ThreadParams threadParams) {
4551
Meter meter = sdk.getMeter();
52+
Tracer tracer = sdk.getTracer();
53+
span = tracer.spanBuilder("benchmark").startSpan();
54+
// We suppress warnings on closing here, as we rely on tests to make sure context is closed.
55+
contextScope = span.makeCurrent();
4656
op = opBuilder.build(meter);
4757
threadUniqueLabelSet =
4858
Attributes.builder().put("KEY", String.valueOf(threadParams.getThreadIndex())).build();
4959
}
60+
61+
@TearDown
62+
public void tearDown(ThreadParams threadParms) {
63+
contextScope.close();
64+
span.end();
65+
}
5066
}
5167

5268
@Benchmark

sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/MetricsTestOperationBuilder.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import io.opentelemetry.api.metrics.LongCounter;
1616
import io.opentelemetry.api.metrics.LongHistogram;
1717
import io.opentelemetry.api.metrics.Meter;
18+
import java.util.concurrent.ThreadLocalRandom;
1819

1920
/**
2021
* This enum allows for iteration over all of the operations that we want to benchmark. To ensure
@@ -80,12 +81,13 @@ public void performBound() {
8081

8182
@Override
8283
public void perform(Attributes labels) {
83-
metric.record(5.0d, labels);
84+
// We record different values to try to hit more areas of the histogram buckets.
85+
metric.record(ThreadLocalRandom.current().nextDouble(0, 20_000d), labels);
8486
}
8587

8688
@Override
8789
public void performBound() {
88-
boundMetric.record(5.0d);
90+
boundMetric.record(ThreadLocalRandom.current().nextDouble(0, 20_000d));
8991
}
9092
};
9193
}),
@@ -103,12 +105,12 @@ public void performBound() {
103105

104106
@Override
105107
public void perform(Attributes labels) {
106-
metric.record(5L, labels);
108+
metric.record(ThreadLocalRandom.current().nextLong(0, 20_000L), labels);
107109
}
108110

109111
@Override
110112
public void performBound() {
111-
boundMetric.record(5L);
113+
boundMetric.record(ThreadLocalRandom.current().nextLong(0, 20_000L));
112114
}
113115
};
114116
});

sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/TestSdk.java

+29
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@
77

88
import io.opentelemetry.api.metrics.Meter;
99
import io.opentelemetry.api.metrics.MeterProvider;
10+
import io.opentelemetry.api.trace.Tracer;
1011
import io.opentelemetry.sdk.common.Clock;
12+
import io.opentelemetry.sdk.metrics.exemplar.ExemplarFilter;
13+
import io.opentelemetry.sdk.metrics.exemplar.ExemplarSampler;
1114
import io.opentelemetry.sdk.resources.Resource;
15+
import io.opentelemetry.sdk.trace.SdkTracerProvider;
16+
import io.opentelemetry.sdk.trace.samplers.Sampler;
1217

1318
@SuppressWarnings("ImmutableEnumChecker")
1419
public enum TestSdk {
@@ -19,6 +24,19 @@ Meter build() {
1924
return MeterProvider.noop().get("io.opentelemetry.sdk.metrics");
2025
}
2126
}),
27+
SDK_NO_EXEMPLARS(
28+
new SdkBuilder() {
29+
@Override
30+
Meter build() {
31+
return SdkMeterProvider.builder()
32+
.setClock(Clock.getDefault())
33+
.setResource(Resource.empty())
34+
.setExemplarSampler(
35+
ExemplarSampler.builder().setFilter(ExemplarFilter.neverSample()).build())
36+
.build()
37+
.get("io.opentelemetry.sdk.metrics");
38+
}
39+
}),
2240
SDK(
2341
new SdkBuilder() {
2442
@Override
@@ -41,7 +59,18 @@ public Meter getMeter() {
4159
return sdkBuilder.build();
4260
}
4361

62+
public Tracer getTracer() {
63+
return sdkBuilder.buildTracer();
64+
}
65+
4466
private abstract static class SdkBuilder {
4567
abstract Meter build();
68+
69+
protected Tracer buildTracer() {
70+
return SdkTracerProvider.builder()
71+
.setSampler(Sampler.alwaysOn())
72+
.build()
73+
.get("io.opentelemetry.sdk.metrics");
74+
}
4675
}
4776
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.metrics.exemplar;
7+
8+
import io.opentelemetry.sdk.common.Clock;
9+
import io.opentelemetry.sdk.metrics.view.Aggregation;
10+
import io.opentelemetry.sdk.metrics.view.ExplicitBucketHistogramAggregation;
11+
12+
class DefaultExemplarReservoirFactory implements ExemplarReservoirFactory {
13+
14+
static final ExemplarReservoirFactory INSTANCE = new DefaultExemplarReservoirFactory();
15+
16+
private DefaultExemplarReservoirFactory() {}
17+
18+
@Override
19+
public ExemplarReservoir createReservoir(Aggregation aggregation) {
20+
Clock clock = Clock.getDefault();
21+
// For histograms, line up reservoirs with buckets.
22+
if (aggregation instanceof ExplicitBucketHistogramAggregation) {
23+
return HistogramBucketExemplarReservoir.create(
24+
clock, ((ExplicitBucketHistogramAggregation) aggregation).getBucketBoundaries());
25+
}
26+
// By default, reduce threading contention.
27+
return new FixedSizeExemplarReservoir(clock, Runtime.getRuntime().availableProcessors());
28+
}
29+
}

sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/exemplar/ExemplarReservoirFactory.java

+5
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,9 @@ public interface ExemplarReservoirFactory {
1515
* @param aggregation The aggregation configuration.
1616
*/
1717
ExemplarReservoir createReservoir(Aggregation aggregation);
18+
19+
/** Returns the default factory that collects exemplars. */
20+
static ExemplarReservoirFactory defaultFactory() {
21+
return DefaultExemplarReservoirFactory.INSTANCE;
22+
}
1823
}

sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/exemplar/ExemplarSampler.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public ExemplarReservoir createReservoir(Aggregation aggregation) {
3838
/** Returns a builder with default exemplar sampling configuration. */
3939
public static Builder builder() {
4040
return new AutoValue_ExemplarSampler.Builder()
41-
.setFactory(ignore -> ExemplarReservoir.noSamples())
41+
.setFactory(ExemplarReservoirFactory.defaultFactory())
4242
.setFilter(ExemplarFilter.sampleWithTraces());
4343
}
4444

sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorage.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public static <T> AsynchronousMetricStorage doubleAsynchronousAccumulator(
4444
final MetricDescriptor metricDescriptor = MetricDescriptor.create(view, instrument);
4545
Aggregator<T> aggregator =
4646
view.getAggregation()
47-
.config(instrument)
47+
.getFactory(instrument)
4848
.create(
4949
resource,
5050
instrumentationLibraryInfo,
@@ -84,7 +84,7 @@ public static <T> AsynchronousMetricStorage longAsynchronousAccumulator(
8484
final MetricDescriptor metricDescriptor = MetricDescriptor.create(view, instrument);
8585
Aggregator<T> aggregator =
8686
view.getAggregation()
87-
.config(instrument)
87+
.getFactory(instrument)
8888
.create(
8989
resource,
9090
instrumentationLibraryInfo,

sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterSharedState.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public final WriteableMetricStorage registerSynchronousMetricStorage(
6868
List<WriteableMetricStorage> storage = new ArrayList<>(views.size());
6969
for (View view : views) {
7070
// TODO - move this in a better location.
71-
if (view.getAggregation().config(instrument) == null) {
71+
if (view.getAggregation().getFactory(instrument) == null) {
7272
continue;
7373
}
7474
try {
@@ -105,7 +105,7 @@ public final void registerLongAsynchronousInstrument(
105105
.findViews(instrument, getInstrumentationLibraryInfo());
106106
for (View view : views) {
107107
// TODO - move this in a better location.
108-
if (view.getAggregation().config(instrument) == null) {
108+
if (view.getAggregation().getFactory(instrument) == null) {
109109
continue;
110110
}
111111
try {
@@ -136,7 +136,7 @@ public final void registerDoubleAsynchronousInstrument(
136136
.findViews(instrument, getInstrumentationLibraryInfo());
137137
for (View view : views) {
138138
// TODO - move this in a better location.
139-
if (view.getAggregation().config(instrument) == null) {
139+
if (view.getAggregation().getFactory(instrument) == null) {
140140
continue;
141141
}
142142
try {

sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorage.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import io.opentelemetry.sdk.metrics.internal.aggregator.AggregatorHandle;
1616
import io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor;
1717
import io.opentelemetry.sdk.metrics.internal.view.AttributesProcessor;
18+
import io.opentelemetry.sdk.metrics.view.Aggregation;
1819
import io.opentelemetry.sdk.metrics.view.View;
1920
import io.opentelemetry.sdk.resources.Resource;
2021
import java.util.Map;
@@ -45,15 +46,16 @@ public static <T> SynchronousMetricStorage<T> create(
4546
long startEpochNanos,
4647
ExemplarSampler sampler) {
4748
final MetricDescriptor metricDescriptor = MetricDescriptor.create(view, instrumentDescriptor);
49+
final Aggregation resolved = view.getAggregation().resolve(instrumentDescriptor);
4850
final Aggregator<T> aggregator =
49-
view.getAggregation()
50-
.config(instrumentDescriptor)
51+
resolved
52+
.getFactory(instrumentDescriptor)
5153
.create(
5254
resource,
5355
instrumentationLibraryInfo,
5456
instrumentDescriptor,
5557
metricDescriptor,
56-
() -> sampler.createReservoir(view.getAggregation()));
58+
() -> sampler.createReservoir(resolved));
5759
return new SynchronousMetricStorage<>(
5860
metricDescriptor,
5961
aggregator,

0 commit comments

Comments
 (0)