From 2870209fdb2500017ef253ef55313bb2e3db89ec Mon Sep 17 00:00:00 2001 From: jack-berg <34418638+jack-berg@users.noreply.github.com> Date: Tue, 11 Apr 2023 17:03:55 -0500 Subject: [PATCH] Prototype histogram advice API (i.e. Hints) (#5217) --- .../opentelemetry-sdk-testing.txt | 5 +- .../ExtendedDoubleHistogramBuilder.java | 18 ++ .../metrics/ExtendedLongHistogramBuilder.java | 18 ++ .../metrics/HistogramAdviceConfigurer.java | 17 ++ .../sdk/OpenTelemetrySdkTest.java | 3 + sdk/metrics/build.gradle.kts | 1 + .../descriptor/InstrumentDescriptorTest.java | 52 ++++- .../opentelemetry/testing/SourceInfoTest.java | 23 +- .../metrics/AbstractInstrumentBuilder.java | 38 +++- .../sdk/metrics/SdkDoubleCounter.java | 7 +- .../sdk/metrics/SdkDoubleHistogram.java | 20 +- .../sdk/metrics/SdkDoubleUpDownCounter.java | 7 +- .../sdk/metrics/SdkLongGaugeBuilder.java | 7 +- .../sdk/metrics/SdkLongHistogram.java | 27 ++- .../metrics/internal/descriptor/Advice.java | 31 +++ .../descriptor/InstrumentDescriptor.java | 7 +- .../internal/descriptor/MetricDescriptor.java | 7 +- .../internal/view/DefaultAggregation.java | 10 +- .../AbstractInstrumentBuilderTest.java | 3 +- .../sdk/metrics/AbstractInstrumentTest.java | 8 +- .../opentelemetry/sdk/metrics/AdviceTest.java | 203 ++++++++++++++++++ .../sdk/metrics/AggregationTest.java | 3 +- .../sdk/metrics/SdkMeterProviderTest.java | 3 + .../metrics/SdkObservableInstrumentTest.java | 7 +- .../aggregator/DoubleSumAggregatorTest.java | 14 +- .../aggregator/LongSumAggregatorTest.java | 14 +- .../descriptor/MetricDescriptorTest.java | 39 +++- .../state/AsynchronousMetricStorageTest.java | 17 +- .../state/CallbackRegistrationTest.java | 16 +- .../state/MetricStorageRegistryTest.java | 3 +- .../state/SynchronousMetricStorageTest.java | 8 +- .../internal/view/ViewRegistryTest.java | 131 +++++++++-- .../exporter/InMemoryMetricReader.java | 35 ++- .../exporter/InMemoryMetricReaderTest.java | 3 +- 34 files changed, 703 insertions(+), 102 deletions(-) create mode 100644 extensions/incubator/src/main/java/io/opentelemetry/extension/incubator/metrics/ExtendedDoubleHistogramBuilder.java create mode 100644 extensions/incubator/src/main/java/io/opentelemetry/extension/incubator/metrics/ExtendedLongHistogramBuilder.java create mode 100644 extensions/incubator/src/main/java/io/opentelemetry/extension/incubator/metrics/HistogramAdviceConfigurer.java create mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/descriptor/Advice.java create mode 100644 sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AdviceTest.java diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-testing.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-testing.txt index df26146497b..b25be9033f2 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-testing.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-testing.txt @@ -1,2 +1,5 @@ Comparing source compatibility of against -No changes. \ No newline at end of file +*** MODIFIED CLASS: PUBLIC io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader create(io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector, io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.metrics.Aggregation getDefaultAggregation(io.opentelemetry.sdk.metrics.InstrumentType) diff --git a/extensions/incubator/src/main/java/io/opentelemetry/extension/incubator/metrics/ExtendedDoubleHistogramBuilder.java b/extensions/incubator/src/main/java/io/opentelemetry/extension/incubator/metrics/ExtendedDoubleHistogramBuilder.java new file mode 100644 index 00000000000..bc45f29227a --- /dev/null +++ b/extensions/incubator/src/main/java/io/opentelemetry/extension/incubator/metrics/ExtendedDoubleHistogramBuilder.java @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.extension.incubator.metrics; + +import io.opentelemetry.api.metrics.DoubleHistogramBuilder; +import java.util.function.Consumer; + +/** Extended {@link DoubleHistogramBuilder} with experimental APIs. */ +public interface ExtendedDoubleHistogramBuilder extends DoubleHistogramBuilder { + + /** Specify advice for histogram implementations. */ + default DoubleHistogramBuilder setAdvice(Consumer adviceConsumer) { + return this; + } +} diff --git a/extensions/incubator/src/main/java/io/opentelemetry/extension/incubator/metrics/ExtendedLongHistogramBuilder.java b/extensions/incubator/src/main/java/io/opentelemetry/extension/incubator/metrics/ExtendedLongHistogramBuilder.java new file mode 100644 index 00000000000..2e95b798619 --- /dev/null +++ b/extensions/incubator/src/main/java/io/opentelemetry/extension/incubator/metrics/ExtendedLongHistogramBuilder.java @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.extension.incubator.metrics; + +import io.opentelemetry.api.metrics.LongHistogramBuilder; +import java.util.function.Consumer; + +/** Extended {@link LongHistogramBuilder} with experimental APIs. */ +public interface ExtendedLongHistogramBuilder extends LongHistogramBuilder { + + /** Specify advice for histogram implementations. */ + default LongHistogramBuilder setAdvice(Consumer adviceConsumer) { + return this; + } +} diff --git a/extensions/incubator/src/main/java/io/opentelemetry/extension/incubator/metrics/HistogramAdviceConfigurer.java b/extensions/incubator/src/main/java/io/opentelemetry/extension/incubator/metrics/HistogramAdviceConfigurer.java new file mode 100644 index 00000000000..67fca913b8c --- /dev/null +++ b/extensions/incubator/src/main/java/io/opentelemetry/extension/incubator/metrics/HistogramAdviceConfigurer.java @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.extension.incubator.metrics; + +import io.opentelemetry.api.metrics.DoubleHistogram; +import io.opentelemetry.api.metrics.LongHistogram; +import java.util.List; + +/** Configure advice for implementations of {@link LongHistogram} and {@link DoubleHistogram}. */ +public interface HistogramAdviceConfigurer { + + /** Specify recommended set of explicit bucket boundaries for this histogram. */ + HistogramAdviceConfigurer setExplicitBucketBoundaries(List bucketBoundaries); +} diff --git a/sdk/all/src/test/java/io/opentelemetry/sdk/OpenTelemetrySdkTest.java b/sdk/all/src/test/java/io/opentelemetry/sdk/OpenTelemetrySdkTest.java index 985c616b3b5..d3ec82b5f8c 100644 --- a/sdk/all/src/test/java/io/opentelemetry/sdk/OpenTelemetrySdkTest.java +++ b/sdk/all/src/test/java/io/opentelemetry/sdk/OpenTelemetrySdkTest.java @@ -48,8 +48,11 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; @ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) class OpenTelemetrySdkTest { @RegisterExtension diff --git a/sdk/metrics/build.gradle.kts b/sdk/metrics/build.gradle.kts index d2ab7c62981..32f4cb5a2e2 100644 --- a/sdk/metrics/build.gradle.kts +++ b/sdk/metrics/build.gradle.kts @@ -15,6 +15,7 @@ otelJava.moduleName.set("io.opentelemetry.sdk.metrics") dependencies { api(project(":api:all")) api(project(":sdk:common")) + implementation(project(":extensions:incubator")) compileOnly("org.codehaus.mojo:animal-sniffer-annotations") diff --git a/sdk/metrics/src/debugEnabledTest/java/io/opentelemetry/sdk/metrics/internal/descriptor/InstrumentDescriptorTest.java b/sdk/metrics/src/debugEnabledTest/java/io/opentelemetry/sdk/metrics/internal/descriptor/InstrumentDescriptorTest.java index cbc1f288905..acb1ae789c3 100644 --- a/sdk/metrics/src/debugEnabledTest/java/io/opentelemetry/sdk/metrics/internal/descriptor/InstrumentDescriptorTest.java +++ b/sdk/metrics/src/debugEnabledTest/java/io/opentelemetry/sdk/metrics/internal/descriptor/InstrumentDescriptorTest.java @@ -22,33 +22,63 @@ class InstrumentDescriptorTest { void equals() { InstrumentDescriptor descriptor = InstrumentDescriptor.create( - "name", "description", "unit", InstrumentType.COUNTER, InstrumentValueType.LONG); + "name", + "description", + "unit", + InstrumentType.COUNTER, + InstrumentValueType.LONG, + Advice.empty()); assertThat(descriptor) .isEqualTo( InstrumentDescriptor.create( - "name", "description", "unit", InstrumentType.COUNTER, InstrumentValueType.LONG)); + "name", + "description", + "unit", + InstrumentType.COUNTER, + InstrumentValueType.LONG, + Advice.empty())); // Validate getSourceInfo() is not equal for otherwise equal descriptors assertThat(descriptor.getSourceInfo()) .isNotEqualTo( InstrumentDescriptor.create( - "name", "description", "unit", InstrumentType.COUNTER, InstrumentValueType.LONG) + "name", + "description", + "unit", + InstrumentType.COUNTER, + InstrumentValueType.LONG, + Advice.empty()) .getSourceInfo()); // Validate that name, description, unit, type, and value type are considered in equals assertThat(descriptor) .isNotEqualTo( InstrumentDescriptor.create( - "foo", "description", "unit", InstrumentType.COUNTER, InstrumentValueType.LONG)); + "foo", + "description", + "unit", + InstrumentType.COUNTER, + InstrumentValueType.LONG, + Advice.empty())); assertThat(descriptor) .isNotEqualTo( InstrumentDescriptor.create( - "name", "foo", "unit", InstrumentType.COUNTER, InstrumentValueType.LONG)); + "name", + "foo", + "unit", + InstrumentType.COUNTER, + InstrumentValueType.LONG, + Advice.empty())); assertThat(descriptor) .isNotEqualTo( InstrumentDescriptor.create( - "name", "description", "foo", InstrumentType.COUNTER, InstrumentValueType.LONG)); + "name", + "description", + "foo", + InstrumentType.COUNTER, + InstrumentValueType.LONG, + Advice.empty())); assertThat(descriptor) .isNotEqualTo( InstrumentDescriptor.create( @@ -56,10 +86,16 @@ void equals() { "description", "unit", InstrumentType.UP_DOWN_COUNTER, - InstrumentValueType.LONG)); + InstrumentValueType.LONG, + Advice.empty())); assertThat(descriptor) .isNotEqualTo( InstrumentDescriptor.create( - "name", "description", "unit", InstrumentType.COUNTER, InstrumentValueType.DOUBLE)); + "name", + "description", + "unit", + InstrumentType.COUNTER, + InstrumentValueType.DOUBLE, + Advice.empty())); } } diff --git a/sdk/metrics/src/debugEnabledTest/java/io/opentelemetry/testing/SourceInfoTest.java b/sdk/metrics/src/debugEnabledTest/java/io/opentelemetry/testing/SourceInfoTest.java index bb6dc42123e..64efb419820 100644 --- a/sdk/metrics/src/debugEnabledTest/java/io/opentelemetry/testing/SourceInfoTest.java +++ b/sdk/metrics/src/debugEnabledTest/java/io/opentelemetry/testing/SourceInfoTest.java @@ -11,6 +11,7 @@ import io.opentelemetry.sdk.metrics.InstrumentValueType; import io.opentelemetry.sdk.metrics.View; import io.opentelemetry.sdk.metrics.internal.debug.SourceInfo; +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.state.DebugUtils; @@ -23,10 +24,10 @@ class SourceInfoTest { @Test void sourceInfoFindsStackTrace() { - assertThat(info.shortDebugString()).isEqualTo("SourceInfoTest.java:22"); + assertThat(info.shortDebugString()).isEqualTo("SourceInfoTest.java:23"); assertThat(info.multiLineDebugString()) .startsWith( - "\tat io.opentelemetry.testing.SourceInfoTest.(SourceInfoTest.java:22)\n"); + "\tat io.opentelemetry.testing.SourceInfoTest.(SourceInfoTest.java:23)\n"); } @Test @@ -40,7 +41,8 @@ void testDuplicateExceptionMessage_pureInstruments() { "description", "unit", InstrumentType.OBSERVABLE_COUNTER, - InstrumentValueType.DOUBLE)); + InstrumentValueType.DOUBLE, + Advice.empty())); MetricDescriptor simpleWithNewDescription = MetricDescriptor.create( View.builder().build(), @@ -50,7 +52,8 @@ void testDuplicateExceptionMessage_pureInstruments() { "description2", "unit2", InstrumentType.COUNTER, - InstrumentValueType.LONG)); + InstrumentValueType.LONG, + Advice.empty())); assertThat(DebugUtils.duplicateMetricErrorMessage(simple, simpleWithNewDescription)) .contains("Found duplicate metric definition: name") .contains("- InstrumentDescription [description2] does not match [description]") @@ -76,7 +79,8 @@ void testDuplicateExceptionMessage_viewBasedConflict() { "description", "unit", InstrumentType.HISTOGRAM, - InstrumentValueType.DOUBLE)); + InstrumentValueType.DOUBLE, + Advice.empty())); MetricDescriptor simpleWithNewDescription = MetricDescriptor.create( View.builder().build(), @@ -86,7 +90,8 @@ void testDuplicateExceptionMessage_viewBasedConflict() { "description2", "unit", InstrumentType.HISTOGRAM, - InstrumentValueType.DOUBLE)); + InstrumentValueType.DOUBLE, + Advice.empty())); assertThat(DebugUtils.duplicateMetricErrorMessage(simple, simpleWithNewDescription)) .contains("Found duplicate metric definition: name2") .contains(simple.getSourceInstrument().getSourceInfo().multiLineDebugString()) @@ -111,7 +116,8 @@ void testDuplicateExceptionMessage_viewBasedConflict2() { "description", "unit2", InstrumentType.HISTOGRAM, - InstrumentValueType.DOUBLE)); + InstrumentValueType.DOUBLE, + Advice.empty())); MetricDescriptor simpleWithNewDescription = MetricDescriptor.create( problemView, @@ -121,7 +127,8 @@ void testDuplicateExceptionMessage_viewBasedConflict2() { "description", "unit", InstrumentType.HISTOGRAM, - InstrumentValueType.DOUBLE)); + InstrumentValueType.DOUBLE, + Advice.empty())); assertThat(DebugUtils.duplicateMetricErrorMessage(simple, simpleWithNewDescription)) .contains("Found duplicate metric definition: name") .contains("VIEW defined") diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractInstrumentBuilder.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractInstrumentBuilder.java index fd38837b6f3..db4c8e46d25 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractInstrumentBuilder.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractInstrumentBuilder.java @@ -7,6 +7,7 @@ import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; import io.opentelemetry.api.metrics.ObservableLongMeasurement; +import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.state.CallbackRegistration; import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; @@ -27,6 +28,7 @@ abstract class AbstractInstrumentBuilder T swapBuilder(SwapBuilder swapper) { return swapper.newBuilder( - meterProviderSharedState, meterSharedState, instrumentName, description, unit); + meterProviderSharedState, meterSharedState, instrumentName, description, unit, advice); + } + + protected void setAdvice(Advice advice) { + this.advice = advice; } final I buildSynchronousInstrument( BiFunction instrumentFactory) { InstrumentDescriptor descriptor = - InstrumentDescriptor.create(instrumentName, description, unit, type, valueType); + InstrumentDescriptor.create(instrumentName, description, unit, type, valueType, advice); WriteableMetricStorage storage = meterSharedState.registerSynchronousMetricStorage(descriptor, meterProviderSharedState); return instrumentFactory.apply(descriptor, storage); @@ -96,7 +123,7 @@ final SdkObservableInstrument registerLongAsynchronousInstrument( final SdkObservableMeasurement buildObservableMeasurement(InstrumentType type) { InstrumentDescriptor descriptor = - InstrumentDescriptor.create(instrumentName, description, unit, type, valueType); + InstrumentDescriptor.create(instrumentName, description, unit, type, valueType, advice); return meterSharedState.registerObservableMeasurement(descriptor); } @@ -104,7 +131,7 @@ final SdkObservableMeasurement buildObservableMeasurement(InstrumentType type) { public String toString() { return this.getClass().getSimpleName() + "{descriptor=" - + InstrumentDescriptor.create(instrumentName, description, unit, type, valueType) + + InstrumentDescriptor.create(instrumentName, description, unit, type, valueType, advice) + "}"; } @@ -115,6 +142,7 @@ T newBuilder( MeterSharedState meterSharedState, String name, String description, - String unit); + String unit, + Advice advice); } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java index 7f2a4bcdf51..6b0bbaa6876 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleCounter.java @@ -12,6 +12,7 @@ import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; import io.opentelemetry.context.Context; import io.opentelemetry.sdk.internal.ThrottlingLogger; +import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; import io.opentelemetry.sdk.metrics.internal.state.MeterSharedState; @@ -62,7 +63,8 @@ static final class SdkDoubleCounterBuilder MeterSharedState sharedState, String name, String description, - String unit) { + String unit, + Advice advice) { super( meterProviderSharedState, sharedState, @@ -70,7 +72,8 @@ static final class SdkDoubleCounterBuilder InstrumentValueType.DOUBLE, name, description, - unit); + unit, + advice); } @Override diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java index 1b1bf98de73..983af957273 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleHistogram.java @@ -7,14 +7,18 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.DoubleHistogram; -import io.opentelemetry.api.metrics.DoubleHistogramBuilder; import io.opentelemetry.api.metrics.LongHistogramBuilder; import io.opentelemetry.context.Context; +import io.opentelemetry.extension.incubator.metrics.ExtendedDoubleHistogramBuilder; +import io.opentelemetry.extension.incubator.metrics.HistogramAdviceConfigurer; import io.opentelemetry.sdk.internal.ThrottlingLogger; +import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; import io.opentelemetry.sdk.metrics.internal.state.MeterSharedState; import io.opentelemetry.sdk.metrics.internal.state.WriteableMetricStorage; +import java.util.List; +import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; @@ -54,7 +58,7 @@ public void record(double value) { static final class SdkDoubleHistogramBuilder extends AbstractInstrumentBuilder - implements DoubleHistogramBuilder { + implements ExtendedDoubleHistogramBuilder, HistogramAdviceConfigurer { SdkDoubleHistogramBuilder( MeterProviderSharedState meterProviderSharedState, @@ -75,6 +79,12 @@ protected SdkDoubleHistogramBuilder getThis() { return this; } + @Override + public SdkDoubleHistogramBuilder setAdvice(Consumer adviceConsumer) { + adviceConsumer.accept(this); + return this; + } + @Override public SdkDoubleHistogram build() { return buildSynchronousInstrument(SdkDoubleHistogram::new); @@ -84,5 +94,11 @@ public SdkDoubleHistogram build() { public LongHistogramBuilder ofLongs() { return swapBuilder(SdkLongHistogram.SdkLongHistogramBuilder::new); } + + @Override + public HistogramAdviceConfigurer setExplicitBucketBoundaries(List bucketBoundaries) { + setAdvice(Advice.create(bucketBoundaries)); + return this; + } } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java index ef9bca7eca8..4c7f2c95196 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleUpDownCounter.java @@ -11,6 +11,7 @@ import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; import io.opentelemetry.api.metrics.ObservableDoubleUpDownCounter; import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; import io.opentelemetry.sdk.metrics.internal.state.MeterSharedState; @@ -50,7 +51,8 @@ static final class SdkDoubleUpDownCounterBuilder MeterSharedState sharedState, String name, String description, - String unit) { + String unit, + Advice advice) { super( meterProviderSharedState, sharedState, @@ -58,7 +60,8 @@ static final class SdkDoubleUpDownCounterBuilder InstrumentValueType.DOUBLE, name, description, - unit); + unit, + advice); } @Override diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGaugeBuilder.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGaugeBuilder.java index e1d0b6e1df6..ea6bad737c8 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGaugeBuilder.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGaugeBuilder.java @@ -8,6 +8,7 @@ import io.opentelemetry.api.metrics.LongGaugeBuilder; import io.opentelemetry.api.metrics.ObservableLongGauge; import io.opentelemetry.api.metrics.ObservableLongMeasurement; +import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; import io.opentelemetry.sdk.metrics.internal.state.MeterSharedState; import java.util.function.Consumer; @@ -20,7 +21,8 @@ final class SdkLongGaugeBuilder extends AbstractInstrumentBuilder implements LongHistogramBuilder { + extends AbstractInstrumentBuilder + implements ExtendedLongHistogramBuilder, HistogramAdviceConfigurer { SdkLongHistogramBuilder( MeterProviderSharedState meterProviderSharedState, MeterSharedState sharedState, String name, String description, - String unit) { + String unit, + Advice advice) { super( meterProviderSharedState, sharedState, @@ -67,7 +73,8 @@ static final class SdkLongHistogramBuilder InstrumentValueType.LONG, name, description, - unit); + unit, + advice); } @Override @@ -75,9 +82,21 @@ protected SdkLongHistogramBuilder getThis() { return this; } + @Override + public SdkLongHistogramBuilder setAdvice(Consumer adviceConsumer) { + adviceConsumer.accept(this); + return this; + } + @Override public SdkLongHistogram build() { return buildSynchronousInstrument(SdkLongHistogram::new); } + + @Override + public HistogramAdviceConfigurer setExplicitBucketBoundaries(List bucketBoundaries) { + setAdvice(Advice.create(bucketBoundaries)); + return this; + } } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/descriptor/Advice.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/descriptor/Advice.java new file mode 100644 index 00000000000..d88ab7359e6 --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/descriptor/Advice.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics.internal.descriptor; + +import com.google.auto.value.AutoValue; +import java.util.List; +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; + +@AutoValue +@Immutable +public abstract class Advice { + + private static final Advice EMPTY_ADVICE = create(null); + + public static Advice empty() { + return EMPTY_ADVICE; + } + + public static Advice create(@Nullable List explicitBucketBoundaries) { + return new AutoValue_Advice(explicitBucketBoundaries); + } + + Advice() {} + + @Nullable + public abstract List getExplicitBucketBoundaries(); +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/descriptor/InstrumentDescriptor.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/descriptor/InstrumentDescriptor.java index c3d74cc004a..e4c4aacc95e 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/descriptor/InstrumentDescriptor.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/descriptor/InstrumentDescriptor.java @@ -29,8 +29,9 @@ public static InstrumentDescriptor create( String description, String unit, InstrumentType type, - InstrumentValueType valueType) { - return new AutoValue_InstrumentDescriptor(name, description, unit, type, valueType); + InstrumentValueType valueType, + Advice advice) { + return new AutoValue_InstrumentDescriptor(name, description, unit, type, valueType, advice); } InstrumentDescriptor() {} @@ -45,6 +46,8 @@ public static InstrumentDescriptor create( public abstract InstrumentValueType getValueType(); + public abstract Advice getAdvice(); + /** * Debugging information for this instrument. Ignored from {@link #equals(Object)} and {@link * #toString()}. diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/descriptor/MetricDescriptor.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/descriptor/MetricDescriptor.java index 9c883319139..7990b9d3a6e 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/descriptor/MetricDescriptor.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/descriptor/MetricDescriptor.java @@ -40,7 +40,12 @@ public static MetricDescriptor create(String name, String description, String un View.builder().build(), SourceInfo.fromCurrentStack(), InstrumentDescriptor.create( - name, description, unit, InstrumentType.OBSERVABLE_GAUGE, InstrumentValueType.DOUBLE)); + name, + description, + unit, + InstrumentType.OBSERVABLE_GAUGE, + InstrumentValueType.DOUBLE, + Advice.empty())); } /** Constructs a metric descriptor for a given View + instrument. */ 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 c0760c0b51e..798c9ea11b4 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 @@ -35,7 +35,7 @@ public static Aggregation getInstance() { private DefaultAggregation() {} - private static Aggregation resolve(InstrumentDescriptor instrument) { + private static Aggregation resolve(InstrumentDescriptor instrument, boolean withAdvice) { switch (instrument.getType()) { case COUNTER: case UP_DOWN_COUNTER: @@ -43,6 +43,10 @@ private static Aggregation resolve(InstrumentDescriptor instrument) { case OBSERVABLE_UP_DOWN_COUNTER: return SumAggregation.getInstance(); case HISTOGRAM: + if (withAdvice && instrument.getAdvice().getExplicitBucketBoundaries() != null) { + return ExplicitBucketHistogramAggregation.create( + instrument.getAdvice().getExplicitBucketBoundaries()); + } return ExplicitBucketHistogramAggregation.getDefault(); case OBSERVABLE_GAUGE: return LastValueAggregation.getInstance(); @@ -54,14 +58,14 @@ private static Aggregation resolve(InstrumentDescriptor instrument) { @Override public Aggregator createAggregator( InstrumentDescriptor instrumentDescriptor, ExemplarFilter exemplarFilter) { - return ((AggregatorFactory) resolve(instrumentDescriptor)) + return ((AggregatorFactory) resolve(instrumentDescriptor, /* withAdvice= */ true)) .createAggregator(instrumentDescriptor, exemplarFilter); } @Override public boolean isCompatibleWithInstrument(InstrumentDescriptor instrumentDescriptor) { // This should always return true - return ((AggregatorFactory) resolve(instrumentDescriptor)) + return ((AggregatorFactory) resolve(instrumentDescriptor, /* withAdvice= */ false)) .isCompatibleWithInstrument(instrumentDescriptor); } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AbstractInstrumentBuilderTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AbstractInstrumentBuilderTest.java index ec79e45960c..ad008e65fd3 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AbstractInstrumentBuilderTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AbstractInstrumentBuilderTest.java @@ -40,7 +40,8 @@ void stringRepresentation() { + "description=instrument-description, " + "unit=instrument-unit, " + "type=COUNTER, " - + "valueType=LONG" + + "valueType=LONG, " + + "advice=Advice{explicitBucketBoundaries=null}" + "}}"); } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AbstractInstrumentTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AbstractInstrumentTest.java index 48083106607..659a8260c5a 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AbstractInstrumentTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AbstractInstrumentTest.java @@ -7,6 +7,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import org.junit.jupiter.api.Test; @@ -14,7 +15,12 @@ class AbstractInstrumentTest { private static final InstrumentDescriptor INSTRUMENT_DESCRIPTOR = InstrumentDescriptor.create( - "name", "description", "1", InstrumentType.COUNTER, InstrumentValueType.LONG); + "name", + "description", + "1", + InstrumentType.COUNTER, + InstrumentValueType.LONG, + Advice.empty()); @Test void getValues() { diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AdviceTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AdviceTest.java new file mode 100644 index 00000000000..8325fd7350a --- /dev/null +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AdviceTest.java @@ -0,0 +1,203 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics; + +import static io.opentelemetry.sdk.metrics.Aggregation.explicitBucketHistogram; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; + +import io.opentelemetry.api.metrics.DoubleHistogram; +import io.opentelemetry.api.metrics.LongHistogram; +import io.opentelemetry.extension.incubator.metrics.ExtendedDoubleHistogramBuilder; +import io.opentelemetry.extension.incubator.metrics.ExtendedLongHistogramBuilder; +import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; +import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; +import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; +import java.util.Arrays; +import java.util.Collections; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Stream; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class AdviceTest { + + private SdkMeterProvider meterProvider = SdkMeterProvider.builder().build(); + + @AfterEach + void cleanup() { + meterProvider.close(); + } + + @ParameterizedTest + @MethodSource("histogramsWithoutAdvice") + void histogramWithoutAdvice(Function> histogramBuilder) { + InMemoryMetricReader reader = InMemoryMetricReader.create(); + meterProvider = SdkMeterProvider.builder().registerMetricReader(reader).build(); + + Consumer histogramRecorder = histogramBuilder.apply(meterProvider); + histogramRecorder.accept(5L); + histogramRecorder.accept(15L); + histogramRecorder.accept(25L); + histogramRecorder.accept(35L); + + // Should use default bucket bounds + assertThat(reader.collectAllMetrics()) + .satisfiesExactly( + metric -> + assertThat(metric) + .hasHistogramSatisfying( + histogram -> + histogram.hasPointsSatisfying( + point -> + point + .hasBucketCounts( + 0, 1, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + .hasBucketBoundaries( + 0d, 5d, 10d, 25d, 50d, 75d, 100d, 250d, 500d, 750d, + 1_000d, 2_500d, 5_000d, 7_500d, 10_000d)))); + } + + @ParameterizedTest + @MethodSource("histogramsWithAdvice") + void histogramWithAdvice(Function> histogramBuilder) { + InMemoryMetricReader reader = InMemoryMetricReader.create(); + meterProvider = SdkMeterProvider.builder().registerMetricReader(reader).build(); + + Consumer histogramRecorder = histogramBuilder.apply(meterProvider); + histogramRecorder.accept(5L); + histogramRecorder.accept(15L); + histogramRecorder.accept(25L); + histogramRecorder.accept(35L); + + // Bucket bounds from advice should be used + assertThat(reader.collectAllMetrics()) + .satisfiesExactly( + metric -> + assertThat(metric) + .hasName("histogram") + .hasHistogramSatisfying( + histogram -> + histogram.hasPointsSatisfying( + point -> + point + .hasBucketCounts(1, 1, 1, 1) + .hasBucketBoundaries(10.0, 20.0, 30.0)))); + } + + @ParameterizedTest + @MethodSource("histogramsWithAdvice") + void histogramWithAdviceAndViews(Function> histogramBuilder) { + InMemoryMetricReader reader = InMemoryMetricReader.create(); + meterProvider = + SdkMeterProvider.builder() + .registerMetricReader(reader) + .registerView( + InstrumentSelector.builder().setType(InstrumentType.HISTOGRAM).build(), + View.builder() + .setAggregation(explicitBucketHistogram(Collections.singletonList(50.0))) + .build()) + .build(); + + Consumer histogramRecorder = histogramBuilder.apply(meterProvider); + histogramRecorder.accept(5L); + histogramRecorder.accept(15L); + histogramRecorder.accept(25L); + histogramRecorder.accept(35L); + + // View should take priority over bucket bounds from advice + assertThat(reader.collectAllMetrics()) + .satisfiesExactly( + metric -> + assertThat(metric) + .hasName("histogram") + .hasHistogramSatisfying( + histogram -> + histogram.hasPointsSatisfying( + point -> point.hasBucketCounts(4, 0).hasBucketBoundaries(50.0)))); + } + + @ParameterizedTest + @MethodSource("histogramsWithAdvice") + void histogramWithAdviceAndReaderAggregationPreference( + Function> histogramBuilder) { + InMemoryMetricReader reader = + InMemoryMetricReader.create( + AggregationTemporalitySelector.alwaysCumulative(), + DefaultAggregationSelector.getDefault() + .with( + InstrumentType.HISTOGRAM, + explicitBucketHistogram(Collections.singletonList(50.0)))); + meterProvider = SdkMeterProvider.builder().registerMetricReader(reader).build(); + + Consumer histogramRecorder = histogramBuilder.apply(meterProvider); + histogramRecorder.accept(5L); + histogramRecorder.accept(15L); + histogramRecorder.accept(25L); + histogramRecorder.accept(35L); + + // Reader aggregation preference should take priority over bucket bounds from advice + assertThat(reader.collectAllMetrics()) + .satisfiesExactly( + metric -> + assertThat(metric) + .hasName("histogram") + .hasHistogramSatisfying( + histogram -> + histogram.hasPointsSatisfying( + point -> point.hasBucketCounts(4, 0).hasBucketBoundaries(50.0)))); + } + + private static Stream histogramsWithoutAdvice() { + return Stream.of( + Arguments.of( + (Function>) + meterProvider -> { + DoubleHistogram build = + meterProvider.get("meter").histogramBuilder("histogram").build(); + return build::record; + }), + Arguments.of( + (Function>) + meterProvider -> { + LongHistogram build = + meterProvider.get("meter").histogramBuilder("histogram").ofLongs().build(); + return build::record; + })); + } + + private static Stream histogramsWithAdvice() { + return Stream.of( + Arguments.of( + (Function>) + meterProvider -> { + DoubleHistogram build = + ((ExtendedDoubleHistogramBuilder) + meterProvider.get("meter").histogramBuilder("histogram")) + .setAdvice( + advice -> + advice.setExplicitBucketBoundaries( + Arrays.asList(10.0, 20.0, 30.0))) + .build(); + return build::record; + }), + Arguments.of( + (Function>) + meterProvider -> { + LongHistogram build = + ((ExtendedLongHistogramBuilder) + meterProvider.get("meter").histogramBuilder("histogram").ofLongs()) + .setAdvice( + advice -> + advice.setExplicitBucketBoundaries( + Arrays.asList(10.0, 20.0, 30.0))) + .build(); + return build::record; + })); + } +} diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AggregationTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AggregationTest.java index 2bab930bddc..544eded9b84 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AggregationTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AggregationTest.java @@ -8,6 +8,7 @@ import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.sdk.metrics.internal.aggregator.AggregatorFactory; +import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import java.util.Collections; import org.junit.jupiter.api.Test; @@ -105,6 +106,6 @@ void aggregationIsCompatible() { private static InstrumentDescriptor descriptorForType(InstrumentType instrumentType) { return InstrumentDescriptor.create( - "name", "description", "unit", instrumentType, InstrumentValueType.DOUBLE); + "name", "description", "unit", instrumentType, InstrumentValueType.DOUBLE, Advice.empty()); } } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkMeterProviderTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkMeterProviderTest.java index be8ea25eea3..479dcd62088 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkMeterProviderTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkMeterProviderTest.java @@ -52,8 +52,11 @@ import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; @ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) class SdkMeterProviderTest { private static final Resource RESOURCE = Resource.create(Attributes.of(AttributeKey.stringKey("resource_key"), "resource_value")); diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkObservableInstrumentTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkObservableInstrumentTest.java index b0438fa27cc..2a865288678 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkObservableInstrumentTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkObservableInstrumentTest.java @@ -13,6 +13,7 @@ import io.github.netmikey.logunit.api.LogCapturer; import io.opentelemetry.internal.testing.slf4j.SuppressLogger; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.state.CallbackRegistration; import io.opentelemetry.sdk.metrics.internal.state.MeterSharedState; @@ -46,7 +47,8 @@ void setup() { "description", "unit", InstrumentType.COUNTER, - InstrumentValueType.DOUBLE), + InstrumentValueType.DOUBLE, + Advice.empty()), Collections.emptyList())), () -> {}); @@ -80,7 +82,8 @@ void stringRepresentation() { + "description=description, " + "unit=unit, " + "type=COUNTER, " - + "valueType=DOUBLE}" + + "valueType=DOUBLE, " + + "advice=Advice{explicitBucketBoundaries=null}}" + "]}}"); } } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/aggregator/DoubleSumAggregatorTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/aggregator/DoubleSumAggregatorTest.java index 4a0ef1b8c10..15377186150 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/aggregator/DoubleSumAggregatorTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/aggregator/DoubleSumAggregatorTest.java @@ -21,6 +21,7 @@ import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableDoubleExemplarData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableDoublePointData; +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.ExemplarReservoir; @@ -51,7 +52,8 @@ class DoubleSumAggregatorTest { "instrument_description", "instrument_unit", InstrumentType.COUNTER, - InstrumentValueType.DOUBLE), + InstrumentValueType.DOUBLE, + Advice.empty()), ExemplarReservoir::doubleNoSamples); @Test @@ -136,7 +138,8 @@ void aggregateThenMaybeReset_WithExemplars() { "instrument_description", "instrument_unit", InstrumentType.COUNTER, - InstrumentValueType.DOUBLE), + InstrumentValueType.DOUBLE, + Advice.empty()), () -> reservoir); AggregatorHandle aggregatorHandle = aggregator.createHandle(); @@ -165,7 +168,12 @@ void mergeAndDiff() { DoubleSumAggregator aggregator = new DoubleSumAggregator( InstrumentDescriptor.create( - "name", "description", "unit", instrumentType, InstrumentValueType.LONG), + "name", + "description", + "unit", + instrumentType, + InstrumentValueType.LONG, + Advice.empty()), ExemplarReservoir::doubleNoSamples); DoublePointData diffed = diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/aggregator/LongSumAggregatorTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/aggregator/LongSumAggregatorTest.java index be129d21108..d6f0f189834 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/aggregator/LongSumAggregatorTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/aggregator/LongSumAggregatorTest.java @@ -21,6 +21,7 @@ import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableLongExemplarData; import io.opentelemetry.sdk.metrics.internal.data.ImmutableLongPointData; +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.ExemplarReservoir; @@ -50,7 +51,8 @@ class LongSumAggregatorTest { "instrument_description", "instrument_unit", InstrumentType.COUNTER, - InstrumentValueType.LONG), + InstrumentValueType.LONG, + Advice.empty()), ExemplarReservoir::longNoSamples); @Test @@ -132,7 +134,8 @@ void aggregateThenMaybeReset_WithExemplars() { "instrument_description", "instrument_unit", InstrumentType.COUNTER, - InstrumentValueType.LONG), + InstrumentValueType.LONG, + Advice.empty()), () -> reservoir); AggregatorHandle aggregatorHandle = aggregator.createHandle(); aggregatorHandle.recordLong(0, attributes, Context.root()); @@ -159,7 +162,12 @@ void mergeAndDiff() { LongSumAggregator aggregator = new LongSumAggregator( InstrumentDescriptor.create( - "name", "description", "unit", instrumentType, InstrumentValueType.LONG), + "name", + "description", + "unit", + instrumentType, + InstrumentValueType.LONG, + Advice.empty()), ExemplarReservoir::longNoSamples); LongPointData diffed = diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/descriptor/MetricDescriptorTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/descriptor/MetricDescriptorTest.java index dc26e8c196a..ebcd681432c 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/descriptor/MetricDescriptorTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/descriptor/MetricDescriptorTest.java @@ -21,7 +21,12 @@ void metricDescriptor_preservesInstrumentDescriptor() { View view = View.builder().build(); InstrumentDescriptor instrument = InstrumentDescriptor.create( - "name", "description", "unit", InstrumentType.COUNTER, InstrumentValueType.DOUBLE); + "name", + "description", + "unit", + InstrumentType.COUNTER, + InstrumentValueType.DOUBLE, + Advice.empty()); MetricDescriptor simple = MetricDescriptor.create(view, SourceInfo.fromCurrentStack(), instrument); assertThat(simple.getName()).isEqualTo("name"); @@ -36,7 +41,12 @@ void metricDescriptor_overridesFromView() { View view = View.builder().setName("new_name").setDescription("new_description").build(); InstrumentDescriptor instrument = InstrumentDescriptor.create( - "name", "description", "unit", InstrumentType.HISTOGRAM, InstrumentValueType.DOUBLE); + "name", + "description", + "unit", + InstrumentType.HISTOGRAM, + InstrumentValueType.DOUBLE, + Advice.empty()); MetricDescriptor simple = MetricDescriptor.create(view, SourceInfo.fromCurrentStack(), instrument); assertThat(simple.getName()).isEqualTo("new_name"); @@ -51,7 +61,12 @@ void metricDescriptor_isCompatible() { View view = View.builder().build(); InstrumentDescriptor instrument = InstrumentDescriptor.create( - "name", "description", "unit", InstrumentType.COUNTER, InstrumentValueType.DOUBLE); + "name", + "description", + "unit", + InstrumentType.COUNTER, + InstrumentValueType.DOUBLE, + Advice.empty()); MetricDescriptor descriptor = MetricDescriptor.create(view, SourceInfo.fromCurrentStack(), instrument); // Same name, description, source name, source description, source unit, source type, and source @@ -66,7 +81,8 @@ void metricDescriptor_isCompatible() { "description", "unit", InstrumentType.COUNTER, - InstrumentValueType.DOUBLE)))) + InstrumentValueType.DOUBLE, + Advice.empty())))) .isTrue(); // Different name overridden by view is not compatible assertThat( @@ -103,7 +119,8 @@ void metricDescriptor_isCompatible() { "description", "unit", InstrumentType.COUNTER, - InstrumentValueType.DOUBLE)))) + InstrumentValueType.DOUBLE, + Advice.empty())))) .isFalse(); // Different instrument source description is not compatible assertThat( @@ -116,7 +133,8 @@ void metricDescriptor_isCompatible() { "foo", "unit", InstrumentType.COUNTER, - InstrumentValueType.DOUBLE)))) + InstrumentValueType.DOUBLE, + Advice.empty())))) .isFalse(); // Different instrument source unit is not compatible assertThat( @@ -129,7 +147,8 @@ void metricDescriptor_isCompatible() { "description", "foo", InstrumentType.COUNTER, - InstrumentValueType.DOUBLE)))) + InstrumentValueType.DOUBLE, + Advice.empty())))) .isFalse(); // Different instrument source type is not compatible assertThat( @@ -142,7 +161,8 @@ void metricDescriptor_isCompatible() { "description", "unit", InstrumentType.HISTOGRAM, - InstrumentValueType.DOUBLE)))) + InstrumentValueType.DOUBLE, + Advice.empty())))) .isFalse(); // Different instrument source value type is not compatible assertThat( @@ -155,7 +175,8 @@ void metricDescriptor_isCompatible() { "description", "unit", InstrumentType.COUNTER, - InstrumentValueType.LONG)))) + InstrumentValueType.LONG, + Advice.empty())))) .isFalse(); } } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorageTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorageTest.java index 11cfcbdea30..cdd38a9c9d1 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorageTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorageTest.java @@ -23,6 +23,7 @@ import io.opentelemetry.sdk.metrics.data.AggregationTemporality; import io.opentelemetry.sdk.metrics.export.MetricReader; import io.opentelemetry.sdk.metrics.internal.debug.SourceInfo; +import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.export.RegisteredReader; import io.opentelemetry.sdk.metrics.internal.view.AttributesProcessor; @@ -72,7 +73,8 @@ void setup() { "description", "unit", InstrumentType.COUNTER, - InstrumentValueType.LONG)); + InstrumentValueType.LONG, + Advice.empty())); doubleCounterStorage = AsynchronousMetricStorage.create( registeredReader, @@ -82,7 +84,8 @@ void setup() { "description", "unit", InstrumentType.COUNTER, - InstrumentValueType.DOUBLE)); + InstrumentValueType.DOUBLE, + Advice.empty())); } @Test @@ -148,7 +151,12 @@ void record_ProcessesAttributes() { AttributesProcessor.filterByKeyName(key -> key.equals("key1")), SourceInfo.noSourceInfo()), InstrumentDescriptor.create( - "name", "description", "unit", InstrumentType.COUNTER, InstrumentValueType.LONG)); + "name", + "description", + "unit", + InstrumentType.COUNTER, + InstrumentValueType.LONG, + Advice.empty())); storage.record( longMeasurement(0, 1, 1, Attributes.builder().put("key1", "a").put("key2", "b").build())); @@ -275,7 +283,8 @@ void collect_DeltaComputesDiff() { "description", "unit", InstrumentType.COUNTER, - InstrumentValueType.LONG)); + InstrumentValueType.LONG, + Advice.empty())); // Record measurement and collect at time 10 longCounterStorage.record(longMeasurement(0, 10, 3, Attributes.empty())); diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/CallbackRegistrationTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/CallbackRegistrationTest.java index 7a35d9940d6..b7c1dae870b 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/CallbackRegistrationTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/CallbackRegistrationTest.java @@ -22,6 +22,7 @@ import io.opentelemetry.sdk.metrics.InstrumentType; import io.opentelemetry.sdk.metrics.InstrumentValueType; import io.opentelemetry.sdk.metrics.export.MetricReader; +import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.export.RegisteredReader; import io.opentelemetry.sdk.metrics.internal.view.ViewRegistry; @@ -50,14 +51,16 @@ class CallbackRegistrationTest { "description", "unit", InstrumentType.OBSERVABLE_COUNTER, - InstrumentValueType.LONG); + InstrumentValueType.LONG, + Advice.empty()); private static final InstrumentDescriptor DOUBLE_INSTRUMENT = InstrumentDescriptor.create( "double-counter", "description", "unit", InstrumentType.OBSERVABLE_COUNTER, - InstrumentValueType.LONG); + InstrumentValueType.LONG, + Advice.empty()); @RegisterExtension LogCapturer logs = LogCapturer.create().captureForType(CallbackRegistration.class); @@ -102,7 +105,8 @@ void stringRepresentation() { + "description=description, " + "unit=unit, " + "type=OBSERVABLE_COUNTER, " - + "valueType=LONG" + + "valueType=LONG, " + + "advice=Advice{explicitBucketBoundaries=null}" + "}]}"); assertThat( CallbackRegistration.create(Arrays.asList(measurement1, measurement2), callback) @@ -115,13 +119,15 @@ void stringRepresentation() { + "description=description, " + "unit=unit, " + "type=OBSERVABLE_COUNTER, " - + "valueType=LONG}, " + + "valueType=LONG, " + + "advice=Advice{explicitBucketBoundaries=null}}, " + "InstrumentDescriptor{" + "name=long-counter, " + "description=description, " + "unit=unit, " + "type=OBSERVABLE_COUNTER, " - + "valueType=LONG" + + "valueType=LONG, " + + "advice=Advice{explicitBucketBoundaries=null}" + "}]}"); } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistryTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistryTest.java index 514bf330f0e..8b664ad5d3e 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistryTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistryTest.java @@ -17,6 +17,7 @@ import io.opentelemetry.sdk.metrics.View; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.internal.debug.SourceInfo; +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.resources.Resource; @@ -84,7 +85,7 @@ private static MetricDescriptor descriptor( View.builder().build(), SourceInfo.fromCurrentStack(), InstrumentDescriptor.create( - name, description, "1", instrumentType, InstrumentValueType.DOUBLE)); + name, description, "1", instrumentType, InstrumentValueType.DOUBLE, Advice.empty())); } private static final class TestMetricStorage implements MetricStorage, WriteableMetricStorage { 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 6886cf4e6ba..3104f387806 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 @@ -25,6 +25,7 @@ import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.internal.aggregator.Aggregator; import io.opentelemetry.sdk.metrics.internal.aggregator.AggregatorFactory; +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; @@ -44,7 +45,12 @@ public class SynchronousMetricStorageTest { InstrumentationScopeInfo.builder("test").setVersion("1.0").build(); private static final InstrumentDescriptor DESCRIPTOR = InstrumentDescriptor.create( - "name", "description", "unit", InstrumentType.COUNTER, InstrumentValueType.DOUBLE); + "name", + "description", + "unit", + InstrumentType.COUNTER, + InstrumentValueType.DOUBLE, + Advice.empty()); private static final MetricDescriptor METRIC_DESCRIPTOR = MetricDescriptor.create("name", "description", "unit"); diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistryTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistryTest.java index 60367f1d973..08234ebef47 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistryTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistryTest.java @@ -19,6 +19,7 @@ import io.opentelemetry.sdk.metrics.View; import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; import io.opentelemetry.sdk.metrics.internal.debug.SourceInfo; +import io.opentelemetry.sdk.metrics.internal.descriptor.Advice; import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import java.util.Arrays; import java.util.Collections; @@ -53,14 +54,19 @@ void findViews_SelectionOnType() { assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "", "", "", InstrumentType.COUNTER, InstrumentValueType.LONG), + "", "", "", InstrumentType.COUNTER, InstrumentValueType.LONG, Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(registeredView)); // this one doesn't match, so it gets the default still. assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "", "", "", InstrumentType.UP_DOWN_COUNTER, InstrumentValueType.LONG), + "", + "", + "", + InstrumentType.UP_DOWN_COUNTER, + InstrumentValueType.LONG, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); @@ -80,14 +86,19 @@ void findViews_SelectionOnUnit() { assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "", "", "ms", InstrumentType.COUNTER, InstrumentValueType.LONG), + "", "", "ms", InstrumentType.COUNTER, InstrumentValueType.LONG, Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(registeredView)); // this one doesn't match, so it gets the default still. assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "", "", "", InstrumentType.UP_DOWN_COUNTER, InstrumentValueType.LONG), + "", + "", + "", + InstrumentType.UP_DOWN_COUNTER, + InstrumentValueType.LONG, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); @@ -107,14 +118,24 @@ void findViews_SelectionOnName() { assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "overridden", "", "", InstrumentType.COUNTER, InstrumentValueType.LONG), + "overridden", + "", + "", + InstrumentType.COUNTER, + InstrumentValueType.LONG, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(registeredView)); // this one doesn't match, so it gets the default still. assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "default", "", "", InstrumentType.COUNTER, InstrumentValueType.LONG), + "default", + "", + "", + InstrumentType.COUNTER, + InstrumentValueType.LONG, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); @@ -140,13 +161,23 @@ void findViews_MultipleMatchingViews() { assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "overridden", "", "", InstrumentType.COUNTER, InstrumentValueType.LONG), + "overridden", + "", + "", + InstrumentType.COUNTER, + InstrumentValueType.LONG, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Arrays.asList(registeredView1, registeredView2)); assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "default", "", "", InstrumentType.COUNTER, InstrumentValueType.LONG), + "default", + "", + "", + InstrumentType.COUNTER, + InstrumentValueType.LONG, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(registeredView2)); @@ -169,21 +200,36 @@ void findViews_SelectionTypeAndName() { assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "overrides", "", "", InstrumentType.COUNTER, InstrumentValueType.LONG), + "overrides", + "", + "", + InstrumentType.COUNTER, + InstrumentValueType.LONG, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(registeredView)); // this one doesn't match, so it gets the default still. assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "overrides", "", "", InstrumentType.UP_DOWN_COUNTER, InstrumentValueType.LONG), + "overrides", + "", + "", + InstrumentType.UP_DOWN_COUNTER, + InstrumentValueType.LONG, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); // this one doesn't match, so it gets the default still. assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "default", "", "", InstrumentType.COUNTER, InstrumentValueType.LONG), + "default", + "", + "", + InstrumentType.COUNTER, + InstrumentValueType.LONG, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); @@ -214,7 +260,12 @@ void findViews_DefaultAggregationSelector() { assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "test", "", "", InstrumentType.COUNTER, InstrumentValueType.DOUBLE), + "test", + "", + "", + InstrumentType.COUNTER, + InstrumentValueType.DOUBLE, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); // Histogram instrument named overridden should match the registered view, for which the @@ -222,7 +273,12 @@ void findViews_DefaultAggregationSelector() { assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "overridden", "", "", InstrumentType.HISTOGRAM, InstrumentValueType.DOUBLE), + "overridden", + "", + "", + InstrumentType.HISTOGRAM, + InstrumentValueType.DOUBLE, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(registeredView)); // Histogram instrument named default should match no views, and should receive a default view @@ -231,7 +287,12 @@ void findViews_DefaultAggregationSelector() { assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "default", "", "", InstrumentType.HISTOGRAM, InstrumentValueType.DOUBLE), + "default", + "", + "", + InstrumentType.HISTOGRAM, + InstrumentValueType.DOUBLE, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo( Collections.singletonList( @@ -248,7 +309,12 @@ void findViews_DefaultAggregationSelector() { assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "default", "", "", InstrumentType.OBSERVABLE_GAUGE, InstrumentValueType.DOUBLE), + "default", + "", + "", + InstrumentType.OBSERVABLE_GAUGE, + InstrumentValueType.DOUBLE, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); logs.assertContains( @@ -269,7 +335,12 @@ void findViews_IncompatibleViewIgnored() { assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "test", "", "", InstrumentType.OBSERVABLE_COUNTER, InstrumentValueType.LONG), + "test", + "", + "", + InstrumentType.OBSERVABLE_COUNTER, + InstrumentValueType.LONG, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); @@ -283,31 +354,46 @@ void defaults() { assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "", "", "", InstrumentType.COUNTER, InstrumentValueType.LONG), + "", "", "", InstrumentType.COUNTER, InstrumentValueType.LONG, Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "", "", "", InstrumentType.UP_DOWN_COUNTER, InstrumentValueType.LONG), + "", + "", + "", + InstrumentType.UP_DOWN_COUNTER, + InstrumentValueType.LONG, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "", "", "", InstrumentType.HISTOGRAM, InstrumentValueType.LONG), + "", "", "", InstrumentType.HISTOGRAM, InstrumentValueType.LONG, Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "", "", "", InstrumentType.OBSERVABLE_COUNTER, InstrumentValueType.LONG), + "", + "", + "", + InstrumentType.OBSERVABLE_COUNTER, + InstrumentValueType.LONG, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); assertThat( viewRegistry.findViews( InstrumentDescriptor.create( - "", "", "", InstrumentType.OBSERVABLE_GAUGE, InstrumentValueType.LONG), + "", + "", + "", + InstrumentType.OBSERVABLE_GAUGE, + InstrumentValueType.LONG, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); assertThat( @@ -317,7 +403,8 @@ void defaults() { "", "", InstrumentType.OBSERVABLE_UP_DOWN_COUNTER, - InstrumentValueType.LONG), + InstrumentValueType.LONG, + Advice.empty()), INSTRUMENTATION_SCOPE_INFO)) .isEqualTo(Collections.singletonList(DEFAULT_REGISTERED_VIEW)); diff --git a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/exporter/InMemoryMetricReader.java b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/exporter/InMemoryMetricReader.java index ec679f9db74..dbe85356566 100644 --- a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/exporter/InMemoryMetricReader.java +++ b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/exporter/InMemoryMetricReader.java @@ -6,10 +6,13 @@ package io.opentelemetry.sdk.testing.exporter; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.metrics.Aggregation; import io.opentelemetry.sdk.metrics.InstrumentType; import io.opentelemetry.sdk.metrics.data.AggregationTemporality; import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; import io.opentelemetry.sdk.metrics.export.CollectionRegistration; +import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; import io.opentelemetry.sdk.metrics.export.MetricReader; import io.opentelemetry.sdk.metrics.internal.export.MetricProducer; import java.util.Collection; @@ -45,22 +48,35 @@ * @since 1.14.0 */ public class InMemoryMetricReader implements MetricReader { - private final AggregationTemporality aggregationTemporality; + private final AggregationTemporalitySelector aggregationTemporalitySelector; + private final DefaultAggregationSelector defaultAggregationSelector; private final AtomicBoolean isShutdown = new AtomicBoolean(false); private volatile MetricProducer metricProducer = MetricProducer.noop(); /** Returns a new {@link InMemoryMetricReader}. */ public static InMemoryMetricReader create() { - return new InMemoryMetricReader(AggregationTemporality.CUMULATIVE); + return new InMemoryMetricReader( + AggregationTemporalitySelector.alwaysCumulative(), DefaultAggregationSelector.getDefault()); + } + + /** Returns a new {@link InMemoryMetricReader}. */ + public static InMemoryMetricReader create( + AggregationTemporalitySelector aggregationTemporalitySelector, + DefaultAggregationSelector defaultAggregationSelector) { + return new InMemoryMetricReader(aggregationTemporalitySelector, defaultAggregationSelector); } /** Creates a new {@link InMemoryMetricReader} that prefers DELTA aggregation. */ public static InMemoryMetricReader createDelta() { - return new InMemoryMetricReader(AggregationTemporality.DELTA); + return new InMemoryMetricReader( + unused -> AggregationTemporality.DELTA, DefaultAggregationSelector.getDefault()); } - private InMemoryMetricReader(AggregationTemporality aggregationTemporality) { - this.aggregationTemporality = aggregationTemporality; + private InMemoryMetricReader( + AggregationTemporalitySelector aggregationTemporalitySelector, + DefaultAggregationSelector defaultAggregationSelector) { + this.aggregationTemporalitySelector = aggregationTemporalitySelector; + this.defaultAggregationSelector = defaultAggregationSelector; } /** Returns all metrics accumulated since the last call. */ @@ -78,7 +94,12 @@ public void register(CollectionRegistration registration) { @Override public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) { - return aggregationTemporality; + return aggregationTemporalitySelector.getAggregationTemporality(instrumentType); + } + + @Override + public Aggregation getDefaultAggregation(InstrumentType instrumentType) { + return defaultAggregationSelector.getDefaultAggregation(instrumentType); } @Override @@ -95,6 +116,6 @@ public CompletableResultCode shutdown() { @Override public String toString() { - return "InMemoryMetricReader{aggregationTemporality=" + aggregationTemporality + "}"; + return "InMemoryMetricReader{}"; } } diff --git a/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/exporter/InMemoryMetricReaderTest.java b/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/exporter/InMemoryMetricReaderTest.java index 9df4a48c783..8dadfd14bbd 100644 --- a/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/exporter/InMemoryMetricReaderTest.java +++ b/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/exporter/InMemoryMetricReaderTest.java @@ -92,7 +92,6 @@ void shutdown_Cumulative() { @Test void stringRepresentation() { - assertThat(deltaReader.toString()) - .isEqualTo("InMemoryMetricReader{aggregationTemporality=DELTA}"); + assertThat(deltaReader.toString()).isEqualTo("InMemoryMetricReader{}"); } }