From c13895373a0a05ca637108998770202db59c7b9c Mon Sep 17 00:00:00 2001 From: Jack Berg <34418638+jack-berg@users.noreply.github.com> Date: Sat, 18 Oct 2025 13:23:59 -0500 Subject: [PATCH 1/2] Stabilize ExemplarFilter --- .../opentelemetry-sdk-metrics.txt | 10 ++++- .../OtlpExporterIntegrationTest.java | 16 +++----- .../MeterProviderConfiguration.java | 9 ++-- .../MeterProviderConfigurationTest.java | 8 ++-- .../io/opentelemetry/sdk/metrics/TestSdk.java | 1 - .../aggregator/HistogramCollectBenchmark.java | 15 ++++--- .../InstrumentGarbageCollectionBenchmark.java | 5 +-- .../sdk/metrics/ExemplarFilter.java | 41 +++++++++++++++++++ .../sdk/metrics/SdkMeterProvider.java | 4 +- .../sdk/metrics/SdkMeterProviderBuilder.java | 18 ++++---- .../internal/SdkMeterProviderUtil.java | 21 ---------- .../aggregator/AggregatorFactory.java | 6 +-- .../internal/exemplar/AlwaysOffFilter.java | 8 +++- .../internal/exemplar/AlwaysOnFilter.java | 8 +++- .../DoubleFilteredExemplarReservoir.java | 5 ++- ...ilter.java => ExemplarFilterInternal.java} | 33 +++++++-------- .../exemplar/ExemplarReservoirFactory.java | 2 +- .../LongFilteredExemplarReservoir.java | 4 +- .../exemplar/TraceBasedExemplarFilter.java | 8 +++- .../state/AsynchronousMetricStorage.java | 5 ++- .../state/MeterProviderSharedState.java | 8 ++-- .../state/SynchronousMetricStorage.java | 4 +- .../Base2ExponentialHistogramAggregation.java | 4 +- .../internal/view/DefaultAggregation.java | 4 +- .../internal/view/DropAggregation.java | 4 +- .../ExplicitBucketHistogramAggregation.java | 4 +- .../internal/view/LastValueAggregation.java | 4 +- .../metrics/internal/view/SumAggregation.java | 4 +- .../sdk/metrics/InstrumentBuilderTest.java | 7 +++- .../internal/exemplar/ExemplarFilterTest.java | 24 +++++++---- .../FilteredExemplarReservoirTest.java | 2 +- .../state/SynchronousMetricStorageTest.java | 9 ++-- ...e2ExponentialHistogramAggregationTest.java | 5 ++- 33 files changed, 176 insertions(+), 134 deletions(-) create mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/ExemplarFilter.java rename sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/{ExemplarFilter.java => ExemplarFilterInternal.java} (53%) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt index a97cc879eb4..f8e8f4c44b5 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt @@ -1,2 +1,10 @@ Comparing source compatibility of opentelemetry-sdk-metrics-1.56.0-SNAPSHOT.jar against opentelemetry-sdk-metrics-1.55.0.jar -No changes. \ No newline at end of file ++++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.metrics.ExemplarFilter (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.metrics.ExemplarFilter alwaysOff() + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.metrics.ExemplarFilter alwaysOn() + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.metrics.ExemplarFilter traceBased() +*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder setExemplarFilter(io.opentelemetry.sdk.metrics.ExemplarFilter) diff --git a/integration-tests/otlp/src/main/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java b/integration-tests/otlp/src/main/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java index c45e62b7348..583e1542029 100644 --- a/integration-tests/otlp/src/main/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java +++ b/integration-tests/otlp/src/main/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java @@ -65,12 +65,10 @@ import io.opentelemetry.sdk.logs.SdkLoggerProvider; import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import io.opentelemetry.sdk.metrics.ExemplarFilter; import io.opentelemetry.sdk.metrics.SdkMeterProvider; -import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.metrics.export.MetricExporter; import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; -import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.IdGenerator; import io.opentelemetry.sdk.trace.SdkTracerProvider; @@ -461,18 +459,16 @@ void testOtlpHttpMetricExport_mtls() throws Exception { } private static void testMetricExport(MetricExporter metricExporter) { - SdkMeterProviderBuilder meterProviderBuilder = + SdkMeterProvider meterProvider = SdkMeterProvider.builder() .setResource(RESOURCE) .registerMetricReader( PeriodicMetricReader.builder(metricExporter) .setInterval(Duration.ofSeconds(Integer.MAX_VALUE)) - .build()); - - // Enable alwaysOn exemplar filter, instead of default traceBased filter - SdkMeterProviderUtil.setExemplarFilter(meterProviderBuilder, ExemplarFilter.alwaysOn()); - - SdkMeterProvider meterProvider = meterProviderBuilder.build(); + .build()) + // Enable alwaysOn exemplar filter, instead of default traceBased filter + .setExemplarFilter(ExemplarFilter.alwaysOn()) + .build(); Meter meter = meterProvider.meterBuilder(OtlpExporterIntegrationTest.class.getName()).build(); diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/MeterProviderConfiguration.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/MeterProviderConfiguration.java index 8686c1208c1..7395bd17bd4 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/MeterProviderConfiguration.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/MeterProviderConfiguration.java @@ -9,11 +9,10 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; +import io.opentelemetry.sdk.metrics.ExemplarFilter; import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.metrics.export.MetricExporter; import io.opentelemetry.sdk.metrics.export.MetricReader; -import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.metrics.internal.state.MetricStorage; import java.io.Closeable; import java.util.Collections; @@ -43,14 +42,14 @@ static void configureMeterProvider( config.getString("otel.metrics.exemplar.filter", "trace_based").toLowerCase(Locale.ROOT); switch (exemplarFilter) { case "always_off": - SdkMeterProviderUtil.setExemplarFilter(meterProviderBuilder, ExemplarFilter.alwaysOff()); + meterProviderBuilder.setExemplarFilter(ExemplarFilter.alwaysOff()); break; case "always_on": - SdkMeterProviderUtil.setExemplarFilter(meterProviderBuilder, ExemplarFilter.alwaysOn()); + meterProviderBuilder.setExemplarFilter(ExemplarFilter.alwaysOn()); break; case "trace_based": default: - SdkMeterProviderUtil.setExemplarFilter(meterProviderBuilder, ExemplarFilter.traceBased()); + meterProviderBuilder.setExemplarFilter(ExemplarFilter.traceBased()); break; } diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/MeterProviderConfigurationTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/MeterProviderConfigurationTest.java index 900ba509d71..5c9de0a891d 100644 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/MeterProviderConfigurationTest.java +++ b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/MeterProviderConfigurationTest.java @@ -14,7 +14,7 @@ import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.metrics.internal.exemplar.AlwaysOffFilter; import io.opentelemetry.sdk.metrics.internal.exemplar.AlwaysOnFilter; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal; import io.opentelemetry.sdk.metrics.internal.exemplar.TraceBasedExemplarFilter; import java.util.ArrayList; import java.util.Collections; @@ -45,7 +45,8 @@ void configureMeterProvider_ConfiguresExemplarFilter() { .isInstanceOf(AlwaysOnFilter.class); } - private static ObjectAssert assertExemplarFilter(Map config) { + private static ObjectAssert assertExemplarFilter( + Map config) { Map configWithDefault = new HashMap<>(config); configWithDefault.put("otel.metrics.exporter", "none"); SdkMeterProviderBuilder builder = SdkMeterProvider.builder(); @@ -57,6 +58,7 @@ private static ObjectAssert assertExemplarFilter(Map a, new ArrayList<>()); return assertThat(builder) - .extracting("exemplarFilter", as(InstanceOfAssertFactories.type(ExemplarFilter.class))); + .extracting( + "exemplarFilter", as(InstanceOfAssertFactories.type(ExemplarFilterInternal.class))); } } diff --git a/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/TestSdk.java b/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/TestSdk.java index d4b415953a9..64bcc03ad6b 100644 --- a/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/TestSdk.java +++ b/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/TestSdk.java @@ -9,7 +9,6 @@ import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.sdk.common.Clock; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; import io.opentelemetry.sdk.trace.SdkTracerProvider; diff --git a/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/internal/aggregator/HistogramCollectBenchmark.java b/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/internal/aggregator/HistogramCollectBenchmark.java index acc6bdca538..be316162e7b 100644 --- a/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/internal/aggregator/HistogramCollectBenchmark.java +++ b/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/internal/aggregator/HistogramCollectBenchmark.java @@ -9,15 +9,13 @@ import io.opentelemetry.api.metrics.DoubleHistogram; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.metrics.Aggregation; +import io.opentelemetry.sdk.metrics.ExemplarFilter; import io.opentelemetry.sdk.metrics.InstrumentType; import io.opentelemetry.sdk.metrics.SdkMeterProvider; -import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.metrics.data.AggregationTemporality; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.export.MetricExporter; import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; -import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import java.time.Duration; import java.util.ArrayList; import java.util.Collection; @@ -64,7 +62,7 @@ public static class ThreadState { @Setup public void setup() { - SdkMeterProviderBuilder builder = + SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder() .registerMetricReader( PeriodicMetricReader.builder( @@ -74,10 +72,11 @@ public void setup() { aggregationTemporality, aggregationGenerator.aggregation)) // Effectively disable periodic reading so reading is only done on #flush() .setInterval(Duration.ofSeconds(Integer.MAX_VALUE)) - .build()); - // Disable exemplars - SdkMeterProviderUtil.setExemplarFilter(builder, ExemplarFilter.alwaysOff()); - sdkMeterProvider = builder.build(); + .build()) + // Disable exemplars + .setExemplarFilter(ExemplarFilter.alwaysOff()) + .build(); + histogram = sdkMeterProvider.get("meter").histogramBuilder("histogram").build(); random = new Random(); diff --git a/sdk/metrics/src/jmhBasedTest/java/io/opentelemetry/sdk/metrics/internal/state/InstrumentGarbageCollectionBenchmark.java b/sdk/metrics/src/jmhBasedTest/java/io/opentelemetry/sdk/metrics/internal/state/InstrumentGarbageCollectionBenchmark.java index d1d33632b65..3d3f9174d44 100644 --- a/sdk/metrics/src/jmhBasedTest/java/io/opentelemetry/sdk/metrics/internal/state/InstrumentGarbageCollectionBenchmark.java +++ b/sdk/metrics/src/jmhBasedTest/java/io/opentelemetry/sdk/metrics/internal/state/InstrumentGarbageCollectionBenchmark.java @@ -7,12 +7,11 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.sdk.common.export.MemoryMode; +import io.opentelemetry.sdk.metrics.ExemplarFilter; import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.metrics.data.AggregationTemporality; import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; -import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.metrics.internal.state.TestInstrumentType.InstrumentTester; import io.opentelemetry.sdk.metrics.internal.state.TestInstrumentType.TestInstrumentsState; import java.time.Duration; @@ -96,7 +95,7 @@ public void setup() { attributesList = AttributesGenerator.generate(cardinality); // Disable exemplars - SdkMeterProviderUtil.setExemplarFilter(builder, ExemplarFilter.alwaysOff()); + builder.setExemplarFilter(ExemplarFilter.alwaysOff()); sdkMeterProvider = builder.build(); testInstrumentsState = diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/ExemplarFilter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/ExemplarFilter.java new file mode 100644 index 00000000000..e493173b108 --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/ExemplarFilter.java @@ -0,0 +1,41 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics; + +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.metrics.internal.exemplar.AlwaysOffFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.AlwaysOnFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.DoubleExemplarReservoir; +import io.opentelemetry.sdk.metrics.internal.exemplar.LongExemplarReservoir; +import io.opentelemetry.sdk.metrics.internal.exemplar.TraceBasedExemplarFilter; + +/** + * Exemplar filters are used to pre-filter measurements before attempting to store them in a + * reservoir ({@link DoubleExemplarReservoir}, {@link LongExemplarReservoir}. + * + * @see SdkMeterProviderBuilder#setExemplarFilter(ExemplarFilter) + */ +// TODO(jack-berg): Have methods when custom filters are supported. +@SuppressWarnings("InterfaceWithOnlyStatics") +public interface ExemplarFilter { + /** + * A filter that only accepts measurements where there is a {@code Span} in {@link Context} that + * is being sampled. + */ + static ExemplarFilter traceBased() { + return TraceBasedExemplarFilter.getInstance(); + } + + /** A filter which makes all measurements eligible for being an exemplar. */ + static ExemplarFilter alwaysOn() { + return AlwaysOnFilter.getInstance(); + } + + /** A filter which makes no measurements eligible for being an exemplar. */ + static ExemplarFilter alwaysOff() { + return AlwaysOffFilter.getInstance(); + } +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java index a2a076fd9a0..36f0bd92fb0 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java @@ -21,7 +21,7 @@ import io.opentelemetry.sdk.metrics.export.MetricReader; import io.opentelemetry.sdk.metrics.internal.MeterConfig; import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal; import io.opentelemetry.sdk.metrics.internal.export.RegisteredReader; import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; import io.opentelemetry.sdk.metrics.internal.view.RegisteredView; @@ -67,7 +67,7 @@ public static SdkMeterProviderBuilder builder() { List metricProducers, Clock clock, Resource resource, - ExemplarFilter exemplarFilter, + ExemplarFilterInternal exemplarFilter, ScopeConfigurator meterConfigurator) { long startEpochNanos = clock.now(); this.registeredViews = registeredViews; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java index 90d0c7a8fef..c0810cac3e3 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java @@ -15,7 +15,7 @@ import io.opentelemetry.sdk.metrics.internal.MeterConfig; import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; import io.opentelemetry.sdk.metrics.internal.debug.SourceInfo; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal; import io.opentelemetry.sdk.metrics.internal.view.RegisteredView; import io.opentelemetry.sdk.resources.Resource; import java.util.ArrayList; @@ -36,7 +36,8 @@ public final class SdkMeterProviderBuilder { * * @see #setExemplarFilter(ExemplarFilter) */ - private static final ExemplarFilter DEFAULT_EXEMPLAR_FILTER = ExemplarFilter.traceBased(); + private static final ExemplarFilterInternal DEFAULT_EXEMPLAR_FILTER = + ExemplarFilterInternal.asExemplarFilterInternal(ExemplarFilter.traceBased()); private Clock clock = Clock.getDefault(); private Resource resource = Resource.getDefault(); @@ -44,7 +45,7 @@ public final class SdkMeterProviderBuilder { new IdentityHashMap<>(); private final List metricProducers = new ArrayList<>(); private final List registeredViews = new ArrayList<>(); - private ExemplarFilter exemplarFilter = DEFAULT_EXEMPLAR_FILTER; + private ExemplarFilterInternal exemplarFilter = DEFAULT_EXEMPLAR_FILTER; private ScopeConfiguratorBuilder meterConfiguratorBuilder = MeterConfig.configuratorBuilder(); @@ -80,14 +81,9 @@ public SdkMeterProviderBuilder addResource(Resource resource) { return this; } - /** - * Assign an {@link ExemplarFilter} for all metrics created by Meters. - * - *

This method is experimental so not public. You may reflectively call it using {@link - * SdkMeterProviderUtil#setExemplarFilter(SdkMeterProviderBuilder, ExemplarFilter)}. - */ - SdkMeterProviderBuilder setExemplarFilter(ExemplarFilter filter) { - this.exemplarFilter = filter; + /** Set the {@link ExemplarFilter} used for all instruments from all meters. */ + public SdkMeterProviderBuilder setExemplarFilter(ExemplarFilter filter) { + this.exemplarFilter = ExemplarFilterInternal.asExemplarFilterInternal(filter); return this; } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/SdkMeterProviderUtil.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/SdkMeterProviderUtil.java index c324900ab7d..18a60fa2836 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/SdkMeterProviderUtil.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/SdkMeterProviderUtil.java @@ -10,7 +10,6 @@ import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.metrics.ViewBuilder; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.metrics.internal.view.AttributesProcessor; import io.opentelemetry.sdk.metrics.internal.view.StringPredicates; import java.lang.reflect.InvocationTargetException; @@ -29,26 +28,6 @@ public final class SdkMeterProviderUtil { private SdkMeterProviderUtil() {} - /** - * Reflectively assign the {@link ExemplarFilter} to the {@link SdkMeterProviderBuilder}. - * - * @param sdkMeterProviderBuilder the builder - */ - public static SdkMeterProviderBuilder setExemplarFilter( - SdkMeterProviderBuilder sdkMeterProviderBuilder, ExemplarFilter exemplarFilter) { - try { - Method method = - SdkMeterProviderBuilder.class.getDeclaredMethod( - "setExemplarFilter", ExemplarFilter.class); - method.setAccessible(true); - method.invoke(sdkMeterProviderBuilder, exemplarFilter); - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { - throw new IllegalStateException( - "Error calling setExemplarFilter on SdkMeterProviderBuilder", e); - } - return sdkMeterProviderBuilder; - } - /** Reflectively set the {@link ScopeConfigurator} to the {@link SdkMeterProvider}. */ public static void setMeterConfigurator( SdkMeterProvider sdkMeterProvider, ScopeConfigurator scopeConfigurator) { diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/aggregator/AggregatorFactory.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/aggregator/AggregatorFactory.java index 8c5941acba3..0d6ba79b0a5 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/aggregator/AggregatorFactory.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/aggregator/AggregatorFactory.java @@ -8,7 +8,7 @@ import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.metrics.data.PointData; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal; /** * An internal interface for returning an Aggregator from an Aggregation. @@ -32,12 +32,12 @@ public interface AggregatorFactory { */ Aggregator createAggregator( InstrumentDescriptor instrumentDescriptor, - ExemplarFilter exemplarFilter, + ExemplarFilterInternal exemplarFilter, MemoryMode memoryMode); /** * Determine if the {@link Aggregator} produced by {@link #createAggregator(InstrumentDescriptor, - * ExemplarFilter, MemoryMode)} is compatible with the {@code instrumentDescriptor}. + * ExemplarFilterInternal, MemoryMode)} is compatible with the {@code instrumentDescriptor}. */ boolean isCompatibleWithInstrument(InstrumentDescriptor instrumentDescriptor); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/AlwaysOffFilter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/AlwaysOffFilter.java index 22bfab3ce1a..1f44151b4ad 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/AlwaysOffFilter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/AlwaysOffFilter.java @@ -14,11 +14,15 @@ *

This class is internal and is hence not for public use. Its APIs are unstable and can change * at any time. */ -public final class AlwaysOffFilter implements ExemplarFilter { - static final ExemplarFilter INSTANCE = new AlwaysOffFilter(); +public final class AlwaysOffFilter implements ExemplarFilterInternal { + private static final ExemplarFilterInternal INSTANCE = new AlwaysOffFilter(); private AlwaysOffFilter() {} + public static ExemplarFilterInternal getInstance() { + return INSTANCE; + } + @Override public boolean shouldSampleMeasurement(long value, Attributes attributes, Context context) { return false; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/AlwaysOnFilter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/AlwaysOnFilter.java index e1804bb2de2..bea21ccee28 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/AlwaysOnFilter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/AlwaysOnFilter.java @@ -14,11 +14,15 @@ *

This class is internal and is hence not for public use. Its APIs are unstable and can change * at any time. */ -public final class AlwaysOnFilter implements ExemplarFilter { - static final ExemplarFilter INSTANCE = new AlwaysOnFilter(); +public final class AlwaysOnFilter implements ExemplarFilterInternal { + private static final ExemplarFilterInternal INSTANCE = new AlwaysOnFilter(); private AlwaysOnFilter() {} + public static ExemplarFilterInternal getInstance() { + return INSTANCE; + } + @Override public boolean shouldSampleMeasurement(long value, Attributes attributes, Context context) { return true; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/DoubleFilteredExemplarReservoir.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/DoubleFilteredExemplarReservoir.java index 9d768e56a10..884453a3959 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/DoubleFilteredExemplarReservoir.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/DoubleFilteredExemplarReservoir.java @@ -12,10 +12,11 @@ /** A reservoir that has a pre-filter on measurements. */ class DoubleFilteredExemplarReservoir implements DoubleExemplarReservoir { - private final ExemplarFilter filter; + private final ExemplarFilterInternal filter; private final DoubleExemplarReservoir reservoir; - DoubleFilteredExemplarReservoir(ExemplarFilter filter, DoubleExemplarReservoir reservoir) { + DoubleFilteredExemplarReservoir( + ExemplarFilterInternal filter, DoubleExemplarReservoir reservoir) { this.filter = filter; this.reservoir = reservoir; } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarFilter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarFilterInternal.java similarity index 53% rename from sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarFilter.java rename to sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarFilterInternal.java index 6d14d7c25b1..aa3858d670a 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarFilter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarFilterInternal.java @@ -7,6 +7,7 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.metrics.ExemplarFilter; /** * Exemplar filters are used to pre-filter measurements before attempting to store them in a @@ -15,28 +16,24 @@ *

This class is internal and is hence not for public use. Its APIs are unstable and can change * at any time. */ -public interface ExemplarFilter { - /** Returns whether or not a reservoir should attempt to filter a measurement. */ - boolean shouldSampleMeasurement(long value, Attributes attributes, Context context); - - /** Returns whether or not a reservoir should attempt to filter a measurement. */ - boolean shouldSampleMeasurement(double value, Attributes attributes, Context context); +public interface ExemplarFilterInternal extends ExemplarFilter { /** - * A filter that only accepts measurements where there is a {@code Span} in {@link Context} that - * is being sampled. + * Utility for casting {@link ExemplarFilter} to {@link ExemplarFilterInternal}, throwing if + * {@code filter} does not implement {@link ExemplarFilterInternal}. */ - static ExemplarFilter traceBased() { - return TraceBasedExemplarFilter.INSTANCE; + static ExemplarFilterInternal asExemplarFilterInternal(ExemplarFilter filter) { + if (!(filter instanceof ExemplarFilterInternal)) { + throw new IllegalArgumentException( + "Custom ExemplarFilter implementations are currently not supported. " + + "Use one of the standard implementations returned by the static factories in the ExemplarFilter class."); + } + return (ExemplarFilterInternal) filter; } - /** A filter which makes all measurements eligible for being an exemplar. */ - static ExemplarFilter alwaysOn() { - return AlwaysOnFilter.INSTANCE; - } + /** Returns whether or not a reservoir should attempt to filter a measurement. */ + boolean shouldSampleMeasurement(long value, Attributes attributes, Context context); - /** A filter which makes no measurements eligible for being an exemplar. */ - static ExemplarFilter alwaysOff() { - return AlwaysOffFilter.INSTANCE; - } + /** Returns whether or not a reservoir should attempt to filter a measurement. */ + boolean shouldSampleMeasurement(double value, Attributes attributes, Context context); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarReservoirFactory.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarReservoirFactory.java index b44f08b7746..2c6b74aa7f7 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarReservoirFactory.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarReservoirFactory.java @@ -24,7 +24,7 @@ public interface ExemplarReservoirFactory { * pre-filter. */ static ExemplarReservoirFactory filtered( - ExemplarFilter filter, ExemplarReservoirFactory original) { + ExemplarFilterInternal filter, ExemplarReservoirFactory original) { return new ExemplarReservoirFactory() { @Override public DoubleExemplarReservoir createDoubleExemplarReservoir() { diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/LongFilteredExemplarReservoir.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/LongFilteredExemplarReservoir.java index 1cd2024674d..db7a8291687 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/LongFilteredExemplarReservoir.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/LongFilteredExemplarReservoir.java @@ -12,10 +12,10 @@ /** A reservoir that has a pre-filter on measurements. */ class LongFilteredExemplarReservoir implements LongExemplarReservoir { - private final ExemplarFilter filter; + private final ExemplarFilterInternal filter; private final LongExemplarReservoir reservoir; - LongFilteredExemplarReservoir(ExemplarFilter filter, LongExemplarReservoir reservoir) { + LongFilteredExemplarReservoir(ExemplarFilterInternal filter, LongExemplarReservoir reservoir) { this.filter = filter; this.reservoir = reservoir; } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/TraceBasedExemplarFilter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/TraceBasedExemplarFilter.java index 69d166eb101..5ce78847c1f 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/TraceBasedExemplarFilter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/TraceBasedExemplarFilter.java @@ -15,12 +15,16 @@ *

This class is internal and is hence not for public use. Its APIs are unstable and can change * at any time. */ -public final class TraceBasedExemplarFilter implements ExemplarFilter { +public final class TraceBasedExemplarFilter implements ExemplarFilterInternal { - static final ExemplarFilter INSTANCE = new TraceBasedExemplarFilter(); + private static final ExemplarFilterInternal INSTANCE = new TraceBasedExemplarFilter(); private TraceBasedExemplarFilter() {} + public static ExemplarFilterInternal getInstance() { + return INSTANCE; + } + @Override public boolean shouldSampleMeasurement(long value, Attributes attributes, Context context) { return hasSampledTrace(context); diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorage.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorage.java index 62a686e35b2..77f159168e7 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorage.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorage.java @@ -14,6 +14,7 @@ import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.internal.ThrottlingLogger; +import io.opentelemetry.sdk.metrics.ExemplarFilter; import io.opentelemetry.sdk.metrics.View; import io.opentelemetry.sdk.metrics.data.AggregationTemporality; import io.opentelemetry.sdk.metrics.data.MetricData; @@ -24,7 +25,7 @@ import io.opentelemetry.sdk.metrics.internal.aggregator.EmptyMetricData; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal; import io.opentelemetry.sdk.metrics.internal.export.RegisteredReader; import io.opentelemetry.sdk.metrics.internal.view.AttributesProcessor; import io.opentelemetry.sdk.metrics.internal.view.RegisteredView; @@ -136,7 +137,7 @@ public static AsynchronousMetricStorage create( ((AggregatorFactory) view.getAggregation()) .createAggregator( instrumentDescriptor, - ExemplarFilter.alwaysOff(), + ExemplarFilterInternal.asExemplarFilterInternal(ExemplarFilter.alwaysOff()), registeredReader.getReader().getMemoryMode()); return new AsynchronousMetricStorage<>( registeredReader, diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java index aaf932d9202..1e42b854463 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java @@ -8,7 +8,7 @@ import com.google.auto.value.AutoValue; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.metrics.SdkMeterProvider; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal; import io.opentelemetry.sdk.resources.Resource; import javax.annotation.concurrent.Immutable; @@ -23,7 +23,7 @@ public abstract class MeterProviderSharedState { public static MeterProviderSharedState create( - Clock clock, Resource resource, ExemplarFilter exemplarFilter, long startEpochNanos) { + Clock clock, Resource resource, ExemplarFilterInternal exemplarFilter, long startEpochNanos) { MeterProviderSharedState sharedState = new AutoValue_MeterProviderSharedState(clock, resource, startEpochNanos, exemplarFilter); return sharedState; @@ -40,6 +40,6 @@ public static MeterProviderSharedState create( /** Returns the timestamp when the {@link SdkMeterProvider} was started, in epoch nanos. */ public abstract long getStartEpochNanos(); - /** Returns the {@link ExemplarFilter} for remembering synchronous measurements. */ - public abstract ExemplarFilter getExemplarFilter(); + /** Returns the {@link ExemplarFilterInternal} for remembering synchronous measurements. */ + public abstract ExemplarFilterInternal getExemplarFilter(); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorage.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorage.java index bc9d8f60610..9df16e17911 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorage.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorage.java @@ -12,7 +12,7 @@ import io.opentelemetry.sdk.metrics.internal.aggregator.AggregatorFactory; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal; import io.opentelemetry.sdk.metrics.internal.export.RegisteredReader; import io.opentelemetry.sdk.metrics.internal.view.RegisteredView; @@ -39,7 +39,7 @@ static SynchronousMetricStorage create( RegisteredReader registeredReader, RegisteredView registeredView, InstrumentDescriptor instrumentDescriptor, - ExemplarFilter exemplarFilter, + ExemplarFilterInternal exemplarFilter, boolean enabled) { View view = registeredView.getView(); MetricDescriptor metricDescriptor = diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/Base2ExponentialHistogramAggregation.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/Base2ExponentialHistogramAggregation.java index b1ada9252e4..870ac9f4d89 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/Base2ExponentialHistogramAggregation.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/Base2ExponentialHistogramAggregation.java @@ -17,7 +17,7 @@ import io.opentelemetry.sdk.metrics.internal.aggregator.AggregatorFactory; import io.opentelemetry.sdk.metrics.internal.aggregator.DoubleBase2ExponentialHistogramAggregator; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarReservoirFactory; /** @@ -67,7 +67,7 @@ public static Aggregation create(int maxBuckets, int maxScale) { @SuppressWarnings("unchecked") public Aggregator createAggregator( InstrumentDescriptor instrumentDescriptor, - ExemplarFilter exemplarFilter, + ExemplarFilterInternal exemplarFilter, MemoryMode memoryMode) { return (Aggregator) new DoubleBase2ExponentialHistogramAggregator( diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/DefaultAggregation.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/DefaultAggregation.java index e329ff9425f..182246f2801 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/DefaultAggregation.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/DefaultAggregation.java @@ -12,7 +12,7 @@ import io.opentelemetry.sdk.metrics.internal.aggregator.Aggregator; import io.opentelemetry.sdk.metrics.internal.aggregator.AggregatorFactory; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal; import java.util.logging.Level; import java.util.logging.Logger; @@ -59,7 +59,7 @@ private static Aggregation resolve(InstrumentDescriptor instrument, boolean with @Override public Aggregator createAggregator( InstrumentDescriptor instrumentDescriptor, - ExemplarFilter exemplarFilter, + ExemplarFilterInternal exemplarFilter, MemoryMode memoryMode) { return ((AggregatorFactory) resolve(instrumentDescriptor, /* withAdvice= */ true)) .createAggregator(instrumentDescriptor, exemplarFilter, memoryMode); diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/DropAggregation.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/DropAggregation.java index 38db4acd381..592c74f013a 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/DropAggregation.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/DropAggregation.java @@ -11,7 +11,7 @@ import io.opentelemetry.sdk.metrics.internal.aggregator.Aggregator; import io.opentelemetry.sdk.metrics.internal.aggregator.AggregatorFactory; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal; /** * Configuration representing no aggregation. @@ -33,7 +33,7 @@ private DropAggregation() {} @SuppressWarnings("unchecked") public Aggregator createAggregator( InstrumentDescriptor instrumentDescriptor, - ExemplarFilter exemplarFilter, + ExemplarFilterInternal exemplarFilter, MemoryMode memoryMode) { return (Aggregator) Aggregator.drop(); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ExplicitBucketHistogramAggregation.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ExplicitBucketHistogramAggregation.java index 40c0dbabc8d..d4af55fd0ad 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ExplicitBucketHistogramAggregation.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ExplicitBucketHistogramAggregation.java @@ -14,7 +14,7 @@ import io.opentelemetry.sdk.metrics.internal.aggregator.DoubleExplicitBucketHistogramAggregator; import io.opentelemetry.sdk.metrics.internal.aggregator.ExplicitBucketHistogramUtils; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarReservoirFactory; import java.util.List; @@ -51,7 +51,7 @@ private ExplicitBucketHistogramAggregation(List bucketBoundaries) { @SuppressWarnings("unchecked") public Aggregator createAggregator( InstrumentDescriptor instrumentDescriptor, - ExemplarFilter exemplarFilter, + ExemplarFilterInternal exemplarFilter, MemoryMode memoryMode) { return (Aggregator) new DoubleExplicitBucketHistogramAggregator( diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/LastValueAggregation.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/LastValueAggregation.java index 5157d846025..ee2a0e98d24 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/LastValueAggregation.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/LastValueAggregation.java @@ -16,7 +16,7 @@ import io.opentelemetry.sdk.metrics.internal.aggregator.DoubleLastValueAggregator; import io.opentelemetry.sdk.metrics.internal.aggregator.LongLastValueAggregator; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarReservoirFactory; /** @@ -39,7 +39,7 @@ private LastValueAggregation() {} @SuppressWarnings("unchecked") public Aggregator createAggregator( InstrumentDescriptor instrumentDescriptor, - ExemplarFilter exemplarFilter, + ExemplarFilterInternal exemplarFilter, MemoryMode memoryMode) { ExemplarReservoirFactory reservoirFactory = diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/SumAggregation.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/SumAggregation.java index 52a24521348..42a003182be 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/SumAggregation.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/SumAggregation.java @@ -15,7 +15,7 @@ import io.opentelemetry.sdk.metrics.internal.aggregator.DoubleSumAggregator; import io.opentelemetry.sdk.metrics.internal.aggregator.LongSumAggregator; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; +import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarReservoirFactory; /** @@ -37,7 +37,7 @@ private SumAggregation() {} @SuppressWarnings("unchecked") public Aggregator createAggregator( InstrumentDescriptor instrumentDescriptor, - ExemplarFilter exemplarFilter, + ExemplarFilterInternal exemplarFilter, MemoryMode memoryMode) { ExemplarReservoirFactory reservoirFactory = ExemplarReservoirFactory.filtered( diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java index de1a351e619..6c54636ee4f 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentBuilderTest.java @@ -5,12 +5,12 @@ package io.opentelemetry.sdk.metrics; +import static io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal.asExemplarFilterInternal; import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.metrics.internal.MeterConfig; import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.time.TestClock; @@ -21,7 +21,10 @@ class InstrumentBuilderTest { public static final MeterProviderSharedState PROVIDER_SHARED_STATE = MeterProviderSharedState.create( - TestClock.create(), Resource.getDefault(), ExemplarFilter.alwaysOff(), 0); + TestClock.create(), + Resource.getDefault(), + asExemplarFilterInternal(ExemplarFilter.alwaysOff()), + 0); static final InstrumentationScopeInfo SCOPE = InstrumentationScopeInfo.create("scope-name"); public static final SdkMeter SDK_METER = new SdkMeter( diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarFilterTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarFilterTest.java index 2db304b229b..dfdf69d6f3f 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarFilterTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarFilterTest.java @@ -5,6 +5,7 @@ package io.opentelemetry.sdk.metrics.internal.exemplar; +import static io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal.asExemplarFilterInternal; import static org.assertj.core.api.Assertions.as; import static org.assertj.core.api.Assertions.assertThat; @@ -14,9 +15,9 @@ import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceState; import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.metrics.ExemplarFilter; import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; -import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.Test; @@ -27,7 +28,7 @@ class ExemplarFilterTest { @Test void alwaysOff_NeverReturnsTrue() { assertThat( - ExemplarFilter.alwaysOff() + asExemplarFilterInternal(ExemplarFilter.alwaysOff()) .shouldSampleMeasurement(1, Attributes.empty(), Context.root())) .isFalse(); } @@ -35,7 +36,7 @@ void alwaysOff_NeverReturnsTrue() { @Test void alwaysOn_AlwaysReturnsTrue() { assertThat( - ExemplarFilter.alwaysOn() + asExemplarFilterInternal(ExemplarFilter.alwaysOn()) .shouldSampleMeasurement(1, Attributes.empty(), Context.root())) .isTrue(); } @@ -43,7 +44,7 @@ void alwaysOn_AlwaysReturnsTrue() { @Test void withSampledTrace_ReturnsFalseOnNoContext() { assertThat( - ExemplarFilter.traceBased() + asExemplarFilterInternal(ExemplarFilter.traceBased()) .shouldSampleMeasurement(1, Attributes.empty(), Context.root())) .isFalse(); } @@ -56,7 +57,9 @@ void traceBased_sampleWithTrace() { Span.wrap( SpanContext.createFromRemoteParent( TRACE_ID, SPAN_ID, TraceFlags.getSampled(), TraceState.getDefault()))); - assertThat(ExemplarFilter.traceBased().shouldSampleMeasurement(1, Attributes.empty(), context)) + assertThat( + asExemplarFilterInternal(ExemplarFilter.traceBased()) + .shouldSampleMeasurement(1, Attributes.empty(), context)) .isTrue(); } @@ -68,16 +71,19 @@ void traceBased_notSampleUnsampledTrace() { Span.wrap( SpanContext.createFromRemoteParent( TRACE_ID, SPAN_ID, TraceFlags.getDefault(), TraceState.getDefault()))); - assertThat(ExemplarFilter.traceBased().shouldSampleMeasurement(1, Attributes.empty(), context)) + assertThat( + asExemplarFilterInternal(ExemplarFilter.traceBased()) + .shouldSampleMeasurement(1, Attributes.empty(), context)) .isFalse(); } @Test void setExemplarFilter() { - SdkMeterProviderBuilder builder = SdkMeterProvider.builder(); - SdkMeterProviderUtil.setExemplarFilter(builder, ExemplarFilter.alwaysOn()); + SdkMeterProviderBuilder builder = + SdkMeterProvider.builder().setExemplarFilter(ExemplarFilter.alwaysOn()); assertThat(builder) - .extracting("exemplarFilter", as(InstanceOfAssertFactories.type(ExemplarFilter.class))) + .extracting( + "exemplarFilter", as(InstanceOfAssertFactories.type(ExemplarFilterInternal.class))) .isEqualTo(ExemplarFilter.alwaysOn()); } } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/exemplar/FilteredExemplarReservoirTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/exemplar/FilteredExemplarReservoirTest.java index 7e4262981f3..1abc9e73cd4 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/exemplar/FilteredExemplarReservoirTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/exemplar/FilteredExemplarReservoirTest.java @@ -25,7 +25,7 @@ class FilteredExemplarReservoirTest { @Mock DoubleExemplarReservoir doubleReservoir; @Mock LongExemplarReservoir longReservoir; - @Mock ExemplarFilter filter; + @Mock ExemplarFilterInternal filter; @Test void testFilterDouble_preventsSampling() { diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorageTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorageTest.java index e79f3ad9718..a3175578d77 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorageTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorageTest.java @@ -6,6 +6,7 @@ package io.opentelemetry.sdk.metrics.internal.state; import static io.opentelemetry.sdk.common.export.MemoryMode.IMMUTABLE_DATA; +import static io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal.asExemplarFilterInternal; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry; import static org.mockito.Mockito.never; @@ -23,6 +24,7 @@ import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.metrics.Aggregation; +import io.opentelemetry.sdk.metrics.ExemplarFilter; import io.opentelemetry.sdk.metrics.InstrumentType; import io.opentelemetry.sdk.metrics.InstrumentValueType; import io.opentelemetry.sdk.metrics.data.AggregationTemporality; @@ -35,7 +37,6 @@ import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.metrics.internal.export.RegisteredReader; import io.opentelemetry.sdk.metrics.internal.view.AttributesProcessor; import io.opentelemetry.sdk.metrics.internal.view.ViewRegistry; @@ -102,7 +103,8 @@ private void initialize(MemoryMode memoryMode) { aggregator = spy( ((AggregatorFactory) Aggregation.sum()) - .createAggregator(DESCRIPTOR, ExemplarFilter.alwaysOff(), memoryMode)); + .createAggregator( + DESCRIPTOR, asExemplarFilterInternal(ExemplarFilter.alwaysOff()), memoryMode)); } @ParameterizedTest @@ -826,7 +828,8 @@ private static Stream concurrentStressTestArguments() { for (MemoryMode memoryMode : MemoryMode.values()) { Aggregator aggregator = ((AggregatorFactory) Aggregation.sum()) - .createAggregator(DESCRIPTOR, ExemplarFilter.alwaysOff(), memoryMode); + .createAggregator( + DESCRIPTOR, asExemplarFilterInternal(ExemplarFilter.alwaysOff()), memoryMode); argumentsList.add( Arguments.of( diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/Base2ExponentialHistogramAggregationTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/Base2ExponentialHistogramAggregationTest.java index 57e096e01c1..ee10e75d679 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/Base2ExponentialHistogramAggregationTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/Base2ExponentialHistogramAggregationTest.java @@ -5,6 +5,7 @@ package io.opentelemetry.sdk.metrics.internal.view; +import static io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal.asExemplarFilterInternal; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -12,6 +13,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.metrics.Aggregation; +import io.opentelemetry.sdk.metrics.ExemplarFilter; import io.opentelemetry.sdk.metrics.InstrumentType; import io.opentelemetry.sdk.metrics.InstrumentValueType; import io.opentelemetry.sdk.metrics.data.ExponentialHistogramPointData; @@ -20,7 +22,6 @@ import io.opentelemetry.sdk.metrics.internal.aggregator.AggregatorHandle; import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import org.junit.jupiter.api.Test; class Base2ExponentialHistogramAggregationTest { @@ -57,7 +58,7 @@ void minimumBucketsCanAccommodateMaxRange() { InstrumentType.HISTOGRAM, InstrumentValueType.DOUBLE, Advice.empty()), - ExemplarFilter.alwaysOff(), + asExemplarFilterInternal(ExemplarFilter.alwaysOff()), MemoryMode.IMMUTABLE_DATA); AggregatorHandle handle = aggregator.createHandle(); // Record max range From 4d6e9937ca149fe6a6aededae5a9460dcd93f562 Mon Sep 17 00:00:00 2001 From: Jack Berg <34418638+jack-berg@users.noreply.github.com> Date: Sun, 19 Oct 2025 12:49:26 -0500 Subject: [PATCH 2/2] Add test coverage --- .../internal/exemplar/ExemplarFilterTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarFilterTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarFilterTest.java index dfdf69d6f3f..aea2361585e 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarFilterTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/exemplar/ExemplarFilterTest.java @@ -8,6 +8,7 @@ import static io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilterInternal.asExemplarFilterInternal; import static org.assertj.core.api.Assertions.as; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; @@ -86,4 +87,16 @@ void setExemplarFilter() { "exemplarFilter", as(InstanceOfAssertFactories.type(ExemplarFilterInternal.class))) .isEqualTo(ExemplarFilter.alwaysOn()); } + + @Test + void asExemplarFilterInternal_Valid() { + assertThat(asExemplarFilterInternal(ExemplarFilter.traceBased())) + .isSameAs(ExemplarFilter.traceBased()); + assertThat(asExemplarFilterInternal(ExemplarFilter.alwaysOff())) + .isSameAs(ExemplarFilter.alwaysOff()); + assertThat(asExemplarFilterInternal(ExemplarFilter.alwaysOn())) + .isSameAs(ExemplarFilter.alwaysOn()); + assertThatThrownBy(() -> asExemplarFilterInternal(new ExemplarFilter() {})) + .isInstanceOf(IllegalArgumentException.class); + } }