From 0752a4bb176088e8d3594ec8418013dc91479a64 Mon Sep 17 00:00:00 2001 From: Josh Suereth Date: Tue, 10 Aug 2021 16:23:08 -0400 Subject: [PATCH] Overhaul sdk.metrics package for new SDK: Decouple Instrument + Storage per-metric. (#3455) * Peel away dependency between instrument API hooks and aggregator package. - Create new BoundStorageHandle interface for synchronous instruments to use. - Update all SDK instruments to use it. * Set up interfaces for storage registry. * Create MetricStorage abstraction - Wire all SDK instruments through a MetricStorage abstraction. - Move all wiring of measurements -> aggregators into an internal package. - Migrate previous "Accumulation" classes to "storage" classes - Do just enough to get things compiling (not tested yet) Goal is to have the "Aggregator" package not referenced in the sdk.metrics package directly in the future. * Fix tests for metric storage refactoring. - Move tests to appropriate location - For now just make view-things public - Fix possible bug in test of labels processor + appending attributes in a test.... * Remove instrument registry (now metric registry) * Rename DoubleValueRecorder => DoubleHistogram in SDK * Rename LongValueRecorderSdk => LongHistogramSdk. * Rename ValueObserver -> Gauge * Rename instrument type enum Update enum to match specification. * Move ViewRegistry + Helper into internal package * Fixes to benchmarks * Add missing javadoc * Remove references to Labels * Fixes from review. * Rework tryUnmap to test the exposed interface --- .../io/opentelemetry/sdk/metrics/TestSdk.java | 2 +- .../aggregator/DoubleHistogramBenchmark.java | 2 +- .../DoubleMinMaxSumCountBenchmark.java | 2 +- .../LongMinMaxSumCountBenchmark.java | 6 +- .../sdk/metrics/AbstractAccumulator.java | 49 ------ .../AbstractAsynchronousInstrument.java | 25 --- .../sdk/metrics/AbstractInstrument.java | 7 - .../metrics/AbstractInstrumentBuilder.java | 45 ++---- .../AbstractSynchronousInstrument.java | 31 ---- .../sdk/metrics/DoubleCounterSdk.java | 40 ++--- .../sdk/metrics/DoubleGaugeBuilderSdk.java | 49 ++++++ ...corderSdk.java => DoubleHistogramSdk.java} | 50 +++--- .../sdk/metrics/DoubleSumObserverSdk.java | 16 -- .../sdk/metrics/DoubleUpDownCounterSdk.java | 43 +++--- .../metrics/DoubleUpDownSumObserverSdk.java | 16 -- .../sdk/metrics/DoubleValueObserverSdk.java | 57 ------- .../sdk/metrics/InstrumentRegistry.java | 56 ------- .../sdk/metrics/LongCounterSdk.java | 46 +++--- .../sdk/metrics/LongGaugeBuilderSdk.java | 49 ++++++ ...RecorderSdk.java => LongHistogramSdk.java} | 43 +++--- .../sdk/metrics/LongSumObserverSdk.java | 16 -- .../sdk/metrics/LongUpDownCounterSdk.java | 43 +++--- .../sdk/metrics/LongUpDownSumObserverSdk.java | 16 -- .../sdk/metrics/LongValueObserverSdk.java | 57 ------- .../sdk/metrics/MeterProviderSharedState.java | 28 ---- .../sdk/metrics/MeterSharedState.java | 22 --- .../opentelemetry/sdk/metrics/SdkMeter.java | 17 +-- .../sdk/metrics/SdkMeterProvider.java | 2 + .../sdk/metrics/SdkMeterProviderBuilder.java | 2 + .../aggregator/AbstractSumAggregator.java | 23 +-- .../metrics/aggregator/AggregatorHandle.java | 16 +- .../sdk/metrics/common/InstrumentType.java | 8 +- .../internal/descriptor/MetricDescriptor.java | 42 +++++ .../state/AsynchronousMetricStorage.java} | 59 ++++--- .../internal/state/BoundStorageHandle.java | 24 +++ .../state}/InstrumentProcessor.java | 33 ++-- .../state/MeterProviderSharedState.java | 63 ++++++++ .../internal/state/MeterSharedState.java | 84 ++++++++++ .../metrics/internal/state/MetricStorage.java | 29 ++++ .../internal/state/MetricStorageRegistry.java | 79 ++++++++++ .../state/SynchronousMetricStorage.java} | 50 ++++-- .../state/WriteableMetricStorage.java | 39 +++++ .../{ => internal/view}/ViewRegistry.java | 26 +++- .../view}/ViewRegistryBuilder.java | 22 ++- .../sdk/metrics/AbstractInstrumentTest.java | 8 - .../sdk/metrics/DoubleCounterSdkTest.java | 10 +- ...st.java => DoubleGaugeBuilderSdkTest.java} | 4 +- ...kTest.java => DoubleHistogramSdkTest.java} | 24 +-- .../sdk/metrics/DoubleSumObserverSdkTest.java | 4 +- .../metrics/DoubleUpDownCounterSdkTest.java | 10 +- .../DoubleUpDownSumObserverSdkTest.java | 2 +- .../sdk/metrics/InstrumentRegistryTest.java | 97 ------------ .../sdk/metrics/LongCounterSdkTest.java | 10 +- ...Test.java => LongGaugeBuilderSdkTest.java} | 4 +- ...SdkTest.java => LongHistogramSdkTest.java} | 28 ++-- .../sdk/metrics/LongSumObserverSdkTest.java | 4 +- .../sdk/metrics/LongUpDownCounterSdkTest.java | 10 +- .../metrics/LongUpDownSumObserverSdkTest.java | 2 +- .../sdk/metrics/SdkMeterTest.java | 144 +++++++++--------- .../aggregator/AggregatorFactoryTest.java | 8 +- .../aggregator/CountAggregatorTest.java | 12 +- .../DoubleHistogramAggregatorTest.java | 6 +- .../DoubleLastValueAggregatorTest.java | 2 +- .../DoubleMinMaxSumCountAggregatorTest.java | 6 +- .../LongLastValueAggregatorTest.java | 2 +- .../LongMinMaxSumCountAggregatorTest.java | 6 +- .../state/AsynchronousMetricStorageTest.java} | 19 +-- .../state/MetricStorageRegistryTest.java | 116 ++++++++++++++ .../state/SynchronousMetricStorageTest.java} | 82 ++++++---- .../{ => internal/view}/ViewRegistryTest.java | 10 +- 70 files changed, 1104 insertions(+), 960 deletions(-) delete mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractAccumulator.java delete mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractAsynchronousInstrument.java delete mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractSynchronousInstrument.java create mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleGaugeBuilderSdk.java rename sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/{DoubleValueRecorderSdk.java => DoubleHistogramSdk.java} (56%) delete mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleSumObserverSdk.java delete mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleUpDownSumObserverSdk.java delete mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleValueObserverSdk.java delete mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentRegistry.java create mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongGaugeBuilderSdk.java rename sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/{LongValueRecorderSdk.java => LongHistogramSdk.java} (64%) delete mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongSumObserverSdk.java delete mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongUpDownSumObserverSdk.java delete mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongValueObserverSdk.java delete mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterProviderSharedState.java delete mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterSharedState.java create mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/descriptor/MetricDescriptor.java rename sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/{AsynchronousInstrumentAccumulator.java => internal/state/AsynchronousMetricStorage.java} (57%) create mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/BoundStorageHandle.java rename sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/{ => internal/state}/InstrumentProcessor.java (70%) create mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java create mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterSharedState.java create mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorage.java create mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistry.java rename sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/{SynchronousInstrumentAccumulator.java => internal/state/SynchronousMetricStorage.java} (65%) create mode 100644 sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/WriteableMetricStorage.java rename sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/{ => internal/view}/ViewRegistry.java (76%) rename sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/{ => internal/view}/ViewRegistryBuilder.java (68%) rename sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/{DoubleValueObserverSdkTest.java => DoubleGaugeBuilderSdkTest.java} (96%) rename sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/{DoubleValueRecorderSdkTest.java => DoubleHistogramSdkTest.java} (94%) delete mode 100644 sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentRegistryTest.java rename sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/{LongValueObserverSdkTest.java => LongGaugeBuilderSdkTest.java} (96%) rename sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/{LongValueRecorderSdkTest.java => LongHistogramSdkTest.java} (94%) rename sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/{AsynchronousInstrumentAccumulatorTest.java => internal/state/AsynchronousMetricStorageTest.java} (84%) create mode 100644 sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistryTest.java rename sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/{SynchronousInstrumentAccumulatorTest.java => internal/state/SynchronousMetricStorageTest.java} (53%) rename sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/{ => internal/view}/ViewRegistryTest.java (94%) diff --git a/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/TestSdk.java b/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/TestSdk.java index ef4280493b..4eeed51895 100644 --- a/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/TestSdk.java +++ b/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/TestSdk.java @@ -35,7 +35,7 @@ public enum TestSdk { .registerView( InstrumentSelector.builder() .setInstrumentNameRegex(".*histogram_recorder") - .setInstrumentType(InstrumentType.VALUE_RECORDER) + .setInstrumentType(InstrumentType.HISTOGRAM) .build(), // Histogram buckets the same as the metrics prototype/prometheus. View.builder() diff --git a/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/aggregator/DoubleHistogramBenchmark.java b/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/aggregator/DoubleHistogramBenchmark.java index f1ae34ba6b..9ef8b1ca49 100644 --- a/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/aggregator/DoubleHistogramBenchmark.java +++ b/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/aggregator/DoubleHistogramBenchmark.java @@ -37,7 +37,7 @@ public class DoubleHistogramBenchmark { "name", "description", "1", - InstrumentType.VALUE_RECORDER, + InstrumentType.HISTOGRAM, InstrumentValueType.DOUBLE)); private AggregatorHandle aggregatorHandle; diff --git a/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/aggregator/DoubleMinMaxSumCountBenchmark.java b/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/aggregator/DoubleMinMaxSumCountBenchmark.java index 52365ce1e5..6ec6daa245 100644 --- a/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/aggregator/DoubleMinMaxSumCountBenchmark.java +++ b/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/aggregator/DoubleMinMaxSumCountBenchmark.java @@ -35,7 +35,7 @@ public class DoubleMinMaxSumCountBenchmark { "name", "description", "1", - InstrumentType.VALUE_RECORDER, + InstrumentType.HISTOGRAM, InstrumentValueType.DOUBLE)); private AggregatorHandle aggregatorHandle; diff --git a/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/aggregator/LongMinMaxSumCountBenchmark.java b/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/aggregator/LongMinMaxSumCountBenchmark.java index b15d470429..3e95240049 100644 --- a/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/aggregator/LongMinMaxSumCountBenchmark.java +++ b/sdk/metrics/src/jmh/java/io/opentelemetry/sdk/metrics/aggregator/LongMinMaxSumCountBenchmark.java @@ -32,11 +32,7 @@ public class LongMinMaxSumCountBenchmark { Resource.getDefault(), InstrumentationLibraryInfo.empty(), InstrumentDescriptor.create( - "name", - "description", - "1", - InstrumentType.VALUE_RECORDER, - InstrumentValueType.LONG)); + "name", "description", "1", InstrumentType.HISTOGRAM, InstrumentValueType.LONG)); private AggregatorHandle aggregatorHandle; @Setup(Level.Trial) diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractAccumulator.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractAccumulator.java deleted file mode 100644 index b3543c6b80..0000000000 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractAccumulator.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.metrics; - -import io.opentelemetry.sdk.metrics.aggregator.Aggregator; -import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.data.MetricData; -import io.opentelemetry.sdk.metrics.processor.LabelsProcessor; -import java.util.List; - -abstract class AbstractAccumulator { - /** - * Returns the list of metrics collected. - * - * @return returns the list of metrics collected. - */ - abstract List collectAll(long epochNanos); - - static Aggregator getAggregator( - MeterProviderSharedState meterProviderSharedState, - MeterSharedState meterSharedState, - InstrumentDescriptor descriptor) { - return meterProviderSharedState - .getViewRegistry() - .findView(descriptor) - .getAggregatorFactory() - .create( - meterProviderSharedState.getResource(), - meterSharedState.getInstrumentationLibraryInfo(), - descriptor); - } - - static LabelsProcessor getLabelsProcessor( - MeterProviderSharedState meterProviderSharedState, - MeterSharedState meterSharedState, - InstrumentDescriptor descriptor) { - return meterProviderSharedState - .getViewRegistry() - .findView(descriptor) - .getLabelsProcessorFactory() - .create( - meterProviderSharedState.getResource(), - meterSharedState.getInstrumentationLibraryInfo(), - descriptor); - } -} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractAsynchronousInstrument.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractAsynchronousInstrument.java deleted file mode 100644 index 915f11cacf..0000000000 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractAsynchronousInstrument.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.metrics; - -import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.data.MetricData; -import java.util.List; - -abstract class AbstractAsynchronousInstrument extends AbstractInstrument { - private final AsynchronousInstrumentAccumulator accumulator; - - AbstractAsynchronousInstrument( - InstrumentDescriptor descriptor, AsynchronousInstrumentAccumulator accumulator) { - super(descriptor); - this.accumulator = accumulator; - } - - @Override - final List collectAll(long epochNanos) { - return accumulator.collectAll(epochNanos); - } -} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractInstrument.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractInstrument.java index 8e0853afc2..9dd0e62fed 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractInstrument.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractInstrument.java @@ -6,8 +6,6 @@ package io.opentelemetry.sdk.metrics; import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.data.MetricData; -import java.util.List; abstract class AbstractInstrument implements Instrument { @@ -22,11 +20,6 @@ abstract class AbstractInstrument implements Instrument { return descriptor; } - /** - * Collects records from all the entries (labelSet, Bound) that changed since the previous call. - */ - abstract List collectAll(long epochNanos); - @Override public boolean equals(Object o) { if (this == o) { 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 d22b8b5022..803ff5bcb0 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 @@ -10,6 +10,9 @@ import io.opentelemetry.api.metrics.ObservableLongMeasurement; import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.common.InstrumentType; import io.opentelemetry.sdk.metrics.common.InstrumentValueType; +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.function.BiFunction; import java.util.function.Consumer; @@ -58,43 +61,25 @@ public abstract class AbstractInstrumentBuilder I buildSynchronousInstrument( InstrumentType type, InstrumentValueType valueType, - BiFunction, I> instrumentFactory) { + BiFunction instrumentFactory) { InstrumentDescriptor descriptor = makeDescriptor(type, valueType); - return meterSharedState - .getInstrumentRegistry() - .register( - instrumentFactory.apply( - descriptor, - SynchronousInstrumentAccumulator.create( - meterProviderSharedState, meterSharedState, descriptor))); + WriteableMetricStorage storage = + meterSharedState.registerSynchronousMetricStorage(descriptor, meterProviderSharedState); + return instrumentFactory.apply(descriptor, storage); } - final I buildDoubleAsynchronousInstrument( - InstrumentType type, - Consumer updater, - BiFunction instrumentFactory) { + final void registerDoubleAsynchronousInstrument( + InstrumentType type, Consumer updater) { InstrumentDescriptor descriptor = makeDescriptor(type, InstrumentValueType.DOUBLE); - return meterSharedState - .getInstrumentRegistry() - .register( - instrumentFactory.apply( - descriptor, - AsynchronousInstrumentAccumulator.doubleAsynchronousAccumulator( - meterProviderSharedState, meterSharedState, descriptor, updater))); + meterSharedState.registerDoubleAsynchronousInstrument( + descriptor, meterProviderSharedState, updater); } - final I buildLongAsynchronousInstrument( - InstrumentType type, - Consumer updater, - BiFunction instrumentFactory) { + final void registerLongAsynchronousInstrument( + InstrumentType type, Consumer updater) { InstrumentDescriptor descriptor = makeDescriptor(type, InstrumentValueType.LONG); - return meterSharedState - .getInstrumentRegistry() - .register( - instrumentFactory.apply( - descriptor, - AsynchronousInstrumentAccumulator.longAsynchronousAccumulator( - meterProviderSharedState, meterSharedState, descriptor, updater))); + meterSharedState.registerLongAsynchronousInstrument( + descriptor, meterProviderSharedState, updater); } @FunctionalInterface diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractSynchronousInstrument.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractSynchronousInstrument.java deleted file mode 100644 index 1f4f2afb9c..0000000000 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AbstractSynchronousInstrument.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.metrics; - -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.sdk.metrics.aggregator.AggregatorHandle; -import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.data.MetricData; -import java.util.List; - -abstract class AbstractSynchronousInstrument extends AbstractInstrument { - private final SynchronousInstrumentAccumulator accumulator; - - AbstractSynchronousInstrument( - InstrumentDescriptor descriptor, SynchronousInstrumentAccumulator accumulator) { - super(descriptor); - this.accumulator = accumulator; - } - - @Override - final List collectAll(long epochNanos) { - return accumulator.collectAll(epochNanos); - } - - AggregatorHandle acquireHandle(Attributes labels) { - return accumulator.bind(labels); - } -} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleCounterSdk.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleCounterSdk.java index 28505bdbf8..af05dcfab7 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleCounterSdk.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleCounterSdk.java @@ -12,27 +12,32 @@ import io.opentelemetry.api.metrics.DoubleCounterBuilder; import io.opentelemetry.api.metrics.LongCounterBuilder; import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; import io.opentelemetry.context.Context; -import io.opentelemetry.sdk.metrics.aggregator.AggregatorHandle; import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.common.InstrumentType; import io.opentelemetry.sdk.metrics.common.InstrumentValueType; +import io.opentelemetry.sdk.metrics.internal.state.BoundStorageHandle; +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.function.Consumer; -final class DoubleCounterSdk extends AbstractSynchronousInstrument implements DoubleCounter { +final class DoubleCounterSdk extends AbstractInstrument implements DoubleCounter { + private final WriteableMetricStorage storage; - private DoubleCounterSdk( - InstrumentDescriptor descriptor, SynchronousInstrumentAccumulator accumulator) { - super(descriptor, accumulator); + private DoubleCounterSdk(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + super(descriptor); + this.storage = storage; } @Override - public void add(double increment, Attributes labels, Context context) { - AggregatorHandle aggregatorHandle = acquireHandle(labels); + public void add(double increment, Attributes attributes, Context context) { + BoundStorageHandle aggregatorHandle = storage.bind(attributes); try { if (increment < 0) { throw new IllegalArgumentException("Counters can only increase"); } - aggregatorHandle.recordDouble(increment); + + aggregatorHandle.recordDouble(increment, attributes, context); } finally { aggregatorHandle.release(); } @@ -49,15 +54,17 @@ final class DoubleCounterSdk extends AbstractSynchronousInstrument implements Do } @Override - public BoundDoubleCounter bind(Attributes labels) { - return new BoundInstrument(acquireHandle(labels)); + public BoundDoubleCounter bind(Attributes attributes) { + return new BoundInstrument(storage.bind(attributes), attributes); } static final class BoundInstrument implements BoundDoubleCounter { - private final AggregatorHandle aggregatorHandle; + private final BoundStorageHandle handle; + private final Attributes attributes; - BoundInstrument(AggregatorHandle aggregatorHandle) { - this.aggregatorHandle = aggregatorHandle; + BoundInstrument(BoundStorageHandle handle, Attributes attributes) { + this.handle = handle; + this.attributes = attributes; } @Override @@ -65,7 +72,7 @@ final class DoubleCounterSdk extends AbstractSynchronousInstrument implements Do if (increment < 0) { throw new IllegalArgumentException("Counters can only increase"); } - aggregatorHandle.recordDouble(increment); + handle.recordDouble(increment, attributes, context); } @Override @@ -75,7 +82,7 @@ final class DoubleCounterSdk extends AbstractSynchronousInstrument implements Do @Override public void unbind() { - aggregatorHandle.release(); + handle.release(); } } @@ -116,8 +123,7 @@ final class DoubleCounterSdk extends AbstractSynchronousInstrument implements Do @Override public void buildWithCallback(Consumer callback) { - buildDoubleAsynchronousInstrument( - InstrumentType.SUM_OBSERVER, callback, DoubleSumObserverSdk::new); + registerDoubleAsynchronousInstrument(InstrumentType.OBSERVABLE_SUM, callback); } } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleGaugeBuilderSdk.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleGaugeBuilderSdk.java new file mode 100644 index 0000000000..db422a86b9 --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleGaugeBuilderSdk.java @@ -0,0 +1,49 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics; + +import io.opentelemetry.api.metrics.DoubleGaugeBuilder; +import io.opentelemetry.api.metrics.LongGaugeBuilder; +import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; +import io.opentelemetry.sdk.metrics.common.InstrumentType; +import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; +import io.opentelemetry.sdk.metrics.internal.state.MeterSharedState; +import java.util.function.Consumer; + +final class DoubleGaugeBuilderSdk extends AbstractInstrumentBuilder + implements DoubleGaugeBuilder { + + DoubleGaugeBuilderSdk( + MeterProviderSharedState meterProviderSharedState, + MeterSharedState meterSharedState, + String name) { + this(meterProviderSharedState, meterSharedState, name, "", "1"); + } + + DoubleGaugeBuilderSdk( + MeterProviderSharedState meterProviderSharedState, + MeterSharedState sharedState, + String name, + String description, + String unit) { + super(meterProviderSharedState, sharedState, name, description, unit); + } + + @Override + protected DoubleGaugeBuilderSdk getThis() { + return this; + } + + @Override + public LongGaugeBuilder ofLongs() { + return swapBuilder(LongGaugeBuilderSdk::new); + } + + @Override + public void buildWithCallback(Consumer callback) { + registerDoubleAsynchronousInstrument(InstrumentType.OBSERVABLE_GAUGE, callback); + } +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleValueRecorderSdk.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleHistogramSdk.java similarity index 56% rename from sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleValueRecorderSdk.java rename to sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleHistogramSdk.java index d6fb15521b..78c42c196a 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleValueRecorderSdk.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleHistogramSdk.java @@ -11,32 +11,30 @@ 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.sdk.metrics.aggregator.AggregatorHandle; import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.common.InstrumentType; import io.opentelemetry.sdk.metrics.common.InstrumentValueType; +import io.opentelemetry.sdk.metrics.internal.state.BoundStorageHandle; +import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; +import io.opentelemetry.sdk.metrics.internal.state.MeterSharedState; +import io.opentelemetry.sdk.metrics.internal.state.WriteableMetricStorage; -final class DoubleValueRecorderSdk extends AbstractSynchronousInstrument - implements DoubleHistogram { +final class DoubleHistogramSdk extends AbstractInstrument implements DoubleHistogram { + private final WriteableMetricStorage storage; - private DoubleValueRecorderSdk( - InstrumentDescriptor descriptor, SynchronousInstrumentAccumulator accumulator) { - super(descriptor, accumulator); + private DoubleHistogramSdk(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + super(descriptor); + this.storage = storage; } @Override - public void record(double value, Attributes labels, Context context) { - AggregatorHandle aggregatorHandle = acquireHandle(labels); - try { - aggregatorHandle.recordDouble(value); - } finally { - aggregatorHandle.release(); - } + public void record(double value, Attributes attributes, Context context) { + storage.recordDouble(value, attributes, context); } @Override - public void record(double value, Attributes labels) { - record(value, labels, Context.current()); + public void record(double value, Attributes attributes) { + record(value, attributes, Context.current()); } @Override @@ -45,20 +43,22 @@ final class DoubleValueRecorderSdk extends AbstractSynchronousInstrument } @Override - public BoundDoubleHistogram bind(Attributes labels) { - return new BoundInstrument(acquireHandle(labels)); + public BoundDoubleHistogram bind(Attributes attributes) { + return new BoundInstrument(storage.bind(attributes), attributes); } static final class BoundInstrument implements BoundDoubleHistogram { - private final AggregatorHandle aggregatorHandle; + private final BoundStorageHandle aggregatorHandle; + private final Attributes attributes; - BoundInstrument(AggregatorHandle aggregatorHandle) { - this.aggregatorHandle = aggregatorHandle; + BoundInstrument(BoundStorageHandle handle, Attributes attributes) { + this.aggregatorHandle = handle; + this.attributes = attributes; } @Override public void record(double value, Context context) { - aggregatorHandle.recordDouble(value); + aggregatorHandle.recordDouble(value, attributes, context); } @Override @@ -72,7 +72,7 @@ final class DoubleValueRecorderSdk extends AbstractSynchronousInstrument } } - static final class Builder extends AbstractInstrumentBuilder + static final class Builder extends AbstractInstrumentBuilder implements DoubleHistogramBuilder { Builder( @@ -97,14 +97,14 @@ final class DoubleValueRecorderSdk extends AbstractSynchronousInstrument } @Override - public DoubleValueRecorderSdk build() { + public DoubleHistogramSdk build() { return buildSynchronousInstrument( - InstrumentType.VALUE_RECORDER, InstrumentValueType.DOUBLE, DoubleValueRecorderSdk::new); + InstrumentType.HISTOGRAM, InstrumentValueType.DOUBLE, DoubleHistogramSdk::new); } @Override public LongHistogramBuilder ofLongs() { - return swapBuilder(LongValueRecorderSdk.Builder::new); + return swapBuilder(LongHistogramSdk.Builder::new); } } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleSumObserverSdk.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleSumObserverSdk.java deleted file mode 100644 index dac43ce1b9..0000000000 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleSumObserverSdk.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.metrics; - -import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; - -final class DoubleSumObserverSdk extends AbstractAsynchronousInstrument { - - DoubleSumObserverSdk( - InstrumentDescriptor descriptor, AsynchronousInstrumentAccumulator accumulator) { - super(descriptor, accumulator); - } -} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleUpDownCounterSdk.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleUpDownCounterSdk.java index d6fd2bace6..1935c08d94 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleUpDownCounterSdk.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleUpDownCounterSdk.java @@ -12,28 +12,26 @@ import io.opentelemetry.api.metrics.DoubleUpDownCounterBuilder; import io.opentelemetry.api.metrics.LongUpDownCounterBuilder; import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; import io.opentelemetry.context.Context; -import io.opentelemetry.sdk.metrics.aggregator.AggregatorHandle; import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.common.InstrumentType; import io.opentelemetry.sdk.metrics.common.InstrumentValueType; +import io.opentelemetry.sdk.metrics.internal.state.BoundStorageHandle; +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.function.Consumer; -final class DoubleUpDownCounterSdk extends AbstractSynchronousInstrument - implements DoubleUpDownCounter { +final class DoubleUpDownCounterSdk extends AbstractInstrument implements DoubleUpDownCounter { + private final WriteableMetricStorage storage; - private DoubleUpDownCounterSdk( - InstrumentDescriptor descriptor, SynchronousInstrumentAccumulator accumulator) { - super(descriptor, accumulator); + private DoubleUpDownCounterSdk(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + super(descriptor); + this.storage = storage; } @Override - public void add(double increment, Attributes labels, Context context) { - AggregatorHandle aggregatorHandle = acquireHandle(labels); - try { - aggregatorHandle.recordDouble(increment); - } finally { - aggregatorHandle.release(); - } + public void add(double increment, Attributes attributes, Context context) { + storage.recordDouble(increment, attributes, context); } @Override @@ -47,20 +45,22 @@ final class DoubleUpDownCounterSdk extends AbstractSynchronousInstrument } @Override - public BoundDoubleUpDownCounter bind(Attributes labels) { - return new BoundInstrument(acquireHandle(labels)); + public BoundDoubleUpDownCounter bind(Attributes attributes) { + return new BoundInstrument(storage.bind(attributes), attributes); } static final class BoundInstrument implements BoundDoubleUpDownCounter { - private final AggregatorHandle aggregatorHandle; + private final BoundStorageHandle handle; + private final Attributes attributes; - BoundInstrument(AggregatorHandle aggregatorHandle) { - this.aggregatorHandle = aggregatorHandle; + BoundInstrument(BoundStorageHandle handle, Attributes attributes) { + this.handle = handle; + this.attributes = attributes; } @Override public void add(double increment, Context context) { - aggregatorHandle.recordDouble(increment); + handle.recordDouble(increment, attributes, context); } @Override @@ -70,7 +70,7 @@ final class DoubleUpDownCounterSdk extends AbstractSynchronousInstrument @Override public void unbind() { - aggregatorHandle.release(); + handle.release(); } } @@ -111,8 +111,7 @@ final class DoubleUpDownCounterSdk extends AbstractSynchronousInstrument @Override public void buildWithCallback(Consumer callback) { - buildDoubleAsynchronousInstrument( - InstrumentType.UP_DOWN_SUM_OBSERVER, callback, DoubleUpDownSumObserverSdk::new); + registerDoubleAsynchronousInstrument(InstrumentType.OBSERVABLE_UP_DOWN_SUM, callback); } } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleUpDownSumObserverSdk.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleUpDownSumObserverSdk.java deleted file mode 100644 index a2188ea03e..0000000000 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleUpDownSumObserverSdk.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.metrics; - -import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; - -final class DoubleUpDownSumObserverSdk extends AbstractAsynchronousInstrument { - - DoubleUpDownSumObserverSdk( - InstrumentDescriptor descriptor, AsynchronousInstrumentAccumulator accumulator) { - super(descriptor, accumulator); - } -} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleValueObserverSdk.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleValueObserverSdk.java deleted file mode 100644 index ca65f48546..0000000000 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/DoubleValueObserverSdk.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.metrics; - -import io.opentelemetry.api.metrics.DoubleGaugeBuilder; -import io.opentelemetry.api.metrics.LongGaugeBuilder; -import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; -import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.common.InstrumentType; -import java.util.function.Consumer; - -final class DoubleValueObserverSdk extends AbstractAsynchronousInstrument { - - DoubleValueObserverSdk( - InstrumentDescriptor descriptor, AsynchronousInstrumentAccumulator accumulator) { - super(descriptor, accumulator); - } - - static final class Builder extends AbstractInstrumentBuilder - implements DoubleGaugeBuilder { - - Builder( - MeterProviderSharedState meterProviderSharedState, - MeterSharedState meterSharedState, - String name) { - this(meterProviderSharedState, meterSharedState, name, "", "1"); - } - - Builder( - MeterProviderSharedState meterProviderSharedState, - MeterSharedState sharedState, - String name, - String description, - String unit) { - super(meterProviderSharedState, sharedState, name, description, unit); - } - - @Override - protected Builder getThis() { - return this; - } - - @Override - public LongGaugeBuilder ofLongs() { - return swapBuilder(LongValueObserverSdk.Builder::new); - } - - @Override - public void buildWithCallback(Consumer callback) { - buildDoubleAsynchronousInstrument( - InstrumentType.VALUE_OBSERVER, callback, DoubleValueObserverSdk::new); - } - } -} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentRegistry.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentRegistry.java deleted file mode 100644 index aaebd6a31b..0000000000 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentRegistry.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.metrics; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * Basic registry class for metrics instruments. The current implementation allows instruments to be - * registered only once for a given name. - * - *

TODO: Discuss what is the right behavior when an already registered Instrument with the same - * name is present. TODO: Decide what is the identifier for an Instrument? Only name? - */ -final class InstrumentRegistry { - private final ConcurrentMap registry = new ConcurrentHashMap<>(); - - /** - * Registers the given {@code instrument} to this registry. Returns the registered instrument if - * no other instrument with the same name is registered or a previously registered instrument with - * same name and equal with the current instrument, otherwise throws an exception. - * - * @param instrument the newly created {@code Instrument}. - * @return the given instrument if no instrument with same name already registered, otherwise the - * previous registered instrument. - * @throws IllegalArgumentException if instrument cannot be registered. - */ - @SuppressWarnings("unchecked") - I register(I instrument) { - AbstractInstrument oldInstrument = - registry.putIfAbsent(instrument.getDescriptor().getName().toLowerCase(), instrument); - if (oldInstrument != null) { - if (!instrument.getClass().isInstance(oldInstrument) || !instrument.equals(oldInstrument)) { - throw new IllegalArgumentException( - "Instrument with same name and different descriptor already created."); - } - return (I) oldInstrument; - } - return instrument; - } - - /** - * Returns a {@code Collection} view of the registered instruments. - * - * @return a {@code Collection} view of the registered instruments. - */ - Collection getInstruments() { - return Collections.unmodifiableCollection(new ArrayList<>(registry.values())); - } -} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongCounterSdk.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongCounterSdk.java index 47c74872de..1aa843012b 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongCounterSdk.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongCounterSdk.java @@ -12,30 +12,29 @@ import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.LongCounterBuilder; import io.opentelemetry.api.metrics.ObservableLongMeasurement; import io.opentelemetry.context.Context; -import io.opentelemetry.sdk.metrics.aggregator.AggregatorHandle; import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.common.InstrumentType; import io.opentelemetry.sdk.metrics.common.InstrumentValueType; +import io.opentelemetry.sdk.metrics.internal.state.BoundStorageHandle; +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.function.Consumer; -final class LongCounterSdk extends AbstractSynchronousInstrument implements LongCounter { +final class LongCounterSdk extends AbstractInstrument implements LongCounter { + private final WriteableMetricStorage storage; - private LongCounterSdk( - InstrumentDescriptor descriptor, SynchronousInstrumentAccumulator accumulator) { - super(descriptor, accumulator); + private LongCounterSdk(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + super(descriptor); + this.storage = storage; } @Override - public void add(long increment, Attributes labels, Context context) { - AggregatorHandle aggregatorHandle = acquireHandle(labels); - try { - if (increment < 0) { - throw new IllegalArgumentException("Counters can only increase"); - } - aggregatorHandle.recordLong(increment); - } finally { - aggregatorHandle.release(); + public void add(long increment, Attributes attributes, Context context) { + if (increment < 0) { + throw new IllegalArgumentException("Counters can only increase"); } + storage.recordLong(increment, attributes, context); } @Override @@ -49,15 +48,17 @@ final class LongCounterSdk extends AbstractSynchronousInstrument implements Long } @Override - public BoundLongCounter bind(Attributes labels) { - return new BoundInstrument(acquireHandle(labels)); + public BoundLongCounter bind(Attributes attributes) { + return new BoundInstrument(storage.bind(attributes), attributes); } static final class BoundInstrument implements BoundLongCounter { - private final AggregatorHandle aggregatorHandle; + private final BoundStorageHandle handle; + private final Attributes attributes; - BoundInstrument(AggregatorHandle aggregatorHandle) { - this.aggregatorHandle = aggregatorHandle; + BoundInstrument(BoundStorageHandle handle, Attributes attributes) { + this.handle = handle; + this.attributes = attributes; } @Override @@ -65,7 +66,7 @@ final class LongCounterSdk extends AbstractSynchronousInstrument implements Long if (increment < 0) { throw new IllegalArgumentException("Counters can only increase"); } - aggregatorHandle.recordLong(increment); + handle.recordLong(increment, attributes, context); } @Override @@ -75,7 +76,7 @@ final class LongCounterSdk extends AbstractSynchronousInstrument implements Long @Override public void unbind() { - aggregatorHandle.release(); + handle.release(); } } @@ -116,8 +117,7 @@ final class LongCounterSdk extends AbstractSynchronousInstrument implements Long @Override public void buildWithCallback(Consumer callback) { - buildLongAsynchronousInstrument( - InstrumentType.SUM_OBSERVER, callback, LongSumObserverSdk::new); + registerLongAsynchronousInstrument(InstrumentType.OBSERVABLE_SUM, callback); } } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongGaugeBuilderSdk.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongGaugeBuilderSdk.java new file mode 100644 index 0000000000..28daca7d9a --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongGaugeBuilderSdk.java @@ -0,0 +1,49 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics; + +import io.opentelemetry.api.metrics.DoubleGaugeBuilder; +import io.opentelemetry.api.metrics.LongGaugeBuilder; +import io.opentelemetry.api.metrics.ObservableLongMeasurement; +import io.opentelemetry.sdk.metrics.common.InstrumentType; +import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; +import io.opentelemetry.sdk.metrics.internal.state.MeterSharedState; +import java.util.function.Consumer; + +final class LongGaugeBuilderSdk extends AbstractInstrumentBuilder + implements LongGaugeBuilder { + + LongGaugeBuilderSdk( + MeterProviderSharedState meterProviderSharedState, + MeterSharedState meterSharedState, + String name) { + this(meterProviderSharedState, meterSharedState, name, "", "1"); + } + + LongGaugeBuilderSdk( + MeterProviderSharedState meterProviderSharedState, + MeterSharedState sharedState, + String name, + String description, + String unit) { + super(meterProviderSharedState, sharedState, name, description, unit); + } + + @Override + protected LongGaugeBuilderSdk getThis() { + return this; + } + + @Override + public DoubleGaugeBuilder ofDoubles() { + return swapBuilder(DoubleGaugeBuilderSdk::new); + } + + @Override + public void buildWithCallback(Consumer callback) { + registerLongAsynchronousInstrument(InstrumentType.OBSERVABLE_GAUGE, callback); + } +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongValueRecorderSdk.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongHistogramSdk.java similarity index 64% rename from sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongValueRecorderSdk.java rename to sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongHistogramSdk.java index 809d169f91..7fdf48ae17 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongValueRecorderSdk.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongHistogramSdk.java @@ -11,26 +11,25 @@ import io.opentelemetry.api.metrics.DoubleHistogramBuilder; import io.opentelemetry.api.metrics.LongHistogram; import io.opentelemetry.api.metrics.LongHistogramBuilder; import io.opentelemetry.context.Context; -import io.opentelemetry.sdk.metrics.aggregator.AggregatorHandle; import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.common.InstrumentType; import io.opentelemetry.sdk.metrics.common.InstrumentValueType; +import io.opentelemetry.sdk.metrics.internal.state.BoundStorageHandle; +import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; +import io.opentelemetry.sdk.metrics.internal.state.MeterSharedState; +import io.opentelemetry.sdk.metrics.internal.state.WriteableMetricStorage; -final class LongValueRecorderSdk extends AbstractSynchronousInstrument implements LongHistogram { +final class LongHistogramSdk extends AbstractInstrument implements LongHistogram { + private final WriteableMetricStorage storage; - private LongValueRecorderSdk( - InstrumentDescriptor descriptor, SynchronousInstrumentAccumulator accumulator) { - super(descriptor, accumulator); + private LongHistogramSdk(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + super(descriptor); + this.storage = storage; } @Override public void record(long value, Attributes attributes, Context context) { - AggregatorHandle aggregatorHandle = acquireHandle(attributes); - try { - aggregatorHandle.recordLong(value); - } finally { - aggregatorHandle.release(); - } + storage.recordLong(value, attributes, context); } @Override @@ -45,19 +44,21 @@ final class LongValueRecorderSdk extends AbstractSynchronousInstrument implement @Override public BoundLongHistogram bind(Attributes attributes) { - return new BoundInstrument(acquireHandle(attributes)); + return new BoundInstrument(storage.bind(attributes), attributes); } static final class BoundInstrument implements BoundLongHistogram { - private final AggregatorHandle aggregatorHandle; + private final BoundStorageHandle handle; + private final Attributes attributes; - BoundInstrument(AggregatorHandle aggregatorHandle) { - this.aggregatorHandle = aggregatorHandle; + BoundInstrument(BoundStorageHandle handle, Attributes attributes) { + this.handle = handle; + this.attributes = attributes; } @Override public void record(long value, Context context) { - aggregatorHandle.recordLong(value); + handle.recordLong(value, attributes, context); } @Override @@ -67,11 +68,11 @@ final class LongValueRecorderSdk extends AbstractSynchronousInstrument implement @Override public void unbind() { - aggregatorHandle.release(); + handle.release(); } } - static final class Builder extends AbstractInstrumentBuilder + static final class Builder extends AbstractInstrumentBuilder implements LongHistogramBuilder { Builder( @@ -96,14 +97,14 @@ final class LongValueRecorderSdk extends AbstractSynchronousInstrument implement } @Override - public LongValueRecorderSdk build() { + public LongHistogramSdk build() { return buildSynchronousInstrument( - InstrumentType.VALUE_RECORDER, InstrumentValueType.LONG, LongValueRecorderSdk::new); + InstrumentType.HISTOGRAM, InstrumentValueType.LONG, LongHistogramSdk::new); } @Override public DoubleHistogramBuilder ofDoubles() { - return swapBuilder(DoubleValueRecorderSdk.Builder::new); + return swapBuilder(DoubleHistogramSdk.Builder::new); } } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongSumObserverSdk.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongSumObserverSdk.java deleted file mode 100644 index b33203a478..0000000000 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongSumObserverSdk.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.metrics; - -import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; - -final class LongSumObserverSdk extends AbstractAsynchronousInstrument { - - LongSumObserverSdk( - InstrumentDescriptor descriptor, AsynchronousInstrumentAccumulator accumulator) { - super(descriptor, accumulator); - } -} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongUpDownCounterSdk.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongUpDownCounterSdk.java index 0bf43e50ce..af6975ef87 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongUpDownCounterSdk.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongUpDownCounterSdk.java @@ -12,28 +12,26 @@ import io.opentelemetry.api.metrics.LongUpDownCounter; import io.opentelemetry.api.metrics.LongUpDownCounterBuilder; import io.opentelemetry.api.metrics.ObservableLongMeasurement; import io.opentelemetry.context.Context; -import io.opentelemetry.sdk.metrics.aggregator.AggregatorHandle; import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.common.InstrumentType; import io.opentelemetry.sdk.metrics.common.InstrumentValueType; +import io.opentelemetry.sdk.metrics.internal.state.BoundStorageHandle; +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.function.Consumer; -final class LongUpDownCounterSdk extends AbstractSynchronousInstrument - implements LongUpDownCounter { +final class LongUpDownCounterSdk extends AbstractInstrument implements LongUpDownCounter { + private final WriteableMetricStorage storage; - private LongUpDownCounterSdk( - InstrumentDescriptor descriptor, SynchronousInstrumentAccumulator accumulator) { - super(descriptor, accumulator); + private LongUpDownCounterSdk(InstrumentDescriptor descriptor, WriteableMetricStorage storage) { + super(descriptor); + this.storage = storage; } @Override - public void add(long increment, Attributes labels, Context context) { - AggregatorHandle aggregatorHandle = acquireHandle(labels); - try { - aggregatorHandle.recordLong(increment); - } finally { - aggregatorHandle.release(); - } + public void add(long increment, Attributes attributes, Context context) { + storage.recordLong(increment, attributes, context); } @Override @@ -47,20 +45,22 @@ final class LongUpDownCounterSdk extends AbstractSynchronousInstrument } @Override - public BoundLongUpDownCounter bind(Attributes labels) { - return new BoundInstrument(acquireHandle(labels)); + public BoundLongUpDownCounter bind(Attributes attributes) { + return new BoundInstrument(storage.bind(attributes), attributes); } static final class BoundInstrument implements BoundLongUpDownCounter { - private final AggregatorHandle aggregatorHandle; + private final BoundStorageHandle handle; + private final Attributes attributes; - BoundInstrument(AggregatorHandle aggregatorHandle) { - this.aggregatorHandle = aggregatorHandle; + BoundInstrument(BoundStorageHandle handle, Attributes attributes) { + this.handle = handle; + this.attributes = attributes; } @Override public void add(long increment, Context context) { - aggregatorHandle.recordLong(increment); + handle.recordLong(increment, attributes, context); } @Override @@ -70,7 +70,7 @@ final class LongUpDownCounterSdk extends AbstractSynchronousInstrument @Override public void unbind() { - aggregatorHandle.release(); + handle.release(); } } @@ -111,8 +111,7 @@ final class LongUpDownCounterSdk extends AbstractSynchronousInstrument @Override public void buildWithCallback(Consumer callback) { - buildLongAsynchronousInstrument( - InstrumentType.UP_DOWN_SUM_OBSERVER, callback, LongUpDownSumObserverSdk::new); + registerLongAsynchronousInstrument(InstrumentType.OBSERVABLE_UP_DOWN_SUM, callback); } } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongUpDownSumObserverSdk.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongUpDownSumObserverSdk.java deleted file mode 100644 index 6507f1aeb3..0000000000 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongUpDownSumObserverSdk.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.metrics; - -import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; - -final class LongUpDownSumObserverSdk extends AbstractAsynchronousInstrument { - - LongUpDownSumObserverSdk( - InstrumentDescriptor descriptor, AsynchronousInstrumentAccumulator accumulator) { - super(descriptor, accumulator); - } -} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongValueObserverSdk.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongValueObserverSdk.java deleted file mode 100644 index 3b16f352ea..0000000000 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/LongValueObserverSdk.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.metrics; - -import io.opentelemetry.api.metrics.DoubleGaugeBuilder; -import io.opentelemetry.api.metrics.LongGaugeBuilder; -import io.opentelemetry.api.metrics.ObservableLongMeasurement; -import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.common.InstrumentType; -import java.util.function.Consumer; - -final class LongValueObserverSdk extends AbstractAsynchronousInstrument { - - LongValueObserverSdk( - InstrumentDescriptor descriptor, AsynchronousInstrumentAccumulator accumulator) { - super(descriptor, accumulator); - } - - static final class Builder extends AbstractInstrumentBuilder - implements LongGaugeBuilder { - - Builder( - MeterProviderSharedState meterProviderSharedState, - MeterSharedState meterSharedState, - String name) { - this(meterProviderSharedState, meterSharedState, name, "", "1"); - } - - Builder( - MeterProviderSharedState meterProviderSharedState, - MeterSharedState sharedState, - String name, - String description, - String unit) { - super(meterProviderSharedState, sharedState, name, description, unit); - } - - @Override - protected Builder getThis() { - return this; - } - - @Override - public DoubleGaugeBuilder ofDoubles() { - return swapBuilder(DoubleValueObserverSdk.Builder::new); - } - - @Override - public void buildWithCallback(Consumer callback) { - buildLongAsynchronousInstrument( - InstrumentType.VALUE_OBSERVER, callback, LongValueObserverSdk::new); - } - } -} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterProviderSharedState.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterProviderSharedState.java deleted file mode 100644 index cf2182840e..0000000000 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterProviderSharedState.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.metrics; - -import com.google.auto.value.AutoValue; -import io.opentelemetry.sdk.common.Clock; -import io.opentelemetry.sdk.resources.Resource; -import javax.annotation.concurrent.Immutable; - -@AutoValue -@Immutable -abstract class MeterProviderSharedState { - static MeterProviderSharedState create( - Clock clock, Resource resource, ViewRegistry viewRegistry) { - return new AutoValue_MeterProviderSharedState(clock, resource, viewRegistry, clock.now()); - } - - abstract Clock getClock(); - - abstract Resource getResource(); - - abstract ViewRegistry getViewRegistry(); - - abstract long getStartEpochNanos(); -} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterSharedState.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterSharedState.java deleted file mode 100644 index b73a32a3ad..0000000000 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/MeterSharedState.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.metrics; - -import com.google.auto.value.AutoValue; -import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; -import javax.annotation.concurrent.Immutable; - -@AutoValue -@Immutable -abstract class MeterSharedState { - static MeterSharedState create(InstrumentationLibraryInfo instrumentationLibraryInfo) { - return new AutoValue_MeterSharedState(instrumentationLibraryInfo, new InstrumentRegistry()); - } - - abstract InstrumentationLibraryInfo getInstrumentationLibraryInfo(); - - abstract InstrumentRegistry getInstrumentRegistry(); -} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java index e1604131a3..8e60d3c307 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeter.java @@ -12,9 +12,9 @@ import io.opentelemetry.api.metrics.LongUpDownCounterBuilder; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.metrics.data.MetricData; -import java.util.ArrayList; +import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; +import io.opentelemetry.sdk.metrics.internal.state.MeterSharedState; import java.util.Collection; -import java.util.List; /** {@link SdkMeter} is SDK implementation of {@link Meter}. */ final class SdkMeter implements Meter { @@ -28,19 +28,14 @@ final class SdkMeter implements Meter { this.meterSharedState = MeterSharedState.create(instrumentationLibraryInfo); } + // Only used in testing.... InstrumentationLibraryInfo getInstrumentationLibraryInfo() { return meterSharedState.getInstrumentationLibraryInfo(); } /** Collects all the metric recordings that changed since the previous call. */ Collection collectAll(long epochNanos) { - InstrumentRegistry instrumentRegistry = meterSharedState.getInstrumentRegistry(); - Collection instruments = instrumentRegistry.getInstruments(); - List result = new ArrayList<>(instruments.size()); - for (AbstractInstrument instrument : instruments) { - result.addAll(instrument.collectAll(epochNanos)); - } - return result; + return meterSharedState.collectAll(meterProviderSharedState, epochNanos); } @Override @@ -55,11 +50,11 @@ final class SdkMeter implements Meter { @Override public DoubleHistogramBuilder histogramBuilder(String name) { - return new DoubleValueRecorderSdk.Builder(meterProviderSharedState, meterSharedState, name); + return new DoubleHistogramSdk.Builder(meterProviderSharedState, meterSharedState, name); } @Override public DoubleGaugeBuilder gaugeBuilder(String name) { - return new DoubleValueObserverSdk.Builder(meterProviderSharedState, meterSharedState, name); + return new DoubleGaugeBuilderSdk(meterProviderSharedState, meterSharedState, name); } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java index b25f1f4e13..d716e035cb 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProvider.java @@ -12,6 +12,8 @@ import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.export.MetricProducer; +import io.opentelemetry.sdk.metrics.internal.state.MeterProviderSharedState; +import io.opentelemetry.sdk.metrics.internal.view.ViewRegistry; import io.opentelemetry.sdk.resources.Resource; import java.util.ArrayList; import java.util.Collection; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java index e25ce2b0ac..a027bb514f 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SdkMeterProviderBuilder.java @@ -7,6 +7,8 @@ package io.opentelemetry.sdk.metrics; import io.opentelemetry.api.metrics.GlobalMeterProvider; import io.opentelemetry.sdk.common.Clock; +import io.opentelemetry.sdk.metrics.internal.view.ViewRegistry; +import io.opentelemetry.sdk.metrics.internal.view.ViewRegistryBuilder; import io.opentelemetry.sdk.metrics.view.InstrumentSelector; import io.opentelemetry.sdk.metrics.view.View; import io.opentelemetry.sdk.resources.Resource; diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/aggregator/AbstractSumAggregator.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/aggregator/AbstractSumAggregator.java index 92dbe4b388..484447f691 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/aggregator/AbstractSumAggregator.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/aggregator/AbstractSumAggregator.java @@ -27,17 +27,17 @@ abstract class AbstractSumAggregator extends AbstractAggregator { instrumentDescriptor, resolveStateful(instrumentDescriptor.getType(), temporality)); InstrumentType type = instrumentDescriptor.getType(); - this.isMonotonic = type == InstrumentType.COUNTER || type == InstrumentType.SUM_OBSERVER; + this.isMonotonic = type == InstrumentType.COUNTER || type == InstrumentType.OBSERVABLE_SUM; this.temporality = temporality; this.mergeStrategy = resolveMergeStrategy(type, temporality); } /** * Resolve whether the aggregator should be stateful. For the special case {@link - * InstrumentType#SUM_OBSERVER} and {@link InstrumentType#UP_DOWN_SUM_OBSERVER} instruments, state - * is required if temporality is {@link AggregationTemporality#DELTA}. Because the observed values - * are cumulative sums, we must maintain state to compute delta sums between collections. For - * other instruments, state is required if temporality is {@link + * InstrumentType#OBSERVABLE_SUM} and {@link InstrumentType#OBSERVABLE_UP_DOWN_SUM} instruments, + * state is required if temporality is {@link AggregationTemporality#DELTA}. Because the observed + * values are cumulative sums, we must maintain state to compute delta sums between collections. + * For other instruments, state is required if temporality is {@link * AggregationTemporality#CUMULATIVE}. * * @param instrumentType the instrument type @@ -46,8 +46,8 @@ abstract class AbstractSumAggregator extends AbstractAggregator { */ private static boolean resolveStateful( InstrumentType instrumentType, AggregationTemporality temporality) { - if (instrumentType == InstrumentType.SUM_OBSERVER - || instrumentType == InstrumentType.UP_DOWN_SUM_OBSERVER) { + if (instrumentType == InstrumentType.OBSERVABLE_SUM + || instrumentType == InstrumentType.OBSERVABLE_UP_DOWN_SUM) { return temporality == AggregationTemporality.DELTA; } else { return temporality == AggregationTemporality.CUMULATIVE; @@ -57,8 +57,9 @@ abstract class AbstractSumAggregator extends AbstractAggregator { /** * Resolve the aggregator merge strategy. The merge strategy is SUM in all cases except where * temporality is {@link AggregationTemporality#DELTA} and instrument type is {@link - * InstrumentType#SUM_OBSERVER} or {@link InstrumentType#UP_DOWN_SUM_OBSERVER}. In these special - * cases, the observed values are cumulative sums so we must take a diff to compute the delta sum. + * InstrumentType#OBSERVABLE_SUM} or {@link InstrumentType#OBSERVABLE_UP_DOWN_SUM}. In these + * special cases, the observed values are cumulative sums so we must take a diff to compute the + * delta sum. * * @param instrumentType the instrument type * @param temporality the temporality @@ -67,8 +68,8 @@ abstract class AbstractSumAggregator extends AbstractAggregator { // Visible for testing static MergeStrategy resolveMergeStrategy( InstrumentType instrumentType, AggregationTemporality temporality) { - if ((instrumentType == InstrumentType.SUM_OBSERVER - || instrumentType == InstrumentType.UP_DOWN_SUM_OBSERVER) + if ((instrumentType == InstrumentType.OBSERVABLE_SUM + || instrumentType == InstrumentType.OBSERVABLE_UP_DOWN_SUM) && temporality == AggregationTemporality.DELTA) { return MergeStrategy.DIFF; } else { diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/aggregator/AggregatorHandle.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/aggregator/AggregatorHandle.java index 6b6114be8d..396142efb3 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/aggregator/AggregatorHandle.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/aggregator/AggregatorHandle.java @@ -5,6 +5,9 @@ package io.opentelemetry.sdk.metrics.aggregator; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.metrics.internal.state.BoundStorageHandle; import java.util.concurrent.atomic.AtomicLong; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; @@ -23,7 +26,7 @@ import javax.annotation.concurrent.ThreadSafe; * of the bits are used for reference (usage) counting. */ @ThreadSafe -public abstract class AggregatorHandle { +public abstract class AggregatorHandle implements BoundStorageHandle { // Atomically counts the number of references (usages) while also keeping a state of // mapped/unmapped into a registry map. private final AtomicLong refCountMapped; @@ -50,6 +53,7 @@ public abstract class AggregatorHandle { } /** Release this {@code Aggregator}. It decreases the reference usage. */ + @Override public final void release() { // Every reference adds/removes 2 instead of 1 to avoid changing the mapping bit. refCountMapped.getAndAdd(-2L); @@ -96,6 +100,11 @@ public abstract class AggregatorHandle { hasRecordings = true; } + @Override + public final void recordLong(long value, Attributes attributes, Context context) { + recordLong(value); + } + /** * Concrete Aggregator instances should implement this method in order support recordings of long * values. @@ -115,6 +124,11 @@ public abstract class AggregatorHandle { hasRecordings = true; } + @Override + public final void recordDouble(double value, Attributes attributes, Context context) { + recordDouble(value); + } + /** * Concrete Aggregator instances should implement this method in order support recordings of * double values. diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/common/InstrumentType.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/common/InstrumentType.java index e584e0c7c4..5fbe2bb152 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/common/InstrumentType.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/common/InstrumentType.java @@ -9,8 +9,8 @@ package io.opentelemetry.sdk.metrics.common; public enum InstrumentType { COUNTER, UP_DOWN_COUNTER, - VALUE_RECORDER, - SUM_OBSERVER, - UP_DOWN_SUM_OBSERVER, - VALUE_OBSERVER, + HISTOGRAM, + OBSERVABLE_SUM, + OBSERVABLE_UP_DOWN_SUM, + OBSERVABLE_GAUGE, } 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 new file mode 100644 index 0000000000..aab7c9c2e4 --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/descriptor/MetricDescriptor.java @@ -0,0 +1,42 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics.internal.descriptor; + +import com.google.auto.value.AutoValue; +import com.google.auto.value.extension.memoized.Memoized; +import javax.annotation.concurrent.Immutable; + +/** + * Describes a metric that will be output. + * + *

Provides equality/identity semantics for detecting duplicate metrics of incompatible. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@AutoValue +@Immutable +public abstract class MetricDescriptor { + + public static MetricDescriptor create(String name, String description, String unit) { + return new AutoValue_MetricDescriptor(name, description, unit); + } + + public abstract String getName(); + + public abstract String getDescription(); + + public abstract String getUnit(); + + @Memoized + @Override + public abstract int hashCode(); + + public boolean isCompatibleWith(MetricDescriptor other) { + // TODO: implement. + return equals(other); + } +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AsynchronousInstrumentAccumulator.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorage.java similarity index 57% rename from sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AsynchronousInstrumentAccumulator.java rename to sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorage.java index e6fe984831..a64a0d20d9 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/AsynchronousInstrumentAccumulator.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorage.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.sdk.metrics; +package io.opentelemetry.sdk.metrics.internal.state; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; @@ -12,28 +12,35 @@ import io.opentelemetry.context.Context; import io.opentelemetry.sdk.metrics.aggregator.Aggregator; import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor; import io.opentelemetry.sdk.metrics.processor.LabelsProcessor; -import java.util.List; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; -final class AsynchronousInstrumentAccumulator extends AbstractAccumulator { +/** + * Stores aggregated {@link MetricData} for asynchronous instruments. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class AsynchronousMetricStorage implements MetricStorage { + private final MetricDescriptor metricDescriptor; private final ReentrantLock collectLock = new ReentrantLock(); private final InstrumentProcessor instrumentProcessor; private final Runnable metricUpdater; - static AsynchronousInstrumentAccumulator doubleAsynchronousAccumulator( + /** Constructs storage for {@code double} valued instruments. */ + public static AsynchronousMetricStorage doubleAsynchronousAccumulator( MeterProviderSharedState meterProviderSharedState, MeterSharedState meterSharedState, InstrumentDescriptor descriptor, Consumer metricUpdater) { - Aggregator aggregator = - getAggregator(meterProviderSharedState, meterSharedState, descriptor); + Aggregator aggregator = meterProviderSharedState.getAggregator(meterSharedState, descriptor); final InstrumentProcessor instrumentProcessor = new InstrumentProcessor<>(aggregator, meterProviderSharedState.getStartEpochNanos()); final LabelsProcessor labelsProcessor = - getLabelsProcessor(meterProviderSharedState, meterSharedState, descriptor); + meterProviderSharedState.getLabelsProcessor(meterSharedState, descriptor); final ObservableDoubleMeasurement result = new ObservableDoubleMeasurement() { @@ -50,22 +57,26 @@ final class AsynchronousInstrumentAccumulator extends AbstractAccumulator { } }; - return new AsynchronousInstrumentAccumulator( - instrumentProcessor, () -> metricUpdater.accept(result)); + return new AsynchronousMetricStorage( + // TODO: View can change metric name/description. Update this when wired in. + MetricDescriptor.create( + descriptor.getName(), descriptor.getDescription(), descriptor.getUnit()), + instrumentProcessor, + () -> metricUpdater.accept(result)); } - static AsynchronousInstrumentAccumulator longAsynchronousAccumulator( + /** Constructs storage for {@code long} valued instruments. */ + public static AsynchronousMetricStorage longAsynchronousAccumulator( MeterProviderSharedState meterProviderSharedState, MeterSharedState meterSharedState, InstrumentDescriptor descriptor, Consumer metricUpdater) { - Aggregator aggregator = - getAggregator(meterProviderSharedState, meterSharedState, descriptor); + Aggregator aggregator = meterProviderSharedState.getAggregator(meterSharedState, descriptor); final InstrumentProcessor instrumentProcessor = new InstrumentProcessor<>(aggregator, meterProviderSharedState.getStartEpochNanos()); final LabelsProcessor labelsProcessor = - getLabelsProcessor(meterProviderSharedState, meterSharedState, descriptor); + meterProviderSharedState.getLabelsProcessor(meterSharedState, descriptor); final ObservableLongMeasurement result = new ObservableLongMeasurement() { @@ -81,18 +92,25 @@ final class AsynchronousInstrumentAccumulator extends AbstractAccumulator { observe(value, Attributes.empty()); } }; - return new AsynchronousInstrumentAccumulator( - instrumentProcessor, () -> metricUpdater.accept(result)); + return new AsynchronousMetricStorage( + // TODO: View can change metric name/description. Update this when wired in. + MetricDescriptor.create( + descriptor.getName(), descriptor.getDescription(), descriptor.getUnit()), + instrumentProcessor, + () -> metricUpdater.accept(result)); } - private AsynchronousInstrumentAccumulator( - InstrumentProcessor instrumentProcessor, Runnable metricUpdater) { + private AsynchronousMetricStorage( + MetricDescriptor metricDescriptor, + InstrumentProcessor instrumentProcessor, + Runnable metricUpdater) { + this.metricDescriptor = metricDescriptor; this.instrumentProcessor = instrumentProcessor; this.metricUpdater = metricUpdater; } @Override - List collectAll(long epochNanos) { + public MetricData collectAndReset(long startEpochNanos, long epochNanos) { collectLock.lock(); try { metricUpdater.run(); @@ -101,4 +119,9 @@ final class AsynchronousInstrumentAccumulator extends AbstractAccumulator { collectLock.unlock(); } } + + @Override + public MetricDescriptor getMetricDescriptor() { + return metricDescriptor; + } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/BoundStorageHandle.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/BoundStorageHandle.java new file mode 100644 index 0000000000..4cf7fb8367 --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/BoundStorageHandle.java @@ -0,0 +1,24 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics.internal.state; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.context.Context; + +/** + * A bound handle for recording measurements against a particular set of attributes. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public interface BoundStorageHandle { + /** Records a measurement. */ + void recordLong(long value, Attributes attributes, Context context); + /** Records a measurement. */ + void recordDouble(double value, Attributes attributes, Context context); + /** Release this handle back to the storage. */ + void release(); +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentProcessor.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/InstrumentProcessor.java similarity index 70% rename from sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentProcessor.java rename to sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/InstrumentProcessor.java index 5afd286c80..3d8803add6 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/InstrumentProcessor.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/InstrumentProcessor.java @@ -3,23 +3,24 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.sdk.metrics; +package io.opentelemetry.sdk.metrics.internal.state; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.sdk.metrics.aggregator.Aggregator; import io.opentelemetry.sdk.metrics.data.MetricData; -import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; /** * An {@code InstrumentProcessor} represents an internal instance of an {@code Accumulator} for a * specific {code Instrument}. It records individual measurements (via the {@code Aggregator}). It - * batches together {@code Aggregator}s for the similar sets of labels. + * batches together {@code Aggregator}s for the similar sets of attributes. * *

An entire collection cycle must be protected by a lock. A collection cycle is defined by * multiple calls to {@code #batch(...)} followed by one {@code #completeCollectionCycle(...)}; + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. */ final class InstrumentProcessor { private final Aggregator aggregator; @@ -35,19 +36,17 @@ final class InstrumentProcessor { } /** - * Batches multiple entries together that are part of the same metric. It may remove labels from - * the {@link Labels} and merge aggregations together. + * Batches multiple entries together that are part of the same metric. It may remove attributes + * from the {@link Attributes} and merge aggregations together. * - * @param labelSet the {@link Labels} associated with this {@code Aggregator}. + * @param attributes the {@link Attributes} associated with this {@code Aggregator}. * @param accumulation the accumulation produced by this instrument. */ - void batch(Attributes labelSet, T accumulation) { - T currentAccumulation = accumulationMap.get(labelSet); - if (currentAccumulation == null) { - accumulationMap.put(labelSet, accumulation); - return; + void batch(Attributes attributes, T accumulation) { + T currentAccumulation = accumulationMap.putIfAbsent(attributes, accumulation); + if (currentAccumulation != null) { + accumulationMap.put(attributes, aggregator.merge(currentAccumulation, accumulation)); } - accumulationMap.put(labelSet, aggregator.merge(currentAccumulation, accumulation)); } /** @@ -58,11 +57,11 @@ final class InstrumentProcessor { *

Based on the configured options this method may reset the internal state to produce deltas, * or keep the internal state to produce cumulative metrics. * - * @return the list of metrics batched in this Batcher. + * @return the metric batched or {@code null}. */ - List completeCollectionCycle(long epochNanos) { + MetricData completeCollectionCycle(long epochNanos) { if (accumulationMap.isEmpty()) { - return Collections.emptyList(); + return null; } MetricData metricData = @@ -73,6 +72,6 @@ final class InstrumentProcessor { accumulationMap = new HashMap<>(); } - return metricData == null ? Collections.emptyList() : Collections.singletonList(metricData); + return metricData; } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java new file mode 100644 index 0000000000..6aca4bdd98 --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterProviderSharedState.java @@ -0,0 +1,63 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics.internal.state; + +import com.google.auto.value.AutoValue; +import io.opentelemetry.sdk.common.Clock; +import io.opentelemetry.sdk.metrics.aggregator.Aggregator; +import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; +import io.opentelemetry.sdk.metrics.internal.view.ViewRegistry; +import io.opentelemetry.sdk.metrics.processor.LabelsProcessor; +import io.opentelemetry.sdk.resources.Resource; +import javax.annotation.concurrent.Immutable; + +/** + * State for a {@code MeterProvider}. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@AutoValue +@Immutable +public abstract class MeterProviderSharedState { + public static MeterProviderSharedState create( + Clock clock, Resource resource, ViewRegistry viewRegistry) { + return new AutoValue_MeterProviderSharedState(clock, resource, viewRegistry, clock.now()); + } + + /** Returns the clock used for measurements. */ + public abstract Clock getClock(); + + /** Returns the {@link Resource} to attach telemetry to. */ + abstract Resource getResource(); + + /** Returns the {@link ViewRegistry} for custom aggregation and metric definitions. */ + abstract ViewRegistry getViewRegistry(); + + /** + * Returns the timestamp when this {@code MeterProvider} was started, in nanoseconds since Unix + * epoch time. + */ + abstract long getStartEpochNanos(); + + /** Returns the {@link Aggregator} to use for a given instrument. */ + public Aggregator getAggregator( + MeterSharedState meterSharedState, InstrumentDescriptor descriptor) { + return getViewRegistry() + .findView(descriptor) + .getAggregatorFactory() + .create(getResource(), meterSharedState.getInstrumentationLibraryInfo(), descriptor); + } + + /** Returns the {@link LabelsProcessor} to use for a given instrument. */ + public LabelsProcessor getLabelsProcessor( + MeterSharedState meterSharedState, InstrumentDescriptor descriptor) { + return getViewRegistry() + .findView(descriptor) + .getLabelsProcessorFactory() + .create(getResource(), meterSharedState.getInstrumentationLibraryInfo(), descriptor); + } +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterSharedState.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterSharedState.java new file mode 100644 index 0000000000..2fc2b5532d --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MeterSharedState.java @@ -0,0 +1,84 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics.internal.state; + +import com.google.auto.value.AutoValue; +import io.opentelemetry.api.metrics.ObservableDoubleMeasurement; +import io.opentelemetry.api.metrics.ObservableLongMeasurement; +import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; +import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; +import io.opentelemetry.sdk.metrics.data.MetricData; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.Consumer; +import javax.annotation.concurrent.Immutable; + +/** + * State for a {@code Meter}. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@AutoValue +@Immutable +public abstract class MeterSharedState { + public static MeterSharedState create(InstrumentationLibraryInfo instrumentationLibraryInfo) { + return new AutoValue_MeterSharedState(instrumentationLibraryInfo, new MetricStorageRegistry()); + } + + // only visible for testing. + /** Returns the {@link InstrumentationLibraryInfo} for this {@code Meter}. */ + public abstract InstrumentationLibraryInfo getInstrumentationLibraryInfo(); + + /** Returns the metric storage for metrics in this {@code Meter}. */ + abstract MetricStorageRegistry getMetricStorageRegistry(); + + /** Collects all accumulated metric stream points. */ + public List collectAll( + MeterProviderSharedState meterProviderSharedState, long epochNanos) { + Collection metrics = getMetricStorageRegistry().getMetrics(); + List result = new ArrayList<>(metrics.size()); + for (MetricStorage metric : metrics) { + MetricData current = + metric.collectAndReset(meterProviderSharedState.getStartEpochNanos(), epochNanos); + if (current != null) { + result.add(current); + } + } + return result; + } + + /** Registers new synchronous storage associated with a given instrument. */ + public final WriteableMetricStorage registerSynchronousMetricStorage( + InstrumentDescriptor instrument, MeterProviderSharedState meterProviderSharedState) { + return getMetricStorageRegistry() + .register(SynchronousMetricStorage.create(meterProviderSharedState, this, instrument)); + } + + /** Registers new asynchronous storage associated with a given {@code long} instrument. */ + public final MetricStorage registerLongAsynchronousInstrument( + InstrumentDescriptor instrument, + MeterProviderSharedState meterProviderSharedState, + Consumer metricUpdater) { + return getMetricStorageRegistry() + .register( + AsynchronousMetricStorage.longAsynchronousAccumulator( + meterProviderSharedState, this, instrument, metricUpdater)); + } + + /** Registers new asynchronous storage associated with a given {@code double} instrument. */ + public final MetricStorage registerDoubleAsynchronousInstrument( + InstrumentDescriptor instrument, + MeterProviderSharedState meterProviderSharedState, + Consumer metricUpdater) { + + return getMetricStorageRegistry() + .register( + AsynchronousMetricStorage.doubleAsynchronousAccumulator( + meterProviderSharedState, this, instrument, metricUpdater)); + } +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorage.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorage.java new file mode 100644 index 0000000000..01c92bfded --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorage.java @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics.internal.state; + +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor; + +/** + * Stores collected {@link MetricData}. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public interface MetricStorage { + + /** Returns a description of the metric produced in this storage. */ + MetricDescriptor getMetricDescriptor(); + /** + * Collects the metrics from this storage and resets for the next collection period. + * + * @param startEpochNanos The start timestamp for this SDK. + * @param epochNanos The timestamp for this collection. + * @return The {@link MetricData} from this collection period, or {@code null}. + */ + MetricData collectAndReset(long startEpochNanos, long epochNanos); +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistry.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistry.java new file mode 100644 index 0000000000..30097bf290 --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistry.java @@ -0,0 +1,79 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics.internal.state; + +import io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * Responsible for storing metrics (by name) and returning access to input pipeline for instrument + * wiring. + * + *

The rules of the registry: + * + *

    + *
  • Only one storage type may be registered per-name. Repeated look-ups per-name will return + * the same storage. + *
  • The metric descriptor should be "compatible", when returning an existing metric storage, + * i.e. same type of metric, same name, description etc. + *
  • The registered storage type MUST be either always Asynchronous or always Synchronous. No + * mixing and matching. + *
+ * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public class MetricStorageRegistry { + private final ConcurrentMap registry = new ConcurrentHashMap<>(); + + /** + * Returns a {@code Collection} view of the registered {@link MetricStorage}. + * + * @return a {@code Collection} view of the registered {@link MetricStorage}. + */ + public Collection getMetrics() { + return Collections.unmodifiableCollection(new ArrayList<>(registry.values())); + } + + /** + * Registers the given {@code Metric} to this registry. Returns the registered storage if no other + * metric with the same name is registered or a previously registered metric with same name and + * equal with the current metric, otherwise throws an exception. + * + * @param storage the metric storage to use or discard. + * @return the given metric storage if no metric with same name already registered, otherwise the + * previous registered instrument. + * @throws IllegalArgumentException if instrument cannot be registered. + */ + @SuppressWarnings("unchecked") + public I register(I storage) { + MetricDescriptor descriptor = storage.getMetricDescriptor(); + MetricStorage oldOrNewStorage = + registry.computeIfAbsent(descriptor.getName().toLowerCase(), key -> storage); + // Make sure the storage is compatible. + if (!oldOrNewStorage.getMetricDescriptor().isCompatibleWith(descriptor)) { + throw new IllegalArgumentException( + "Metric with same name and different descriptor already created. Found: " + + oldOrNewStorage.getMetricDescriptor() + + ", Want: " + + descriptor); + } + // Make sure we aren't mixing sync + async. + if (!storage.getClass().equals(oldOrNewStorage.getClass())) { + throw new IllegalArgumentException( + "Metric with same name and different instrument already created. Found: " + + oldOrNewStorage.getClass() + + ", Want: " + + storage.getClass()); + } + + return (I) oldOrNewStorage; + } +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SynchronousInstrumentAccumulator.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorage.java similarity index 65% rename from sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SynchronousInstrumentAccumulator.java rename to sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorage.java index b95077418c..02c6049338 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/SynchronousInstrumentAccumulator.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorage.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.sdk.metrics; +package io.opentelemetry.sdk.metrics.internal.state; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.context.Context; @@ -11,36 +11,48 @@ import io.opentelemetry.sdk.metrics.aggregator.Aggregator; import io.opentelemetry.sdk.metrics.aggregator.AggregatorHandle; import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor; import io.opentelemetry.sdk.metrics.processor.LabelsProcessor; -import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; -final class SynchronousInstrumentAccumulator extends AbstractAccumulator { +/** + * Stores aggregated {@link MetricData} for synchronous instruments. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class SynchronousMetricStorage implements WriteableMetricStorage { + private final MetricDescriptor metricDescriptor; private final ConcurrentHashMap> aggregatorLabels; private final ReentrantLock collectLock; private final Aggregator aggregator; private final InstrumentProcessor instrumentProcessor; private final LabelsProcessor labelsProcessor; - static SynchronousInstrumentAccumulator create( + /** Constructs metric storage for a given synchronous instrument. */ + public static SynchronousMetricStorage create( MeterProviderSharedState meterProviderSharedState, MeterSharedState meterSharedState, InstrumentDescriptor descriptor) { - Aggregator aggregator = - getAggregator(meterProviderSharedState, meterSharedState, descriptor); - return new SynchronousInstrumentAccumulator<>( + Aggregator aggregator = meterProviderSharedState.getAggregator(meterSharedState, descriptor); + return new SynchronousMetricStorage<>( + // TODO: View can change metric name/description. Update this when wired in. + MetricDescriptor.create( + descriptor.getName(), descriptor.getDescription(), descriptor.getUnit()), aggregator, new InstrumentProcessor<>(aggregator, meterProviderSharedState.getStartEpochNanos()), - getLabelsProcessor(meterProviderSharedState, meterSharedState, descriptor)); + meterProviderSharedState.getLabelsProcessor(meterSharedState, descriptor)); } - SynchronousInstrumentAccumulator( + SynchronousMetricStorage( + MetricDescriptor metricDescriptor, Aggregator aggregator, InstrumentProcessor instrumentProcessor, LabelsProcessor labelsProcessor) { + this.metricDescriptor = metricDescriptor; aggregatorLabels = new ConcurrentHashMap<>(); collectLock = new ReentrantLock(); this.aggregator = aggregator; @@ -48,10 +60,11 @@ final class SynchronousInstrumentAccumulator extends AbstractAccumulator { this.labelsProcessor = labelsProcessor; } - AggregatorHandle bind(Attributes labels) { - Objects.requireNonNull(labels, "labels"); - labels = labelsProcessor.onLabelsBound(Context.current(), labels); - AggregatorHandle aggregatorHandle = aggregatorLabels.get(labels); + @Override + public BoundStorageHandle bind(Attributes attributes) { + Objects.requireNonNull(attributes, "attributes"); + attributes = labelsProcessor.onLabelsBound(Context.current(), attributes); + AggregatorHandle aggregatorHandle = aggregatorLabels.get(attributes); if (aggregatorHandle != null && aggregatorHandle.acquire()) { // At this moment it is guaranteed that the Bound is in the map and will not be removed. return aggregatorHandle; @@ -61,7 +74,7 @@ final class SynchronousInstrumentAccumulator extends AbstractAccumulator { aggregatorHandle = aggregator.createHandle(); while (true) { AggregatorHandle boundAggregatorHandle = - aggregatorLabels.putIfAbsent(labels, aggregatorHandle); + aggregatorLabels.putIfAbsent(attributes, aggregatorHandle); if (boundAggregatorHandle != null) { if (boundAggregatorHandle.acquire()) { // At this moment it is guaranteed that the Bound is in the map and will not be removed. @@ -69,7 +82,7 @@ final class SynchronousInstrumentAccumulator extends AbstractAccumulator { } // Try to remove the boundAggregator. This will race with the collect method, but only one // will succeed. - aggregatorLabels.remove(labels, boundAggregatorHandle); + aggregatorLabels.remove(attributes, boundAggregatorHandle); continue; } return aggregatorHandle; @@ -77,7 +90,7 @@ final class SynchronousInstrumentAccumulator extends AbstractAccumulator { } @Override - List collectAll(long epochNanos) { + public MetricData collectAndReset(long startEpochNanos, long epochNanos) { collectLock.lock(); try { for (Map.Entry> entry : aggregatorLabels.entrySet()) { @@ -98,4 +111,9 @@ final class SynchronousInstrumentAccumulator extends AbstractAccumulator { collectLock.unlock(); } } + + @Override + public MetricDescriptor getMetricDescriptor() { + return metricDescriptor; + } } diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/WriteableMetricStorage.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/WriteableMetricStorage.java new file mode 100644 index 0000000000..90bd7e147b --- /dev/null +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/WriteableMetricStorage.java @@ -0,0 +1,39 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics.internal.state; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.context.Context; + +/** + * Stores {@link MetricData} and allows synchronous writes of measurements. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public interface WriteableMetricStorage extends MetricStorage { + /** Bind an efficient storage handle for a set of attributes. */ + BoundStorageHandle bind(Attributes attributes); + + /** Records a measurement. */ + default void recordLong(long value, Attributes attributes, Context context) { + BoundStorageHandle handle = bind(attributes); + try { + handle.recordLong(value, attributes, context); + } finally { + handle.release(); + } + } + /** Records a measurement. */ + default void recordDouble(double value, Attributes attributes, Context context) { + BoundStorageHandle handle = bind(attributes); + try { + handle.recordDouble(value, attributes, context); + } finally { + handle.release(); + } + } +} diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/ViewRegistry.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistry.java similarity index 76% rename from sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/ViewRegistry.java rename to sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistry.java index 5f778fbd1e..fd9846853d 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/ViewRegistry.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistry.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.sdk.metrics; +package io.opentelemetry.sdk.metrics.internal.view; import io.opentelemetry.sdk.metrics.aggregator.AggregatorFactory; import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; @@ -19,9 +19,12 @@ import javax.annotation.concurrent.Immutable; /** * Central location for Views to be registered. Registration of a view is done via the {@link * SdkMeterProviderBuilder}. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. */ @Immutable -final class ViewRegistry { +public final class ViewRegistry { static final View CUMULATIVE_SUM = View.builder() .setAggregatorFactory(AggregatorFactory.sum(AggregationTemporality.CUMULATIVE)) @@ -41,11 +44,18 @@ final class ViewRegistry { this.configuration.put(instrumentType, new LinkedHashMap<>(patternViewLinkedHashMap))); } - static ViewRegistryBuilder builder() { + /** Returns a builder of {@link ViewRegistry}. */ + public static ViewRegistryBuilder builder() { return new ViewRegistryBuilder(); } - View findView(InstrumentDescriptor descriptor) { + /** + * Returns the metric {@link View} for a given instrument. + * + * @param descriptor description of the instrument. + * @return The {@link View} for this instrument, or a default aggregation view. + */ + public View findView(InstrumentDescriptor descriptor) { LinkedHashMap configPerType = configuration.get(descriptor.getType()); for (Map.Entry entry : configPerType.entrySet()) { if (entry.getKey().matcher(descriptor.getName()).matches()) { @@ -60,12 +70,12 @@ final class ViewRegistry { switch (descriptor.getType()) { case COUNTER: case UP_DOWN_COUNTER: - case SUM_OBSERVER: - case UP_DOWN_SUM_OBSERVER: + case OBSERVABLE_SUM: + case OBSERVABLE_UP_DOWN_SUM: return CUMULATIVE_SUM; - case VALUE_RECORDER: + case HISTOGRAM: return SUMMARY; - case VALUE_OBSERVER: + case OBSERVABLE_GAUGE: return LAST_VALUE; } throw new IllegalArgumentException("Unknown descriptor type: " + descriptor.getType()); diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/ViewRegistryBuilder.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistryBuilder.java similarity index 68% rename from sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/ViewRegistryBuilder.java rename to sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistryBuilder.java index 3131cc08c2..1a55800a0c 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/ViewRegistryBuilder.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistryBuilder.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.sdk.metrics; +package io.opentelemetry.sdk.metrics.internal.view; import io.opentelemetry.sdk.metrics.common.InstrumentType; import io.opentelemetry.sdk.metrics.view.InstrumentSelector; @@ -12,7 +12,13 @@ import java.util.EnumMap; import java.util.LinkedHashMap; import java.util.regex.Pattern; -class ViewRegistryBuilder { +/** + * Builder for {@link ViewRegistry}. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public class ViewRegistryBuilder { private final EnumMap> configuration = new EnumMap<>(InstrumentType.class); private static final LinkedHashMap EMPTY_CONFIG = new LinkedHashMap<>(); @@ -23,11 +29,19 @@ class ViewRegistryBuilder { } } - ViewRegistry build() { + /** Returns the {@link ViewRegistry}. */ + public ViewRegistry build() { return new ViewRegistry(configuration); } - ViewRegistryBuilder addView(InstrumentSelector selector, View view) { + /** + * Adds a new view to the registry. + * + * @param selector The instruments that should have their defaults altered. + * @param view The {@link View} metric definition. + * @return this + */ + public ViewRegistryBuilder addView(InstrumentSelector selector, View view) { LinkedHashMap parentConfiguration = configuration.get(selector.getInstrumentType()); configuration.put( 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 1315218a6b..7615d233f9 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 @@ -10,9 +10,6 @@ import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.common.InstrumentType; import io.opentelemetry.sdk.metrics.common.InstrumentValueType; -import io.opentelemetry.sdk.metrics.data.MetricData; -import java.util.Collections; -import java.util.List; import org.junit.jupiter.api.Test; /** Unit tests for {@link AbstractInstrument}. */ @@ -31,10 +28,5 @@ class AbstractInstrumentTest { TestInstrument(InstrumentDescriptor descriptor) { super(descriptor); } - - @Override - List collectAll(long epochNanos) { - return Collections.emptyList(); - } } } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleCounterSdkTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleCounterSdkTest.java index 9a586525f0..41547d95d6 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleCounterSdkTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleCounterSdkTest.java @@ -33,18 +33,18 @@ class DoubleCounterSdkTest { private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName()); @Test - void add_PreventNullLabels() { + void add_PreventNullAttributes() { assertThatThrownBy( () -> sdkMeter.counterBuilder("testCounter").ofDoubles().build().add(1.0, null)) .isInstanceOf(NullPointerException.class) - .hasMessage("labels"); + .hasMessage("attributes"); } @Test - void bound_PreventNullLabels() { + void bound_PreventNullAttributes() { assertThatThrownBy(() -> sdkMeter.counterBuilder("testCounter").ofDoubles().build().bind(null)) .isInstanceOf(NullPointerException.class) - .hasMessage("labels"); + .hasMessage("attributes"); } @Test @@ -60,7 +60,7 @@ class DoubleCounterSdkTest { @Test @SuppressWarnings("unchecked") - void collectMetrics_WithEmptyLabel() { + void collectMetrics_WithEmptyAttributes() { DoubleCounter doubleCounter = sdkMeter .counterBuilder("testCounter") diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleValueObserverSdkTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleGaugeBuilderSdkTest.java similarity index 96% rename from sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleValueObserverSdkTest.java rename to sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleGaugeBuilderSdkTest.java index 407da16498..1a9d803f09 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleValueObserverSdkTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleGaugeBuilderSdkTest.java @@ -17,11 +17,11 @@ import java.time.Duration; import org.junit.jupiter.api.Test; /** Unit tests for {@link DoubleValueObserverSdk}. */ -class DoubleValueObserverSdkTest { +class DoubleGaugeBuilderSdkTest { private static final Resource RESOURCE = Resource.create(Attributes.of(stringKey("resource_key"), "resource_value")); private static final InstrumentationLibraryInfo INSTRUMENTATION_LIBRARY_INFO = - InstrumentationLibraryInfo.create(DoubleValueObserverSdkTest.class.getName(), null); + InstrumentationLibraryInfo.create(DoubleGaugeBuilderSdkTest.class.getName(), null); private final TestClock testClock = TestClock.create(); private final SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder().setClock(testClock).setResource(RESOURCE).build(); diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleValueRecorderSdkTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleHistogramSdkTest.java similarity index 94% rename from sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleValueRecorderSdkTest.java rename to sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleHistogramSdkTest.java index 34e1d1e126..126ad7058b 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleValueRecorderSdkTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleHistogramSdkTest.java @@ -28,30 +28,30 @@ import java.util.Collections; import java.util.List; import org.junit.jupiter.api.Test; -/** Unit tests for {@link DoubleValueRecorderSdk}. */ -class DoubleValueRecorderSdkTest { +/** Unit tests for {@link DoubleHistogramSdk}. */ +class DoubleHistogramSdkTest { private static final long SECOND_NANOS = 1_000_000_000; private static final Resource RESOURCE = Resource.create(Attributes.of(stringKey("resource_key"), "resource_value")); private static final InstrumentationLibraryInfo INSTRUMENTATION_LIBRARY_INFO = - InstrumentationLibraryInfo.create(DoubleValueRecorderSdkTest.class.getName(), null); + InstrumentationLibraryInfo.create(DoubleHistogramSdkTest.class.getName(), null); private final TestClock testClock = TestClock.create(); private final SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder().setClock(testClock).setResource(RESOURCE).build(); private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName()); @Test - void record_PreventNullLabels() { + void record_PreventNullAttributes() { assertThatThrownBy(() -> sdkMeter.histogramBuilder("testRecorder").build().record(1.0, null)) .isInstanceOf(NullPointerException.class) - .hasMessage("labels"); + .hasMessage("attributes"); } @Test - void bound_PreventNullLabels() { + void bound_PreventNullAttributes() { assertThatThrownBy(() -> sdkMeter.histogramBuilder("testRecorder").build().bind(null)) .isInstanceOf(NullPointerException.class) - .hasMessage("labels"); + .hasMessage("attributes"); } @Test @@ -67,7 +67,7 @@ class DoubleValueRecorderSdkTest { } @Test - void collectMetrics_WithEmptyLabel() { + void collectMetrics_WithEmptyAttributes() { DoubleHistogram doubleRecorder = sdkMeter .histogramBuilder("testRecorder") @@ -188,7 +188,7 @@ class DoubleValueRecorderSdkTest { StressTestRunner.Builder stressTestBuilder = StressTestRunner.builder() - .setInstrument((DoubleValueRecorderSdk) doubleRecorder) + .setInstrument((DoubleHistogramSdk) doubleRecorder) .setCollectionIntervalMs(100); for (int i = 0; i < 4; i++) { @@ -196,7 +196,7 @@ class DoubleValueRecorderSdkTest { StressTestRunner.Operation.create( 1_000, 2, - new DoubleValueRecorderSdkTest.OperationUpdaterDirectCall(doubleRecorder, "K", "V"))); + new DoubleHistogramSdkTest.OperationUpdaterDirectCall(doubleRecorder, "K", "V"))); stressTestBuilder.addOperation( StressTestRunner.Operation.create( 1_000, @@ -233,7 +233,7 @@ class DoubleValueRecorderSdkTest { StressTestRunner.Builder stressTestBuilder = StressTestRunner.builder() - .setInstrument((DoubleValueRecorderSdk) doubleRecorder) + .setInstrument((DoubleHistogramSdk) doubleRecorder) .setCollectionIntervalMs(100); for (int i = 0; i < 4; i++) { @@ -241,7 +241,7 @@ class DoubleValueRecorderSdkTest { StressTestRunner.Operation.create( 2_000, 1, - new DoubleValueRecorderSdkTest.OperationUpdaterDirectCall( + new DoubleHistogramSdkTest.OperationUpdaterDirectCall( doubleRecorder, keys[i], values[i]))); stressTestBuilder.addOperation( diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleSumObserverSdkTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleSumObserverSdkTest.java index 77f92f041d..3ee7134390 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleSumObserverSdkTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleSumObserverSdkTest.java @@ -109,7 +109,9 @@ class DoubleSumObserverSdkTest { SdkMeterProvider sdkMeterProvider = sdkMeterProviderBuilder .registerView( - InstrumentSelector.builder().setInstrumentType(InstrumentType.SUM_OBSERVER).build(), + InstrumentSelector.builder() + .setInstrumentType(InstrumentType.OBSERVABLE_SUM) + .build(), View.builder() .setLabelsProcessorFactory(LabelsProcessorFactory.noop()) .setAggregatorFactory(AggregatorFactory.sum(AggregationTemporality.DELTA)) diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleUpDownCounterSdkTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleUpDownCounterSdkTest.java index 962c594abb..8ac2bd1639 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleUpDownCounterSdkTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleUpDownCounterSdkTest.java @@ -33,7 +33,7 @@ class DoubleUpDownCounterSdkTest { private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName()); @Test - void add_PreventNullLabels() { + void add_PreventNullAttributes() { assertThatThrownBy( () -> sdkMeter @@ -42,15 +42,15 @@ class DoubleUpDownCounterSdkTest { .build() .add(1.0, null)) .isInstanceOf(NullPointerException.class) - .hasMessage("labels"); + .hasMessage("attributes"); } @Test - void bound_PreventNullLabels() { + void bound_PreventNullAttributes() { assertThatThrownBy( () -> sdkMeter.upDownCounterBuilder("testUpDownCounter").ofDoubles().build().bind(null)) .isInstanceOf(NullPointerException.class) - .hasMessage("labels"); + .hasMessage("attributes"); } @Test @@ -68,7 +68,7 @@ class DoubleUpDownCounterSdkTest { @Test @SuppressWarnings("unchecked") - void collectMetrics_WithEmptyLabel() { + void collectMetrics_WithEmptyAttributes() { DoubleUpDownCounter doubleUpDownCounter = sdkMeter .upDownCounterBuilder("testUpDownCounter") diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleUpDownSumObserverSdkTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleUpDownSumObserverSdkTest.java index 42a8823565..297b7ef130 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleUpDownSumObserverSdkTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/DoubleUpDownSumObserverSdkTest.java @@ -106,7 +106,7 @@ class DoubleUpDownSumObserverSdkTest { sdkMeterProviderBuilder .registerView( InstrumentSelector.builder() - .setInstrumentType(InstrumentType.UP_DOWN_SUM_OBSERVER) + .setInstrumentType(InstrumentType.OBSERVABLE_UP_DOWN_SUM) .build(), View.builder() .setLabelsProcessorFactory(LabelsProcessorFactory.noop()) diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentRegistryTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentRegistryTest.java deleted file mode 100644 index 8412b4cf25..0000000000 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/InstrumentRegistryTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.metrics; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; -import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; -import io.opentelemetry.sdk.metrics.common.InstrumentType; -import io.opentelemetry.sdk.metrics.common.InstrumentValueType; -import io.opentelemetry.sdk.metrics.data.MetricData; -import java.util.Collections; -import java.util.List; -import org.junit.jupiter.api.Test; - -/** Unit tests for {@link InstrumentRegistry}. */ -class InstrumentRegistryTest { - private static final InstrumentDescriptor INSTRUMENT_DESCRIPTOR = - InstrumentDescriptor.create( - "name", "description", "1", InstrumentType.COUNTER, InstrumentValueType.LONG); - private static final InstrumentDescriptor OTHER_INSTRUMENT_DESCRIPTOR = - InstrumentDescriptor.create( - "name", "other_description", "1", InstrumentType.COUNTER, InstrumentValueType.LONG); - - @Test - void register() { - MeterSharedState meterSharedState = MeterSharedState.create(InstrumentationLibraryInfo.empty()); - TestInstrument testInstrument = new TestInstrument(INSTRUMENT_DESCRIPTOR); - assertThat(meterSharedState.getInstrumentRegistry().register(testInstrument)) - .isSameAs(testInstrument); - assertThat(meterSharedState.getInstrumentRegistry().register(testInstrument)) - .isSameAs(testInstrument); - assertThat( - meterSharedState - .getInstrumentRegistry() - .register(new TestInstrument(INSTRUMENT_DESCRIPTOR))) - .isSameAs(testInstrument); - } - - @Test - void register_OtherDescriptor() { - MeterSharedState meterSharedState = MeterSharedState.create(InstrumentationLibraryInfo.empty()); - TestInstrument testInstrument = new TestInstrument(INSTRUMENT_DESCRIPTOR); - assertThat(meterSharedState.getInstrumentRegistry().register(testInstrument)) - .isSameAs(testInstrument); - - assertThatThrownBy( - () -> - meterSharedState - .getInstrumentRegistry() - .register(new TestInstrument(OTHER_INSTRUMENT_DESCRIPTOR))) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); - } - - @Test - void register_OtherInstance() { - MeterSharedState meterSharedState = MeterSharedState.create(InstrumentationLibraryInfo.empty()); - TestInstrument testInstrument = new TestInstrument(INSTRUMENT_DESCRIPTOR); - assertThat(meterSharedState.getInstrumentRegistry().register(testInstrument)) - .isSameAs(testInstrument); - - assertThatThrownBy( - () -> - meterSharedState - .getInstrumentRegistry() - .register(new OtherTestInstrument(INSTRUMENT_DESCRIPTOR))) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); - } - - private static final class TestInstrument extends AbstractInstrument { - TestInstrument(InstrumentDescriptor descriptor) { - super(descriptor); - } - - @Override - List collectAll(long epochNanos) { - return Collections.emptyList(); - } - } - - private static final class OtherTestInstrument extends AbstractInstrument { - OtherTestInstrument(InstrumentDescriptor descriptor) { - super(descriptor); - } - - @Override - List collectAll(long epochNanos) { - return Collections.emptyList(); - } - } -} diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongCounterSdkTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongCounterSdkTest.java index ff655b4277..f4be172892 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongCounterSdkTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongCounterSdkTest.java @@ -33,17 +33,17 @@ class LongCounterSdkTest { private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName()); @Test - void add_PreventNullLabels() { + void add_PreventNullAttributes() { assertThatThrownBy(() -> sdkMeter.counterBuilder("testCounter").build().add(1, null)) .isInstanceOf(NullPointerException.class) - .hasMessage("labels"); + .hasMessage("attributes"); } @Test - void bound_PreventNullLabels() { + void bound_PreventNullAttributes() { assertThatThrownBy(() -> sdkMeter.counterBuilder("testCounter").build().bind(null)) .isInstanceOf(NullPointerException.class) - .hasMessage("labels"); + .hasMessage("attributes"); } @Test @@ -59,7 +59,7 @@ class LongCounterSdkTest { @Test @SuppressWarnings("unchecked") - void collectMetrics_WithEmptyLabels() { + void collectMetrics_WithEmptyAttributes() { LongCounter longCounter = sdkMeter.counterBuilder("testCounter").setDescription("description").setUnit("By").build(); testClock.advance(Duration.ofNanos(SECOND_NANOS)); diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongValueObserverSdkTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongGaugeBuilderSdkTest.java similarity index 96% rename from sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongValueObserverSdkTest.java rename to sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongGaugeBuilderSdkTest.java index 52242a4528..9b5f04274a 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongValueObserverSdkTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongGaugeBuilderSdkTest.java @@ -17,11 +17,11 @@ import java.time.Duration; import org.junit.jupiter.api.Test; /** Unit tests for {@link LongValueObserverSdk}. */ -class LongValueObserverSdkTest { +class LongGaugeBuilderSdkTest { private static final Resource RESOURCE = Resource.create(Attributes.of(stringKey("resource_key"), "resource_value")); private static final InstrumentationLibraryInfo INSTRUMENTATION_LIBRARY_INFO = - InstrumentationLibraryInfo.create(LongValueObserverSdkTest.class.getName(), null); + InstrumentationLibraryInfo.create(LongGaugeBuilderSdkTest.class.getName(), null); private final TestClock testClock = TestClock.create(); private final SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder().setClock(testClock).setResource(RESOURCE).build(); diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongValueRecorderSdkTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongHistogramSdkTest.java similarity index 94% rename from sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongValueRecorderSdkTest.java rename to sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongHistogramSdkTest.java index 554328cc8c..bee329cfec 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongValueRecorderSdkTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongHistogramSdkTest.java @@ -28,31 +28,31 @@ import java.util.Collections; import java.util.List; import org.junit.jupiter.api.Test; -/** Unit tests for {@link LongValueRecorderSdk}. */ -class LongValueRecorderSdkTest { +/** Unit tests for {@link LongHistogramSdk}. */ +class LongHistogramSdkTest { private static final long SECOND_NANOS = 1_000_000_000; private static final Resource RESOURCE = Resource.create(Attributes.of(stringKey("resource_key"), "resource_value")); private static final InstrumentationLibraryInfo INSTRUMENTATION_LIBRARY_INFO = - InstrumentationLibraryInfo.create(LongValueRecorderSdkTest.class.getName(), null); + InstrumentationLibraryInfo.create(LongHistogramSdkTest.class.getName(), null); private final TestClock testClock = TestClock.create(); private final SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder().setClock(testClock).setResource(RESOURCE).build(); private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName()); @Test - void record_PreventNullLabels() { + void record_PreventNullAttributes() { assertThatThrownBy( () -> sdkMeter.histogramBuilder("testRecorder").ofLongs().build().record(1, null)) .isInstanceOf(NullPointerException.class) - .hasMessage("labels"); + .hasMessage("attributes"); } @Test - void bound_PreventNullLabels() { + void bound_PreventNullAttributes() { assertThatThrownBy(() -> sdkMeter.histogramBuilder("testRecorder").ofLongs().build().bind(null)) .isInstanceOf(NullPointerException.class) - .hasMessage("labels"); + .hasMessage("attributes"); } @Test @@ -67,7 +67,7 @@ class LongValueRecorderSdkTest { } @Test - void collectMetrics_WithEmptyLabel() { + void collectMetrics_WithEmptyAttributes() { LongHistogram longRecorder = sdkMeter .histogramBuilder("testRecorder") @@ -188,7 +188,7 @@ class LongValueRecorderSdkTest { StressTestRunner.Builder stressTestBuilder = StressTestRunner.builder() - .setInstrument((LongValueRecorderSdk) longRecorder) + .setInstrument((LongHistogramSdk) longRecorder) .setCollectionIntervalMs(100); for (int i = 0; i < 4; i++) { @@ -196,12 +196,12 @@ class LongValueRecorderSdkTest { StressTestRunner.Operation.create( 2_000, 1, - new LongValueRecorderSdkTest.OperationUpdaterDirectCall(longRecorder, "K", "V"))); + new LongHistogramSdkTest.OperationUpdaterDirectCall(longRecorder, "K", "V"))); stressTestBuilder.addOperation( StressTestRunner.Operation.create( 2_000, 1, - new LongValueRecorderSdkTest.OperationUpdaterWithBinding( + new LongHistogramSdkTest.OperationUpdaterWithBinding( longRecorder.bind(Attributes.builder().put("K", "V").build())))); } @@ -233,7 +233,7 @@ class LongValueRecorderSdkTest { StressTestRunner.Builder stressTestBuilder = StressTestRunner.builder() - .setInstrument((LongValueRecorderSdk) longRecorder) + .setInstrument((LongHistogramSdk) longRecorder) .setCollectionIntervalMs(100); for (int i = 0; i < 4; i++) { @@ -241,14 +241,14 @@ class LongValueRecorderSdkTest { StressTestRunner.Operation.create( 1_000, 2, - new LongValueRecorderSdkTest.OperationUpdaterDirectCall( + new LongHistogramSdkTest.OperationUpdaterDirectCall( longRecorder, keys[i], values[i]))); stressTestBuilder.addOperation( StressTestRunner.Operation.create( 1_000, 2, - new LongValueRecorderSdkTest.OperationUpdaterWithBinding( + new LongHistogramSdkTest.OperationUpdaterWithBinding( longRecorder.bind(Attributes.builder().put(keys[i], values[i]).build())))); } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongSumObserverSdkTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongSumObserverSdkTest.java index 1b5b1f7e9d..6d452792c6 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongSumObserverSdkTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongSumObserverSdkTest.java @@ -103,7 +103,9 @@ class LongSumObserverSdkTest { SdkMeterProvider sdkMeterProvider = sdkMeterProviderBuilder .registerView( - InstrumentSelector.builder().setInstrumentType(InstrumentType.SUM_OBSERVER).build(), + InstrumentSelector.builder() + .setInstrumentType(InstrumentType.OBSERVABLE_SUM) + .build(), View.builder() .setLabelsProcessorFactory(LabelsProcessorFactory.noop()) .setAggregatorFactory(AggregatorFactory.sum(AggregationTemporality.DELTA)) diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongUpDownCounterSdkTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongUpDownCounterSdkTest.java index f30e93d775..15cab6c8d9 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongUpDownCounterSdkTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongUpDownCounterSdkTest.java @@ -33,17 +33,17 @@ class LongUpDownCounterSdkTest { private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName()); @Test - void add_PreventNullLabels() { + void add_PreventNullAttributes() { assertThatThrownBy(() -> sdkMeter.upDownCounterBuilder("testCounter").build().add(1, null)) .isInstanceOf(NullPointerException.class) - .hasMessage("labels"); + .hasMessage("attributes"); } @Test - void bound_PreventNullLabels() { + void bound_PreventNullAttributes() { assertThatThrownBy(() -> sdkMeter.upDownCounterBuilder("testUpDownCounter").build().bind(null)) .isInstanceOf(NullPointerException.class) - .hasMessage("labels"); + .hasMessage("attributes"); } @Test @@ -61,7 +61,7 @@ class LongUpDownCounterSdkTest { @Test @SuppressWarnings("unchecked") - void collectMetrics_WithEmptyLabel() { + void collectMetrics_WithEmptyAttributes() { LongUpDownCounter longUpDownCounter = sdkMeter .upDownCounterBuilder("testUpDownCounter") diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongUpDownSumObserverSdkTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongUpDownSumObserverSdkTest.java index 03c4b4386a..85f186fe2b 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongUpDownSumObserverSdkTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/LongUpDownSumObserverSdkTest.java @@ -104,7 +104,7 @@ class LongUpDownSumObserverSdkTest { sdkMeterProviderBuilder .registerView( InstrumentSelector.builder() - .setInstrumentType(InstrumentType.UP_DOWN_SUM_OBSERVER) + .setInstrumentType(InstrumentType.OBSERVABLE_UP_DOWN_SUM) .build(), View.builder() .setLabelsProcessorFactory(LabelsProcessorFactory.noop()) diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkMeterTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkMeterTest.java index 8e94ba6e12..3b2409e155 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkMeterTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SdkMeterTest.java @@ -31,20 +31,21 @@ class SdkMeterTest { .build(); assertThat(longCounter).isNotNull(); - assertThat( - sdkMeter - .counterBuilder("testLongCounter") - .setDescription("My very own counter") - .setUnit("metric tonnes") - .build()) - .isSameAs(longCounter); + // Note: We no longer get the same instrument instance as these instances are lightweight + // objects backed by storage now. Here we just make sure it doesn't throw to grab + // a second instance. + sdkMeter + .counterBuilder("testLongCounter") + .setDescription("My very own counter") + .setUnit("metric tonnes") + .build(); assertThatThrownBy(() -> sdkMeter.counterBuilder("testLongCounter").build()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); assertThatThrownBy(() -> sdkMeter.counterBuilder("testLongCounter".toUpperCase()).build()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); } @Test @@ -57,21 +58,22 @@ class SdkMeterTest { .build(); assertThat(longUpDownCounter).isNotNull(); - assertThat( - sdkMeter - .upDownCounterBuilder("testLongUpDownCounter") - .setDescription("My very own counter") - .setUnit("metric tonnes") - .build()) - .isSameAs(longUpDownCounter); + // Note: We no longer get the same instrument instance as these instances are lightweight + // objects backed by storage now. Here we just make sure it doesn't throw to grab + // a second instance. + sdkMeter + .upDownCounterBuilder("testLongUpDownCounter") + .setDescription("My very own counter") + .setUnit("metric tonnes") + .build(); assertThatThrownBy(() -> sdkMeter.upDownCounterBuilder("testLongUpDownCounter").build()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); assertThatThrownBy( () -> sdkMeter.upDownCounterBuilder("testLongUpDownCounter".toUpperCase()).build()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); } @Test @@ -85,23 +87,24 @@ class SdkMeterTest { .build(); assertThat(longValueRecorder).isNotNull(); - assertThat( - sdkMeter - .histogramBuilder("testLongValueRecorder") - .ofLongs() - .setDescription("My very own counter") - .setUnit("metric tonnes") - .build()) - .isSameAs(longValueRecorder); + // Note: We no longer get the same instrument instance as these instances are lightweight + // objects backed by storage now. Here we just make sure it doesn't throw to grab + // a second instance. + sdkMeter + .histogramBuilder("testLongValueRecorder") + .ofLongs() + .setDescription("My very own counter") + .setUnit("metric tonnes") + .build(); assertThatThrownBy(() -> sdkMeter.histogramBuilder("testLongValueRecorder").ofLongs().build()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); assertThatThrownBy( () -> sdkMeter.histogramBuilder("testLongValueRecorder".toUpperCase()).ofLongs().build()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); } @Test @@ -116,7 +119,7 @@ class SdkMeterTest { assertThatThrownBy( () -> sdkMeter.gaugeBuilder("longValueObserver").ofLongs().buildWithCallback(x -> {})) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); assertThatThrownBy( () -> sdkMeter @@ -124,7 +127,7 @@ class SdkMeterTest { .ofLongs() .buildWithCallback(x -> {})) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); } @Test @@ -138,7 +141,7 @@ class SdkMeterTest { assertThatThrownBy( () -> sdkMeter.counterBuilder("testLongSumObserver").buildWithCallback(x -> {})) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); assertThatThrownBy( () -> @@ -146,7 +149,7 @@ class SdkMeterTest { .counterBuilder("testLongSumObserver".toUpperCase()) .buildWithCallback(x -> {})) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); } @Test @@ -163,7 +166,7 @@ class SdkMeterTest { .upDownCounterBuilder("testLongUpDownSumObserver") .buildWithCallback(x -> {})) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); assertThatThrownBy( () -> @@ -171,7 +174,7 @@ class SdkMeterTest { .upDownCounterBuilder("testLongUpDownSumObserver".toUpperCase()) .buildWithCallback(x -> {})) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); } @Test @@ -185,22 +188,23 @@ class SdkMeterTest { .build(); assertThat(doubleCounter).isNotNull(); - assertThat( - sdkMeter - .counterBuilder("testDoubleCounter") - .ofDoubles() - .setDescription("My very own counter") - .setUnit("metric tonnes") - .build()) - .isSameAs(doubleCounter); + // Note: We no longer get the same instrument instance as these instances are lightweight + // objects backed by storage now. Here we just make sure it doesn't throw to grab + // a second instance. + sdkMeter + .counterBuilder("testDoubleCounter") + .ofDoubles() + .setDescription("My very own counter") + .setUnit("metric tonnes") + .build(); assertThatThrownBy(() -> sdkMeter.counterBuilder("testDoubleCounter").ofDoubles().build()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); assertThatThrownBy( () -> sdkMeter.counterBuilder("testDoubleCounter".toUpperCase()).ofDoubles().build()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); } @Test @@ -214,19 +218,20 @@ class SdkMeterTest { .build(); assertThat(doubleUpDownCounter).isNotNull(); - assertThat( - sdkMeter - .upDownCounterBuilder("testDoubleUpDownCounter") - .ofDoubles() - .setDescription("My very own counter") - .setUnit("metric tonnes") - .build()) - .isSameAs(doubleUpDownCounter); + // Note: We no longer get the same instrument instance as these instances are lightweight + // objects backed by storage now. Here we just make sure it doesn't throw to grab + // a second instance. + sdkMeter + .upDownCounterBuilder("testDoubleUpDownCounter") + .ofDoubles() + .setDescription("My very own counter") + .setUnit("metric tonnes") + .build(); assertThatThrownBy( () -> sdkMeter.upDownCounterBuilder("testDoubleUpDownCounter").ofDoubles().build()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); assertThatThrownBy( () -> sdkMeter @@ -234,7 +239,7 @@ class SdkMeterTest { .ofDoubles() .build()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); } @Test @@ -247,21 +252,22 @@ class SdkMeterTest { .build(); assertThat(doubleValueRecorder).isNotNull(); - assertThat( - sdkMeter - .histogramBuilder("testDoubleValueRecorder") - .setDescription("My very own ValueRecorder") - .setUnit("metric tonnes") - .build()) - .isSameAs(doubleValueRecorder); + // Note: We no longer get the same instrument instance as these instances are lightweight + // objects backed by storage now. Here we just make sure it doesn't throw to grab + // a second instance. + sdkMeter + .histogramBuilder("testDoubleValueRecorder") + .setDescription("My very own ValueRecorder") + .setUnit("metric tonnes") + .build(); assertThatThrownBy(() -> sdkMeter.histogramBuilder("testDoubleValueRecorder").build()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); assertThatThrownBy( () -> sdkMeter.histogramBuilder("testDoubleValueRecorder".toUpperCase()).build()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); } @Test @@ -280,7 +286,7 @@ class SdkMeterTest { .ofDoubles() .buildWithCallback(x -> {})) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); assertThatThrownBy( () -> sdkMeter @@ -288,7 +294,7 @@ class SdkMeterTest { .ofDoubles() .buildWithCallback(x -> {})) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); } @Test @@ -307,7 +313,7 @@ class SdkMeterTest { .ofDoubles() .buildWithCallback(x -> {})) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); assertThatThrownBy( () -> sdkMeter @@ -315,7 +321,7 @@ class SdkMeterTest { .ofDoubles() .buildWithCallback(x -> {})) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); } @Test @@ -329,13 +335,13 @@ class SdkMeterTest { assertThatThrownBy( () -> sdkMeter.gaugeBuilder("doubleValueObserver").buildWithCallback(x -> {})) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); assertThatThrownBy( () -> sdkMeter .gaugeBuilder("doubleValueObserver".toUpperCase()) .buildWithCallback(x -> {})) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Instrument with same name and different descriptor already created."); + .hasMessageContaining("Metric with same name and different descriptor already created."); } } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/AggregatorFactoryTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/AggregatorFactoryTest.java index df1f668bc2..5f1bf093bb 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/AggregatorFactoryTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/AggregatorFactoryTest.java @@ -139,7 +139,7 @@ class AggregatorFactoryTest { "name", "description", "unit", - InstrumentType.VALUE_RECORDER, + InstrumentType.HISTOGRAM, InstrumentValueType.LONG))) .isInstanceOf(DoubleHistogramAggregator.class); assertThat( @@ -150,7 +150,7 @@ class AggregatorFactoryTest { "name", "description", "unit", - InstrumentType.VALUE_RECORDER, + InstrumentType.HISTOGRAM, InstrumentValueType.DOUBLE))) .isInstanceOf(DoubleHistogramAggregator.class); @@ -163,7 +163,7 @@ class AggregatorFactoryTest { "name", "description", "unit", - InstrumentType.VALUE_RECORDER, + InstrumentType.HISTOGRAM, InstrumentValueType.LONG)) .isStateful()) .isFalse(); @@ -177,7 +177,7 @@ class AggregatorFactoryTest { "name", "description", "unit", - InstrumentType.VALUE_RECORDER, + InstrumentType.HISTOGRAM, InstrumentValueType.DOUBLE)) .isStateful()) .isTrue(); diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/CountAggregatorTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/CountAggregatorTest.java index d6c377484c..d3277dccd8 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/CountAggregatorTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/CountAggregatorTest.java @@ -26,22 +26,14 @@ class CountAggregatorTest { Resource.getDefault(), InstrumentationLibraryInfo.empty(), InstrumentDescriptor.create( - "name", - "description", - "unit", - InstrumentType.VALUE_RECORDER, - InstrumentValueType.LONG), + "name", "description", "unit", InstrumentType.HISTOGRAM, InstrumentValueType.LONG), AggregationTemporality.CUMULATIVE); private static final CountAggregator deltaAggregator = new CountAggregator( Resource.getDefault(), InstrumentationLibraryInfo.empty(), InstrumentDescriptor.create( - "name", - "description", - "unit", - InstrumentType.VALUE_RECORDER, - InstrumentValueType.LONG), + "name", "description", "unit", InstrumentType.HISTOGRAM, InstrumentValueType.LONG), AggregationTemporality.DELTA); @Test diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/DoubleHistogramAggregatorTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/DoubleHistogramAggregatorTest.java index 18a9a4847e..f840ed1bf8 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/DoubleHistogramAggregatorTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/DoubleHistogramAggregatorTest.java @@ -32,11 +32,7 @@ public class DoubleHistogramAggregatorTest { Resource.getDefault(), InstrumentationLibraryInfo.empty(), InstrumentDescriptor.create( - "name", - "description", - "unit", - InstrumentType.VALUE_RECORDER, - InstrumentValueType.LONG), + "name", "description", "unit", InstrumentType.HISTOGRAM, InstrumentValueType.LONG), boundaries, /* stateful= */ false); diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/DoubleLastValueAggregatorTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/DoubleLastValueAggregatorTest.java index a335db61c2..014e81521c 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/DoubleLastValueAggregatorTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/DoubleLastValueAggregatorTest.java @@ -28,7 +28,7 @@ class DoubleLastValueAggregatorTest { "name", "description", "unit", - InstrumentType.VALUE_OBSERVER, + InstrumentType.OBSERVABLE_GAUGE, InstrumentValueType.DOUBLE)); @Test diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/DoubleMinMaxSumCountAggregatorTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/DoubleMinMaxSumCountAggregatorTest.java index 114bf70253..e57bd2a4b0 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/DoubleMinMaxSumCountAggregatorTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/DoubleMinMaxSumCountAggregatorTest.java @@ -31,11 +31,7 @@ class DoubleMinMaxSumCountAggregatorTest { Resource.getDefault(), InstrumentationLibraryInfo.empty(), InstrumentDescriptor.create( - "name", - "description", - "unit", - InstrumentType.VALUE_RECORDER, - InstrumentValueType.DOUBLE)); + "name", "description", "unit", InstrumentType.HISTOGRAM, InstrumentValueType.DOUBLE)); @Test void createHandle() { diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/LongLastValueAggregatorTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/LongLastValueAggregatorTest.java index 5eb7b3775e..60b76794b2 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/LongLastValueAggregatorTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/LongLastValueAggregatorTest.java @@ -29,7 +29,7 @@ class LongLastValueAggregatorTest { "name", "description", "unit", - InstrumentType.VALUE_OBSERVER, + InstrumentType.OBSERVABLE_GAUGE, InstrumentValueType.LONG)); @Test diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/LongMinMaxSumCountAggregatorTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/LongMinMaxSumCountAggregatorTest.java index 3b49ffe8b4..85cbc38f12 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/LongMinMaxSumCountAggregatorTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/aggregator/LongMinMaxSumCountAggregatorTest.java @@ -31,11 +31,7 @@ class LongMinMaxSumCountAggregatorTest { Resource.getDefault(), InstrumentationLibraryInfo.empty(), InstrumentDescriptor.create( - "name", - "description", - "unit", - InstrumentType.VALUE_RECORDER, - InstrumentValueType.LONG)); + "name", "description", "unit", InstrumentType.HISTOGRAM, InstrumentValueType.LONG)); @Test void createHandle() { diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AsynchronousInstrumentAccumulatorTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorageTest.java similarity index 84% rename from sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AsynchronousInstrumentAccumulatorTest.java rename to sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorageTest.java index 349064ab1f..798edbf51b 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/AsynchronousInstrumentAccumulatorTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/AsynchronousMetricStorageTest.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.sdk.metrics; +package io.opentelemetry.sdk.metrics.internal.state; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.context.Context; @@ -12,6 +12,7 @@ import io.opentelemetry.sdk.metrics.aggregator.AggregatorFactory; import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.common.InstrumentType; import io.opentelemetry.sdk.metrics.common.InstrumentValueType; +import io.opentelemetry.sdk.metrics.internal.view.ViewRegistry; import io.opentelemetry.sdk.metrics.processor.LabelsProcessor; import io.opentelemetry.sdk.metrics.view.InstrumentSelector; import io.opentelemetry.sdk.metrics.view.View; @@ -21,7 +22,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; -public class AsynchronousInstrumentAccumulatorTest { +public class AsynchronousMetricStorageTest { private final TestClock testClock = TestClock.create(); private MeterProviderSharedState meterProviderSharedState; private final MeterSharedState meterSharedState = @@ -43,7 +44,7 @@ public class AsynchronousInstrumentAccumulatorTest { ViewRegistry.builder() .addView( InstrumentSelector.builder() - .setInstrumentType(InstrumentType.VALUE_OBSERVER) + .setInstrumentType(InstrumentType.OBSERVABLE_GAUGE) .build(), View.builder() .setAggregatorFactory(AggregatorFactory.lastValue()) @@ -58,33 +59,33 @@ public class AsynchronousInstrumentAccumulatorTest { @Test void doubleAsynchronousAccumulator_LabelsProcessor_used() { - AsynchronousInstrumentAccumulator.doubleAsynchronousAccumulator( + AsynchronousMetricStorage.doubleAsynchronousAccumulator( meterProviderSharedState, meterSharedState, InstrumentDescriptor.create( "name", "description", "unit", - InstrumentType.VALUE_OBSERVER, + InstrumentType.OBSERVABLE_GAUGE, InstrumentValueType.DOUBLE), value -> value.observe(1.0, Attributes.empty())) - .collectAll(testClock.nanoTime()); + .collectAndReset(0, testClock.now()); Mockito.verify(spyLabelProcessor).onLabelsBound(Context.current(), Attributes.empty()); } @Test void longAsynchronousAccumulator_LabelsProcessor_used() { - AsynchronousInstrumentAccumulator.longAsynchronousAccumulator( + AsynchronousMetricStorage.longAsynchronousAccumulator( meterProviderSharedState, meterSharedState, InstrumentDescriptor.create( "name", "description", "unit", - InstrumentType.VALUE_OBSERVER, + InstrumentType.OBSERVABLE_GAUGE, InstrumentValueType.LONG), value -> value.observe(1, Attributes.empty())) - .collectAll(testClock.nanoTime()); + .collectAndReset(0, testClock.nanoTime()); Mockito.verify(spyLabelProcessor).onLabelsBound(Context.current(), Attributes.empty()); } } 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 new file mode 100644 index 0000000000..af1b091e96 --- /dev/null +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/MetricStorageRegistryTest.java @@ -0,0 +1,116 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.metrics.internal.state; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link MetricStorageRegistry}. */ +class MetricStorageRegistryTest { + private static final MetricDescriptor METRIC_DESCRIPTOR = + MetricDescriptor.create("name", "description", "1"); + private static final MetricDescriptor OTHER_METRIC_DESCRIPTOR = + MetricDescriptor.create("name", "other_description", "1"); + + @Test + void register() { + MeterSharedState meterSharedState = MeterSharedState.create(InstrumentationLibraryInfo.empty()); + TestMetricStorage testInstrument = new TestMetricStorage(METRIC_DESCRIPTOR); + assertThat(meterSharedState.getMetricStorageRegistry().register(testInstrument)) + .isSameAs(testInstrument); + assertThat(meterSharedState.getMetricStorageRegistry().register(testInstrument)) + .isSameAs(testInstrument); + assertThat( + meterSharedState + .getMetricStorageRegistry() + .register(new TestMetricStorage(METRIC_DESCRIPTOR))) + .isSameAs(testInstrument); + } + + @Test + void register_OtherDescriptor() { + MeterSharedState meterSharedState = MeterSharedState.create(InstrumentationLibraryInfo.empty()); + TestMetricStorage testInstrument = new TestMetricStorage(METRIC_DESCRIPTOR); + assertThat(meterSharedState.getMetricStorageRegistry().register(testInstrument)) + .isSameAs(testInstrument); + + assertThatThrownBy( + () -> + meterSharedState + .getMetricStorageRegistry() + .register(new TestMetricStorage(OTHER_METRIC_DESCRIPTOR))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Metric with same name and different descriptor already created."); + } + + @Test + void register_OtherInstance() { + MeterSharedState meterSharedState = MeterSharedState.create(InstrumentationLibraryInfo.empty()); + TestMetricStorage testInstrument = new TestMetricStorage(METRIC_DESCRIPTOR); + assertThat(meterSharedState.getMetricStorageRegistry().register(testInstrument)) + .isSameAs(testInstrument); + + assertThatThrownBy( + () -> + meterSharedState + .getMetricStorageRegistry() + .register(new OtherTestMetricStorage(METRIC_DESCRIPTOR))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Metric with same name and different instrument already created."); + } + + private static final class TestMetricStorage implements WriteableMetricStorage { + private final MetricDescriptor descriptor; + + TestMetricStorage(MetricDescriptor descriptor) { + this.descriptor = descriptor; + } + + @Override + public MetricDescriptor getMetricDescriptor() { + return descriptor; + } + + @Override + public MetricData collectAndReset(long startEpochNanos, long epochNanos) { + return null; + } + + @Override + public BoundStorageHandle bind(Attributes attributes) { + return null; + } + } + + private static final class OtherTestMetricStorage implements WriteableMetricStorage { + private final MetricDescriptor descriptor; + + OtherTestMetricStorage(MetricDescriptor descriptor) { + this.descriptor = descriptor; + } + + @Override + public MetricDescriptor getMetricDescriptor() { + return descriptor; + } + + @Override + public MetricData collectAndReset(long startEpochNanos, long epochNanos) { + return null; + } + + @Override + public BoundStorageHandle bind(Attributes attributes) { + return null; + } + } +} diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SynchronousInstrumentAccumulatorTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorageTest.java similarity index 53% rename from sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SynchronousInstrumentAccumulatorTest.java rename to sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorageTest.java index e296cb4694..25e1b032d2 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/SynchronousInstrumentAccumulatorTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/state/SynchronousMetricStorageTest.java @@ -3,9 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.sdk.metrics; +package io.opentelemetry.sdk.metrics.internal.state; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static io.opentelemetry.sdk.testing.assertj.metrics.MetricAssertions.assertThat; import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.common.Attributes; @@ -13,23 +14,24 @@ import io.opentelemetry.context.Context; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.metrics.aggregator.Aggregator; import io.opentelemetry.sdk.metrics.aggregator.AggregatorFactory; -import io.opentelemetry.sdk.metrics.aggregator.AggregatorHandle; import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor; import io.opentelemetry.sdk.metrics.common.InstrumentType; import io.opentelemetry.sdk.metrics.common.InstrumentValueType; import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.internal.descriptor.MetricDescriptor; import io.opentelemetry.sdk.metrics.processor.LabelsProcessor; import io.opentelemetry.sdk.metrics.processor.LabelsProcessorFactory; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.time.TestClock; -import java.util.List; import org.junit.jupiter.api.Test; import org.mockito.Mockito; -public class SynchronousInstrumentAccumulatorTest { +public class SynchronousMetricStorageTest { private static final InstrumentDescriptor DESCRIPTOR = InstrumentDescriptor.create( "name", "description", "unit", InstrumentType.COUNTER, InstrumentValueType.DOUBLE); + private static final MetricDescriptor METRIC_DESCRIPTOR = + MetricDescriptor.create("name", "description", "unit"); private final TestClock testClock = TestClock.create(); private final Aggregator aggregator = AggregatorFactory.lastValue() @@ -41,9 +43,12 @@ public class SynchronousInstrumentAccumulatorTest { @Test void labelsProcessor_used() { LabelsProcessor spyLabelsProcessor = Mockito.spy(this.labelsProcessor); - SynchronousInstrumentAccumulator accumulator = - new SynchronousInstrumentAccumulator<>( - aggregator, new InstrumentProcessor<>(aggregator, testClock.now()), spyLabelsProcessor); + SynchronousMetricStorage accumulator = + new SynchronousMetricStorage<>( + METRIC_DESCRIPTOR, + aggregator, + new InstrumentProcessor<>(aggregator, testClock.now()), + spyLabelsProcessor); accumulator.bind(Attributes.empty()); Mockito.verify(spyLabelsProcessor).onLabelsBound(Context.current(), Attributes.empty()); } @@ -59,44 +64,55 @@ public class SynchronousInstrumentAccumulatorTest { } }; LabelsProcessor spyLabelsProcessor = Mockito.spy(labelsProcessor); - SynchronousInstrumentAccumulator accumulator = - new SynchronousInstrumentAccumulator<>( - aggregator, new InstrumentProcessor<>(aggregator, testClock.now()), spyLabelsProcessor); - AggregatorHandle aggregatorHandle = accumulator.bind(labels); - aggregatorHandle.recordDouble(1); - List md = accumulator.collectAll(testClock.now()); - md.stream() - .flatMap(m -> m.getLongGaugeData().getPoints().stream()) - .forEach( - p -> assertThat(p.getAttributes()).hasSize(1).containsEntry("modifiedK", "modifiedV")); + SynchronousMetricStorage accumulator = + new SynchronousMetricStorage<>( + METRIC_DESCRIPTOR, + aggregator, + new InstrumentProcessor<>(aggregator, testClock.now()), + spyLabelsProcessor); + BoundStorageHandle handle = accumulator.bind(labels); + handle.recordDouble(1, labels, Context.root()); + MetricData md = accumulator.collectAndReset(0, testClock.now()); + assertThat(md) + .hasDoubleGauge() + .points() + .allSatisfy( + p -> + assertThat(p) + .attributes() + .hasSize(2) + .containsEntry("modifiedK", "modifiedV") + .containsEntry("K", "V")); } @Test - void sameAggregator_ForSameLabelSet() { - SynchronousInstrumentAccumulator accumulator = - new SynchronousInstrumentAccumulator<>( - aggregator, new InstrumentProcessor<>(aggregator, testClock.now()), labelsProcessor); - AggregatorHandle aggregatorHandle = - accumulator.bind(Attributes.builder().put("K", "V").build()); - AggregatorHandle duplicateAggregatorHandle = + void sameAggregator_ForSameAttributes() { + SynchronousMetricStorage accumulator = + new SynchronousMetricStorage<>( + METRIC_DESCRIPTOR, + aggregator, + new InstrumentProcessor<>(aggregator, testClock.now()), + labelsProcessor); + BoundStorageHandle handle = accumulator.bind(Attributes.builder().put("K", "V").build()); + BoundStorageHandle duplicateHandle = accumulator.bind(Attributes.builder().put("K", "V").build()); try { - assertThat(duplicateAggregatorHandle).isSameAs(aggregatorHandle); - accumulator.collectAll(testClock.now()); - AggregatorHandle anotherDuplicateAggregatorHandle = + assertThat(duplicateHandle).isSameAs(handle); + accumulator.collectAndReset(0, testClock.now()); + BoundStorageHandle anotherDuplicateAggregatorHandle = accumulator.bind(Attributes.builder().put("K", "V").build()); try { - assertThat(anotherDuplicateAggregatorHandle).isSameAs(aggregatorHandle); + assertThat(anotherDuplicateAggregatorHandle).isSameAs(handle); } finally { anotherDuplicateAggregatorHandle.release(); } } finally { - duplicateAggregatorHandle.release(); - aggregatorHandle.release(); + duplicateHandle.release(); + handle.release(); } - // At this point we should be able to unmap because all references are gone. Because this is an - // internal detail we cannot call collectAll after this anymore. - assertThat(aggregatorHandle.tryUnmap()).isTrue(); + // If we try to collect once all bound references are gone AND no recordings have occurred, we + // should not see any labels (or metric). + assertThat(accumulator.collectAndReset(0, testClock.now())).isNull(); } } diff --git a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/ViewRegistryTest.java b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistryTest.java similarity index 94% rename from sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/ViewRegistryTest.java rename to sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistryTest.java index 008aff8821..b6433902f9 100644 --- a/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/ViewRegistryTest.java +++ b/sdk/metrics/src/test/java/io/opentelemetry/sdk/metrics/internal/view/ViewRegistryTest.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.sdk.metrics; +package io.opentelemetry.sdk.metrics.internal.view; import static org.assertj.core.api.Assertions.assertThat; @@ -154,22 +154,22 @@ class ViewRegistryTest { assertThat( viewRegistry.findView( InstrumentDescriptor.create( - "", "", "", InstrumentType.VALUE_RECORDER, InstrumentValueType.LONG))) + "", "", "", InstrumentType.HISTOGRAM, InstrumentValueType.LONG))) .isSameAs(ViewRegistry.SUMMARY); assertThat( viewRegistry.findView( InstrumentDescriptor.create( - "", "", "", InstrumentType.SUM_OBSERVER, InstrumentValueType.LONG))) + "", "", "", InstrumentType.OBSERVABLE_SUM, InstrumentValueType.LONG))) .isSameAs(ViewRegistry.CUMULATIVE_SUM); assertThat( viewRegistry.findView( InstrumentDescriptor.create( - "", "", "", InstrumentType.VALUE_OBSERVER, InstrumentValueType.LONG))) + "", "", "", InstrumentType.OBSERVABLE_GAUGE, InstrumentValueType.LONG))) .isSameAs(ViewRegistry.LAST_VALUE); assertThat( viewRegistry.findView( InstrumentDescriptor.create( - "", "", "", InstrumentType.UP_DOWN_SUM_OBSERVER, InstrumentValueType.LONG))) + "", "", "", InstrumentType.OBSERVABLE_UP_DOWN_SUM, InstrumentValueType.LONG))) .isSameAs(ViewRegistry.CUMULATIVE_SUM); } }