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
This commit is contained in:
parent
171c62cf05
commit
0752a4bb17
|
|
@ -35,7 +35,7 @@ public enum TestSdk {
|
||||||
.registerView(
|
.registerView(
|
||||||
InstrumentSelector.builder()
|
InstrumentSelector.builder()
|
||||||
.setInstrumentNameRegex(".*histogram_recorder")
|
.setInstrumentNameRegex(".*histogram_recorder")
|
||||||
.setInstrumentType(InstrumentType.VALUE_RECORDER)
|
.setInstrumentType(InstrumentType.HISTOGRAM)
|
||||||
.build(),
|
.build(),
|
||||||
// Histogram buckets the same as the metrics prototype/prometheus.
|
// Histogram buckets the same as the metrics prototype/prometheus.
|
||||||
View.builder()
|
View.builder()
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ public class DoubleHistogramBenchmark {
|
||||||
"name",
|
"name",
|
||||||
"description",
|
"description",
|
||||||
"1",
|
"1",
|
||||||
InstrumentType.VALUE_RECORDER,
|
InstrumentType.HISTOGRAM,
|
||||||
InstrumentValueType.DOUBLE));
|
InstrumentValueType.DOUBLE));
|
||||||
private AggregatorHandle<HistogramAccumulation> aggregatorHandle;
|
private AggregatorHandle<HistogramAccumulation> aggregatorHandle;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ public class DoubleMinMaxSumCountBenchmark {
|
||||||
"name",
|
"name",
|
||||||
"description",
|
"description",
|
||||||
"1",
|
"1",
|
||||||
InstrumentType.VALUE_RECORDER,
|
InstrumentType.HISTOGRAM,
|
||||||
InstrumentValueType.DOUBLE));
|
InstrumentValueType.DOUBLE));
|
||||||
private AggregatorHandle<MinMaxSumCountAccumulation> aggregatorHandle;
|
private AggregatorHandle<MinMaxSumCountAccumulation> aggregatorHandle;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,7 @@ public class LongMinMaxSumCountBenchmark {
|
||||||
Resource.getDefault(),
|
Resource.getDefault(),
|
||||||
InstrumentationLibraryInfo.empty(),
|
InstrumentationLibraryInfo.empty(),
|
||||||
InstrumentDescriptor.create(
|
InstrumentDescriptor.create(
|
||||||
"name",
|
"name", "description", "1", InstrumentType.HISTOGRAM, InstrumentValueType.LONG));
|
||||||
"description",
|
|
||||||
"1",
|
|
||||||
InstrumentType.VALUE_RECORDER,
|
|
||||||
InstrumentValueType.LONG));
|
|
||||||
private AggregatorHandle<MinMaxSumCountAccumulation> aggregatorHandle;
|
private AggregatorHandle<MinMaxSumCountAccumulation> aggregatorHandle;
|
||||||
|
|
||||||
@Setup(Level.Trial)
|
@Setup(Level.Trial)
|
||||||
|
|
|
||||||
|
|
@ -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<MetricData> collectAll(long epochNanos);
|
|
||||||
|
|
||||||
static <T> Aggregator<T> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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<MetricData> collectAll(long epochNanos) {
|
|
||||||
return accumulator.collectAll(epochNanos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,8 +6,6 @@
|
||||||
package io.opentelemetry.sdk.metrics;
|
package io.opentelemetry.sdk.metrics;
|
||||||
|
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor;
|
import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor;
|
||||||
import io.opentelemetry.sdk.metrics.data.MetricData;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
abstract class AbstractInstrument implements Instrument {
|
abstract class AbstractInstrument implements Instrument {
|
||||||
|
|
||||||
|
|
@ -22,11 +20,6 @@ abstract class AbstractInstrument implements Instrument {
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Collects records from all the entries (labelSet, Bound) that changed since the previous call.
|
|
||||||
*/
|
|
||||||
abstract List<MetricData> collectAll(long epochNanos);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) {
|
if (this == o) {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@ import io.opentelemetry.api.metrics.ObservableLongMeasurement;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor;
|
import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentValueType;
|
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.BiFunction;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
|
@ -58,43 +61,25 @@ public abstract class AbstractInstrumentBuilder<BuilderT extends AbstractInstrum
|
||||||
final <I extends AbstractInstrument> I buildSynchronousInstrument(
|
final <I extends AbstractInstrument> I buildSynchronousInstrument(
|
||||||
InstrumentType type,
|
InstrumentType type,
|
||||||
InstrumentValueType valueType,
|
InstrumentValueType valueType,
|
||||||
BiFunction<InstrumentDescriptor, SynchronousInstrumentAccumulator<?>, I> instrumentFactory) {
|
BiFunction<InstrumentDescriptor, WriteableMetricStorage, I> instrumentFactory) {
|
||||||
InstrumentDescriptor descriptor = makeDescriptor(type, valueType);
|
InstrumentDescriptor descriptor = makeDescriptor(type, valueType);
|
||||||
return meterSharedState
|
WriteableMetricStorage storage =
|
||||||
.getInstrumentRegistry()
|
meterSharedState.registerSynchronousMetricStorage(descriptor, meterProviderSharedState);
|
||||||
.register(
|
return instrumentFactory.apply(descriptor, storage);
|
||||||
instrumentFactory.apply(
|
|
||||||
descriptor,
|
|
||||||
SynchronousInstrumentAccumulator.create(
|
|
||||||
meterProviderSharedState, meterSharedState, descriptor)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final <I extends AbstractInstrument> I buildDoubleAsynchronousInstrument(
|
final void registerDoubleAsynchronousInstrument(
|
||||||
InstrumentType type,
|
InstrumentType type, Consumer<ObservableDoubleMeasurement> updater) {
|
||||||
Consumer<ObservableDoubleMeasurement> updater,
|
|
||||||
BiFunction<InstrumentDescriptor, AsynchronousInstrumentAccumulator, I> instrumentFactory) {
|
|
||||||
InstrumentDescriptor descriptor = makeDescriptor(type, InstrumentValueType.DOUBLE);
|
InstrumentDescriptor descriptor = makeDescriptor(type, InstrumentValueType.DOUBLE);
|
||||||
return meterSharedState
|
meterSharedState.registerDoubleAsynchronousInstrument(
|
||||||
.getInstrumentRegistry()
|
descriptor, meterProviderSharedState, updater);
|
||||||
.register(
|
|
||||||
instrumentFactory.apply(
|
|
||||||
descriptor,
|
|
||||||
AsynchronousInstrumentAccumulator.doubleAsynchronousAccumulator(
|
|
||||||
meterProviderSharedState, meterSharedState, descriptor, updater)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final <I extends AbstractInstrument> I buildLongAsynchronousInstrument(
|
final void registerLongAsynchronousInstrument(
|
||||||
InstrumentType type,
|
InstrumentType type, Consumer<ObservableLongMeasurement> updater) {
|
||||||
Consumer<ObservableLongMeasurement> updater,
|
|
||||||
BiFunction<InstrumentDescriptor, AsynchronousInstrumentAccumulator, I> instrumentFactory) {
|
|
||||||
InstrumentDescriptor descriptor = makeDescriptor(type, InstrumentValueType.LONG);
|
InstrumentDescriptor descriptor = makeDescriptor(type, InstrumentValueType.LONG);
|
||||||
return meterSharedState
|
meterSharedState.registerLongAsynchronousInstrument(
|
||||||
.getInstrumentRegistry()
|
descriptor, meterProviderSharedState, updater);
|
||||||
.register(
|
|
||||||
instrumentFactory.apply(
|
|
||||||
descriptor,
|
|
||||||
AsynchronousInstrumentAccumulator.longAsynchronousAccumulator(
|
|
||||||
meterProviderSharedState, meterSharedState, descriptor, updater)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
|
|
|
||||||
|
|
@ -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<MetricData> collectAll(long epochNanos) {
|
|
||||||
return accumulator.collectAll(epochNanos);
|
|
||||||
}
|
|
||||||
|
|
||||||
AggregatorHandle<?> acquireHandle(Attributes labels) {
|
|
||||||
return accumulator.bind(labels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -12,27 +12,32 @@ import io.opentelemetry.api.metrics.DoubleCounterBuilder;
|
||||||
import io.opentelemetry.api.metrics.LongCounterBuilder;
|
import io.opentelemetry.api.metrics.LongCounterBuilder;
|
||||||
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
|
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
|
||||||
import io.opentelemetry.context.Context;
|
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.InstrumentDescriptor;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentValueType;
|
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;
|
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(
|
private DoubleCounterSdk(InstrumentDescriptor descriptor, WriteableMetricStorage storage) {
|
||||||
InstrumentDescriptor descriptor, SynchronousInstrumentAccumulator<?> accumulator) {
|
super(descriptor);
|
||||||
super(descriptor, accumulator);
|
this.storage = storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(double increment, Attributes labels, Context context) {
|
public void add(double increment, Attributes attributes, Context context) {
|
||||||
AggregatorHandle<?> aggregatorHandle = acquireHandle(labels);
|
BoundStorageHandle aggregatorHandle = storage.bind(attributes);
|
||||||
try {
|
try {
|
||||||
if (increment < 0) {
|
if (increment < 0) {
|
||||||
throw new IllegalArgumentException("Counters can only increase");
|
throw new IllegalArgumentException("Counters can only increase");
|
||||||
}
|
}
|
||||||
aggregatorHandle.recordDouble(increment);
|
|
||||||
|
aggregatorHandle.recordDouble(increment, attributes, context);
|
||||||
} finally {
|
} finally {
|
||||||
aggregatorHandle.release();
|
aggregatorHandle.release();
|
||||||
}
|
}
|
||||||
|
|
@ -49,15 +54,17 @@ final class DoubleCounterSdk extends AbstractSynchronousInstrument implements Do
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BoundDoubleCounter bind(Attributes labels) {
|
public BoundDoubleCounter bind(Attributes attributes) {
|
||||||
return new BoundInstrument(acquireHandle(labels));
|
return new BoundInstrument(storage.bind(attributes), attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class BoundInstrument implements BoundDoubleCounter {
|
static final class BoundInstrument implements BoundDoubleCounter {
|
||||||
private final AggregatorHandle<?> aggregatorHandle;
|
private final BoundStorageHandle handle;
|
||||||
|
private final Attributes attributes;
|
||||||
|
|
||||||
BoundInstrument(AggregatorHandle<?> aggregatorHandle) {
|
BoundInstrument(BoundStorageHandle handle, Attributes attributes) {
|
||||||
this.aggregatorHandle = aggregatorHandle;
|
this.handle = handle;
|
||||||
|
this.attributes = attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -65,7 +72,7 @@ final class DoubleCounterSdk extends AbstractSynchronousInstrument implements Do
|
||||||
if (increment < 0) {
|
if (increment < 0) {
|
||||||
throw new IllegalArgumentException("Counters can only increase");
|
throw new IllegalArgumentException("Counters can only increase");
|
||||||
}
|
}
|
||||||
aggregatorHandle.recordDouble(increment);
|
handle.recordDouble(increment, attributes, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -75,7 +82,7 @@ final class DoubleCounterSdk extends AbstractSynchronousInstrument implements Do
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unbind() {
|
public void unbind() {
|
||||||
aggregatorHandle.release();
|
handle.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,8 +123,7 @@ final class DoubleCounterSdk extends AbstractSynchronousInstrument implements Do
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void buildWithCallback(Consumer<ObservableDoubleMeasurement> callback) {
|
public void buildWithCallback(Consumer<ObservableDoubleMeasurement> callback) {
|
||||||
buildDoubleAsynchronousInstrument(
|
registerDoubleAsynchronousInstrument(InstrumentType.OBSERVABLE_SUM, callback);
|
||||||
InstrumentType.SUM_OBSERVER, callback, DoubleSumObserverSdk::new);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<DoubleGaugeBuilderSdk>
|
||||||
|
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<ObservableDoubleMeasurement> callback) {
|
||||||
|
registerDoubleAsynchronousInstrument(InstrumentType.OBSERVABLE_GAUGE, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,32 +11,30 @@ import io.opentelemetry.api.metrics.DoubleHistogram;
|
||||||
import io.opentelemetry.api.metrics.DoubleHistogramBuilder;
|
import io.opentelemetry.api.metrics.DoubleHistogramBuilder;
|
||||||
import io.opentelemetry.api.metrics.LongHistogramBuilder;
|
import io.opentelemetry.api.metrics.LongHistogramBuilder;
|
||||||
import io.opentelemetry.context.Context;
|
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.InstrumentDescriptor;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentValueType;
|
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
|
final class DoubleHistogramSdk extends AbstractInstrument implements DoubleHistogram {
|
||||||
implements DoubleHistogram {
|
private final WriteableMetricStorage storage;
|
||||||
|
|
||||||
private DoubleValueRecorderSdk(
|
private DoubleHistogramSdk(InstrumentDescriptor descriptor, WriteableMetricStorage storage) {
|
||||||
InstrumentDescriptor descriptor, SynchronousInstrumentAccumulator<?> accumulator) {
|
super(descriptor);
|
||||||
super(descriptor, accumulator);
|
this.storage = storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void record(double value, Attributes labels, Context context) {
|
public void record(double value, Attributes attributes, Context context) {
|
||||||
AggregatorHandle<?> aggregatorHandle = acquireHandle(labels);
|
storage.recordDouble(value, attributes, context);
|
||||||
try {
|
|
||||||
aggregatorHandle.recordDouble(value);
|
|
||||||
} finally {
|
|
||||||
aggregatorHandle.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void record(double value, Attributes labels) {
|
public void record(double value, Attributes attributes) {
|
||||||
record(value, labels, Context.current());
|
record(value, attributes, Context.current());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -45,20 +43,22 @@ final class DoubleValueRecorderSdk extends AbstractSynchronousInstrument
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BoundDoubleHistogram bind(Attributes labels) {
|
public BoundDoubleHistogram bind(Attributes attributes) {
|
||||||
return new BoundInstrument(acquireHandle(labels));
|
return new BoundInstrument(storage.bind(attributes), attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class BoundInstrument implements BoundDoubleHistogram {
|
static final class BoundInstrument implements BoundDoubleHistogram {
|
||||||
private final AggregatorHandle<?> aggregatorHandle;
|
private final BoundStorageHandle aggregatorHandle;
|
||||||
|
private final Attributes attributes;
|
||||||
|
|
||||||
BoundInstrument(AggregatorHandle<?> aggregatorHandle) {
|
BoundInstrument(BoundStorageHandle handle, Attributes attributes) {
|
||||||
this.aggregatorHandle = aggregatorHandle;
|
this.aggregatorHandle = handle;
|
||||||
|
this.attributes = attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void record(double value, Context context) {
|
public void record(double value, Context context) {
|
||||||
aggregatorHandle.recordDouble(value);
|
aggregatorHandle.recordDouble(value, attributes, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -72,7 +72,7 @@ final class DoubleValueRecorderSdk extends AbstractSynchronousInstrument
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class Builder extends AbstractInstrumentBuilder<DoubleValueRecorderSdk.Builder>
|
static final class Builder extends AbstractInstrumentBuilder<DoubleHistogramSdk.Builder>
|
||||||
implements DoubleHistogramBuilder {
|
implements DoubleHistogramBuilder {
|
||||||
|
|
||||||
Builder(
|
Builder(
|
||||||
|
|
@ -97,14 +97,14 @@ final class DoubleValueRecorderSdk extends AbstractSynchronousInstrument
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DoubleValueRecorderSdk build() {
|
public DoubleHistogramSdk build() {
|
||||||
return buildSynchronousInstrument(
|
return buildSynchronousInstrument(
|
||||||
InstrumentType.VALUE_RECORDER, InstrumentValueType.DOUBLE, DoubleValueRecorderSdk::new);
|
InstrumentType.HISTOGRAM, InstrumentValueType.DOUBLE, DoubleHistogramSdk::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LongHistogramBuilder ofLongs() {
|
public LongHistogramBuilder ofLongs() {
|
||||||
return swapBuilder(LongValueRecorderSdk.Builder::new);
|
return swapBuilder(LongHistogramSdk.Builder::new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -12,28 +12,26 @@ import io.opentelemetry.api.metrics.DoubleUpDownCounterBuilder;
|
||||||
import io.opentelemetry.api.metrics.LongUpDownCounterBuilder;
|
import io.opentelemetry.api.metrics.LongUpDownCounterBuilder;
|
||||||
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
|
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
|
||||||
import io.opentelemetry.context.Context;
|
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.InstrumentDescriptor;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentValueType;
|
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;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
final class DoubleUpDownCounterSdk extends AbstractSynchronousInstrument
|
final class DoubleUpDownCounterSdk extends AbstractInstrument implements DoubleUpDownCounter {
|
||||||
implements DoubleUpDownCounter {
|
private final WriteableMetricStorage storage;
|
||||||
|
|
||||||
private DoubleUpDownCounterSdk(
|
private DoubleUpDownCounterSdk(InstrumentDescriptor descriptor, WriteableMetricStorage storage) {
|
||||||
InstrumentDescriptor descriptor, SynchronousInstrumentAccumulator<?> accumulator) {
|
super(descriptor);
|
||||||
super(descriptor, accumulator);
|
this.storage = storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(double increment, Attributes labels, Context context) {
|
public void add(double increment, Attributes attributes, Context context) {
|
||||||
AggregatorHandle<?> aggregatorHandle = acquireHandle(labels);
|
storage.recordDouble(increment, attributes, context);
|
||||||
try {
|
|
||||||
aggregatorHandle.recordDouble(increment);
|
|
||||||
} finally {
|
|
||||||
aggregatorHandle.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -47,20 +45,22 @@ final class DoubleUpDownCounterSdk extends AbstractSynchronousInstrument
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BoundDoubleUpDownCounter bind(Attributes labels) {
|
public BoundDoubleUpDownCounter bind(Attributes attributes) {
|
||||||
return new BoundInstrument(acquireHandle(labels));
|
return new BoundInstrument(storage.bind(attributes), attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class BoundInstrument implements BoundDoubleUpDownCounter {
|
static final class BoundInstrument implements BoundDoubleUpDownCounter {
|
||||||
private final AggregatorHandle<?> aggregatorHandle;
|
private final BoundStorageHandle handle;
|
||||||
|
private final Attributes attributes;
|
||||||
|
|
||||||
BoundInstrument(AggregatorHandle<?> aggregatorHandle) {
|
BoundInstrument(BoundStorageHandle handle, Attributes attributes) {
|
||||||
this.aggregatorHandle = aggregatorHandle;
|
this.handle = handle;
|
||||||
|
this.attributes = attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(double increment, Context context) {
|
public void add(double increment, Context context) {
|
||||||
aggregatorHandle.recordDouble(increment);
|
handle.recordDouble(increment, attributes, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -70,7 +70,7 @@ final class DoubleUpDownCounterSdk extends AbstractSynchronousInstrument
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unbind() {
|
public void unbind() {
|
||||||
aggregatorHandle.release();
|
handle.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,8 +111,7 @@ final class DoubleUpDownCounterSdk extends AbstractSynchronousInstrument
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void buildWithCallback(Consumer<ObservableDoubleMeasurement> callback) {
|
public void buildWithCallback(Consumer<ObservableDoubleMeasurement> callback) {
|
||||||
buildDoubleAsynchronousInstrument(
|
registerDoubleAsynchronousInstrument(InstrumentType.OBSERVABLE_UP_DOWN_SUM, callback);
|
||||||
InstrumentType.UP_DOWN_SUM_OBSERVER, callback, DoubleUpDownSumObserverSdk::new);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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<DoubleValueObserverSdk.Builder>
|
|
||||||
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<ObservableDoubleMeasurement> callback) {
|
|
||||||
buildDoubleAsynchronousInstrument(
|
|
||||||
InstrumentType.VALUE_OBSERVER, callback, DoubleValueObserverSdk::new);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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.
|
|
||||||
*
|
|
||||||
* <p>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<String, AbstractInstrument> 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 extends AbstractInstrument> 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<AbstractInstrument> getInstruments() {
|
|
||||||
return Collections.unmodifiableCollection(new ArrayList<>(registry.values()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -12,30 +12,29 @@ import io.opentelemetry.api.metrics.LongCounter;
|
||||||
import io.opentelemetry.api.metrics.LongCounterBuilder;
|
import io.opentelemetry.api.metrics.LongCounterBuilder;
|
||||||
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
|
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
|
||||||
import io.opentelemetry.context.Context;
|
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.InstrumentDescriptor;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentValueType;
|
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;
|
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(
|
private LongCounterSdk(InstrumentDescriptor descriptor, WriteableMetricStorage storage) {
|
||||||
InstrumentDescriptor descriptor, SynchronousInstrumentAccumulator<?> accumulator) {
|
super(descriptor);
|
||||||
super(descriptor, accumulator);
|
this.storage = storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(long increment, Attributes labels, Context context) {
|
public void add(long increment, Attributes attributes, Context context) {
|
||||||
AggregatorHandle<?> aggregatorHandle = acquireHandle(labels);
|
if (increment < 0) {
|
||||||
try {
|
throw new IllegalArgumentException("Counters can only increase");
|
||||||
if (increment < 0) {
|
|
||||||
throw new IllegalArgumentException("Counters can only increase");
|
|
||||||
}
|
|
||||||
aggregatorHandle.recordLong(increment);
|
|
||||||
} finally {
|
|
||||||
aggregatorHandle.release();
|
|
||||||
}
|
}
|
||||||
|
storage.recordLong(increment, attributes, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -49,15 +48,17 @@ final class LongCounterSdk extends AbstractSynchronousInstrument implements Long
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BoundLongCounter bind(Attributes labels) {
|
public BoundLongCounter bind(Attributes attributes) {
|
||||||
return new BoundInstrument(acquireHandle(labels));
|
return new BoundInstrument(storage.bind(attributes), attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class BoundInstrument implements BoundLongCounter {
|
static final class BoundInstrument implements BoundLongCounter {
|
||||||
private final AggregatorHandle<?> aggregatorHandle;
|
private final BoundStorageHandle handle;
|
||||||
|
private final Attributes attributes;
|
||||||
|
|
||||||
BoundInstrument(AggregatorHandle<?> aggregatorHandle) {
|
BoundInstrument(BoundStorageHandle handle, Attributes attributes) {
|
||||||
this.aggregatorHandle = aggregatorHandle;
|
this.handle = handle;
|
||||||
|
this.attributes = attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -65,7 +66,7 @@ final class LongCounterSdk extends AbstractSynchronousInstrument implements Long
|
||||||
if (increment < 0) {
|
if (increment < 0) {
|
||||||
throw new IllegalArgumentException("Counters can only increase");
|
throw new IllegalArgumentException("Counters can only increase");
|
||||||
}
|
}
|
||||||
aggregatorHandle.recordLong(increment);
|
handle.recordLong(increment, attributes, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -75,7 +76,7 @@ final class LongCounterSdk extends AbstractSynchronousInstrument implements Long
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unbind() {
|
public void unbind() {
|
||||||
aggregatorHandle.release();
|
handle.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,8 +117,7 @@ final class LongCounterSdk extends AbstractSynchronousInstrument implements Long
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void buildWithCallback(Consumer<ObservableLongMeasurement> callback) {
|
public void buildWithCallback(Consumer<ObservableLongMeasurement> callback) {
|
||||||
buildLongAsynchronousInstrument(
|
registerLongAsynchronousInstrument(InstrumentType.OBSERVABLE_SUM, callback);
|
||||||
InstrumentType.SUM_OBSERVER, callback, LongSumObserverSdk::new);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<LongGaugeBuilderSdk>
|
||||||
|
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<ObservableLongMeasurement> callback) {
|
||||||
|
registerLongAsynchronousInstrument(InstrumentType.OBSERVABLE_GAUGE, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,26 +11,25 @@ import io.opentelemetry.api.metrics.DoubleHistogramBuilder;
|
||||||
import io.opentelemetry.api.metrics.LongHistogram;
|
import io.opentelemetry.api.metrics.LongHistogram;
|
||||||
import io.opentelemetry.api.metrics.LongHistogramBuilder;
|
import io.opentelemetry.api.metrics.LongHistogramBuilder;
|
||||||
import io.opentelemetry.context.Context;
|
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.InstrumentDescriptor;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentValueType;
|
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(
|
private LongHistogramSdk(InstrumentDescriptor descriptor, WriteableMetricStorage storage) {
|
||||||
InstrumentDescriptor descriptor, SynchronousInstrumentAccumulator<?> accumulator) {
|
super(descriptor);
|
||||||
super(descriptor, accumulator);
|
this.storage = storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void record(long value, Attributes attributes, Context context) {
|
public void record(long value, Attributes attributes, Context context) {
|
||||||
AggregatorHandle<?> aggregatorHandle = acquireHandle(attributes);
|
storage.recordLong(value, attributes, context);
|
||||||
try {
|
|
||||||
aggregatorHandle.recordLong(value);
|
|
||||||
} finally {
|
|
||||||
aggregatorHandle.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -45,19 +44,21 @@ final class LongValueRecorderSdk extends AbstractSynchronousInstrument implement
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BoundLongHistogram bind(Attributes attributes) {
|
public BoundLongHistogram bind(Attributes attributes) {
|
||||||
return new BoundInstrument(acquireHandle(attributes));
|
return new BoundInstrument(storage.bind(attributes), attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class BoundInstrument implements BoundLongHistogram {
|
static final class BoundInstrument implements BoundLongHistogram {
|
||||||
private final AggregatorHandle<?> aggregatorHandle;
|
private final BoundStorageHandle handle;
|
||||||
|
private final Attributes attributes;
|
||||||
|
|
||||||
BoundInstrument(AggregatorHandle<?> aggregatorHandle) {
|
BoundInstrument(BoundStorageHandle handle, Attributes attributes) {
|
||||||
this.aggregatorHandle = aggregatorHandle;
|
this.handle = handle;
|
||||||
|
this.attributes = attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void record(long value, Context context) {
|
public void record(long value, Context context) {
|
||||||
aggregatorHandle.recordLong(value);
|
handle.recordLong(value, attributes, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -67,11 +68,11 @@ final class LongValueRecorderSdk extends AbstractSynchronousInstrument implement
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unbind() {
|
public void unbind() {
|
||||||
aggregatorHandle.release();
|
handle.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class Builder extends AbstractInstrumentBuilder<LongValueRecorderSdk.Builder>
|
static final class Builder extends AbstractInstrumentBuilder<LongHistogramSdk.Builder>
|
||||||
implements LongHistogramBuilder {
|
implements LongHistogramBuilder {
|
||||||
|
|
||||||
Builder(
|
Builder(
|
||||||
|
|
@ -96,14 +97,14 @@ final class LongValueRecorderSdk extends AbstractSynchronousInstrument implement
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LongValueRecorderSdk build() {
|
public LongHistogramSdk build() {
|
||||||
return buildSynchronousInstrument(
|
return buildSynchronousInstrument(
|
||||||
InstrumentType.VALUE_RECORDER, InstrumentValueType.LONG, LongValueRecorderSdk::new);
|
InstrumentType.HISTOGRAM, InstrumentValueType.LONG, LongHistogramSdk::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DoubleHistogramBuilder ofDoubles() {
|
public DoubleHistogramBuilder ofDoubles() {
|
||||||
return swapBuilder(DoubleValueRecorderSdk.Builder::new);
|
return swapBuilder(DoubleHistogramSdk.Builder::new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -12,28 +12,26 @@ import io.opentelemetry.api.metrics.LongUpDownCounter;
|
||||||
import io.opentelemetry.api.metrics.LongUpDownCounterBuilder;
|
import io.opentelemetry.api.metrics.LongUpDownCounterBuilder;
|
||||||
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
|
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
|
||||||
import io.opentelemetry.context.Context;
|
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.InstrumentDescriptor;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentValueType;
|
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;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
final class LongUpDownCounterSdk extends AbstractSynchronousInstrument
|
final class LongUpDownCounterSdk extends AbstractInstrument implements LongUpDownCounter {
|
||||||
implements LongUpDownCounter {
|
private final WriteableMetricStorage storage;
|
||||||
|
|
||||||
private LongUpDownCounterSdk(
|
private LongUpDownCounterSdk(InstrumentDescriptor descriptor, WriteableMetricStorage storage) {
|
||||||
InstrumentDescriptor descriptor, SynchronousInstrumentAccumulator<?> accumulator) {
|
super(descriptor);
|
||||||
super(descriptor, accumulator);
|
this.storage = storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(long increment, Attributes labels, Context context) {
|
public void add(long increment, Attributes attributes, Context context) {
|
||||||
AggregatorHandle<?> aggregatorHandle = acquireHandle(labels);
|
storage.recordLong(increment, attributes, context);
|
||||||
try {
|
|
||||||
aggregatorHandle.recordLong(increment);
|
|
||||||
} finally {
|
|
||||||
aggregatorHandle.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -47,20 +45,22 @@ final class LongUpDownCounterSdk extends AbstractSynchronousInstrument
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BoundLongUpDownCounter bind(Attributes labels) {
|
public BoundLongUpDownCounter bind(Attributes attributes) {
|
||||||
return new BoundInstrument(acquireHandle(labels));
|
return new BoundInstrument(storage.bind(attributes), attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class BoundInstrument implements BoundLongUpDownCounter {
|
static final class BoundInstrument implements BoundLongUpDownCounter {
|
||||||
private final AggregatorHandle<?> aggregatorHandle;
|
private final BoundStorageHandle handle;
|
||||||
|
private final Attributes attributes;
|
||||||
|
|
||||||
BoundInstrument(AggregatorHandle<?> aggregatorHandle) {
|
BoundInstrument(BoundStorageHandle handle, Attributes attributes) {
|
||||||
this.aggregatorHandle = aggregatorHandle;
|
this.handle = handle;
|
||||||
|
this.attributes = attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(long increment, Context context) {
|
public void add(long increment, Context context) {
|
||||||
aggregatorHandle.recordLong(increment);
|
handle.recordLong(increment, attributes, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -70,7 +70,7 @@ final class LongUpDownCounterSdk extends AbstractSynchronousInstrument
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unbind() {
|
public void unbind() {
|
||||||
aggregatorHandle.release();
|
handle.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,8 +111,7 @@ final class LongUpDownCounterSdk extends AbstractSynchronousInstrument
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void buildWithCallback(Consumer<ObservableLongMeasurement> callback) {
|
public void buildWithCallback(Consumer<ObservableLongMeasurement> callback) {
|
||||||
buildLongAsynchronousInstrument(
|
registerLongAsynchronousInstrument(InstrumentType.OBSERVABLE_UP_DOWN_SUM, callback);
|
||||||
InstrumentType.UP_DOWN_SUM_OBSERVER, callback, LongUpDownSumObserverSdk::new);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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<LongValueObserverSdk.Builder>
|
|
||||||
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<ObservableLongMeasurement> callback) {
|
|
||||||
buildLongAsynchronousInstrument(
|
|
||||||
InstrumentType.VALUE_OBSERVER, callback, LongValueObserverSdk::new);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
@ -12,9 +12,9 @@ import io.opentelemetry.api.metrics.LongUpDownCounterBuilder;
|
||||||
import io.opentelemetry.api.metrics.Meter;
|
import io.opentelemetry.api.metrics.Meter;
|
||||||
import io.opentelemetry.sdk.common.InstrumentationLibraryInfo;
|
import io.opentelemetry.sdk.common.InstrumentationLibraryInfo;
|
||||||
import io.opentelemetry.sdk.metrics.data.MetricData;
|
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.Collection;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/** {@link SdkMeter} is SDK implementation of {@link Meter}. */
|
/** {@link SdkMeter} is SDK implementation of {@link Meter}. */
|
||||||
final class SdkMeter implements Meter {
|
final class SdkMeter implements Meter {
|
||||||
|
|
@ -28,19 +28,14 @@ final class SdkMeter implements Meter {
|
||||||
this.meterSharedState = MeterSharedState.create(instrumentationLibraryInfo);
|
this.meterSharedState = MeterSharedState.create(instrumentationLibraryInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only used in testing....
|
||||||
InstrumentationLibraryInfo getInstrumentationLibraryInfo() {
|
InstrumentationLibraryInfo getInstrumentationLibraryInfo() {
|
||||||
return meterSharedState.getInstrumentationLibraryInfo();
|
return meterSharedState.getInstrumentationLibraryInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Collects all the metric recordings that changed since the previous call. */
|
/** Collects all the metric recordings that changed since the previous call. */
|
||||||
Collection<MetricData> collectAll(long epochNanos) {
|
Collection<MetricData> collectAll(long epochNanos) {
|
||||||
InstrumentRegistry instrumentRegistry = meterSharedState.getInstrumentRegistry();
|
return meterSharedState.collectAll(meterProviderSharedState, epochNanos);
|
||||||
Collection<AbstractInstrument> instruments = instrumentRegistry.getInstruments();
|
|
||||||
List<MetricData> result = new ArrayList<>(instruments.size());
|
|
||||||
for (AbstractInstrument instrument : instruments) {
|
|
||||||
result.addAll(instrument.collectAll(epochNanos));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -55,11 +50,11 @@ final class SdkMeter implements Meter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DoubleHistogramBuilder histogramBuilder(String name) {
|
public DoubleHistogramBuilder histogramBuilder(String name) {
|
||||||
return new DoubleValueRecorderSdk.Builder(meterProviderSharedState, meterSharedState, name);
|
return new DoubleHistogramSdk.Builder(meterProviderSharedState, meterSharedState, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DoubleGaugeBuilder gaugeBuilder(String name) {
|
public DoubleGaugeBuilder gaugeBuilder(String name) {
|
||||||
return new DoubleValueObserverSdk.Builder(meterProviderSharedState, meterSharedState, name);
|
return new DoubleGaugeBuilderSdk(meterProviderSharedState, meterSharedState, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ import io.opentelemetry.sdk.common.Clock;
|
||||||
import io.opentelemetry.sdk.internal.ComponentRegistry;
|
import io.opentelemetry.sdk.internal.ComponentRegistry;
|
||||||
import io.opentelemetry.sdk.metrics.data.MetricData;
|
import io.opentelemetry.sdk.metrics.data.MetricData;
|
||||||
import io.opentelemetry.sdk.metrics.export.MetricProducer;
|
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 io.opentelemetry.sdk.resources.Resource;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ package io.opentelemetry.sdk.metrics;
|
||||||
|
|
||||||
import io.opentelemetry.api.metrics.GlobalMeterProvider;
|
import io.opentelemetry.api.metrics.GlobalMeterProvider;
|
||||||
import io.opentelemetry.sdk.common.Clock;
|
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.InstrumentSelector;
|
||||||
import io.opentelemetry.sdk.metrics.view.View;
|
import io.opentelemetry.sdk.metrics.view.View;
|
||||||
import io.opentelemetry.sdk.resources.Resource;
|
import io.opentelemetry.sdk.resources.Resource;
|
||||||
|
|
|
||||||
|
|
@ -27,17 +27,17 @@ abstract class AbstractSumAggregator<T> extends AbstractAggregator<T> {
|
||||||
instrumentDescriptor,
|
instrumentDescriptor,
|
||||||
resolveStateful(instrumentDescriptor.getType(), temporality));
|
resolveStateful(instrumentDescriptor.getType(), temporality));
|
||||||
InstrumentType type = instrumentDescriptor.getType();
|
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.temporality = temporality;
|
||||||
this.mergeStrategy = resolveMergeStrategy(type, temporality);
|
this.mergeStrategy = resolveMergeStrategy(type, temporality);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve whether the aggregator should be stateful. For the special case {@link
|
* Resolve whether the aggregator should be stateful. For the special case {@link
|
||||||
* InstrumentType#SUM_OBSERVER} and {@link InstrumentType#UP_DOWN_SUM_OBSERVER} instruments, state
|
* InstrumentType#OBSERVABLE_SUM} and {@link InstrumentType#OBSERVABLE_UP_DOWN_SUM} instruments,
|
||||||
* is required if temporality is {@link AggregationTemporality#DELTA}. Because the observed values
|
* state is required if temporality is {@link AggregationTemporality#DELTA}. Because the observed
|
||||||
* are cumulative sums, we must maintain state to compute delta sums between collections. For
|
* values are cumulative sums, we must maintain state to compute delta sums between collections.
|
||||||
* other instruments, state is required if temporality is {@link
|
* For other instruments, state is required if temporality is {@link
|
||||||
* AggregationTemporality#CUMULATIVE}.
|
* AggregationTemporality#CUMULATIVE}.
|
||||||
*
|
*
|
||||||
* @param instrumentType the instrument type
|
* @param instrumentType the instrument type
|
||||||
|
|
@ -46,8 +46,8 @@ abstract class AbstractSumAggregator<T> extends AbstractAggregator<T> {
|
||||||
*/
|
*/
|
||||||
private static boolean resolveStateful(
|
private static boolean resolveStateful(
|
||||||
InstrumentType instrumentType, AggregationTemporality temporality) {
|
InstrumentType instrumentType, AggregationTemporality temporality) {
|
||||||
if (instrumentType == InstrumentType.SUM_OBSERVER
|
if (instrumentType == InstrumentType.OBSERVABLE_SUM
|
||||||
|| instrumentType == InstrumentType.UP_DOWN_SUM_OBSERVER) {
|
|| instrumentType == InstrumentType.OBSERVABLE_UP_DOWN_SUM) {
|
||||||
return temporality == AggregationTemporality.DELTA;
|
return temporality == AggregationTemporality.DELTA;
|
||||||
} else {
|
} else {
|
||||||
return temporality == AggregationTemporality.CUMULATIVE;
|
return temporality == AggregationTemporality.CUMULATIVE;
|
||||||
|
|
@ -57,8 +57,9 @@ abstract class AbstractSumAggregator<T> extends AbstractAggregator<T> {
|
||||||
/**
|
/**
|
||||||
* Resolve the aggregator merge strategy. The merge strategy is SUM in all cases except where
|
* 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
|
* temporality is {@link AggregationTemporality#DELTA} and instrument type is {@link
|
||||||
* InstrumentType#SUM_OBSERVER} or {@link InstrumentType#UP_DOWN_SUM_OBSERVER}. In these special
|
* InstrumentType#OBSERVABLE_SUM} or {@link InstrumentType#OBSERVABLE_UP_DOWN_SUM}. In these
|
||||||
* cases, the observed values are cumulative sums so we must take a diff to compute the delta sum.
|
* 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 instrumentType the instrument type
|
||||||
* @param temporality the temporality
|
* @param temporality the temporality
|
||||||
|
|
@ -67,8 +68,8 @@ abstract class AbstractSumAggregator<T> extends AbstractAggregator<T> {
|
||||||
// Visible for testing
|
// Visible for testing
|
||||||
static MergeStrategy resolveMergeStrategy(
|
static MergeStrategy resolveMergeStrategy(
|
||||||
InstrumentType instrumentType, AggregationTemporality temporality) {
|
InstrumentType instrumentType, AggregationTemporality temporality) {
|
||||||
if ((instrumentType == InstrumentType.SUM_OBSERVER
|
if ((instrumentType == InstrumentType.OBSERVABLE_SUM
|
||||||
|| instrumentType == InstrumentType.UP_DOWN_SUM_OBSERVER)
|
|| instrumentType == InstrumentType.OBSERVABLE_UP_DOWN_SUM)
|
||||||
&& temporality == AggregationTemporality.DELTA) {
|
&& temporality == AggregationTemporality.DELTA) {
|
||||||
return MergeStrategy.DIFF;
|
return MergeStrategy.DIFF;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@
|
||||||
|
|
||||||
package io.opentelemetry.sdk.metrics.aggregator;
|
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 java.util.concurrent.atomic.AtomicLong;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
@ -23,7 +26,7 @@ import javax.annotation.concurrent.ThreadSafe;
|
||||||
* of the bits are used for reference (usage) counting.
|
* of the bits are used for reference (usage) counting.
|
||||||
*/
|
*/
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
public abstract class AggregatorHandle<T> {
|
public abstract class AggregatorHandle<T> implements BoundStorageHandle {
|
||||||
// Atomically counts the number of references (usages) while also keeping a state of
|
// Atomically counts the number of references (usages) while also keeping a state of
|
||||||
// mapped/unmapped into a registry map.
|
// mapped/unmapped into a registry map.
|
||||||
private final AtomicLong refCountMapped;
|
private final AtomicLong refCountMapped;
|
||||||
|
|
@ -50,6 +53,7 @@ public abstract class AggregatorHandle<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Release this {@code Aggregator}. It decreases the reference usage. */
|
/** Release this {@code Aggregator}. It decreases the reference usage. */
|
||||||
|
@Override
|
||||||
public final void release() {
|
public final void release() {
|
||||||
// Every reference adds/removes 2 instead of 1 to avoid changing the mapping bit.
|
// Every reference adds/removes 2 instead of 1 to avoid changing the mapping bit.
|
||||||
refCountMapped.getAndAdd(-2L);
|
refCountMapped.getAndAdd(-2L);
|
||||||
|
|
@ -96,6 +100,11 @@ public abstract class AggregatorHandle<T> {
|
||||||
hasRecordings = true;
|
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
|
* Concrete Aggregator instances should implement this method in order support recordings of long
|
||||||
* values.
|
* values.
|
||||||
|
|
@ -115,6 +124,11 @@ public abstract class AggregatorHandle<T> {
|
||||||
hasRecordings = true;
|
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
|
* Concrete Aggregator instances should implement this method in order support recordings of
|
||||||
* double values.
|
* double values.
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ package io.opentelemetry.sdk.metrics.common;
|
||||||
public enum InstrumentType {
|
public enum InstrumentType {
|
||||||
COUNTER,
|
COUNTER,
|
||||||
UP_DOWN_COUNTER,
|
UP_DOWN_COUNTER,
|
||||||
VALUE_RECORDER,
|
HISTOGRAM,
|
||||||
SUM_OBSERVER,
|
OBSERVABLE_SUM,
|
||||||
UP_DOWN_SUM_OBSERVER,
|
OBSERVABLE_UP_DOWN_SUM,
|
||||||
VALUE_OBSERVER,
|
OBSERVABLE_GAUGE,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
*
|
||||||
|
* <p>Provides equality/identity semantics for detecting duplicate metrics of incompatible.
|
||||||
|
*
|
||||||
|
* <p>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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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.common.Attributes;
|
||||||
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
|
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.aggregator.Aggregator;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor;
|
import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor;
|
||||||
import io.opentelemetry.sdk.metrics.data.MetricData;
|
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.LabelsProcessor;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
final class AsynchronousInstrumentAccumulator extends AbstractAccumulator {
|
/**
|
||||||
|
* Stores aggregated {@link MetricData} for asynchronous instruments.
|
||||||
|
*
|
||||||
|
* <p>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 ReentrantLock collectLock = new ReentrantLock();
|
||||||
private final InstrumentProcessor<?> instrumentProcessor;
|
private final InstrumentProcessor<?> instrumentProcessor;
|
||||||
private final Runnable metricUpdater;
|
private final Runnable metricUpdater;
|
||||||
|
|
||||||
static <T> AsynchronousInstrumentAccumulator doubleAsynchronousAccumulator(
|
/** Constructs storage for {@code double} valued instruments. */
|
||||||
|
public static <T> AsynchronousMetricStorage doubleAsynchronousAccumulator(
|
||||||
MeterProviderSharedState meterProviderSharedState,
|
MeterProviderSharedState meterProviderSharedState,
|
||||||
MeterSharedState meterSharedState,
|
MeterSharedState meterSharedState,
|
||||||
InstrumentDescriptor descriptor,
|
InstrumentDescriptor descriptor,
|
||||||
Consumer<ObservableDoubleMeasurement> metricUpdater) {
|
Consumer<ObservableDoubleMeasurement> metricUpdater) {
|
||||||
Aggregator<T> aggregator =
|
Aggregator<T> aggregator = meterProviderSharedState.getAggregator(meterSharedState, descriptor);
|
||||||
getAggregator(meterProviderSharedState, meterSharedState, descriptor);
|
|
||||||
final InstrumentProcessor<T> instrumentProcessor =
|
final InstrumentProcessor<T> instrumentProcessor =
|
||||||
new InstrumentProcessor<>(aggregator, meterProviderSharedState.getStartEpochNanos());
|
new InstrumentProcessor<>(aggregator, meterProviderSharedState.getStartEpochNanos());
|
||||||
|
|
||||||
final LabelsProcessor labelsProcessor =
|
final LabelsProcessor labelsProcessor =
|
||||||
getLabelsProcessor(meterProviderSharedState, meterSharedState, descriptor);
|
meterProviderSharedState.getLabelsProcessor(meterSharedState, descriptor);
|
||||||
|
|
||||||
final ObservableDoubleMeasurement result =
|
final ObservableDoubleMeasurement result =
|
||||||
new ObservableDoubleMeasurement() {
|
new ObservableDoubleMeasurement() {
|
||||||
|
|
@ -50,22 +57,26 @@ final class AsynchronousInstrumentAccumulator extends AbstractAccumulator {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return new AsynchronousInstrumentAccumulator(
|
return new AsynchronousMetricStorage(
|
||||||
instrumentProcessor, () -> metricUpdater.accept(result));
|
// 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 <T> AsynchronousInstrumentAccumulator longAsynchronousAccumulator(
|
/** Constructs storage for {@code long} valued instruments. */
|
||||||
|
public static <T> AsynchronousMetricStorage longAsynchronousAccumulator(
|
||||||
MeterProviderSharedState meterProviderSharedState,
|
MeterProviderSharedState meterProviderSharedState,
|
||||||
MeterSharedState meterSharedState,
|
MeterSharedState meterSharedState,
|
||||||
InstrumentDescriptor descriptor,
|
InstrumentDescriptor descriptor,
|
||||||
Consumer<ObservableLongMeasurement> metricUpdater) {
|
Consumer<ObservableLongMeasurement> metricUpdater) {
|
||||||
Aggregator<T> aggregator =
|
Aggregator<T> aggregator = meterProviderSharedState.getAggregator(meterSharedState, descriptor);
|
||||||
getAggregator(meterProviderSharedState, meterSharedState, descriptor);
|
|
||||||
final InstrumentProcessor<T> instrumentProcessor =
|
final InstrumentProcessor<T> instrumentProcessor =
|
||||||
new InstrumentProcessor<>(aggregator, meterProviderSharedState.getStartEpochNanos());
|
new InstrumentProcessor<>(aggregator, meterProviderSharedState.getStartEpochNanos());
|
||||||
|
|
||||||
final LabelsProcessor labelsProcessor =
|
final LabelsProcessor labelsProcessor =
|
||||||
getLabelsProcessor(meterProviderSharedState, meterSharedState, descriptor);
|
meterProviderSharedState.getLabelsProcessor(meterSharedState, descriptor);
|
||||||
final ObservableLongMeasurement result =
|
final ObservableLongMeasurement result =
|
||||||
new ObservableLongMeasurement() {
|
new ObservableLongMeasurement() {
|
||||||
|
|
||||||
|
|
@ -81,18 +92,25 @@ final class AsynchronousInstrumentAccumulator extends AbstractAccumulator {
|
||||||
observe(value, Attributes.empty());
|
observe(value, Attributes.empty());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return new AsynchronousInstrumentAccumulator(
|
return new AsynchronousMetricStorage(
|
||||||
instrumentProcessor, () -> metricUpdater.accept(result));
|
// 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(
|
private AsynchronousMetricStorage(
|
||||||
InstrumentProcessor<?> instrumentProcessor, Runnable metricUpdater) {
|
MetricDescriptor metricDescriptor,
|
||||||
|
InstrumentProcessor<?> instrumentProcessor,
|
||||||
|
Runnable metricUpdater) {
|
||||||
|
this.metricDescriptor = metricDescriptor;
|
||||||
this.instrumentProcessor = instrumentProcessor;
|
this.instrumentProcessor = instrumentProcessor;
|
||||||
this.metricUpdater = metricUpdater;
|
this.metricUpdater = metricUpdater;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
List<MetricData> collectAll(long epochNanos) {
|
public MetricData collectAndReset(long startEpochNanos, long epochNanos) {
|
||||||
collectLock.lock();
|
collectLock.lock();
|
||||||
try {
|
try {
|
||||||
metricUpdater.run();
|
metricUpdater.run();
|
||||||
|
|
@ -101,4 +119,9 @@ final class AsynchronousInstrumentAccumulator extends AbstractAccumulator {
|
||||||
collectLock.unlock();
|
collectLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MetricDescriptor getMetricDescriptor() {
|
||||||
|
return metricDescriptor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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.
|
||||||
|
*
|
||||||
|
* <p>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();
|
||||||
|
}
|
||||||
|
|
@ -3,23 +3,24 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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.common.Attributes;
|
||||||
import io.opentelemetry.sdk.metrics.aggregator.Aggregator;
|
import io.opentelemetry.sdk.metrics.aggregator.Aggregator;
|
||||||
import io.opentelemetry.sdk.metrics.data.MetricData;
|
import io.opentelemetry.sdk.metrics.data.MetricData;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@code InstrumentProcessor} represents an internal instance of an {@code Accumulator} for a
|
* 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
|
* 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.
|
||||||
*
|
*
|
||||||
* <p>An entire collection cycle must be protected by a lock. A collection cycle is defined by
|
* <p>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(...)};
|
* multiple calls to {@code #batch(...)} followed by one {@code #completeCollectionCycle(...)};
|
||||||
|
*
|
||||||
|
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
|
||||||
|
* at any time.
|
||||||
*/
|
*/
|
||||||
final class InstrumentProcessor<T> {
|
final class InstrumentProcessor<T> {
|
||||||
private final Aggregator<T> aggregator;
|
private final Aggregator<T> aggregator;
|
||||||
|
|
@ -35,19 +36,17 @@ final class InstrumentProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Batches multiple entries together that are part of the same metric. It may remove labels from
|
* Batches multiple entries together that are part of the same metric. It may remove attributes
|
||||||
* the {@link Labels} and merge aggregations together.
|
* 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.
|
* @param accumulation the accumulation produced by this instrument.
|
||||||
*/
|
*/
|
||||||
void batch(Attributes labelSet, T accumulation) {
|
void batch(Attributes attributes, T accumulation) {
|
||||||
T currentAccumulation = accumulationMap.get(labelSet);
|
T currentAccumulation = accumulationMap.putIfAbsent(attributes, accumulation);
|
||||||
if (currentAccumulation == null) {
|
if (currentAccumulation != null) {
|
||||||
accumulationMap.put(labelSet, accumulation);
|
accumulationMap.put(attributes, aggregator.merge(currentAccumulation, accumulation));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
accumulationMap.put(labelSet, aggregator.merge(currentAccumulation, accumulation));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -58,11 +57,11 @@ final class InstrumentProcessor<T> {
|
||||||
* <p>Based on the configured options this method may reset the internal state to produce deltas,
|
* <p>Based on the configured options this method may reset the internal state to produce deltas,
|
||||||
* or keep the internal state to produce cumulative metrics.
|
* 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<MetricData> completeCollectionCycle(long epochNanos) {
|
MetricData completeCollectionCycle(long epochNanos) {
|
||||||
if (accumulationMap.isEmpty()) {
|
if (accumulationMap.isEmpty()) {
|
||||||
return Collections.emptyList();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetricData metricData =
|
MetricData metricData =
|
||||||
|
|
@ -73,6 +72,6 @@ final class InstrumentProcessor<T> {
|
||||||
accumulationMap = new HashMap<>();
|
accumulationMap = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return metricData == null ? Collections.emptyList() : Collections.singletonList(metricData);
|
return metricData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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}.
|
||||||
|
*
|
||||||
|
* <p>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 <T> Aggregator<T> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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}.
|
||||||
|
*
|
||||||
|
* <p>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<MetricData> collectAll(
|
||||||
|
MeterProviderSharedState meterProviderSharedState, long epochNanos) {
|
||||||
|
Collection<MetricStorage> metrics = getMetricStorageRegistry().getMetrics();
|
||||||
|
List<MetricData> 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<ObservableLongMeasurement> 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<ObservableDoubleMeasurement> metricUpdater) {
|
||||||
|
|
||||||
|
return getMetricStorageRegistry()
|
||||||
|
.register(
|
||||||
|
AsynchronousMetricStorage.doubleAsynchronousAccumulator(
|
||||||
|
meterProviderSharedState, this, instrument, metricUpdater));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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}.
|
||||||
|
*
|
||||||
|
* <p>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);
|
||||||
|
}
|
||||||
|
|
@ -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.
|
||||||
|
*
|
||||||
|
* <p>The rules of the registry:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>Only one storage type may be registered per-name. Repeated look-ups per-name will return
|
||||||
|
* the same storage.
|
||||||
|
* <li>The metric descriptor should be "compatible", when returning an existing metric storage,
|
||||||
|
* i.e. same type of metric, same name, description etc.
|
||||||
|
* <li>The registered storage type MUST be either always Asynchronous or always Synchronous. No
|
||||||
|
* mixing and matching.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>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<String, MetricStorage> 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<MetricStorage> 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 extends MetricStorage> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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.common.Attributes;
|
||||||
import io.opentelemetry.context.Context;
|
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.aggregator.AggregatorHandle;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor;
|
import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor;
|
||||||
import io.opentelemetry.sdk.metrics.data.MetricData;
|
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.LabelsProcessor;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
final class SynchronousInstrumentAccumulator<T> extends AbstractAccumulator {
|
/**
|
||||||
|
* Stores aggregated {@link MetricData} for synchronous instruments.
|
||||||
|
*
|
||||||
|
* <p>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<T> implements WriteableMetricStorage {
|
||||||
|
private final MetricDescriptor metricDescriptor;
|
||||||
private final ConcurrentHashMap<Attributes, AggregatorHandle<T>> aggregatorLabels;
|
private final ConcurrentHashMap<Attributes, AggregatorHandle<T>> aggregatorLabels;
|
||||||
private final ReentrantLock collectLock;
|
private final ReentrantLock collectLock;
|
||||||
private final Aggregator<T> aggregator;
|
private final Aggregator<T> aggregator;
|
||||||
private final InstrumentProcessor<T> instrumentProcessor;
|
private final InstrumentProcessor<T> instrumentProcessor;
|
||||||
private final LabelsProcessor labelsProcessor;
|
private final LabelsProcessor labelsProcessor;
|
||||||
|
|
||||||
static <T> SynchronousInstrumentAccumulator<T> create(
|
/** Constructs metric storage for a given synchronous instrument. */
|
||||||
|
public static <T> SynchronousMetricStorage<T> create(
|
||||||
MeterProviderSharedState meterProviderSharedState,
|
MeterProviderSharedState meterProviderSharedState,
|
||||||
MeterSharedState meterSharedState,
|
MeterSharedState meterSharedState,
|
||||||
InstrumentDescriptor descriptor) {
|
InstrumentDescriptor descriptor) {
|
||||||
Aggregator<T> aggregator =
|
Aggregator<T> aggregator = meterProviderSharedState.getAggregator(meterSharedState, descriptor);
|
||||||
getAggregator(meterProviderSharedState, meterSharedState, descriptor);
|
return new SynchronousMetricStorage<>(
|
||||||
return new SynchronousInstrumentAccumulator<>(
|
// TODO: View can change metric name/description. Update this when wired in.
|
||||||
|
MetricDescriptor.create(
|
||||||
|
descriptor.getName(), descriptor.getDescription(), descriptor.getUnit()),
|
||||||
aggregator,
|
aggregator,
|
||||||
new InstrumentProcessor<>(aggregator, meterProviderSharedState.getStartEpochNanos()),
|
new InstrumentProcessor<>(aggregator, meterProviderSharedState.getStartEpochNanos()),
|
||||||
getLabelsProcessor(meterProviderSharedState, meterSharedState, descriptor));
|
meterProviderSharedState.getLabelsProcessor(meterSharedState, descriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
SynchronousInstrumentAccumulator(
|
SynchronousMetricStorage(
|
||||||
|
MetricDescriptor metricDescriptor,
|
||||||
Aggregator<T> aggregator,
|
Aggregator<T> aggregator,
|
||||||
InstrumentProcessor<T> instrumentProcessor,
|
InstrumentProcessor<T> instrumentProcessor,
|
||||||
LabelsProcessor labelsProcessor) {
|
LabelsProcessor labelsProcessor) {
|
||||||
|
this.metricDescriptor = metricDescriptor;
|
||||||
aggregatorLabels = new ConcurrentHashMap<>();
|
aggregatorLabels = new ConcurrentHashMap<>();
|
||||||
collectLock = new ReentrantLock();
|
collectLock = new ReentrantLock();
|
||||||
this.aggregator = aggregator;
|
this.aggregator = aggregator;
|
||||||
|
|
@ -48,10 +60,11 @@ final class SynchronousInstrumentAccumulator<T> extends AbstractAccumulator {
|
||||||
this.labelsProcessor = labelsProcessor;
|
this.labelsProcessor = labelsProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
AggregatorHandle<?> bind(Attributes labels) {
|
@Override
|
||||||
Objects.requireNonNull(labels, "labels");
|
public BoundStorageHandle bind(Attributes attributes) {
|
||||||
labels = labelsProcessor.onLabelsBound(Context.current(), labels);
|
Objects.requireNonNull(attributes, "attributes");
|
||||||
AggregatorHandle<T> aggregatorHandle = aggregatorLabels.get(labels);
|
attributes = labelsProcessor.onLabelsBound(Context.current(), attributes);
|
||||||
|
AggregatorHandle<T> aggregatorHandle = aggregatorLabels.get(attributes);
|
||||||
if (aggregatorHandle != null && aggregatorHandle.acquire()) {
|
if (aggregatorHandle != null && aggregatorHandle.acquire()) {
|
||||||
// At this moment it is guaranteed that the Bound is in the map and will not be removed.
|
// At this moment it is guaranteed that the Bound is in the map and will not be removed.
|
||||||
return aggregatorHandle;
|
return aggregatorHandle;
|
||||||
|
|
@ -61,7 +74,7 @@ final class SynchronousInstrumentAccumulator<T> extends AbstractAccumulator {
|
||||||
aggregatorHandle = aggregator.createHandle();
|
aggregatorHandle = aggregator.createHandle();
|
||||||
while (true) {
|
while (true) {
|
||||||
AggregatorHandle<?> boundAggregatorHandle =
|
AggregatorHandle<?> boundAggregatorHandle =
|
||||||
aggregatorLabels.putIfAbsent(labels, aggregatorHandle);
|
aggregatorLabels.putIfAbsent(attributes, aggregatorHandle);
|
||||||
if (boundAggregatorHandle != null) {
|
if (boundAggregatorHandle != null) {
|
||||||
if (boundAggregatorHandle.acquire()) {
|
if (boundAggregatorHandle.acquire()) {
|
||||||
// At this moment it is guaranteed that the Bound is in the map and will not be removed.
|
// 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<T> extends AbstractAccumulator {
|
||||||
}
|
}
|
||||||
// Try to remove the boundAggregator. This will race with the collect method, but only one
|
// Try to remove the boundAggregator. This will race with the collect method, but only one
|
||||||
// will succeed.
|
// will succeed.
|
||||||
aggregatorLabels.remove(labels, boundAggregatorHandle);
|
aggregatorLabels.remove(attributes, boundAggregatorHandle);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return aggregatorHandle;
|
return aggregatorHandle;
|
||||||
|
|
@ -77,7 +90,7 @@ final class SynchronousInstrumentAccumulator<T> extends AbstractAccumulator {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
List<MetricData> collectAll(long epochNanos) {
|
public MetricData collectAndReset(long startEpochNanos, long epochNanos) {
|
||||||
collectLock.lock();
|
collectLock.lock();
|
||||||
try {
|
try {
|
||||||
for (Map.Entry<Attributes, AggregatorHandle<T>> entry : aggregatorLabels.entrySet()) {
|
for (Map.Entry<Attributes, AggregatorHandle<T>> entry : aggregatorLabels.entrySet()) {
|
||||||
|
|
@ -98,4 +111,9 @@ final class SynchronousInstrumentAccumulator<T> extends AbstractAccumulator {
|
||||||
collectLock.unlock();
|
collectLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MetricDescriptor getMetricDescriptor() {
|
||||||
|
return metricDescriptor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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.
|
||||||
|
*
|
||||||
|
* <p>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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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.aggregator.AggregatorFactory;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentDescriptor;
|
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
|
* Central location for Views to be registered. Registration of a view is done via the {@link
|
||||||
* SdkMeterProviderBuilder}.
|
* SdkMeterProviderBuilder}.
|
||||||
|
*
|
||||||
|
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
|
||||||
|
* at any time.
|
||||||
*/
|
*/
|
||||||
@Immutable
|
@Immutable
|
||||||
final class ViewRegistry {
|
public final class ViewRegistry {
|
||||||
static final View CUMULATIVE_SUM =
|
static final View CUMULATIVE_SUM =
|
||||||
View.builder()
|
View.builder()
|
||||||
.setAggregatorFactory(AggregatorFactory.sum(AggregationTemporality.CUMULATIVE))
|
.setAggregatorFactory(AggregatorFactory.sum(AggregationTemporality.CUMULATIVE))
|
||||||
|
|
@ -41,11 +44,18 @@ final class ViewRegistry {
|
||||||
this.configuration.put(instrumentType, new LinkedHashMap<>(patternViewLinkedHashMap)));
|
this.configuration.put(instrumentType, new LinkedHashMap<>(patternViewLinkedHashMap)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ViewRegistryBuilder builder() {
|
/** Returns a builder of {@link ViewRegistry}. */
|
||||||
|
public static ViewRegistryBuilder builder() {
|
||||||
return new ViewRegistryBuilder();
|
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<Pattern, View> configPerType = configuration.get(descriptor.getType());
|
LinkedHashMap<Pattern, View> configPerType = configuration.get(descriptor.getType());
|
||||||
for (Map.Entry<Pattern, View> entry : configPerType.entrySet()) {
|
for (Map.Entry<Pattern, View> entry : configPerType.entrySet()) {
|
||||||
if (entry.getKey().matcher(descriptor.getName()).matches()) {
|
if (entry.getKey().matcher(descriptor.getName()).matches()) {
|
||||||
|
|
@ -60,12 +70,12 @@ final class ViewRegistry {
|
||||||
switch (descriptor.getType()) {
|
switch (descriptor.getType()) {
|
||||||
case COUNTER:
|
case COUNTER:
|
||||||
case UP_DOWN_COUNTER:
|
case UP_DOWN_COUNTER:
|
||||||
case SUM_OBSERVER:
|
case OBSERVABLE_SUM:
|
||||||
case UP_DOWN_SUM_OBSERVER:
|
case OBSERVABLE_UP_DOWN_SUM:
|
||||||
return CUMULATIVE_SUM;
|
return CUMULATIVE_SUM;
|
||||||
case VALUE_RECORDER:
|
case HISTOGRAM:
|
||||||
return SUMMARY;
|
return SUMMARY;
|
||||||
case VALUE_OBSERVER:
|
case OBSERVABLE_GAUGE:
|
||||||
return LAST_VALUE;
|
return LAST_VALUE;
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("Unknown descriptor type: " + descriptor.getType());
|
throw new IllegalArgumentException("Unknown descriptor type: " + descriptor.getType());
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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.common.InstrumentType;
|
||||||
import io.opentelemetry.sdk.metrics.view.InstrumentSelector;
|
import io.opentelemetry.sdk.metrics.view.InstrumentSelector;
|
||||||
|
|
@ -12,7 +12,13 @@ import java.util.EnumMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
class ViewRegistryBuilder {
|
/**
|
||||||
|
* Builder for {@link ViewRegistry}.
|
||||||
|
*
|
||||||
|
* <p>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<InstrumentType, LinkedHashMap<Pattern, View>> configuration =
|
private final EnumMap<InstrumentType, LinkedHashMap<Pattern, View>> configuration =
|
||||||
new EnumMap<>(InstrumentType.class);
|
new EnumMap<>(InstrumentType.class);
|
||||||
private static final LinkedHashMap<Pattern, View> EMPTY_CONFIG = new LinkedHashMap<>();
|
private static final LinkedHashMap<Pattern, View> EMPTY_CONFIG = new LinkedHashMap<>();
|
||||||
|
|
@ -23,11 +29,19 @@ class ViewRegistryBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewRegistry build() {
|
/** Returns the {@link ViewRegistry}. */
|
||||||
|
public ViewRegistry build() {
|
||||||
return new ViewRegistry(configuration);
|
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<Pattern, View> parentConfiguration =
|
LinkedHashMap<Pattern, View> parentConfiguration =
|
||||||
configuration.get(selector.getInstrumentType());
|
configuration.get(selector.getInstrumentType());
|
||||||
configuration.put(
|
configuration.put(
|
||||||
|
|
@ -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.InstrumentDescriptor;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentValueType;
|
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;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/** Unit tests for {@link AbstractInstrument}. */
|
/** Unit tests for {@link AbstractInstrument}. */
|
||||||
|
|
@ -31,10 +28,5 @@ class AbstractInstrumentTest {
|
||||||
TestInstrument(InstrumentDescriptor descriptor) {
|
TestInstrument(InstrumentDescriptor descriptor) {
|
||||||
super(descriptor);
|
super(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
List<MetricData> collectAll(long epochNanos) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,18 +33,18 @@ class DoubleCounterSdkTest {
|
||||||
private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName());
|
private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName());
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void add_PreventNullLabels() {
|
void add_PreventNullAttributes() {
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() -> sdkMeter.counterBuilder("testCounter").ofDoubles().build().add(1.0, null))
|
() -> sdkMeter.counterBuilder("testCounter").ofDoubles().build().add(1.0, null))
|
||||||
.isInstanceOf(NullPointerException.class)
|
.isInstanceOf(NullPointerException.class)
|
||||||
.hasMessage("labels");
|
.hasMessage("attributes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void bound_PreventNullLabels() {
|
void bound_PreventNullAttributes() {
|
||||||
assertThatThrownBy(() -> sdkMeter.counterBuilder("testCounter").ofDoubles().build().bind(null))
|
assertThatThrownBy(() -> sdkMeter.counterBuilder("testCounter").ofDoubles().build().bind(null))
|
||||||
.isInstanceOf(NullPointerException.class)
|
.isInstanceOf(NullPointerException.class)
|
||||||
.hasMessage("labels");
|
.hasMessage("attributes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -60,7 +60,7 @@ class DoubleCounterSdkTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void collectMetrics_WithEmptyLabel() {
|
void collectMetrics_WithEmptyAttributes() {
|
||||||
DoubleCounter doubleCounter =
|
DoubleCounter doubleCounter =
|
||||||
sdkMeter
|
sdkMeter
|
||||||
.counterBuilder("testCounter")
|
.counterBuilder("testCounter")
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,11 @@ import java.time.Duration;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/** Unit tests for {@link DoubleValueObserverSdk}. */
|
/** Unit tests for {@link DoubleValueObserverSdk}. */
|
||||||
class DoubleValueObserverSdkTest {
|
class DoubleGaugeBuilderSdkTest {
|
||||||
private static final Resource RESOURCE =
|
private static final Resource RESOURCE =
|
||||||
Resource.create(Attributes.of(stringKey("resource_key"), "resource_value"));
|
Resource.create(Attributes.of(stringKey("resource_key"), "resource_value"));
|
||||||
private static final InstrumentationLibraryInfo INSTRUMENTATION_LIBRARY_INFO =
|
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 TestClock testClock = TestClock.create();
|
||||||
private final SdkMeterProvider sdkMeterProvider =
|
private final SdkMeterProvider sdkMeterProvider =
|
||||||
SdkMeterProvider.builder().setClock(testClock).setResource(RESOURCE).build();
|
SdkMeterProvider.builder().setClock(testClock).setResource(RESOURCE).build();
|
||||||
|
|
@ -28,30 +28,30 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/** Unit tests for {@link DoubleValueRecorderSdk}. */
|
/** Unit tests for {@link DoubleHistogramSdk}. */
|
||||||
class DoubleValueRecorderSdkTest {
|
class DoubleHistogramSdkTest {
|
||||||
private static final long SECOND_NANOS = 1_000_000_000;
|
private static final long SECOND_NANOS = 1_000_000_000;
|
||||||
private static final Resource RESOURCE =
|
private static final Resource RESOURCE =
|
||||||
Resource.create(Attributes.of(stringKey("resource_key"), "resource_value"));
|
Resource.create(Attributes.of(stringKey("resource_key"), "resource_value"));
|
||||||
private static final InstrumentationLibraryInfo INSTRUMENTATION_LIBRARY_INFO =
|
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 TestClock testClock = TestClock.create();
|
||||||
private final SdkMeterProvider sdkMeterProvider =
|
private final SdkMeterProvider sdkMeterProvider =
|
||||||
SdkMeterProvider.builder().setClock(testClock).setResource(RESOURCE).build();
|
SdkMeterProvider.builder().setClock(testClock).setResource(RESOURCE).build();
|
||||||
private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName());
|
private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName());
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void record_PreventNullLabels() {
|
void record_PreventNullAttributes() {
|
||||||
assertThatThrownBy(() -> sdkMeter.histogramBuilder("testRecorder").build().record(1.0, null))
|
assertThatThrownBy(() -> sdkMeter.histogramBuilder("testRecorder").build().record(1.0, null))
|
||||||
.isInstanceOf(NullPointerException.class)
|
.isInstanceOf(NullPointerException.class)
|
||||||
.hasMessage("labels");
|
.hasMessage("attributes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void bound_PreventNullLabels() {
|
void bound_PreventNullAttributes() {
|
||||||
assertThatThrownBy(() -> sdkMeter.histogramBuilder("testRecorder").build().bind(null))
|
assertThatThrownBy(() -> sdkMeter.histogramBuilder("testRecorder").build().bind(null))
|
||||||
.isInstanceOf(NullPointerException.class)
|
.isInstanceOf(NullPointerException.class)
|
||||||
.hasMessage("labels");
|
.hasMessage("attributes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -67,7 +67,7 @@ class DoubleValueRecorderSdkTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void collectMetrics_WithEmptyLabel() {
|
void collectMetrics_WithEmptyAttributes() {
|
||||||
DoubleHistogram doubleRecorder =
|
DoubleHistogram doubleRecorder =
|
||||||
sdkMeter
|
sdkMeter
|
||||||
.histogramBuilder("testRecorder")
|
.histogramBuilder("testRecorder")
|
||||||
|
|
@ -188,7 +188,7 @@ class DoubleValueRecorderSdkTest {
|
||||||
|
|
||||||
StressTestRunner.Builder stressTestBuilder =
|
StressTestRunner.Builder stressTestBuilder =
|
||||||
StressTestRunner.builder()
|
StressTestRunner.builder()
|
||||||
.setInstrument((DoubleValueRecorderSdk) doubleRecorder)
|
.setInstrument((DoubleHistogramSdk) doubleRecorder)
|
||||||
.setCollectionIntervalMs(100);
|
.setCollectionIntervalMs(100);
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
|
|
@ -196,7 +196,7 @@ class DoubleValueRecorderSdkTest {
|
||||||
StressTestRunner.Operation.create(
|
StressTestRunner.Operation.create(
|
||||||
1_000,
|
1_000,
|
||||||
2,
|
2,
|
||||||
new DoubleValueRecorderSdkTest.OperationUpdaterDirectCall(doubleRecorder, "K", "V")));
|
new DoubleHistogramSdkTest.OperationUpdaterDirectCall(doubleRecorder, "K", "V")));
|
||||||
stressTestBuilder.addOperation(
|
stressTestBuilder.addOperation(
|
||||||
StressTestRunner.Operation.create(
|
StressTestRunner.Operation.create(
|
||||||
1_000,
|
1_000,
|
||||||
|
|
@ -233,7 +233,7 @@ class DoubleValueRecorderSdkTest {
|
||||||
|
|
||||||
StressTestRunner.Builder stressTestBuilder =
|
StressTestRunner.Builder stressTestBuilder =
|
||||||
StressTestRunner.builder()
|
StressTestRunner.builder()
|
||||||
.setInstrument((DoubleValueRecorderSdk) doubleRecorder)
|
.setInstrument((DoubleHistogramSdk) doubleRecorder)
|
||||||
.setCollectionIntervalMs(100);
|
.setCollectionIntervalMs(100);
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
|
|
@ -241,7 +241,7 @@ class DoubleValueRecorderSdkTest {
|
||||||
StressTestRunner.Operation.create(
|
StressTestRunner.Operation.create(
|
||||||
2_000,
|
2_000,
|
||||||
1,
|
1,
|
||||||
new DoubleValueRecorderSdkTest.OperationUpdaterDirectCall(
|
new DoubleHistogramSdkTest.OperationUpdaterDirectCall(
|
||||||
doubleRecorder, keys[i], values[i])));
|
doubleRecorder, keys[i], values[i])));
|
||||||
|
|
||||||
stressTestBuilder.addOperation(
|
stressTestBuilder.addOperation(
|
||||||
|
|
@ -109,7 +109,9 @@ class DoubleSumObserverSdkTest {
|
||||||
SdkMeterProvider sdkMeterProvider =
|
SdkMeterProvider sdkMeterProvider =
|
||||||
sdkMeterProviderBuilder
|
sdkMeterProviderBuilder
|
||||||
.registerView(
|
.registerView(
|
||||||
InstrumentSelector.builder().setInstrumentType(InstrumentType.SUM_OBSERVER).build(),
|
InstrumentSelector.builder()
|
||||||
|
.setInstrumentType(InstrumentType.OBSERVABLE_SUM)
|
||||||
|
.build(),
|
||||||
View.builder()
|
View.builder()
|
||||||
.setLabelsProcessorFactory(LabelsProcessorFactory.noop())
|
.setLabelsProcessorFactory(LabelsProcessorFactory.noop())
|
||||||
.setAggregatorFactory(AggregatorFactory.sum(AggregationTemporality.DELTA))
|
.setAggregatorFactory(AggregatorFactory.sum(AggregationTemporality.DELTA))
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ class DoubleUpDownCounterSdkTest {
|
||||||
private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName());
|
private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName());
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void add_PreventNullLabels() {
|
void add_PreventNullAttributes() {
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() ->
|
() ->
|
||||||
sdkMeter
|
sdkMeter
|
||||||
|
|
@ -42,15 +42,15 @@ class DoubleUpDownCounterSdkTest {
|
||||||
.build()
|
.build()
|
||||||
.add(1.0, null))
|
.add(1.0, null))
|
||||||
.isInstanceOf(NullPointerException.class)
|
.isInstanceOf(NullPointerException.class)
|
||||||
.hasMessage("labels");
|
.hasMessage("attributes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void bound_PreventNullLabels() {
|
void bound_PreventNullAttributes() {
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() -> sdkMeter.upDownCounterBuilder("testUpDownCounter").ofDoubles().build().bind(null))
|
() -> sdkMeter.upDownCounterBuilder("testUpDownCounter").ofDoubles().build().bind(null))
|
||||||
.isInstanceOf(NullPointerException.class)
|
.isInstanceOf(NullPointerException.class)
|
||||||
.hasMessage("labels");
|
.hasMessage("attributes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -68,7 +68,7 @@ class DoubleUpDownCounterSdkTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void collectMetrics_WithEmptyLabel() {
|
void collectMetrics_WithEmptyAttributes() {
|
||||||
DoubleUpDownCounter doubleUpDownCounter =
|
DoubleUpDownCounter doubleUpDownCounter =
|
||||||
sdkMeter
|
sdkMeter
|
||||||
.upDownCounterBuilder("testUpDownCounter")
|
.upDownCounterBuilder("testUpDownCounter")
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ class DoubleUpDownSumObserverSdkTest {
|
||||||
sdkMeterProviderBuilder
|
sdkMeterProviderBuilder
|
||||||
.registerView(
|
.registerView(
|
||||||
InstrumentSelector.builder()
|
InstrumentSelector.builder()
|
||||||
.setInstrumentType(InstrumentType.UP_DOWN_SUM_OBSERVER)
|
.setInstrumentType(InstrumentType.OBSERVABLE_UP_DOWN_SUM)
|
||||||
.build(),
|
.build(),
|
||||||
View.builder()
|
View.builder()
|
||||||
.setLabelsProcessorFactory(LabelsProcessorFactory.noop())
|
.setLabelsProcessorFactory(LabelsProcessorFactory.noop())
|
||||||
|
|
|
||||||
|
|
@ -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<MetricData> collectAll(long epochNanos) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class OtherTestInstrument extends AbstractInstrument {
|
|
||||||
OtherTestInstrument(InstrumentDescriptor descriptor) {
|
|
||||||
super(descriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
List<MetricData> collectAll(long epochNanos) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -33,17 +33,17 @@ class LongCounterSdkTest {
|
||||||
private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName());
|
private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName());
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void add_PreventNullLabels() {
|
void add_PreventNullAttributes() {
|
||||||
assertThatThrownBy(() -> sdkMeter.counterBuilder("testCounter").build().add(1, null))
|
assertThatThrownBy(() -> sdkMeter.counterBuilder("testCounter").build().add(1, null))
|
||||||
.isInstanceOf(NullPointerException.class)
|
.isInstanceOf(NullPointerException.class)
|
||||||
.hasMessage("labels");
|
.hasMessage("attributes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void bound_PreventNullLabels() {
|
void bound_PreventNullAttributes() {
|
||||||
assertThatThrownBy(() -> sdkMeter.counterBuilder("testCounter").build().bind(null))
|
assertThatThrownBy(() -> sdkMeter.counterBuilder("testCounter").build().bind(null))
|
||||||
.isInstanceOf(NullPointerException.class)
|
.isInstanceOf(NullPointerException.class)
|
||||||
.hasMessage("labels");
|
.hasMessage("attributes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -59,7 +59,7 @@ class LongCounterSdkTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void collectMetrics_WithEmptyLabels() {
|
void collectMetrics_WithEmptyAttributes() {
|
||||||
LongCounter longCounter =
|
LongCounter longCounter =
|
||||||
sdkMeter.counterBuilder("testCounter").setDescription("description").setUnit("By").build();
|
sdkMeter.counterBuilder("testCounter").setDescription("description").setUnit("By").build();
|
||||||
testClock.advance(Duration.ofNanos(SECOND_NANOS));
|
testClock.advance(Duration.ofNanos(SECOND_NANOS));
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,11 @@ import java.time.Duration;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/** Unit tests for {@link LongValueObserverSdk}. */
|
/** Unit tests for {@link LongValueObserverSdk}. */
|
||||||
class LongValueObserverSdkTest {
|
class LongGaugeBuilderSdkTest {
|
||||||
private static final Resource RESOURCE =
|
private static final Resource RESOURCE =
|
||||||
Resource.create(Attributes.of(stringKey("resource_key"), "resource_value"));
|
Resource.create(Attributes.of(stringKey("resource_key"), "resource_value"));
|
||||||
private static final InstrumentationLibraryInfo INSTRUMENTATION_LIBRARY_INFO =
|
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 TestClock testClock = TestClock.create();
|
||||||
private final SdkMeterProvider sdkMeterProvider =
|
private final SdkMeterProvider sdkMeterProvider =
|
||||||
SdkMeterProvider.builder().setClock(testClock).setResource(RESOURCE).build();
|
SdkMeterProvider.builder().setClock(testClock).setResource(RESOURCE).build();
|
||||||
|
|
@ -28,31 +28,31 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/** Unit tests for {@link LongValueRecorderSdk}. */
|
/** Unit tests for {@link LongHistogramSdk}. */
|
||||||
class LongValueRecorderSdkTest {
|
class LongHistogramSdkTest {
|
||||||
private static final long SECOND_NANOS = 1_000_000_000;
|
private static final long SECOND_NANOS = 1_000_000_000;
|
||||||
private static final Resource RESOURCE =
|
private static final Resource RESOURCE =
|
||||||
Resource.create(Attributes.of(stringKey("resource_key"), "resource_value"));
|
Resource.create(Attributes.of(stringKey("resource_key"), "resource_value"));
|
||||||
private static final InstrumentationLibraryInfo INSTRUMENTATION_LIBRARY_INFO =
|
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 TestClock testClock = TestClock.create();
|
||||||
private final SdkMeterProvider sdkMeterProvider =
|
private final SdkMeterProvider sdkMeterProvider =
|
||||||
SdkMeterProvider.builder().setClock(testClock).setResource(RESOURCE).build();
|
SdkMeterProvider.builder().setClock(testClock).setResource(RESOURCE).build();
|
||||||
private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName());
|
private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName());
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void record_PreventNullLabels() {
|
void record_PreventNullAttributes() {
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() -> sdkMeter.histogramBuilder("testRecorder").ofLongs().build().record(1, null))
|
() -> sdkMeter.histogramBuilder("testRecorder").ofLongs().build().record(1, null))
|
||||||
.isInstanceOf(NullPointerException.class)
|
.isInstanceOf(NullPointerException.class)
|
||||||
.hasMessage("labels");
|
.hasMessage("attributes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void bound_PreventNullLabels() {
|
void bound_PreventNullAttributes() {
|
||||||
assertThatThrownBy(() -> sdkMeter.histogramBuilder("testRecorder").ofLongs().build().bind(null))
|
assertThatThrownBy(() -> sdkMeter.histogramBuilder("testRecorder").ofLongs().build().bind(null))
|
||||||
.isInstanceOf(NullPointerException.class)
|
.isInstanceOf(NullPointerException.class)
|
||||||
.hasMessage("labels");
|
.hasMessage("attributes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -67,7 +67,7 @@ class LongValueRecorderSdkTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void collectMetrics_WithEmptyLabel() {
|
void collectMetrics_WithEmptyAttributes() {
|
||||||
LongHistogram longRecorder =
|
LongHistogram longRecorder =
|
||||||
sdkMeter
|
sdkMeter
|
||||||
.histogramBuilder("testRecorder")
|
.histogramBuilder("testRecorder")
|
||||||
|
|
@ -188,7 +188,7 @@ class LongValueRecorderSdkTest {
|
||||||
|
|
||||||
StressTestRunner.Builder stressTestBuilder =
|
StressTestRunner.Builder stressTestBuilder =
|
||||||
StressTestRunner.builder()
|
StressTestRunner.builder()
|
||||||
.setInstrument((LongValueRecorderSdk) longRecorder)
|
.setInstrument((LongHistogramSdk) longRecorder)
|
||||||
.setCollectionIntervalMs(100);
|
.setCollectionIntervalMs(100);
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
|
|
@ -196,12 +196,12 @@ class LongValueRecorderSdkTest {
|
||||||
StressTestRunner.Operation.create(
|
StressTestRunner.Operation.create(
|
||||||
2_000,
|
2_000,
|
||||||
1,
|
1,
|
||||||
new LongValueRecorderSdkTest.OperationUpdaterDirectCall(longRecorder, "K", "V")));
|
new LongHistogramSdkTest.OperationUpdaterDirectCall(longRecorder, "K", "V")));
|
||||||
stressTestBuilder.addOperation(
|
stressTestBuilder.addOperation(
|
||||||
StressTestRunner.Operation.create(
|
StressTestRunner.Operation.create(
|
||||||
2_000,
|
2_000,
|
||||||
1,
|
1,
|
||||||
new LongValueRecorderSdkTest.OperationUpdaterWithBinding(
|
new LongHistogramSdkTest.OperationUpdaterWithBinding(
|
||||||
longRecorder.bind(Attributes.builder().put("K", "V").build()))));
|
longRecorder.bind(Attributes.builder().put("K", "V").build()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,7 +233,7 @@ class LongValueRecorderSdkTest {
|
||||||
|
|
||||||
StressTestRunner.Builder stressTestBuilder =
|
StressTestRunner.Builder stressTestBuilder =
|
||||||
StressTestRunner.builder()
|
StressTestRunner.builder()
|
||||||
.setInstrument((LongValueRecorderSdk) longRecorder)
|
.setInstrument((LongHistogramSdk) longRecorder)
|
||||||
.setCollectionIntervalMs(100);
|
.setCollectionIntervalMs(100);
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
|
|
@ -241,14 +241,14 @@ class LongValueRecorderSdkTest {
|
||||||
StressTestRunner.Operation.create(
|
StressTestRunner.Operation.create(
|
||||||
1_000,
|
1_000,
|
||||||
2,
|
2,
|
||||||
new LongValueRecorderSdkTest.OperationUpdaterDirectCall(
|
new LongHistogramSdkTest.OperationUpdaterDirectCall(
|
||||||
longRecorder, keys[i], values[i])));
|
longRecorder, keys[i], values[i])));
|
||||||
|
|
||||||
stressTestBuilder.addOperation(
|
stressTestBuilder.addOperation(
|
||||||
StressTestRunner.Operation.create(
|
StressTestRunner.Operation.create(
|
||||||
1_000,
|
1_000,
|
||||||
2,
|
2,
|
||||||
new LongValueRecorderSdkTest.OperationUpdaterWithBinding(
|
new LongHistogramSdkTest.OperationUpdaterWithBinding(
|
||||||
longRecorder.bind(Attributes.builder().put(keys[i], values[i]).build()))));
|
longRecorder.bind(Attributes.builder().put(keys[i], values[i]).build()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,7 +103,9 @@ class LongSumObserverSdkTest {
|
||||||
SdkMeterProvider sdkMeterProvider =
|
SdkMeterProvider sdkMeterProvider =
|
||||||
sdkMeterProviderBuilder
|
sdkMeterProviderBuilder
|
||||||
.registerView(
|
.registerView(
|
||||||
InstrumentSelector.builder().setInstrumentType(InstrumentType.SUM_OBSERVER).build(),
|
InstrumentSelector.builder()
|
||||||
|
.setInstrumentType(InstrumentType.OBSERVABLE_SUM)
|
||||||
|
.build(),
|
||||||
View.builder()
|
View.builder()
|
||||||
.setLabelsProcessorFactory(LabelsProcessorFactory.noop())
|
.setLabelsProcessorFactory(LabelsProcessorFactory.noop())
|
||||||
.setAggregatorFactory(AggregatorFactory.sum(AggregationTemporality.DELTA))
|
.setAggregatorFactory(AggregatorFactory.sum(AggregationTemporality.DELTA))
|
||||||
|
|
|
||||||
|
|
@ -33,17 +33,17 @@ class LongUpDownCounterSdkTest {
|
||||||
private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName());
|
private final Meter sdkMeter = sdkMeterProvider.get(getClass().getName());
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void add_PreventNullLabels() {
|
void add_PreventNullAttributes() {
|
||||||
assertThatThrownBy(() -> sdkMeter.upDownCounterBuilder("testCounter").build().add(1, null))
|
assertThatThrownBy(() -> sdkMeter.upDownCounterBuilder("testCounter").build().add(1, null))
|
||||||
.isInstanceOf(NullPointerException.class)
|
.isInstanceOf(NullPointerException.class)
|
||||||
.hasMessage("labels");
|
.hasMessage("attributes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void bound_PreventNullLabels() {
|
void bound_PreventNullAttributes() {
|
||||||
assertThatThrownBy(() -> sdkMeter.upDownCounterBuilder("testUpDownCounter").build().bind(null))
|
assertThatThrownBy(() -> sdkMeter.upDownCounterBuilder("testUpDownCounter").build().bind(null))
|
||||||
.isInstanceOf(NullPointerException.class)
|
.isInstanceOf(NullPointerException.class)
|
||||||
.hasMessage("labels");
|
.hasMessage("attributes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -61,7 +61,7 @@ class LongUpDownCounterSdkTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void collectMetrics_WithEmptyLabel() {
|
void collectMetrics_WithEmptyAttributes() {
|
||||||
LongUpDownCounter longUpDownCounter =
|
LongUpDownCounter longUpDownCounter =
|
||||||
sdkMeter
|
sdkMeter
|
||||||
.upDownCounterBuilder("testUpDownCounter")
|
.upDownCounterBuilder("testUpDownCounter")
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ class LongUpDownSumObserverSdkTest {
|
||||||
sdkMeterProviderBuilder
|
sdkMeterProviderBuilder
|
||||||
.registerView(
|
.registerView(
|
||||||
InstrumentSelector.builder()
|
InstrumentSelector.builder()
|
||||||
.setInstrumentType(InstrumentType.UP_DOWN_SUM_OBSERVER)
|
.setInstrumentType(InstrumentType.OBSERVABLE_UP_DOWN_SUM)
|
||||||
.build(),
|
.build(),
|
||||||
View.builder()
|
View.builder()
|
||||||
.setLabelsProcessorFactory(LabelsProcessorFactory.noop())
|
.setLabelsProcessorFactory(LabelsProcessorFactory.noop())
|
||||||
|
|
|
||||||
|
|
@ -31,20 +31,21 @@ class SdkMeterTest {
|
||||||
.build();
|
.build();
|
||||||
assertThat(longCounter).isNotNull();
|
assertThat(longCounter).isNotNull();
|
||||||
|
|
||||||
assertThat(
|
// Note: We no longer get the same instrument instance as these instances are lightweight
|
||||||
sdkMeter
|
// objects backed by storage now. Here we just make sure it doesn't throw to grab
|
||||||
.counterBuilder("testLongCounter")
|
// a second instance.
|
||||||
.setDescription("My very own counter")
|
sdkMeter
|
||||||
.setUnit("metric tonnes")
|
.counterBuilder("testLongCounter")
|
||||||
.build())
|
.setDescription("My very own counter")
|
||||||
.isSameAs(longCounter);
|
.setUnit("metric tonnes")
|
||||||
|
.build();
|
||||||
|
|
||||||
assertThatThrownBy(() -> sdkMeter.counterBuilder("testLongCounter").build())
|
assertThatThrownBy(() -> sdkMeter.counterBuilder("testLongCounter").build())
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.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())
|
assertThatThrownBy(() -> sdkMeter.counterBuilder("testLongCounter".toUpperCase()).build())
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -57,21 +58,22 @@ class SdkMeterTest {
|
||||||
.build();
|
.build();
|
||||||
assertThat(longUpDownCounter).isNotNull();
|
assertThat(longUpDownCounter).isNotNull();
|
||||||
|
|
||||||
assertThat(
|
// Note: We no longer get the same instrument instance as these instances are lightweight
|
||||||
sdkMeter
|
// objects backed by storage now. Here we just make sure it doesn't throw to grab
|
||||||
.upDownCounterBuilder("testLongUpDownCounter")
|
// a second instance.
|
||||||
.setDescription("My very own counter")
|
sdkMeter
|
||||||
.setUnit("metric tonnes")
|
.upDownCounterBuilder("testLongUpDownCounter")
|
||||||
.build())
|
.setDescription("My very own counter")
|
||||||
.isSameAs(longUpDownCounter);
|
.setUnit("metric tonnes")
|
||||||
|
.build();
|
||||||
|
|
||||||
assertThatThrownBy(() -> sdkMeter.upDownCounterBuilder("testLongUpDownCounter").build())
|
assertThatThrownBy(() -> sdkMeter.upDownCounterBuilder("testLongUpDownCounter").build())
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() -> sdkMeter.upDownCounterBuilder("testLongUpDownCounter".toUpperCase()).build())
|
() -> sdkMeter.upDownCounterBuilder("testLongUpDownCounter".toUpperCase()).build())
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -85,23 +87,24 @@ class SdkMeterTest {
|
||||||
.build();
|
.build();
|
||||||
assertThat(longValueRecorder).isNotNull();
|
assertThat(longValueRecorder).isNotNull();
|
||||||
|
|
||||||
assertThat(
|
// Note: We no longer get the same instrument instance as these instances are lightweight
|
||||||
sdkMeter
|
// objects backed by storage now. Here we just make sure it doesn't throw to grab
|
||||||
.histogramBuilder("testLongValueRecorder")
|
// a second instance.
|
||||||
.ofLongs()
|
sdkMeter
|
||||||
.setDescription("My very own counter")
|
.histogramBuilder("testLongValueRecorder")
|
||||||
.setUnit("metric tonnes")
|
.ofLongs()
|
||||||
.build())
|
.setDescription("My very own counter")
|
||||||
.isSameAs(longValueRecorder);
|
.setUnit("metric tonnes")
|
||||||
|
.build();
|
||||||
|
|
||||||
assertThatThrownBy(() -> sdkMeter.histogramBuilder("testLongValueRecorder").ofLongs().build())
|
assertThatThrownBy(() -> sdkMeter.histogramBuilder("testLongValueRecorder").ofLongs().build())
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() ->
|
() ->
|
||||||
sdkMeter.histogramBuilder("testLongValueRecorder".toUpperCase()).ofLongs().build())
|
sdkMeter.histogramBuilder("testLongValueRecorder".toUpperCase()).ofLongs().build())
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -116,7 +119,7 @@ class SdkMeterTest {
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() -> sdkMeter.gaugeBuilder("longValueObserver").ofLongs().buildWithCallback(x -> {}))
|
() -> sdkMeter.gaugeBuilder("longValueObserver").ofLongs().buildWithCallback(x -> {}))
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() ->
|
() ->
|
||||||
sdkMeter
|
sdkMeter
|
||||||
|
|
@ -124,7 +127,7 @@ class SdkMeterTest {
|
||||||
.ofLongs()
|
.ofLongs()
|
||||||
.buildWithCallback(x -> {}))
|
.buildWithCallback(x -> {}))
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -138,7 +141,7 @@ class SdkMeterTest {
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() -> sdkMeter.counterBuilder("testLongSumObserver").buildWithCallback(x -> {}))
|
() -> sdkMeter.counterBuilder("testLongSumObserver").buildWithCallback(x -> {}))
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
|
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() ->
|
() ->
|
||||||
|
|
@ -146,7 +149,7 @@ class SdkMeterTest {
|
||||||
.counterBuilder("testLongSumObserver".toUpperCase())
|
.counterBuilder("testLongSumObserver".toUpperCase())
|
||||||
.buildWithCallback(x -> {}))
|
.buildWithCallback(x -> {}))
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -163,7 +166,7 @@ class SdkMeterTest {
|
||||||
.upDownCounterBuilder("testLongUpDownSumObserver")
|
.upDownCounterBuilder("testLongUpDownSumObserver")
|
||||||
.buildWithCallback(x -> {}))
|
.buildWithCallback(x -> {}))
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
|
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() ->
|
() ->
|
||||||
|
|
@ -171,7 +174,7 @@ class SdkMeterTest {
|
||||||
.upDownCounterBuilder("testLongUpDownSumObserver".toUpperCase())
|
.upDownCounterBuilder("testLongUpDownSumObserver".toUpperCase())
|
||||||
.buildWithCallback(x -> {}))
|
.buildWithCallback(x -> {}))
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -185,22 +188,23 @@ class SdkMeterTest {
|
||||||
.build();
|
.build();
|
||||||
assertThat(doubleCounter).isNotNull();
|
assertThat(doubleCounter).isNotNull();
|
||||||
|
|
||||||
assertThat(
|
// Note: We no longer get the same instrument instance as these instances are lightweight
|
||||||
sdkMeter
|
// objects backed by storage now. Here we just make sure it doesn't throw to grab
|
||||||
.counterBuilder("testDoubleCounter")
|
// a second instance.
|
||||||
.ofDoubles()
|
sdkMeter
|
||||||
.setDescription("My very own counter")
|
.counterBuilder("testDoubleCounter")
|
||||||
.setUnit("metric tonnes")
|
.ofDoubles()
|
||||||
.build())
|
.setDescription("My very own counter")
|
||||||
.isSameAs(doubleCounter);
|
.setUnit("metric tonnes")
|
||||||
|
.build();
|
||||||
|
|
||||||
assertThatThrownBy(() -> sdkMeter.counterBuilder("testDoubleCounter").ofDoubles().build())
|
assertThatThrownBy(() -> sdkMeter.counterBuilder("testDoubleCounter").ofDoubles().build())
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() -> sdkMeter.counterBuilder("testDoubleCounter".toUpperCase()).ofDoubles().build())
|
() -> sdkMeter.counterBuilder("testDoubleCounter".toUpperCase()).ofDoubles().build())
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -214,19 +218,20 @@ class SdkMeterTest {
|
||||||
.build();
|
.build();
|
||||||
assertThat(doubleUpDownCounter).isNotNull();
|
assertThat(doubleUpDownCounter).isNotNull();
|
||||||
|
|
||||||
assertThat(
|
// Note: We no longer get the same instrument instance as these instances are lightweight
|
||||||
sdkMeter
|
// objects backed by storage now. Here we just make sure it doesn't throw to grab
|
||||||
.upDownCounterBuilder("testDoubleUpDownCounter")
|
// a second instance.
|
||||||
.ofDoubles()
|
sdkMeter
|
||||||
.setDescription("My very own counter")
|
.upDownCounterBuilder("testDoubleUpDownCounter")
|
||||||
.setUnit("metric tonnes")
|
.ofDoubles()
|
||||||
.build())
|
.setDescription("My very own counter")
|
||||||
.isSameAs(doubleUpDownCounter);
|
.setUnit("metric tonnes")
|
||||||
|
.build();
|
||||||
|
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() -> sdkMeter.upDownCounterBuilder("testDoubleUpDownCounter").ofDoubles().build())
|
() -> sdkMeter.upDownCounterBuilder("testDoubleUpDownCounter").ofDoubles().build())
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() ->
|
() ->
|
||||||
sdkMeter
|
sdkMeter
|
||||||
|
|
@ -234,7 +239,7 @@ class SdkMeterTest {
|
||||||
.ofDoubles()
|
.ofDoubles()
|
||||||
.build())
|
.build())
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -247,21 +252,22 @@ class SdkMeterTest {
|
||||||
.build();
|
.build();
|
||||||
assertThat(doubleValueRecorder).isNotNull();
|
assertThat(doubleValueRecorder).isNotNull();
|
||||||
|
|
||||||
assertThat(
|
// Note: We no longer get the same instrument instance as these instances are lightweight
|
||||||
sdkMeter
|
// objects backed by storage now. Here we just make sure it doesn't throw to grab
|
||||||
.histogramBuilder("testDoubleValueRecorder")
|
// a second instance.
|
||||||
.setDescription("My very own ValueRecorder")
|
sdkMeter
|
||||||
.setUnit("metric tonnes")
|
.histogramBuilder("testDoubleValueRecorder")
|
||||||
.build())
|
.setDescription("My very own ValueRecorder")
|
||||||
.isSameAs(doubleValueRecorder);
|
.setUnit("metric tonnes")
|
||||||
|
.build();
|
||||||
|
|
||||||
assertThatThrownBy(() -> sdkMeter.histogramBuilder("testDoubleValueRecorder").build())
|
assertThatThrownBy(() -> sdkMeter.histogramBuilder("testDoubleValueRecorder").build())
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() -> sdkMeter.histogramBuilder("testDoubleValueRecorder".toUpperCase()).build())
|
() -> sdkMeter.histogramBuilder("testDoubleValueRecorder".toUpperCase()).build())
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -280,7 +286,7 @@ class SdkMeterTest {
|
||||||
.ofDoubles()
|
.ofDoubles()
|
||||||
.buildWithCallback(x -> {}))
|
.buildWithCallback(x -> {}))
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() ->
|
() ->
|
||||||
sdkMeter
|
sdkMeter
|
||||||
|
|
@ -288,7 +294,7 @@ class SdkMeterTest {
|
||||||
.ofDoubles()
|
.ofDoubles()
|
||||||
.buildWithCallback(x -> {}))
|
.buildWithCallback(x -> {}))
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -307,7 +313,7 @@ class SdkMeterTest {
|
||||||
.ofDoubles()
|
.ofDoubles()
|
||||||
.buildWithCallback(x -> {}))
|
.buildWithCallback(x -> {}))
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() ->
|
() ->
|
||||||
sdkMeter
|
sdkMeter
|
||||||
|
|
@ -315,7 +321,7 @@ class SdkMeterTest {
|
||||||
.ofDoubles()
|
.ofDoubles()
|
||||||
.buildWithCallback(x -> {}))
|
.buildWithCallback(x -> {}))
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -329,13 +335,13 @@ class SdkMeterTest {
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() -> sdkMeter.gaugeBuilder("doubleValueObserver").buildWithCallback(x -> {}))
|
() -> sdkMeter.gaugeBuilder("doubleValueObserver").buildWithCallback(x -> {}))
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() ->
|
() ->
|
||||||
sdkMeter
|
sdkMeter
|
||||||
.gaugeBuilder("doubleValueObserver".toUpperCase())
|
.gaugeBuilder("doubleValueObserver".toUpperCase())
|
||||||
.buildWithCallback(x -> {}))
|
.buildWithCallback(x -> {}))
|
||||||
.isInstanceOf(IllegalArgumentException.class)
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
.hasMessage("Instrument with same name and different descriptor already created.");
|
.hasMessageContaining("Metric with same name and different descriptor already created.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ class AggregatorFactoryTest {
|
||||||
"name",
|
"name",
|
||||||
"description",
|
"description",
|
||||||
"unit",
|
"unit",
|
||||||
InstrumentType.VALUE_RECORDER,
|
InstrumentType.HISTOGRAM,
|
||||||
InstrumentValueType.LONG)))
|
InstrumentValueType.LONG)))
|
||||||
.isInstanceOf(DoubleHistogramAggregator.class);
|
.isInstanceOf(DoubleHistogramAggregator.class);
|
||||||
assertThat(
|
assertThat(
|
||||||
|
|
@ -150,7 +150,7 @@ class AggregatorFactoryTest {
|
||||||
"name",
|
"name",
|
||||||
"description",
|
"description",
|
||||||
"unit",
|
"unit",
|
||||||
InstrumentType.VALUE_RECORDER,
|
InstrumentType.HISTOGRAM,
|
||||||
InstrumentValueType.DOUBLE)))
|
InstrumentValueType.DOUBLE)))
|
||||||
.isInstanceOf(DoubleHistogramAggregator.class);
|
.isInstanceOf(DoubleHistogramAggregator.class);
|
||||||
|
|
||||||
|
|
@ -163,7 +163,7 @@ class AggregatorFactoryTest {
|
||||||
"name",
|
"name",
|
||||||
"description",
|
"description",
|
||||||
"unit",
|
"unit",
|
||||||
InstrumentType.VALUE_RECORDER,
|
InstrumentType.HISTOGRAM,
|
||||||
InstrumentValueType.LONG))
|
InstrumentValueType.LONG))
|
||||||
.isStateful())
|
.isStateful())
|
||||||
.isFalse();
|
.isFalse();
|
||||||
|
|
@ -177,7 +177,7 @@ class AggregatorFactoryTest {
|
||||||
"name",
|
"name",
|
||||||
"description",
|
"description",
|
||||||
"unit",
|
"unit",
|
||||||
InstrumentType.VALUE_RECORDER,
|
InstrumentType.HISTOGRAM,
|
||||||
InstrumentValueType.DOUBLE))
|
InstrumentValueType.DOUBLE))
|
||||||
.isStateful())
|
.isStateful())
|
||||||
.isTrue();
|
.isTrue();
|
||||||
|
|
|
||||||
|
|
@ -26,22 +26,14 @@ class CountAggregatorTest {
|
||||||
Resource.getDefault(),
|
Resource.getDefault(),
|
||||||
InstrumentationLibraryInfo.empty(),
|
InstrumentationLibraryInfo.empty(),
|
||||||
InstrumentDescriptor.create(
|
InstrumentDescriptor.create(
|
||||||
"name",
|
"name", "description", "unit", InstrumentType.HISTOGRAM, InstrumentValueType.LONG),
|
||||||
"description",
|
|
||||||
"unit",
|
|
||||||
InstrumentType.VALUE_RECORDER,
|
|
||||||
InstrumentValueType.LONG),
|
|
||||||
AggregationTemporality.CUMULATIVE);
|
AggregationTemporality.CUMULATIVE);
|
||||||
private static final CountAggregator deltaAggregator =
|
private static final CountAggregator deltaAggregator =
|
||||||
new CountAggregator(
|
new CountAggregator(
|
||||||
Resource.getDefault(),
|
Resource.getDefault(),
|
||||||
InstrumentationLibraryInfo.empty(),
|
InstrumentationLibraryInfo.empty(),
|
||||||
InstrumentDescriptor.create(
|
InstrumentDescriptor.create(
|
||||||
"name",
|
"name", "description", "unit", InstrumentType.HISTOGRAM, InstrumentValueType.LONG),
|
||||||
"description",
|
|
||||||
"unit",
|
|
||||||
InstrumentType.VALUE_RECORDER,
|
|
||||||
InstrumentValueType.LONG),
|
|
||||||
AggregationTemporality.DELTA);
|
AggregationTemporality.DELTA);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,7 @@ public class DoubleHistogramAggregatorTest {
|
||||||
Resource.getDefault(),
|
Resource.getDefault(),
|
||||||
InstrumentationLibraryInfo.empty(),
|
InstrumentationLibraryInfo.empty(),
|
||||||
InstrumentDescriptor.create(
|
InstrumentDescriptor.create(
|
||||||
"name",
|
"name", "description", "unit", InstrumentType.HISTOGRAM, InstrumentValueType.LONG),
|
||||||
"description",
|
|
||||||
"unit",
|
|
||||||
InstrumentType.VALUE_RECORDER,
|
|
||||||
InstrumentValueType.LONG),
|
|
||||||
boundaries,
|
boundaries,
|
||||||
/* stateful= */ false);
|
/* stateful= */ false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class DoubleLastValueAggregatorTest {
|
||||||
"name",
|
"name",
|
||||||
"description",
|
"description",
|
||||||
"unit",
|
"unit",
|
||||||
InstrumentType.VALUE_OBSERVER,
|
InstrumentType.OBSERVABLE_GAUGE,
|
||||||
InstrumentValueType.DOUBLE));
|
InstrumentValueType.DOUBLE));
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,7 @@ class DoubleMinMaxSumCountAggregatorTest {
|
||||||
Resource.getDefault(),
|
Resource.getDefault(),
|
||||||
InstrumentationLibraryInfo.empty(),
|
InstrumentationLibraryInfo.empty(),
|
||||||
InstrumentDescriptor.create(
|
InstrumentDescriptor.create(
|
||||||
"name",
|
"name", "description", "unit", InstrumentType.HISTOGRAM, InstrumentValueType.DOUBLE));
|
||||||
"description",
|
|
||||||
"unit",
|
|
||||||
InstrumentType.VALUE_RECORDER,
|
|
||||||
InstrumentValueType.DOUBLE));
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void createHandle() {
|
void createHandle() {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class LongLastValueAggregatorTest {
|
||||||
"name",
|
"name",
|
||||||
"description",
|
"description",
|
||||||
"unit",
|
"unit",
|
||||||
InstrumentType.VALUE_OBSERVER,
|
InstrumentType.OBSERVABLE_GAUGE,
|
||||||
InstrumentValueType.LONG));
|
InstrumentValueType.LONG));
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,7 @@ class LongMinMaxSumCountAggregatorTest {
|
||||||
Resource.getDefault(),
|
Resource.getDefault(),
|
||||||
InstrumentationLibraryInfo.empty(),
|
InstrumentationLibraryInfo.empty(),
|
||||||
InstrumentDescriptor.create(
|
InstrumentDescriptor.create(
|
||||||
"name",
|
"name", "description", "unit", InstrumentType.HISTOGRAM, InstrumentValueType.LONG));
|
||||||
"description",
|
|
||||||
"unit",
|
|
||||||
InstrumentType.VALUE_RECORDER,
|
|
||||||
InstrumentValueType.LONG));
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void createHandle() {
|
void createHandle() {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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.common.Attributes;
|
||||||
import io.opentelemetry.context.Context;
|
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.InstrumentDescriptor;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentValueType;
|
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.processor.LabelsProcessor;
|
||||||
import io.opentelemetry.sdk.metrics.view.InstrumentSelector;
|
import io.opentelemetry.sdk.metrics.view.InstrumentSelector;
|
||||||
import io.opentelemetry.sdk.metrics.view.View;
|
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.junit.jupiter.api.Test;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
public class AsynchronousInstrumentAccumulatorTest {
|
public class AsynchronousMetricStorageTest {
|
||||||
private final TestClock testClock = TestClock.create();
|
private final TestClock testClock = TestClock.create();
|
||||||
private MeterProviderSharedState meterProviderSharedState;
|
private MeterProviderSharedState meterProviderSharedState;
|
||||||
private final MeterSharedState meterSharedState =
|
private final MeterSharedState meterSharedState =
|
||||||
|
|
@ -43,7 +44,7 @@ public class AsynchronousInstrumentAccumulatorTest {
|
||||||
ViewRegistry.builder()
|
ViewRegistry.builder()
|
||||||
.addView(
|
.addView(
|
||||||
InstrumentSelector.builder()
|
InstrumentSelector.builder()
|
||||||
.setInstrumentType(InstrumentType.VALUE_OBSERVER)
|
.setInstrumentType(InstrumentType.OBSERVABLE_GAUGE)
|
||||||
.build(),
|
.build(),
|
||||||
View.builder()
|
View.builder()
|
||||||
.setAggregatorFactory(AggregatorFactory.lastValue())
|
.setAggregatorFactory(AggregatorFactory.lastValue())
|
||||||
|
|
@ -58,33 +59,33 @@ public class AsynchronousInstrumentAccumulatorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void doubleAsynchronousAccumulator_LabelsProcessor_used() {
|
void doubleAsynchronousAccumulator_LabelsProcessor_used() {
|
||||||
AsynchronousInstrumentAccumulator.doubleAsynchronousAccumulator(
|
AsynchronousMetricStorage.doubleAsynchronousAccumulator(
|
||||||
meterProviderSharedState,
|
meterProviderSharedState,
|
||||||
meterSharedState,
|
meterSharedState,
|
||||||
InstrumentDescriptor.create(
|
InstrumentDescriptor.create(
|
||||||
"name",
|
"name",
|
||||||
"description",
|
"description",
|
||||||
"unit",
|
"unit",
|
||||||
InstrumentType.VALUE_OBSERVER,
|
InstrumentType.OBSERVABLE_GAUGE,
|
||||||
InstrumentValueType.DOUBLE),
|
InstrumentValueType.DOUBLE),
|
||||||
value -> value.observe(1.0, Attributes.empty()))
|
value -> value.observe(1.0, Attributes.empty()))
|
||||||
.collectAll(testClock.nanoTime());
|
.collectAndReset(0, testClock.now());
|
||||||
Mockito.verify(spyLabelProcessor).onLabelsBound(Context.current(), Attributes.empty());
|
Mockito.verify(spyLabelProcessor).onLabelsBound(Context.current(), Attributes.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void longAsynchronousAccumulator_LabelsProcessor_used() {
|
void longAsynchronousAccumulator_LabelsProcessor_used() {
|
||||||
AsynchronousInstrumentAccumulator.longAsynchronousAccumulator(
|
AsynchronousMetricStorage.longAsynchronousAccumulator(
|
||||||
meterProviderSharedState,
|
meterProviderSharedState,
|
||||||
meterSharedState,
|
meterSharedState,
|
||||||
InstrumentDescriptor.create(
|
InstrumentDescriptor.create(
|
||||||
"name",
|
"name",
|
||||||
"description",
|
"description",
|
||||||
"unit",
|
"unit",
|
||||||
InstrumentType.VALUE_OBSERVER,
|
InstrumentType.OBSERVABLE_GAUGE,
|
||||||
InstrumentValueType.LONG),
|
InstrumentValueType.LONG),
|
||||||
value -> value.observe(1, Attributes.empty()))
|
value -> value.observe(1, Attributes.empty()))
|
||||||
.collectAll(testClock.nanoTime());
|
.collectAndReset(0, testClock.nanoTime());
|
||||||
Mockito.verify(spyLabelProcessor).onLabelsBound(Context.current(), Attributes.empty());
|
Mockito.verify(spyLabelProcessor).onLabelsBound(Context.current(), Attributes.empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,9 +3,10 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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.OpenTelemetryAssertions.assertThat;
|
||||||
|
import static io.opentelemetry.sdk.testing.assertj.metrics.MetricAssertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
import io.opentelemetry.api.common.Attributes;
|
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.common.InstrumentationLibraryInfo;
|
||||||
import io.opentelemetry.sdk.metrics.aggregator.Aggregator;
|
import io.opentelemetry.sdk.metrics.aggregator.Aggregator;
|
||||||
import io.opentelemetry.sdk.metrics.aggregator.AggregatorFactory;
|
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.InstrumentDescriptor;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
||||||
import io.opentelemetry.sdk.metrics.common.InstrumentValueType;
|
import io.opentelemetry.sdk.metrics.common.InstrumentValueType;
|
||||||
import io.opentelemetry.sdk.metrics.data.MetricData;
|
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.LabelsProcessor;
|
||||||
import io.opentelemetry.sdk.metrics.processor.LabelsProcessorFactory;
|
import io.opentelemetry.sdk.metrics.processor.LabelsProcessorFactory;
|
||||||
import io.opentelemetry.sdk.resources.Resource;
|
import io.opentelemetry.sdk.resources.Resource;
|
||||||
import io.opentelemetry.sdk.testing.time.TestClock;
|
import io.opentelemetry.sdk.testing.time.TestClock;
|
||||||
import java.util.List;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
public class SynchronousInstrumentAccumulatorTest {
|
public class SynchronousMetricStorageTest {
|
||||||
private static final InstrumentDescriptor DESCRIPTOR =
|
private static final InstrumentDescriptor DESCRIPTOR =
|
||||||
InstrumentDescriptor.create(
|
InstrumentDescriptor.create(
|
||||||
"name", "description", "unit", InstrumentType.COUNTER, InstrumentValueType.DOUBLE);
|
"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 TestClock testClock = TestClock.create();
|
||||||
private final Aggregator<Long> aggregator =
|
private final Aggregator<Long> aggregator =
|
||||||
AggregatorFactory.lastValue()
|
AggregatorFactory.lastValue()
|
||||||
|
|
@ -41,9 +43,12 @@ public class SynchronousInstrumentAccumulatorTest {
|
||||||
@Test
|
@Test
|
||||||
void labelsProcessor_used() {
|
void labelsProcessor_used() {
|
||||||
LabelsProcessor spyLabelsProcessor = Mockito.spy(this.labelsProcessor);
|
LabelsProcessor spyLabelsProcessor = Mockito.spy(this.labelsProcessor);
|
||||||
SynchronousInstrumentAccumulator<?> accumulator =
|
SynchronousMetricStorage<?> accumulator =
|
||||||
new SynchronousInstrumentAccumulator<>(
|
new SynchronousMetricStorage<>(
|
||||||
aggregator, new InstrumentProcessor<>(aggregator, testClock.now()), spyLabelsProcessor);
|
METRIC_DESCRIPTOR,
|
||||||
|
aggregator,
|
||||||
|
new InstrumentProcessor<>(aggregator, testClock.now()),
|
||||||
|
spyLabelsProcessor);
|
||||||
accumulator.bind(Attributes.empty());
|
accumulator.bind(Attributes.empty());
|
||||||
Mockito.verify(spyLabelsProcessor).onLabelsBound(Context.current(), Attributes.empty());
|
Mockito.verify(spyLabelsProcessor).onLabelsBound(Context.current(), Attributes.empty());
|
||||||
}
|
}
|
||||||
|
|
@ -59,44 +64,55 @@ public class SynchronousInstrumentAccumulatorTest {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
LabelsProcessor spyLabelsProcessor = Mockito.spy(labelsProcessor);
|
LabelsProcessor spyLabelsProcessor = Mockito.spy(labelsProcessor);
|
||||||
SynchronousInstrumentAccumulator<?> accumulator =
|
SynchronousMetricStorage<?> accumulator =
|
||||||
new SynchronousInstrumentAccumulator<>(
|
new SynchronousMetricStorage<>(
|
||||||
aggregator, new InstrumentProcessor<>(aggregator, testClock.now()), spyLabelsProcessor);
|
METRIC_DESCRIPTOR,
|
||||||
AggregatorHandle<?> aggregatorHandle = accumulator.bind(labels);
|
aggregator,
|
||||||
aggregatorHandle.recordDouble(1);
|
new InstrumentProcessor<>(aggregator, testClock.now()),
|
||||||
List<MetricData> md = accumulator.collectAll(testClock.now());
|
spyLabelsProcessor);
|
||||||
md.stream()
|
BoundStorageHandle handle = accumulator.bind(labels);
|
||||||
.flatMap(m -> m.getLongGaugeData().getPoints().stream())
|
handle.recordDouble(1, labels, Context.root());
|
||||||
.forEach(
|
MetricData md = accumulator.collectAndReset(0, testClock.now());
|
||||||
p -> assertThat(p.getAttributes()).hasSize(1).containsEntry("modifiedK", "modifiedV"));
|
assertThat(md)
|
||||||
|
.hasDoubleGauge()
|
||||||
|
.points()
|
||||||
|
.allSatisfy(
|
||||||
|
p ->
|
||||||
|
assertThat(p)
|
||||||
|
.attributes()
|
||||||
|
.hasSize(2)
|
||||||
|
.containsEntry("modifiedK", "modifiedV")
|
||||||
|
.containsEntry("K", "V"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void sameAggregator_ForSameLabelSet() {
|
void sameAggregator_ForSameAttributes() {
|
||||||
SynchronousInstrumentAccumulator<?> accumulator =
|
SynchronousMetricStorage<?> accumulator =
|
||||||
new SynchronousInstrumentAccumulator<>(
|
new SynchronousMetricStorage<>(
|
||||||
aggregator, new InstrumentProcessor<>(aggregator, testClock.now()), labelsProcessor);
|
METRIC_DESCRIPTOR,
|
||||||
AggregatorHandle<?> aggregatorHandle =
|
aggregator,
|
||||||
accumulator.bind(Attributes.builder().put("K", "V").build());
|
new InstrumentProcessor<>(aggregator, testClock.now()),
|
||||||
AggregatorHandle<?> duplicateAggregatorHandle =
|
labelsProcessor);
|
||||||
|
BoundStorageHandle handle = accumulator.bind(Attributes.builder().put("K", "V").build());
|
||||||
|
BoundStorageHandle duplicateHandle =
|
||||||
accumulator.bind(Attributes.builder().put("K", "V").build());
|
accumulator.bind(Attributes.builder().put("K", "V").build());
|
||||||
try {
|
try {
|
||||||
assertThat(duplicateAggregatorHandle).isSameAs(aggregatorHandle);
|
assertThat(duplicateHandle).isSameAs(handle);
|
||||||
accumulator.collectAll(testClock.now());
|
accumulator.collectAndReset(0, testClock.now());
|
||||||
AggregatorHandle<?> anotherDuplicateAggregatorHandle =
|
BoundStorageHandle anotherDuplicateAggregatorHandle =
|
||||||
accumulator.bind(Attributes.builder().put("K", "V").build());
|
accumulator.bind(Attributes.builder().put("K", "V").build());
|
||||||
try {
|
try {
|
||||||
assertThat(anotherDuplicateAggregatorHandle).isSameAs(aggregatorHandle);
|
assertThat(anotherDuplicateAggregatorHandle).isSameAs(handle);
|
||||||
} finally {
|
} finally {
|
||||||
anotherDuplicateAggregatorHandle.release();
|
anotherDuplicateAggregatorHandle.release();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
duplicateAggregatorHandle.release();
|
duplicateHandle.release();
|
||||||
aggregatorHandle.release();
|
handle.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point we should be able to unmap because all references are gone. Because this is an
|
// If we try to collect once all bound references are gone AND no recordings have occurred, we
|
||||||
// internal detail we cannot call collectAll after this anymore.
|
// should not see any labels (or metric).
|
||||||
assertThat(aggregatorHandle.tryUnmap()).isTrue();
|
assertThat(accumulator.collectAndReset(0, testClock.now())).isNull();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
|
@ -154,22 +154,22 @@ class ViewRegistryTest {
|
||||||
assertThat(
|
assertThat(
|
||||||
viewRegistry.findView(
|
viewRegistry.findView(
|
||||||
InstrumentDescriptor.create(
|
InstrumentDescriptor.create(
|
||||||
"", "", "", InstrumentType.VALUE_RECORDER, InstrumentValueType.LONG)))
|
"", "", "", InstrumentType.HISTOGRAM, InstrumentValueType.LONG)))
|
||||||
.isSameAs(ViewRegistry.SUMMARY);
|
.isSameAs(ViewRegistry.SUMMARY);
|
||||||
assertThat(
|
assertThat(
|
||||||
viewRegistry.findView(
|
viewRegistry.findView(
|
||||||
InstrumentDescriptor.create(
|
InstrumentDescriptor.create(
|
||||||
"", "", "", InstrumentType.SUM_OBSERVER, InstrumentValueType.LONG)))
|
"", "", "", InstrumentType.OBSERVABLE_SUM, InstrumentValueType.LONG)))
|
||||||
.isSameAs(ViewRegistry.CUMULATIVE_SUM);
|
.isSameAs(ViewRegistry.CUMULATIVE_SUM);
|
||||||
assertThat(
|
assertThat(
|
||||||
viewRegistry.findView(
|
viewRegistry.findView(
|
||||||
InstrumentDescriptor.create(
|
InstrumentDescriptor.create(
|
||||||
"", "", "", InstrumentType.VALUE_OBSERVER, InstrumentValueType.LONG)))
|
"", "", "", InstrumentType.OBSERVABLE_GAUGE, InstrumentValueType.LONG)))
|
||||||
.isSameAs(ViewRegistry.LAST_VALUE);
|
.isSameAs(ViewRegistry.LAST_VALUE);
|
||||||
assertThat(
|
assertThat(
|
||||||
viewRegistry.findView(
|
viewRegistry.findView(
|
||||||
InstrumentDescriptor.create(
|
InstrumentDescriptor.create(
|
||||||
"", "", "", InstrumentType.UP_DOWN_SUM_OBSERVER, InstrumentValueType.LONG)))
|
"", "", "", InstrumentType.OBSERVABLE_UP_DOWN_SUM, InstrumentValueType.LONG)))
|
||||||
.isSameAs(ViewRegistry.CUMULATIVE_SUM);
|
.isSameAs(ViewRegistry.CUMULATIVE_SUM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue