From 9b327ebe6240607d18a77e141095fd0b43f6560a Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 1 May 2024 11:03:56 -0500 Subject: [PATCH 1/2] Stabilize synchronous gauge --- .../api/metrics/DefaultMeter.java | 43 ++++++++- .../api}/metrics/DoubleGauge.java | 12 ++- .../api/metrics/DoubleGaugeBuilder.java | 13 +++ .../opentelemetry/api}/metrics/LongGauge.java | 12 ++- .../api/metrics/LongGaugeBuilder.java | 13 +++ .../api/metrics/DefaultMeterTest.java | 27 ++++++ .../metrics/ExtendedDoubleGaugeBuilder.java | 12 --- .../metrics/ExtendedLongGaugeBuilder.java | 12 --- .../metrics/ExtendedMetricsApiUsageTest.java | 42 --------- .../current_vs_latest/opentelemetry-api.txt | 19 +++- .../opentelemetry-sdk-metrics.txt | 3 + .../sdk/metrics/InstrumentType.java | 1 + .../sdk/metrics/SdkDoubleGauge.java | 16 ++-- .../sdk/metrics/SdkLongGauge.java | 16 ++-- .../internal/view/DefaultAggregation.java | 1 + .../internal/view/LastValueAggregation.java | 35 ++++++-- .../sdk/metrics/AggregationTest.java | 7 ++ .../sdk/metrics/SdkDoubleGaugeTest.java | 80 +++++++++++++---- .../sdk/metrics/SdkLongGaugeTest.java | 90 ++++++++++++++----- .../AggregationTemporalitySelectorTest.java | 12 ++- .../DefaultAggregationSelectorTest.java | 10 ++- 21 files changed, 340 insertions(+), 136 deletions(-) rename api/{incubator/src/main/java/io/opentelemetry/api/incubator => all/src/main/java/io/opentelemetry/api}/metrics/DoubleGauge.java (61%) rename api/{incubator/src/main/java/io/opentelemetry/api/incubator => all/src/main/java/io/opentelemetry/api}/metrics/LongGauge.java (61%) diff --git a/api/all/src/main/java/io/opentelemetry/api/metrics/DefaultMeter.java b/api/all/src/main/java/io/opentelemetry/api/metrics/DefaultMeter.java index 9cab67f239d..fff36ae9cbb 100644 --- a/api/all/src/main/java/io/opentelemetry/api/metrics/DefaultMeter.java +++ b/api/all/src/main/java/io/opentelemetry/api/metrics/DefaultMeter.java @@ -320,8 +320,10 @@ public LongHistogram build() { } private static class NoopDoubleGaugeBuilder implements DoubleGaugeBuilder { - private static final ObservableDoubleGauge NOOP = new ObservableDoubleGauge() {}; + private static final ObservableDoubleGauge NOOP_OBSERVABLE_GAUGE = + new ObservableDoubleGauge() {}; private static final LongGaugeBuilder NOOP_LONG_GAUGE_BUILDER = new NoopLongGaugeBuilder(); + private static final NoopDoubleGauge NOOP_GAUGE = new NoopDoubleGauge(); @Override public DoubleGaugeBuilder setDescription(String description) { @@ -340,17 +342,34 @@ public LongGaugeBuilder ofLongs() { @Override public ObservableDoubleGauge buildWithCallback(Consumer callback) { - return NOOP; + return NOOP_OBSERVABLE_GAUGE; } @Override public ObservableDoubleMeasurement buildObserver() { return NOOP_OBSERVABLE_DOUBLE_MEASUREMENT; } + + @Override + public DoubleGauge build() { + return NOOP_GAUGE; + } + } + + private static class NoopDoubleGauge implements DoubleGauge { + @Override + public void set(double value) {} + + @Override + public void set(double value, Attributes attributes) {} + + @Override + public void set(double value, Attributes attributes, Context context) {} } private static class NoopLongGaugeBuilder implements LongGaugeBuilder { - private static final ObservableLongGauge NOOP = new ObservableLongGauge() {}; + private static final ObservableLongGauge NOOP_OBSERVABLE_GAUGE = new ObservableLongGauge() {}; + private static final NoopLongGauge NOOP_GAUGE = new NoopLongGauge(); @Override public LongGaugeBuilder setDescription(String description) { @@ -364,13 +383,29 @@ public LongGaugeBuilder setUnit(String unit) { @Override public ObservableLongGauge buildWithCallback(Consumer callback) { - return NOOP; + return NOOP_OBSERVABLE_GAUGE; } @Override public ObservableLongMeasurement buildObserver() { return NOOP_OBSERVABLE_LONG_MEASUREMENT; } + + @Override + public LongGauge build() { + return NOOP_GAUGE; + } + } + + private static class NoopLongGauge implements LongGauge { + @Override + public void set(long value) {} + + @Override + public void set(long value, Attributes attributes) {} + + @Override + public void set(long value, Attributes attributes, Context context) {} } private static class NoopObservableDoubleMeasurement implements ObservableDoubleMeasurement { diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/DoubleGauge.java b/api/all/src/main/java/io/opentelemetry/api/metrics/DoubleGauge.java similarity index 61% rename from api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/DoubleGauge.java rename to api/all/src/main/java/io/opentelemetry/api/metrics/DoubleGauge.java index cee57ce6618..ee42b44aa7f 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/DoubleGauge.java +++ b/api/all/src/main/java/io/opentelemetry/api/metrics/DoubleGauge.java @@ -3,9 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.api.incubator.metrics; +package io.opentelemetry.api.metrics; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.context.Context; import javax.annotation.concurrent.ThreadSafe; /** A gauge instrument that synchronously records {@code double} values. */ @@ -26,5 +27,12 @@ public interface DoubleGauge { */ void set(double value, Attributes attributes); - // TODO(jack-berg): should we add overload with Context argument? + /** + * Records a value with a set of attributes. + * + * @param value The current gauge value. + * @param attributes A set of attributes to associate with the value. + * @param context The explicit context to associate with this measurement. + */ + void set(double value, Attributes attributes, Context context); } diff --git a/api/all/src/main/java/io/opentelemetry/api/metrics/DoubleGaugeBuilder.java b/api/all/src/main/java/io/opentelemetry/api/metrics/DoubleGaugeBuilder.java index f73f0133d66..fadb7a08d5b 100644 --- a/api/all/src/main/java/io/opentelemetry/api/metrics/DoubleGaugeBuilder.java +++ b/api/all/src/main/java/io/opentelemetry/api/metrics/DoubleGaugeBuilder.java @@ -65,4 +65,17 @@ public interface DoubleGaugeBuilder { default ObservableDoubleMeasurement buildObserver() { return DefaultMeter.getInstance().gaugeBuilder("noop").buildObserver(); } + + /** + * Builds and returns a DoubleGauge instrument with the configuration. + * + *

NOTE: This produces a synchronous gauge which records gauge values as they occur. Most users + * will want to instead register an {@link #buildWithCallback(Consumer)} to asynchronously observe + * the value of the gauge when metrics are collected. + * + * @return The DoubleGauge instrument. + */ + default DoubleGauge build() { + return DefaultMeter.getInstance().gaugeBuilder("noop").build(); + } } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/LongGauge.java b/api/all/src/main/java/io/opentelemetry/api/metrics/LongGauge.java similarity index 61% rename from api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/LongGauge.java rename to api/all/src/main/java/io/opentelemetry/api/metrics/LongGauge.java index abc0d00c691..22b940eaa9f 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/LongGauge.java +++ b/api/all/src/main/java/io/opentelemetry/api/metrics/LongGauge.java @@ -3,9 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.api.incubator.metrics; +package io.opentelemetry.api.metrics; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.context.Context; import javax.annotation.concurrent.ThreadSafe; /** A gauge instrument that synchronously records {@code long} values. */ @@ -26,5 +27,12 @@ public interface LongGauge { */ void set(long value, Attributes attributes); - // TODO(jack-berg): should we add overload with Context argument? + /** + * Records a value with a set of attributes. + * + * @param value The current gauge value. + * @param attributes A set of attributes to associate with the value. + * @param context The explicit context to associate with this measurement. + */ + void set(long value, Attributes attributes, Context context); } diff --git a/api/all/src/main/java/io/opentelemetry/api/metrics/LongGaugeBuilder.java b/api/all/src/main/java/io/opentelemetry/api/metrics/LongGaugeBuilder.java index b4eb490906f..3c8340fa007 100644 --- a/api/all/src/main/java/io/opentelemetry/api/metrics/LongGaugeBuilder.java +++ b/api/all/src/main/java/io/opentelemetry/api/metrics/LongGaugeBuilder.java @@ -62,4 +62,17 @@ public interface LongGaugeBuilder { default ObservableLongMeasurement buildObserver() { return DefaultMeter.getInstance().gaugeBuilder("noop").ofLongs().buildObserver(); } + + /** + * Builds and returns a LongGauge instrument with the configuration. + * + *

NOTE: This produces a synchronous gauge which records gauge values as they occur. Most users + * will want to instead register an {@link #buildWithCallback(Consumer)} to asynchronously observe + * the value of the gauge when metrics are collected. + * + * @return The LongGauge instrument. + */ + default LongGauge build() { + return DefaultMeter.getInstance().gaugeBuilder("noop").ofLongs().build(); + } } diff --git a/api/all/src/test/java/io/opentelemetry/api/metrics/DefaultMeterTest.java b/api/all/src/test/java/io/opentelemetry/api/metrics/DefaultMeterTest.java index a42b194f81a..fd9884bdad7 100644 --- a/api/all/src/test/java/io/opentelemetry/api/metrics/DefaultMeterTest.java +++ b/api/all/src/test/java/io/opentelemetry/api/metrics/DefaultMeterTest.java @@ -93,6 +93,20 @@ void noopDoubleHistogram_doesNotThrow() { histogram.record(1.0e-1, Attributes.of(stringKey("thing"), "car"), Context.current()); } + @Test + void noopLongGauage_doesNotThrow() { + LongGauge gauge = + METER + .gaugeBuilder("temperature") + .ofLongs() + .setDescription("The current temperature") + .setUnit("C") + .build(); + gauge.set(1); + gauge.set(2, Attributes.of(stringKey("thing"), "engine")); + gauge.set(2, Attributes.of(stringKey("thing"), "engine"), Context.current()); + } + @Test void noopObservableLongGauage_doesNotThrow() { METER @@ -107,6 +121,19 @@ void noopObservableLongGauage_doesNotThrow() { }); } + @Test + void noopDoubleGauage_doesNotThrow() { + DoubleGauge gauge = + METER + .gaugeBuilder("temperature") + .setDescription("The current temperature") + .setUnit("C") + .build(); + gauge.set(1); + gauge.set(2, Attributes.of(stringKey("thing"), "engine")); + gauge.set(2, Attributes.of(stringKey("thing"), "engine"), Context.current()); + } + @Test void noopObservableDoubleGauage_doesNotThrow() { METER diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGaugeBuilder.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGaugeBuilder.java index 852acc27f5a..eb576559609 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGaugeBuilder.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedDoubleGaugeBuilder.java @@ -8,22 +8,10 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.metrics.DoubleGaugeBuilder; import java.util.List; -import java.util.function.Consumer; /** Extended {@link DoubleGaugeBuilder} with experimental APIs. */ public interface ExtendedDoubleGaugeBuilder extends DoubleGaugeBuilder { - /** - * Builds and returns a DoubleGauge instrument with the configuration. - * - *

NOTE: This produces a synchronous gauge which records gauge values as they occur. Most users - * will want to instead register an {@link #buildWithCallback(Consumer)} to asynchronously observe - * the value of the gauge when metrics are collected. - * - * @return The DoubleGauge instrument. - */ - DoubleGauge build(); - /** * Specify the attribute advice, which suggests the recommended set of attribute keys to be used * for this gauge. diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGaugeBuilder.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGaugeBuilder.java index 44d557e4303..db05e0958f3 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGaugeBuilder.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/metrics/ExtendedLongGaugeBuilder.java @@ -8,22 +8,10 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.metrics.LongGaugeBuilder; import java.util.List; -import java.util.function.Consumer; /** Extended {@link LongGaugeBuilder} with experimental APIs. */ public interface ExtendedLongGaugeBuilder extends LongGaugeBuilder { - /** - * Builds and returns a LongGauge instrument with the configuration. - * - *

NOTE: This produces a synchronous gauge which records gauge values as they occur. Most users - * will want to instead register an {@link #buildWithCallback(Consumer)} to asynchronously observe - * the value of the gauge when metrics are collected. - * - * @return The LongGauge instrument. - */ - LongGauge build(); - /** * Specify the attribute advice, which suggests the recommended set of attribute keys to be used * for this gauge. diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java index ea219c1cc70..5ae6297a2c7 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/metrics/ExtendedMetricsApiUsageTest.java @@ -23,48 +23,6 @@ /** Demonstrating usage of extended Metrics API. */ class ExtendedMetricsApiUsageTest { - @Test - void synchronousGaugeUsage() { - // Setup SdkMeterProvider - InMemoryMetricReader reader = InMemoryMetricReader.create(); - SdkMeterProvider meterProvider = - SdkMeterProvider.builder() - // Default resource used for demonstration purposes - .setResource(Resource.getDefault()) - // In-memory reader used for demonstration purposes - .registerMetricReader(reader) - .build(); - - // Get a Meter for a scope - Meter meter = meterProvider.get("org.foo.my-scope"); - - // Cast GaugeBuilder to ExtendedDoubleGaugeBuilder - DoubleGauge gauge = ((ExtendedDoubleGaugeBuilder) meter.gaugeBuilder("my-gauge")).build(); - - // Call set synchronously to set the value - gauge.set(1.0, Attributes.builder().put("key", "value1").build()); - gauge.set(2.0, Attributes.builder().put("key", "value2").build()); - - assertThat(reader.collectAllMetrics()) - .satisfiesExactly( - metricData -> - assertThat(metricData) - .hasName("my-gauge") - .hasDoubleGaugeSatisfying( - gaugeAssert -> - gaugeAssert.hasPointsSatisfying( - point -> - point - .hasValue(1.0) - .hasAttributes( - Attributes.builder().put("key", "value1").build()), - point -> - point - .hasValue(2.0) - .hasAttributes( - Attributes.builder().put("key", "value2").build())))); - } - @Test void attributesAdvice() { // Setup SdkMeterProvider diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-api.txt b/docs/apidiffs/current_vs_latest/opentelemetry-api.txt index df26146497b..d050fbe201a 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-api.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-api.txt @@ -1,2 +1,19 @@ Comparing source compatibility of against -No changes. \ No newline at end of file ++++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.api.metrics.DoubleGauge (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) void set(double) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) void set(double, io.opentelemetry.api.common.Attributes) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) void set(double, io.opentelemetry.api.common.Attributes, io.opentelemetry.context.Context) +*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.api.metrics.DoubleGaugeBuilder (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.api.metrics.DoubleGauge build() ++++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.api.metrics.LongGauge (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) void set(long) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) void set(long, io.opentelemetry.api.common.Attributes) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) void set(long, io.opentelemetry.api.common.Attributes, io.opentelemetry.context.Context) +*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.api.metrics.LongGaugeBuilder (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.api.metrics.LongGauge build() diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt index 37f807adf9b..ef9c86f56b8 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-metrics.txt @@ -5,3 +5,6 @@ Comparing source compatibility of against *** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector (not serializable) === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 +++ NEW METHOD: PUBLIC(+) STATIC(+) java.lang.String asString(io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector) +*** MODIFIED ENUM: PUBLIC FINAL io.opentelemetry.sdk.metrics.InstrumentType (compatible) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW FIELD: PUBLIC(+) STATIC(+) FINAL(+) io.opentelemetry.sdk.metrics.InstrumentType GAUGE diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentType.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentType.java index d2218ec8773..b876d00cf56 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentType.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentType.java @@ -17,4 +17,5 @@ public enum InstrumentType { OBSERVABLE_COUNTER, OBSERVABLE_UP_DOWN_COUNTER, OBSERVABLE_GAUGE, + GAUGE, } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java index 1de8fa341cf..1c834b18e10 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkDoubleGauge.java @@ -7,8 +7,8 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.metrics.DoubleGauge; import io.opentelemetry.api.incubator.metrics.ExtendedDoubleGaugeBuilder; +import io.opentelemetry.api.metrics.DoubleGauge; import io.opentelemetry.api.metrics.DoubleGaugeBuilder; import io.opentelemetry.api.metrics.LongGaugeBuilder; import io.opentelemetry.api.metrics.ObservableDoubleGauge; @@ -31,8 +31,13 @@ private SdkDoubleGauge(InstrumentDescriptor descriptor, WriteableMetricStorage s } @Override - public void set(double increment, Attributes attributes) { - storage.recordDouble(increment, attributes, Context.root()); + public void set(double value, Attributes attributes) { + storage.recordDouble(value, attributes, Context.current()); + } + + @Override + public void set(double value, Attributes attributes, Context context) { + storage.recordDouble(value, attributes, context); } @Override @@ -48,11 +53,10 @@ static final class SdkDoubleGaugeBuilder implements ExtendedDoubleGaugeBuilder { MeterSharedState meterSharedState, String name) { - // TODO: use InstrumentType.GAUGE when available builder = new InstrumentBuilder( name, - InstrumentType.OBSERVABLE_GAUGE, + InstrumentType.GAUGE, InstrumentValueType.DOUBLE, meterProviderSharedState, meterSharedState); @@ -88,13 +92,11 @@ public LongGaugeBuilder ofLongs() { @Override public ObservableDoubleGauge buildWithCallback(Consumer callback) { - // TODO: use InstrumentType.GAUGE when available return builder.buildDoubleAsynchronousInstrument(InstrumentType.OBSERVABLE_GAUGE, callback); } @Override public ObservableDoubleMeasurement buildObserver() { - // TODO: use InstrumentType.GAUGE when available return builder.buildObservableMeasurement(InstrumentType.OBSERVABLE_GAUGE); } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java index 92d9e84d098..ad7db428bdf 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkLongGauge.java @@ -8,7 +8,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.incubator.metrics.ExtendedLongGaugeBuilder; -import io.opentelemetry.api.incubator.metrics.LongGauge; +import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.LongGaugeBuilder; import io.opentelemetry.api.metrics.ObservableLongGauge; import io.opentelemetry.api.metrics.ObservableLongMeasurement; @@ -31,8 +31,13 @@ private SdkLongGauge(InstrumentDescriptor descriptor, WriteableMetricStorage sto } @Override - public void set(long increment, Attributes attributes) { - storage.recordLong(increment, attributes, Context.root()); + public void set(long value, Attributes attributes) { + storage.recordLong(value, attributes, Context.current()); + } + + @Override + public void set(long value, Attributes attributes, Context context) { + storage.recordLong(value, attributes, context); } @Override @@ -52,11 +57,10 @@ static final class SdkLongGaugeBuilder implements ExtendedLongGaugeBuilder { String unit, Advice.AdviceBuilder adviceBuilder) { - // TODO: use InstrumentType.GAUGE when available builder = new InstrumentBuilder( name, - InstrumentType.OBSERVABLE_GAUGE, + InstrumentType.GAUGE, InstrumentValueType.LONG, meterProviderSharedState, sharedState) @@ -90,13 +94,11 @@ public ExtendedLongGaugeBuilder setAttributesAdvice(List> attrib @Override public ObservableLongGauge buildWithCallback(Consumer callback) { - // TODO: use InstrumentType.GAUGE when available return builder.buildLongAsynchronousInstrument(InstrumentType.OBSERVABLE_GAUGE, callback); } @Override public ObservableLongMeasurement buildObserver() { - // TODO: use InstrumentType.GAUGE when available return builder.buildObservableMeasurement(InstrumentType.OBSERVABLE_GAUGE); } 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 bbcecc08e1d..494e486c333 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 @@ -50,6 +50,7 @@ private static Aggregation resolve(InstrumentDescriptor instrument, boolean with } return ExplicitBucketHistogramAggregation.getDefault(); case OBSERVABLE_GAUGE: + case GAUGE: return LastValueAggregation.getInstance(); } logger.log(Level.WARNING, "Unable to find default aggregation for instrument: " + instrument); 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 7dac6c6241d..693af692c93 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 @@ -5,10 +5,14 @@ package io.opentelemetry.sdk.metrics.internal.view; +import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.export.MemoryMode; +import io.opentelemetry.sdk.internal.RandomSupplier; import io.opentelemetry.sdk.metrics.Aggregation; import io.opentelemetry.sdk.metrics.InstrumentType; +import io.opentelemetry.sdk.metrics.data.DoubleExemplarData; import io.opentelemetry.sdk.metrics.data.ExemplarData; +import io.opentelemetry.sdk.metrics.data.LongExemplarData; import io.opentelemetry.sdk.metrics.data.PointData; import io.opentelemetry.sdk.metrics.internal.aggregator.Aggregator; import io.opentelemetry.sdk.metrics.internal.aggregator.AggregatorFactory; @@ -17,6 +21,7 @@ import io.opentelemetry.sdk.metrics.internal.descriptor.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarFilter; import io.opentelemetry.sdk.metrics.internal.exemplar.ExemplarReservoir; +import java.util.function.Supplier; /** * Last-value aggregation configuration. @@ -44,18 +49,38 @@ public Aggregator createAggr // For the initial version we do not sample exemplars on gauges. switch (instrumentDescriptor.getValueType()) { case LONG: - return (Aggregator) - new LongLastValueAggregator(ExemplarReservoir::longNoSamples, memoryMode); + { + Supplier> reservoirFactory = + () -> + ExemplarReservoir.filtered( + exemplarFilter, + ExemplarReservoir.longFixedSizeReservoir( + Clock.getDefault(), + Runtime.getRuntime().availableProcessors(), + RandomSupplier.platformDefault())); + return (Aggregator) new LongLastValueAggregator(reservoirFactory, memoryMode); + } case DOUBLE: - return (Aggregator) - new DoubleLastValueAggregator(ExemplarReservoir::doubleNoSamples, memoryMode); + { + Supplier> reservoirFactory = + () -> + ExemplarReservoir.filtered( + exemplarFilter, + ExemplarReservoir.doubleFixedSizeReservoir( + Clock.getDefault(), + Runtime.getRuntime().availableProcessors(), + RandomSupplier.platformDefault())); + return (Aggregator) new DoubleLastValueAggregator(reservoirFactory, memoryMode); + } } throw new IllegalArgumentException("Invalid instrument value type"); } @Override public boolean isCompatibleWithInstrument(InstrumentDescriptor instrumentDescriptor) { - return instrumentDescriptor.getType() == InstrumentType.OBSERVABLE_GAUGE; + InstrumentType instrumentType = instrumentDescriptor.getType(); + return instrumentType == InstrumentType.OBSERVABLE_GAUGE + || instrumentType == InstrumentType.GAUGE; } @Override 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 7606b321c9a..be2502ec054 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 @@ -51,11 +51,13 @@ void aggregationIsCompatible() { InstrumentDescriptor observableUpDownCounter = descriptorForType(InstrumentType.OBSERVABLE_UP_DOWN_COUNTER); InstrumentDescriptor observableGauge = descriptorForType(InstrumentType.OBSERVABLE_GAUGE); + InstrumentDescriptor gauge = descriptorForType(InstrumentType.GAUGE); InstrumentDescriptor histogram = descriptorForType(InstrumentType.HISTOGRAM); AggregatorFactory defaultAggregation = ((AggregatorFactory) Aggregation.defaultAggregation()); assertThat(defaultAggregation.isCompatibleWithInstrument(counter)).isTrue(); assertThat(defaultAggregation.isCompatibleWithInstrument(observableCounter)).isTrue(); + assertThat(defaultAggregation.isCompatibleWithInstrument(gauge)).isTrue(); assertThat(defaultAggregation.isCompatibleWithInstrument(upDownCounter)).isTrue(); assertThat(defaultAggregation.isCompatibleWithInstrument(observableUpDownCounter)).isTrue(); assertThat(defaultAggregation.isCompatibleWithInstrument(observableGauge)).isTrue(); @@ -64,6 +66,7 @@ void aggregationIsCompatible() { AggregatorFactory drop = ((AggregatorFactory) Aggregation.drop()); assertThat(drop.isCompatibleWithInstrument(counter)).isTrue(); assertThat(drop.isCompatibleWithInstrument(observableCounter)).isTrue(); + assertThat(drop.isCompatibleWithInstrument(gauge)).isTrue(); assertThat(drop.isCompatibleWithInstrument(upDownCounter)).isTrue(); assertThat(drop.isCompatibleWithInstrument(observableUpDownCounter)).isTrue(); assertThat(drop.isCompatibleWithInstrument(observableGauge)).isTrue(); @@ -75,6 +78,7 @@ void aggregationIsCompatible() { assertThat(sum.isCompatibleWithInstrument(upDownCounter)).isTrue(); assertThat(sum.isCompatibleWithInstrument(observableUpDownCounter)).isTrue(); assertThat(sum.isCompatibleWithInstrument(observableGauge)).isFalse(); + assertThat(sum.isCompatibleWithInstrument(gauge)).isFalse(); assertThat(sum.isCompatibleWithInstrument(histogram)).isTrue(); AggregatorFactory explicitHistogram = @@ -84,6 +88,7 @@ void aggregationIsCompatible() { assertThat(explicitHistogram.isCompatibleWithInstrument(upDownCounter)).isFalse(); assertThat(explicitHistogram.isCompatibleWithInstrument(observableUpDownCounter)).isFalse(); assertThat(explicitHistogram.isCompatibleWithInstrument(observableGauge)).isFalse(); + assertThat(explicitHistogram.isCompatibleWithInstrument(gauge)).isFalse(); assertThat(explicitHistogram.isCompatibleWithInstrument(histogram)).isTrue(); AggregatorFactory exponentialHistogram = @@ -93,6 +98,7 @@ void aggregationIsCompatible() { assertThat(exponentialHistogram.isCompatibleWithInstrument(upDownCounter)).isFalse(); assertThat(exponentialHistogram.isCompatibleWithInstrument(observableUpDownCounter)).isFalse(); assertThat(exponentialHistogram.isCompatibleWithInstrument(observableGauge)).isFalse(); + assertThat(exponentialHistogram.isCompatibleWithInstrument(gauge)).isFalse(); assertThat(exponentialHistogram.isCompatibleWithInstrument(histogram)).isTrue(); AggregatorFactory lastValue = ((AggregatorFactory) Aggregation.lastValue()); @@ -101,6 +107,7 @@ void aggregationIsCompatible() { assertThat(lastValue.isCompatibleWithInstrument(upDownCounter)).isFalse(); assertThat(lastValue.isCompatibleWithInstrument(observableUpDownCounter)).isFalse(); assertThat(lastValue.isCompatibleWithInstrument(observableGauge)).isTrue(); + assertThat(lastValue.isCompatibleWithInstrument(gauge)).isTrue(); assertThat(lastValue.isCompatibleWithInstrument(histogram)).isFalse(); } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkDoubleGaugeTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkDoubleGaugeTest.java index 802029d8448..61c0d3ad0b9 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkDoubleGaugeTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkDoubleGaugeTest.java @@ -11,10 +11,12 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.metrics.DoubleGauge; -import io.opentelemetry.api.incubator.metrics.ExtendedDoubleGaugeBuilder; +import io.opentelemetry.api.metrics.DoubleGauge; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.api.metrics.ObservableDoubleGauge; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Scope; import io.opentelemetry.internal.testing.slf4j.SuppressLogger; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.metrics.internal.state.DefaultSynchronousMetricStorage; @@ -22,7 +24,9 @@ import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; import io.opentelemetry.sdk.testing.time.TestClock; +import io.opentelemetry.sdk.trace.SdkTracerProvider; import java.time.Duration; +import java.util.Collections; import java.util.stream.IntStream; import org.junit.jupiter.api.Test; @@ -47,11 +51,7 @@ class SdkDoubleGaugeTest { @Test void set_PreventNullAttributes() { - assertThatThrownBy( - () -> - ((ExtendedDoubleGaugeBuilder) sdkMeter.gaugeBuilder("testGauge")) - .build() - .set(1.0, null)) + assertThatThrownBy(() -> sdkMeter.gaugeBuilder("testGauge").build().set(1.0, null)) .isInstanceOf(NullPointerException.class) .hasMessage("attributes"); } @@ -59,7 +59,7 @@ void set_PreventNullAttributes() { @Test @SuppressLogger(DefaultSynchronousMetricStorage.class) void set_NaN() { - DoubleGauge gauge = ((ExtendedDoubleGaugeBuilder) sdkMeter.gaugeBuilder("testGauge")).build(); + DoubleGauge gauge = sdkMeter.gaugeBuilder("testGauge").build(); gauge.set(Double.NaN); assertThat(cumulativeReader.collectAllMetrics()).hasSize(0); } @@ -93,16 +93,14 @@ void observable_NaN() { @Test void collectMetrics_NoRecords() { - ((ExtendedDoubleGaugeBuilder) sdkMeter.gaugeBuilder("testGauge")).build(); + sdkMeter.gaugeBuilder("testGauge").build(); assertThat(cumulativeReader.collectAllMetrics()).isEmpty(); } @Test void collectMetrics_WithEmptyAttributes() { DoubleGauge doubleGauge = - ((ExtendedDoubleGaugeBuilder) - sdkMeter.gaugeBuilder("testGauge").setDescription("description").setUnit("K")) - .build(); + sdkMeter.gaugeBuilder("testGauge").setDescription("description").setUnit("K").build(); testClock.advance(Duration.ofNanos(SECOND_NANOS)); doubleGauge.set(12d, Attributes.empty()); doubleGauge.set(13d); @@ -126,11 +124,59 @@ void collectMetrics_WithEmptyAttributes() { .hasValue(13d)))); } + @Test + void collectMetrics_WithExemplars() { + InMemoryMetricReader reader = InMemoryMetricReader.create(); + SdkMeterProvider sdkMeterProvider = + SdkMeterProvider.builder() + .setClock(testClock) + .setResource(RESOURCE) + .registerView( + InstrumentSelector.builder().setName("*").build(), + View.builder().setAttributeFilter(Collections.emptySet()).build()) + .registerMetricReader(reader) + .build(); + Meter sdkMeter = sdkMeterProvider.get(getClass().getName()); + DoubleGauge doubleGauge = + sdkMeter.gaugeBuilder("testGauge").setDescription("description").setUnit("K").build(); + + SdkTracerProvider tracerProvider = SdkTracerProvider.builder().build(); + Tracer tracer = tracerProvider.get("foo"); + + Span span = tracer.spanBuilder("span").startSpan(); + try (Scope unused = span.makeCurrent()) { + doubleGauge.set(12d, Attributes.builder().put("key", "value").build()); + } + + assertThat(reader.collectAllMetrics()) + .satisfiesExactly( + metric -> + assertThat(metric) + .hasResource(RESOURCE) + .hasInstrumentationScope(INSTRUMENTATION_SCOPE_INFO) + .hasName("testGauge") + .hasDescription("description") + .hasUnit("K") + .hasDoubleGaugeSatisfying( + gauge -> + gauge.hasPointsSatisfying( + point -> + point + .hasValue(12d) + .hasExemplarsSatisfying( + exemplar -> + exemplar + .hasValue(12d) + .hasFilteredAttributes( + Attributes.builder() + .put("key", "value") + .build()))))); + } + @Test void collectMetrics_WithMultipleCollects() { long startTime = testClock.now(); - DoubleGauge doubleGauge = - ((ExtendedDoubleGaugeBuilder) sdkMeter.gaugeBuilder("testGauge")).build(); + DoubleGauge doubleGauge = sdkMeter.gaugeBuilder("testGauge").build(); doubleGauge.set(12.1d, Attributes.empty()); doubleGauge.set(123.3d, Attributes.builder().put("K", "V").build()); doubleGauge.set(21.4d, Attributes.empty()); @@ -228,8 +274,7 @@ void collectMetrics_WithMultipleCollects() { @Test void stressTest() { - DoubleGauge doubleGauge = - ((ExtendedDoubleGaugeBuilder) sdkMeter.gaugeBuilder("testGauge")).build(); + DoubleGauge doubleGauge = sdkMeter.gaugeBuilder("testGauge").build(); StressTestRunner.Builder stressTestBuilder = StressTestRunner.builder().setCollectionIntervalMs(100); @@ -268,8 +313,7 @@ void stressTest() { void stressTest_WithDifferentLabelSet() { String[] keys = {"Key_1", "Key_2", "Key_3", "Key_4"}; String[] values = {"Value_1", "Value_2", "Value_3", "Value_4"}; - DoubleGauge doubleGauge = - ((ExtendedDoubleGaugeBuilder) sdkMeter.gaugeBuilder("testGauge")).build(); + DoubleGauge doubleGauge = sdkMeter.gaugeBuilder("testGauge").build(); StressTestRunner.Builder stressTestBuilder = StressTestRunner.builder().setCollectionIntervalMs(100); diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkLongGaugeTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkLongGaugeTest.java index e3bd54ab4d5..0a117e48d82 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkLongGaugeTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkLongGaugeTest.java @@ -11,15 +11,19 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.metrics.ExtendedLongGaugeBuilder; -import io.opentelemetry.api.incubator.metrics.LongGauge; +import io.opentelemetry.api.metrics.LongGauge; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.api.metrics.ObservableLongGauge; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Scope; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; import io.opentelemetry.sdk.testing.time.TestClock; +import io.opentelemetry.sdk.trace.SdkTracerProvider; import java.time.Duration; +import java.util.Collections; import java.util.stream.IntStream; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; @@ -45,11 +49,7 @@ class SdkLongGaugeTest { @Test void set_PreventNullAttributes() { - assertThatThrownBy( - () -> - ((ExtendedLongGaugeBuilder) sdkMeter.gaugeBuilder("testGauge").ofLongs()) - .build() - .set(1, null)) + assertThatThrownBy(() -> sdkMeter.gaugeBuilder("testGauge").ofLongs().build().set(1, null)) .isInstanceOf(NullPointerException.class) .hasMessage("attributes"); } @@ -77,19 +77,18 @@ void observable_RemoveCallback() { @Test void collectMetrics_NoRecords() { - ((ExtendedLongGaugeBuilder) sdkMeter.gaugeBuilder("testGauge").ofLongs()).build(); + sdkMeter.gaugeBuilder("testGauge").ofLongs().build(); assertThat(cumulativeReader.collectAllMetrics()).isEmpty(); } @Test void collectMetrics_WithEmptyAttributes() { LongGauge longGauge = - ((ExtendedLongGaugeBuilder) - sdkMeter - .gaugeBuilder("testGauge") - .ofLongs() - .setDescription("description") - .setUnit("K")) + sdkMeter + .gaugeBuilder("testGauge") + .ofLongs() + .setDescription("description") + .setUnit("K") .build(); testClock.advance(Duration.ofNanos(SECOND_NANOS)); longGauge.set(12, Attributes.empty()); @@ -114,11 +113,64 @@ void collectMetrics_WithEmptyAttributes() { .hasValue(13)))); } + @Test + void collectMetrics_WithExemplars() { + InMemoryMetricReader reader = InMemoryMetricReader.create(); + SdkMeterProvider sdkMeterProvider = + SdkMeterProvider.builder() + .setClock(testClock) + .setResource(RESOURCE) + .registerView( + InstrumentSelector.builder().setName("*").build(), + View.builder().setAttributeFilter(Collections.emptySet()).build()) + .registerMetricReader(reader) + .build(); + Meter sdkMeter = sdkMeterProvider.get(getClass().getName()); + LongGauge longGauge = + sdkMeter + .gaugeBuilder("testGauge") + .setDescription("description") + .setUnit("K") + .ofLongs() + .build(); + + SdkTracerProvider tracerProvider = SdkTracerProvider.builder().build(); + Tracer tracer = tracerProvider.get("foo"); + + Span span = tracer.spanBuilder("span").startSpan(); + try (Scope unused = span.makeCurrent()) { + longGauge.set(12L, Attributes.builder().put("key", "value").build()); + } + + assertThat(reader.collectAllMetrics()) + .satisfiesExactly( + metric -> + assertThat(metric) + .hasResource(RESOURCE) + .hasInstrumentationScope(INSTRUMENTATION_SCOPE_INFO) + .hasName("testGauge") + .hasDescription("description") + .hasUnit("K") + .hasLongGaugeSatisfying( + gauge -> + gauge.hasPointsSatisfying( + point -> + point + .hasValue(12L) + .hasExemplarsSatisfying( + exemplar -> + exemplar + .hasValue(12L) + .hasFilteredAttributes( + Attributes.builder() + .put("key", "value") + .build()))))); + } + @Test void collectMetrics_WithMultipleCollects() { long startTime = testClock.now(); - LongGauge longGauge = - ((ExtendedLongGaugeBuilder) sdkMeter.gaugeBuilder("testGauge").ofLongs()).build(); + LongGauge longGauge = sdkMeter.gaugeBuilder("testGauge").ofLongs().build(); longGauge.set(12, Attributes.empty()); longGauge.set(12, Attributes.builder().put("K", "V").build()); longGauge.set(21, Attributes.empty()); @@ -216,8 +268,7 @@ void collectMetrics_WithMultipleCollects() { @Test void stressTest() { - LongGauge longGauge = - ((ExtendedLongGaugeBuilder) sdkMeter.gaugeBuilder("testGauge").ofLongs()).build(); + LongGauge longGauge = sdkMeter.gaugeBuilder("testGauge").ofLongs().build(); StressTestRunner.Builder stressTestBuilder = StressTestRunner.builder().setCollectionIntervalMs(100); @@ -256,8 +307,7 @@ void stressTest() { void stressTest_WithDifferentLabelSet() { String[] keys = {"Key_1", "Key_2", "Key_3", "Key_4"}; String[] values = {"Value_1", "Value_2", "Value_3", "Value_4"}; - LongGauge longGauge = - ((ExtendedLongGaugeBuilder) sdkMeter.gaugeBuilder("testGauge").ofLongs()).build(); + LongGauge longGauge = sdkMeter.gaugeBuilder("testGauge").ofLongs().build(); StressTestRunner.Builder stressTestBuilder = StressTestRunner.builder().setCollectionIntervalMs(100); diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/export/AggregationTemporalitySelectorTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/export/AggregationTemporalitySelectorTest.java index 30bb02d5db3..fb821ce388e 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/export/AggregationTemporalitySelectorTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/export/AggregationTemporalitySelectorTest.java @@ -28,6 +28,8 @@ void alwaysCumulative() { .isEqualTo(AggregationTemporality.CUMULATIVE); assertThat(selector.getAggregationTemporality(InstrumentType.OBSERVABLE_UP_DOWN_COUNTER)) .isEqualTo(AggregationTemporality.CUMULATIVE); + assertThat(selector.getAggregationTemporality(InstrumentType.GAUGE)) + .isEqualTo(AggregationTemporality.CUMULATIVE); } @Test @@ -45,6 +47,8 @@ void deltaPreferred() { .isEqualTo(AggregationTemporality.CUMULATIVE); assertThat(selector.getAggregationTemporality(InstrumentType.OBSERVABLE_UP_DOWN_COUNTER)) .isEqualTo(AggregationTemporality.CUMULATIVE); + assertThat(selector.getAggregationTemporality(InstrumentType.GAUGE)) + .isEqualTo(AggregationTemporality.DELTA); } @Test @@ -62,6 +66,8 @@ void lowMemory() { .isEqualTo(AggregationTemporality.CUMULATIVE); assertThat(selector.getAggregationTemporality(InstrumentType.OBSERVABLE_UP_DOWN_COUNTER)) .isEqualTo(AggregationTemporality.CUMULATIVE); + assertThat(selector.getAggregationTemporality(InstrumentType.GAUGE)) + .isEqualTo(AggregationTemporality.DELTA); } @Test @@ -76,7 +82,8 @@ void stringRepresentation() { + "HISTOGRAM=CUMULATIVE, " + "OBSERVABLE_COUNTER=CUMULATIVE, " + "OBSERVABLE_UP_DOWN_COUNTER=CUMULATIVE, " - + "OBSERVABLE_GAUGE=CUMULATIVE" + + "OBSERVABLE_GAUGE=CUMULATIVE, " + + "GAUGE=CUMULATIVE" + "}"); assertThat( AggregationTemporalitySelector.asString( @@ -88,7 +95,8 @@ void stringRepresentation() { + "HISTOGRAM=DELTA, " + "OBSERVABLE_COUNTER=DELTA, " + "OBSERVABLE_UP_DOWN_COUNTER=CUMULATIVE, " - + "OBSERVABLE_GAUGE=DELTA" + + "OBSERVABLE_GAUGE=DELTA, " + + "GAUGE=DELTA" + "}"); } } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/export/DefaultAggregationSelectorTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/export/DefaultAggregationSelectorTest.java index 53bd0fbc0b0..1cbf0649c7a 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/export/DefaultAggregationSelectorTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/export/DefaultAggregationSelectorTest.java @@ -45,6 +45,8 @@ void with() { .isEqualTo(Aggregation.defaultAggregation()); assertThat(selector1.getDefaultAggregation(InstrumentType.OBSERVABLE_GAUGE)) .isEqualTo(Aggregation.defaultAggregation()); + assertThat(selector1.getDefaultAggregation(InstrumentType.GAUGE)) + .isEqualTo(Aggregation.defaultAggregation()); DefaultAggregationSelector selector2 = selector1.with(InstrumentType.COUNTER, Aggregation.drop()); @@ -60,6 +62,8 @@ void with() { .isEqualTo(Aggregation.defaultAggregation()); assertThat(selector2.getDefaultAggregation(InstrumentType.OBSERVABLE_GAUGE)) .isEqualTo(Aggregation.defaultAggregation()); + assertThat(selector2.getDefaultAggregation(InstrumentType.GAUGE)) + .isEqualTo(Aggregation.defaultAggregation()); } @Test @@ -72,7 +76,8 @@ void stringRepresentation() { + "HISTOGRAM=default, " + "OBSERVABLE_COUNTER=default, " + "OBSERVABLE_UP_DOWN_COUNTER=default, " - + "OBSERVABLE_GAUGE=default" + + "OBSERVABLE_GAUGE=default, " + + "GAUGE=default" + "}"); assertThat( DefaultAggregationSelector.asString( @@ -85,7 +90,8 @@ void stringRepresentation() { + "HISTOGRAM=base2_exponential_bucket_histogram, " + "OBSERVABLE_COUNTER=default, " + "OBSERVABLE_UP_DOWN_COUNTER=default, " - + "OBSERVABLE_GAUGE=default" + + "OBSERVABLE_GAUGE=default, " + + "GAUGE=default" + "}"); } } From 3cb969301bdf47714a991a8e94d3fd3641c3683f Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Thu, 9 May 2024 12:47:44 -0500 Subject: [PATCH 2/2] Add info about default aggregation to gauge javadoc --- .../java/io/opentelemetry/api/metrics/DoubleGaugeBuilder.java | 3 +++ .../java/io/opentelemetry/api/metrics/LongGaugeBuilder.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/api/all/src/main/java/io/opentelemetry/api/metrics/DoubleGaugeBuilder.java b/api/all/src/main/java/io/opentelemetry/api/metrics/DoubleGaugeBuilder.java index fadb7a08d5b..98e4855d220 100644 --- a/api/all/src/main/java/io/opentelemetry/api/metrics/DoubleGaugeBuilder.java +++ b/api/all/src/main/java/io/opentelemetry/api/metrics/DoubleGaugeBuilder.java @@ -73,6 +73,9 @@ default ObservableDoubleMeasurement buildObserver() { * will want to instead register an {@link #buildWithCallback(Consumer)} to asynchronously observe * the value of the gauge when metrics are collected. * + *

If using the OpenTelemetry SDK, by default gauges use last value aggregation, such that only + * the value of the last recorded measurement is exported. + * * @return The DoubleGauge instrument. */ default DoubleGauge build() { diff --git a/api/all/src/main/java/io/opentelemetry/api/metrics/LongGaugeBuilder.java b/api/all/src/main/java/io/opentelemetry/api/metrics/LongGaugeBuilder.java index 3c8340fa007..7c0fd0e0af2 100644 --- a/api/all/src/main/java/io/opentelemetry/api/metrics/LongGaugeBuilder.java +++ b/api/all/src/main/java/io/opentelemetry/api/metrics/LongGaugeBuilder.java @@ -70,6 +70,9 @@ default ObservableLongMeasurement buildObserver() { * will want to instead register an {@link #buildWithCallback(Consumer)} to asynchronously observe * the value of the gauge when metrics are collected. * + *

If using the OpenTelemetry SDK, by default gauges use last value aggregation, such that only + * the value of the last recorded measurement is exported. + * * @return The LongGauge instrument. */ default LongGauge build() {