Swap old Metrics API for currently specified Metrics API (#3423)

* Update the API to the latest SDK specification.

* API updates to other sdk areas.

* First half of SDK updates for API.

Passing off to other cmoputer.

* Get SDK compiling again.

* Get tests compiling again (and failing).

* Fix bad copy-paste error.

* Get all SDK tests passing.

* More fixes to builds across SDK impls.

* Remove unecessary publics

* more fixes for new API.

* spotless fixes.

* Make tests for metric points order independent.

* Restore readme.

* Fix readmes.

* Add noop meter provider tests for code coverage.

* Add code coverage for assertion library.

* Fix wierd test failure that gradle cache is preventing me from seeing locally.

* Fix javadoc/spelling comments from review.

* Remove marker interfaces.

* Switch from atomic ref to volatile.

* Fixes from review.

* Apply suggestions from code review

Co-authored-by: John Watson <jkwatson@gmail.com>

* Fixes from review.

* Fixes from review.

* Update OTLP HTTP exporter to use new metrics api

Co-authored-by: John Watson <jkwatson@gmail.com>
This commit is contained in:
Josh Suereth 2021-08-05 16:58:49 -04:00 committed by GitHub
parent 20f872d8dc
commit 0ef19291c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
170 changed files with 3066 additions and 5789 deletions

View File

@ -2,8 +2,11 @@
[![Javadocs][javadoc-image]][javadoc-url]
* The code in this module is the implementation of the [experimental OpenTelemetry metrics signal][metrics-spec].
* The default implementation of the interfaces in this module is in the OpenTelemetry metrics SDK module.
* The interfaces in this directory can be implemented to create alternative
implementations of the OpenTelemetry library.
[javadoc-image]: https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-api-metrics.svg
[javadoc-url]: https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api-metrics
[javadoc-url]: https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api-metrics
[metrics-spec]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md

View File

@ -11,6 +11,7 @@ otelJava.moduleName.set("io.opentelemetry.api.metrics")
dependencies {
api(project(":api:all"))
api(project(":context"))
annotationProcessor("com.google.auto.value:auto-value")

View File

@ -1,32 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import io.opentelemetry.api.metrics.common.Labels;
import javax.annotation.concurrent.ThreadSafe;
/**
* {@code AsynchronousInstrument} is an interface that defines a type of instruments that are used
* to report measurements asynchronously.
*
* <p>They are reported by a callback, once per collection interval, and lack Context. They are
* permitted to report only one value per distinct label set per period. If the application observes
* multiple values for the same label set, in a single callback, the last value is the only value
* kept.
*/
@ThreadSafe
public interface AsynchronousInstrument extends Instrument {
/** The result pass to the updater. */
interface LongResult {
void observe(long value, Labels labels);
}
/** The result pass to the updater. */
interface DoubleResult {
void observe(double value, Labels labels);
}
}

View File

@ -1,24 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import java.util.function.Consumer;
/** Builder class for {@link AsynchronousInstrument}. */
public interface AsynchronousInstrumentBuilder<R> extends InstrumentBuilder {
/**
* Sets a consumer that gets executed every collection interval.
*
* <p>Evaluation is deferred until needed, if this {@code AsynchronousInstrument} metric is not
* exported then it will never be called.
*
* @param updater the consumer to be executed before export.
*/
AsynchronousInstrumentBuilder<R> setUpdater(Consumer<R> updater);
@Override
AsynchronousInstrument build();
}

View File

@ -1,85 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import javax.annotation.concurrent.ThreadSafe;
/**
* Util class that can be use to atomically record measurements associated with a set of Metrics.
*
* <p>This class is equivalent with individually calling record on every Measure, but has the
* advantage that all these operations are recorded atomically and it is more efficient.
*/
@ThreadSafe
public interface BatchRecorder {
/**
* Associates the {@link LongValueRecorder} with the given value. Subsequent updates to the same
* {@link LongValueRecorder} will overwrite the previous value.
*
* @param valueRecorder the {@link LongValueRecorder}.
* @param value the value to be associated with {@code valueRecorder}.
* @return this.
*/
BatchRecorder put(LongValueRecorder valueRecorder, long value);
/**
* Associates the {@link DoubleValueRecorder} with the given value. Subsequent updates to the same
* {@link DoubleValueRecorder} will overwrite the previous value.
*
* @param valueRecorder the {@link DoubleValueRecorder}.
* @param value the value to be associated with {@code valueRecorder}.
* @return this.
*/
BatchRecorder put(DoubleValueRecorder valueRecorder, double value);
/**
* Associates the {@link LongCounter} with the given value. Subsequent updates to the same {@link
* LongCounter} will overwrite the previous value.
*
* @param counter the {@link LongCounter}.
* @param value the value to be associated with {@code counter}.
* @return this.
*/
BatchRecorder put(LongCounter counter, long value);
/**
* Associates the {@link DoubleCounter} with the given value. Subsequent updates to the same
* {@link DoubleCounter} will overwrite the previous value.
*
* @param counter the {@link DoubleCounter}.
* @param value the value to be associated with {@code counter}.
* @return this.
*/
BatchRecorder put(DoubleCounter counter, double value);
/**
* Associates the {@link LongUpDownCounter} with the given value. Subsequent updates to the same
* {@link LongCounter} will overwrite the previous value.
*
* @param upDownCounter the {@link LongCounter}.
* @param value the value to be associated with {@code counter}.
* @return this.
*/
BatchRecorder put(LongUpDownCounter upDownCounter, long value);
/**
* Associates the {@link DoubleUpDownCounter} with the given value. Subsequent updates to the same
* {@link DoubleCounter} will overwrite the previous value.
*
* @param upDownCounter the {@link DoubleCounter}.
* @param value the value to be associated with {@code counter}.
* @return this.
*/
BatchRecorder put(DoubleUpDownCounter upDownCounter, double value);
/**
* Records all of measurements at the same time.
*
* <p>This method records all measurements every time it is called, so make sure it is not called
* twice if not needed.
*/
void record();
}

View File

@ -5,20 +5,35 @@
package io.opentelemetry.api.metrics;
import io.opentelemetry.context.Context;
import javax.annotation.concurrent.ThreadSafe;
/** A {@code Bound Instrument} for a {@link DoubleCounter}. */
/** A counter instrument that records {@code double} values with pre-associated attributes. */
@ThreadSafe
public interface BoundDoubleCounter extends BoundSynchronousInstrument {
public interface BoundDoubleCounter {
/**
* Adds the given {@code increment} to the current value. The values cannot be negative.
* Records a value with pre-bound attributes.
*
* <p>The value added is associated with the current {@code Context}.
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param increment the value to add.
* @param value The increment amount. MUST be non-negative.
*/
void add(double increment);
void add(double value);
@Override
/**
* Records a value with pre-bound attributes.
*
* @param value The increment amount. MUST be non-negative.
* @param context The explicit context to associate with this measurement.
*/
void add(double value, Context context);
/**
* Unbinds the current bound instance from the {@link DoubleCounter}.
*
* <p>After this method returns the current instance is considered invalid (not being managed by
* the instrument).
*/
void unbind();
}

View File

@ -0,0 +1,39 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import io.opentelemetry.context.Context;
import javax.annotation.concurrent.ThreadSafe;
/** A histogram instrument that records {@code long} values with pre-associated attributes. */
@ThreadSafe
public interface BoundDoubleHistogram {
/**
* Records a value with a pre-bound set of attributes.
*
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param value The amount of the measurement.
*/
void record(double value);
/**
* Records a value with a pre-bound set of attributes.
*
* @param value The amount of the measurement.
* @param context The explicit context to associate with this measurement.
*/
void record(double value, Context context);
/**
* Unbinds the current bound instance from the {@link DoubleHistogram}.
*
* <p>After this method returns the current instance is considered invalid (not being managed by
* the instrument).
*/
void unbind();
}

View File

@ -5,20 +5,35 @@
package io.opentelemetry.api.metrics;
import io.opentelemetry.context.Context;
import javax.annotation.concurrent.ThreadSafe;
/** A {@code Bound Instrument} for a {@link DoubleUpDownCounter}. */
/** An up-down-counter instrument with pre-bound attributes. */
@ThreadSafe
public interface BoundDoubleUpDownCounter extends BoundSynchronousInstrument {
public interface BoundDoubleUpDownCounter {
/**
* Adds the given {@code increment} to the current value.
* Records a value with pre-bound attributes.
*
* <p>The value added is associated with the current {@code Context}.
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param increment the value to add.
* @param value The increment amount. May be positive, negative or zero.
*/
void add(double increment);
void add(double value);
@Override
/**
* Records a value with a pre-bound attributes.
*
* @param value The increment amount. May be positive, negative or zero.
* @param context The explicit context to associate with this measurement.
*/
void add(double value, Context context);
/**
* Unbinds the current bound instance from the {@link DoubleUpDownCounter}.
*
* <p>After this method returns the current instance is considered invalid (not being managed by
* the instrument).
*/
void unbind();
}

View File

@ -1,23 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import javax.annotation.concurrent.ThreadSafe;
/** A {@code Bound Instrument} for a {@link DoubleValueRecorder}. */
@ThreadSafe
public interface BoundDoubleValueRecorder extends BoundSynchronousInstrument {
/**
* Records the given measurement, associated with the current {@code Context}.
*
* @param value the measurement to record.
* @throws IllegalArgumentException if value is negative.
*/
void record(double value);
@Override
void unbind();
}

View File

@ -5,21 +5,35 @@
package io.opentelemetry.api.metrics;
import io.opentelemetry.context.Context;
import javax.annotation.concurrent.ThreadSafe;
/** A {@code Bound Instrument} for a {@link LongCounter}. */
/** A counter instrument that records {@code long} values with pre-associated attributes. */
@ThreadSafe
public interface BoundLongCounter extends BoundSynchronousInstrument {
public interface BoundLongCounter {
/**
* Records a value with pre-bound attributes.
*
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param value The increment amount. MUST be non-negative.
*/
void add(long value);
/**
* Adds the given {@code increment} to the current value. The values cannot be negative.
* Records a value with pre-bound attributes.
*
* <p>The value added is associated with the current {@code Context}.
*
* @param increment the value to add.
* @param value The increment amount. MUST be non-negative.
* @param context The explicit context to associate with this measurement.
*/
void add(long increment);
void add(long value, Context context);
@Override
/**
* Unbinds the current bound instance from the {@link LongCounter}.
*
* <p>After this method returns the current instance is considered invalid (not being managed by
* the instrument).
*/
void unbind();
}

View File

@ -0,0 +1,39 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import io.opentelemetry.context.Context;
import javax.annotation.concurrent.ThreadSafe;
/** A histogram instrument that records {@code long} values with pre-associated attributes. */
@ThreadSafe
public interface BoundLongHistogram {
/**
* Records a value with a pre-bound set of attributes.
*
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param value The amount of the measurement.
*/
void record(long value);
/**
* Records a value with a pre-bound set of attributes.
*
* @param value The amount of the measurement.
* @param context The explicit context to associate with this measurement.
*/
void record(long value, Context context);
/**
* Unbinds the current bound instance from the {@link LongHistogram}.
*
* <p>After this method returns the current instance is considered invalid (not being managed by
* the instrument).
*/
void unbind();
}

View File

@ -5,21 +5,35 @@
package io.opentelemetry.api.metrics;
import io.opentelemetry.context.Context;
import javax.annotation.concurrent.ThreadSafe;
/** A {@code Bound Instrument} for a {@link LongUpDownCounter}. */
/** An up-down-counter instrument with pre-bound attributes. */
@ThreadSafe
public interface BoundLongUpDownCounter extends BoundSynchronousInstrument {
public interface BoundLongUpDownCounter {
/**
* Records a value with pre-bound attributes.
*
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param value The increment amount. May be positive, negative or zero.
*/
void add(long value);
/**
* Adds the given {@code increment} to the current value.
* Records a value with a pre-bound attributes.
*
* <p>The value added is associated with the current {@code Context}.
*
* @param increment the value to add.
* @param value The increment amount. May be positive, negative or zero.
* @param context The explicit context to associate with this measurement.
*/
void add(long increment);
void add(long value, Context context);
@Override
/**
* Unbinds the current bound instance from the {@link LongUpDownCounter}.
*
* <p>After this method returns the current instance is considered invalid (not being managed by
* the instrument).
*/
void unbind();
}

View File

@ -1,23 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import javax.annotation.concurrent.ThreadSafe;
/** A {@code Bound Instrument} for a {@link LongValueRecorder}. */
@ThreadSafe
public interface BoundLongValueRecorder extends BoundSynchronousInstrument {
/**
* Records the given measurement, associated with the current {@code Context}.
*
* @param value the measurement to record.
* @throws IllegalArgumentException if value is negative.
*/
void record(long value);
@Override
void unbind();
}

View File

@ -1,16 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
interface BoundSynchronousInstrument {
/**
* Unbinds the current {@code Bound} from the Instrument.
*
* <p>After this method returns the current instance {@code Bound} is considered invalid (not
* being managed by the instrument).
*/
void unbind();
}

View File

@ -1,661 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import io.opentelemetry.api.internal.Utils;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.api.metrics.internal.MetricsStringUtils;
import java.util.Objects;
import java.util.function.Consumer;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;
/** No-op implementations of {@link Meter}. */
@ThreadSafe
final class DefaultMeter implements Meter {
private static final DefaultMeter INSTANCE = new DefaultMeter();
private static final String COUNTERS_CAN_ONLY_INCREASE = "Counters can only increase";
/* VisibleForTesting */ static final String ERROR_MESSAGE_INVALID_NAME =
"Name should be a ASCII string with a length no greater than "
+ MetricsStringUtils.METRIC_NAME_MAX_LENGTH
+ " characters.";
static Meter getInstance() {
return INSTANCE;
}
@Override
public DoubleCounterBuilder doubleCounterBuilder(String name) {
Objects.requireNonNull(name, "name");
Utils.checkArgument(MetricsStringUtils.isValidMetricName(name), ERROR_MESSAGE_INVALID_NAME);
return new NoopDoubleCounter.NoopBuilder();
}
@Override
public LongCounterBuilder longCounterBuilder(String name) {
Objects.requireNonNull(name, "name");
Utils.checkArgument(MetricsStringUtils.isValidMetricName(name), ERROR_MESSAGE_INVALID_NAME);
return new NoopLongCounter.NoopBuilder();
}
@Override
public DoubleUpDownCounterBuilder doubleUpDownCounterBuilder(String name) {
Objects.requireNonNull(name, "name");
Utils.checkArgument(MetricsStringUtils.isValidMetricName(name), ERROR_MESSAGE_INVALID_NAME);
return new NoopDoubleUpDownCounter.NoopBuilder();
}
@Override
public LongUpDownCounterBuilder longUpDownCounterBuilder(String name) {
Objects.requireNonNull(name, "name");
Utils.checkArgument(MetricsStringUtils.isValidMetricName(name), ERROR_MESSAGE_INVALID_NAME);
return new NoopLongUpDownCounter.NoopBuilder();
}
@Override
public DoubleValueRecorderBuilder doubleValueRecorderBuilder(String name) {
Objects.requireNonNull(name, "name");
Utils.checkArgument(MetricsStringUtils.isValidMetricName(name), ERROR_MESSAGE_INVALID_NAME);
return new NoopDoubleValueRecorder.NoopBuilder();
}
@Override
public LongValueRecorderBuilder longValueRecorderBuilder(String name) {
Objects.requireNonNull(name, "name");
Utils.checkArgument(MetricsStringUtils.isValidMetricName(name), ERROR_MESSAGE_INVALID_NAME);
return new NoopLongValueRecorder.NoopBuilder();
}
@Override
public DoubleSumObserverBuilder doubleSumObserverBuilder(String name) {
Objects.requireNonNull(name, "name");
Utils.checkArgument(MetricsStringUtils.isValidMetricName(name), ERROR_MESSAGE_INVALID_NAME);
return new NoopDoubleSumObserver.NoopBuilder();
}
@Override
public LongSumObserverBuilder longSumObserverBuilder(String name) {
Objects.requireNonNull(name, "name");
Utils.checkArgument(MetricsStringUtils.isValidMetricName(name), ERROR_MESSAGE_INVALID_NAME);
return new NoopLongSumObserver.NoopBuilder();
}
@Override
public DoubleUpDownSumObserverBuilder doubleUpDownSumObserverBuilder(String name) {
Objects.requireNonNull(name, "name");
Utils.checkArgument(MetricsStringUtils.isValidMetricName(name), ERROR_MESSAGE_INVALID_NAME);
return new NoopDoubleUpDownSumObserver.NoopBuilder();
}
@Override
public LongUpDownSumObserverBuilder longUpDownSumObserverBuilder(String name) {
Objects.requireNonNull(name, "name");
Utils.checkArgument(MetricsStringUtils.isValidMetricName(name), ERROR_MESSAGE_INVALID_NAME);
return new NoopLongUpDownSumObserver.NoopBuilder();
}
@Override
public DoubleValueObserverBuilder doubleValueObserverBuilder(String name) {
Objects.requireNonNull(name, "name");
Utils.checkArgument(MetricsStringUtils.isValidMetricName(name), ERROR_MESSAGE_INVALID_NAME);
return new NoopDoubleValueObserver.NoopBuilder();
}
@Override
public LongValueObserverBuilder longValueObserverBuilder(String name) {
Objects.requireNonNull(name, "name");
Utils.checkArgument(MetricsStringUtils.isValidMetricName(name), ERROR_MESSAGE_INVALID_NAME);
return new NoopLongValueObserver.NoopBuilder();
}
@Override
public BatchRecorder newBatchRecorder(String... keyValuePairs) {
validateLabelPairs(keyValuePairs);
return NoopBatchRecorder.INSTANCE;
}
private DefaultMeter() {}
/** No-op implementation of {@link DoubleCounter} interface. */
@Immutable
private static final class NoopDoubleCounter implements DoubleCounter {
private NoopDoubleCounter() {}
@Override
public void add(double increment, Labels labels) {
Objects.requireNonNull(labels, "labels");
Utils.checkArgument(increment >= 0.0, COUNTERS_CAN_ONLY_INCREASE);
}
@Override
public void add(double increment) {
add(increment, Labels.empty());
}
@Override
public NoopBoundDoubleCounter bind(Labels labels) {
Objects.requireNonNull(labels, "labels");
return NoopBoundDoubleCounter.INSTANCE;
}
@Immutable
private enum NoopBoundDoubleCounter implements BoundDoubleCounter {
INSTANCE;
@Override
public void add(double increment) {
Utils.checkArgument(increment >= 0.0, COUNTERS_CAN_ONLY_INCREASE);
}
@Override
public void unbind() {}
}
private static final class NoopBuilder extends NoopAbstractInstrumentBuilder<NoopBuilder>
implements DoubleCounterBuilder {
@Override
protected NoopBuilder getThis() {
return this;
}
@Override
public DoubleCounter build() {
return new NoopDoubleCounter();
}
}
}
/** No-op implementation of {@link LongCounter} interface. */
@Immutable
private static final class NoopLongCounter implements LongCounter {
private NoopLongCounter() {}
@Override
public void add(long increment, Labels labels) {
Objects.requireNonNull(labels, "labels");
Utils.checkArgument(increment >= 0, COUNTERS_CAN_ONLY_INCREASE);
}
@Override
public void add(long increment) {
add(increment, Labels.empty());
}
@Override
public NoopBoundLongCounter bind(Labels labels) {
Objects.requireNonNull(labels, "labels");
return NoopBoundLongCounter.INSTANCE;
}
@Immutable
private enum NoopBoundLongCounter implements BoundLongCounter {
INSTANCE;
@Override
public void add(long increment) {
Utils.checkArgument(increment >= 0, COUNTERS_CAN_ONLY_INCREASE);
}
@Override
public void unbind() {}
}
private static final class NoopBuilder extends NoopAbstractInstrumentBuilder<NoopBuilder>
implements LongCounterBuilder {
@Override
protected NoopBuilder getThis() {
return this;
}
@Override
public LongCounter build() {
return new NoopLongCounter();
}
}
}
/** No-op implementation of {@link DoubleUpDownCounter} interface. */
@Immutable
private static final class NoopDoubleUpDownCounter implements DoubleUpDownCounter {
private NoopDoubleUpDownCounter() {}
@Override
public void add(double increment, Labels labels) {
Objects.requireNonNull(labels, "labels");
}
@Override
public void add(double increment) {
add(increment, Labels.empty());
}
@Override
public NoopBoundDoubleUpDownCounter bind(Labels labels) {
Objects.requireNonNull(labels, "labels");
return NoopBoundDoubleUpDownCounter.INSTANCE;
}
@Immutable
private enum NoopBoundDoubleUpDownCounter implements BoundDoubleUpDownCounter {
INSTANCE;
@Override
public void add(double increment) {}
@Override
public void unbind() {}
}
private static final class NoopBuilder extends NoopAbstractInstrumentBuilder<NoopBuilder>
implements DoubleUpDownCounterBuilder {
@Override
protected NoopBuilder getThis() {
return this;
}
@Override
public DoubleUpDownCounter build() {
return new NoopDoubleUpDownCounter();
}
}
}
/** No-op implementation of {@link LongUpDownCounter} interface. */
@Immutable
private static final class NoopLongUpDownCounter implements LongUpDownCounter {
private NoopLongUpDownCounter() {}
@Override
public void add(long increment, Labels labels) {
Objects.requireNonNull(labels, "labels");
}
@Override
public void add(long increment) {
add(increment, Labels.empty());
}
@Override
public NoopBoundLongUpDownCounter bind(Labels labels) {
Objects.requireNonNull(labels, "labels");
return NoopBoundLongUpDownCounter.INSTANCE;
}
@Immutable
private enum NoopBoundLongUpDownCounter implements BoundLongUpDownCounter {
INSTANCE;
@Override
public void add(long increment) {}
@Override
public void unbind() {}
}
private static final class NoopBuilder extends NoopAbstractInstrumentBuilder<NoopBuilder>
implements LongUpDownCounterBuilder {
@Override
protected NoopBuilder getThis() {
return this;
}
@Override
public LongUpDownCounter build() {
return new NoopLongUpDownCounter();
}
}
}
/** No-op implementation of {@link DoubleValueRecorder} interface. */
@Immutable
private static final class NoopDoubleValueRecorder implements DoubleValueRecorder {
private NoopDoubleValueRecorder() {}
@Override
public void record(double value, Labels labels) {
Objects.requireNonNull(labels, "labels");
}
@Override
public void record(double value) {
record(value, Labels.empty());
}
@Override
public NoopBoundDoubleValueRecorder bind(Labels labels) {
Objects.requireNonNull(labels, "labels");
return NoopBoundDoubleValueRecorder.INSTANCE;
}
@Immutable
private enum NoopBoundDoubleValueRecorder implements BoundDoubleValueRecorder {
INSTANCE;
@Override
public void record(double value) {}
@Override
public void unbind() {}
}
private static final class NoopBuilder extends NoopAbstractInstrumentBuilder<NoopBuilder>
implements DoubleValueRecorderBuilder {
@Override
protected NoopBuilder getThis() {
return this;
}
@Override
public DoubleValueRecorder build() {
return new NoopDoubleValueRecorder();
}
}
}
/** No-op implementation of {@link LongValueRecorder} interface. */
@Immutable
private static final class NoopLongValueRecorder implements LongValueRecorder {
private NoopLongValueRecorder() {}
@Override
public void record(long value, Labels labels) {
Objects.requireNonNull(labels, "labels");
}
@Override
public void record(long value) {
record(value, Labels.empty());
}
@Override
public NoopBoundLongValueRecorder bind(Labels labels) {
Objects.requireNonNull(labels, "labels");
return NoopBoundLongValueRecorder.INSTANCE;
}
@Immutable
private enum NoopBoundLongValueRecorder implements BoundLongValueRecorder {
INSTANCE;
@Override
public void record(long value) {}
@Override
public void unbind() {}
}
private static final class NoopBuilder extends NoopAbstractInstrumentBuilder<NoopBuilder>
implements LongValueRecorderBuilder {
@Override
protected NoopBuilder getThis() {
return this;
}
@Override
public LongValueRecorder build() {
return new NoopLongValueRecorder();
}
}
}
/** No-op implementation of {@link DoubleSumObserver} interface. */
@Immutable
private static final class NoopDoubleSumObserver implements DoubleSumObserver {
private NoopDoubleSumObserver() {}
private static final class NoopBuilder extends NoopAbstractInstrumentBuilder<NoopBuilder>
implements DoubleSumObserverBuilder {
@Override
protected NoopBuilder getThis() {
return this;
}
@Override
public DoubleSumObserverBuilder setUpdater(Consumer<DoubleResult> updater) {
Objects.requireNonNull(updater, "callback");
return this;
}
@Override
public DoubleSumObserver build() {
return new NoopDoubleSumObserver();
}
}
}
/** No-op implementation of {@link LongSumObserver} interface. */
@Immutable
private static final class NoopLongSumObserver implements LongSumObserver {
private NoopLongSumObserver() {}
private static final class NoopBuilder extends NoopAbstractInstrumentBuilder<NoopBuilder>
implements LongSumObserverBuilder {
@Override
protected NoopBuilder getThis() {
return this;
}
@Override
public NoopBuilder setUpdater(Consumer<LongResult> updater) {
Objects.requireNonNull(updater, "callback");
return this;
}
@Override
public LongSumObserver build() {
return new NoopLongSumObserver();
}
}
}
/** No-op implementation of {@link DoubleUpDownSumObserver} interface. */
@Immutable
private static final class NoopDoubleUpDownSumObserver implements DoubleUpDownSumObserver {
private NoopDoubleUpDownSumObserver() {}
private static final class NoopBuilder extends NoopAbstractInstrumentBuilder<NoopBuilder>
implements DoubleUpDownSumObserverBuilder {
@Override
protected NoopBuilder getThis() {
return this;
}
@Override
public DoubleUpDownSumObserverBuilder setUpdater(Consumer<DoubleResult> updater) {
Objects.requireNonNull(updater, "callback");
return this;
}
@Override
public DoubleUpDownSumObserver build() {
return new NoopDoubleUpDownSumObserver();
}
}
}
/** No-op implementation of {@link LongUpDownSumObserver} interface. */
@Immutable
private static final class NoopLongUpDownSumObserver implements LongUpDownSumObserver {
private NoopLongUpDownSumObserver() {}
private static final class NoopBuilder extends NoopAbstractInstrumentBuilder<NoopBuilder>
implements LongUpDownSumObserverBuilder {
@Override
protected NoopBuilder getThis() {
return this;
}
@Override
public LongUpDownSumObserverBuilder setUpdater(Consumer<LongResult> updater) {
Objects.requireNonNull(updater, "callback");
return this;
}
@Override
public LongUpDownSumObserver build() {
return new NoopLongUpDownSumObserver();
}
}
}
/** No-op implementation of {@link DoubleValueObserver} interface. */
@Immutable
private static final class NoopDoubleValueObserver implements DoubleValueObserver {
private NoopDoubleValueObserver() {}
private static final class NoopBuilder extends NoopAbstractInstrumentBuilder<NoopBuilder>
implements DoubleValueObserverBuilder {
@Override
protected NoopBuilder getThis() {
return this;
}
@Override
public DoubleValueObserverBuilder setUpdater(Consumer<DoubleResult> updater) {
Objects.requireNonNull(updater, "callback");
return this;
}
@Override
public DoubleValueObserver build() {
return new NoopDoubleValueObserver();
}
}
}
/** No-op implementation of {@link LongValueObserver} interface. */
@Immutable
private static final class NoopLongValueObserver implements LongValueObserver {
private NoopLongValueObserver() {}
private static final class NoopBuilder extends NoopAbstractInstrumentBuilder<NoopBuilder>
implements LongValueObserverBuilder {
@Override
protected NoopBuilder getThis() {
return this;
}
@Override
public LongValueObserverBuilder setUpdater(Consumer<LongResult> updater) {
Objects.requireNonNull(updater, "callback");
return this;
}
@Override
public LongValueObserver build() {
return new NoopLongValueObserver();
}
}
}
/** No-op implementation of {@link BatchRecorder} interface. */
private enum NoopBatchRecorder implements BatchRecorder {
INSTANCE;
@Override
public BatchRecorder put(LongValueRecorder valueRecorder, long value) {
Objects.requireNonNull(valueRecorder, "valueRecorder");
return this;
}
@Override
public BatchRecorder put(DoubleValueRecorder valueRecorder, double value) {
Objects.requireNonNull(valueRecorder, "valueRecorder");
return this;
}
@Override
public BatchRecorder put(LongCounter counter, long value) {
Objects.requireNonNull(counter, "counter");
Utils.checkArgument(value >= 0, COUNTERS_CAN_ONLY_INCREASE);
return this;
}
@Override
public BatchRecorder put(DoubleCounter counter, double value) {
Objects.requireNonNull(counter, "counter");
Utils.checkArgument(value >= 0.0, COUNTERS_CAN_ONLY_INCREASE);
return this;
}
@Override
public BatchRecorder put(LongUpDownCounter upDownCounter, long value) {
Objects.requireNonNull(upDownCounter, "upDownCounter");
return this;
}
@Override
public BatchRecorder put(DoubleUpDownCounter upDownCounter, double value) {
Objects.requireNonNull(upDownCounter, "upDownCounter");
return this;
}
@Override
public void record() {}
}
private abstract static class NoopAbstractInstrumentBuilder<
B extends NoopAbstractInstrumentBuilder<B>>
implements InstrumentBuilder {
@Override
public B setDescription(String description) {
Objects.requireNonNull(description, "description");
return getThis();
}
@Override
public B setUnit(String unit) {
Objects.requireNonNull(unit, "unit");
return getThis();
}
protected abstract B getThis();
}
/**
* Validates that the array of Strings is 1) even in length, and 2) they can be formed into valid
* pairs where the first item in the pair is not null.
*
* @param keyValuePairs The String[] to validate for correctness.
* @throws IllegalArgumentException if any of the preconditions are violated.
*/
private static void validateLabelPairs(String[] keyValuePairs) {
Utils.checkArgument(
keyValuePairs.length % 2 == 0,
"You must provide an even number of key/value pair arguments.");
for (int i = 0; i < keyValuePairs.length; i += 2) {
String key = keyValuePairs[i];
Objects.requireNonNull(key, "You cannot provide null keys for label creation.");
}
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
class DefaultMeterBuilder implements MeterBuilder {
private static final MeterBuilder INSTANCE = new DefaultMeterBuilder();
static MeterBuilder getInstance() {
return INSTANCE;
}
@Override
public MeterBuilder setSchemaUrl(String schemaUrl) {
return this;
}
@Override
public MeterBuilder setInstrumentationVersion(String instrumentationVersion) {
return this;
}
@Override
public Meter build() {
return DefaultMeter.getInstance();
}
}

View File

@ -1,30 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import javax.annotation.concurrent.ThreadSafe;
@ThreadSafe
final class DefaultMeterProvider implements MeterProvider {
private static final MeterProvider INSTANCE = new DefaultMeterProvider();
static MeterProvider getInstance() {
return INSTANCE;
}
@Override
public Meter get(String instrumentationName) {
return get(instrumentationName, null);
}
@Override
public Meter get(String instrumentationName, String instrumentationVersion) {
return DefaultMeter.getInstance();
}
private DefaultMeterProvider() {}
}

View File

@ -5,59 +5,46 @@
package io.opentelemetry.api.metrics;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.context.Context;
import javax.annotation.concurrent.ThreadSafe;
/**
* Counter is the most common synchronous instrument. This instrument supports an {@link
* #add(double, Labels)}` function for reporting an increment, and is restricted to non-negative
* increments. The default aggregation is `Sum`.
*
* <p>Example:
*
* <pre>{@code
* class YourClass {
* private static final Meter meter = OpenTelemetry.getMeterProvider().get("my_library_name");
* private static final DoubleCounter counter =
* meter.
* .doubleCounterBuilder("allocated_resources")
* .setDescription("Total allocated resources")
* .setUnit("1")
* .build();
*
* // It is recommended that the API user keep references to a Bound Counters.
* private static final BoundDoubleCounter someWorkBound =
* counter.bind("work_name", "some_work");
*
* void doSomeWork() {
* someWorkBound.add(10.2); // Resources needed for this task.
* // Your code here.
* }
* }
* }</pre>
*/
/** A counter instrument that records {@code double} values. */
@ThreadSafe
public interface DoubleCounter extends SynchronousInstrument<BoundDoubleCounter> {
public interface DoubleCounter {
/**
* Records a value.
*
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param value The increment amount. MUST be non-negative.
*/
void add(double value);
/**
* Adds the given {@code increment} to the current value. The values cannot be negative.
* Records a value with a set of attributes.
*
* <p>The value added is associated with the current {@code Context} and provided set of labels.
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param increment the value to add.
* @param labels the labels to be associated to this recording.
* @param value The increment amount. MUST be non-negative.
* @param attributes A set of attributes to associate with the count.
*/
void add(double increment, Labels labels);
void add(double value, Attributes attributes);
/**
* Adds the given {@code increment} to the current value. The values cannot be negative.
* Records a value with a set of attributes.
*
* <p>The value added is associated with the current {@code Context} and with empty labels.
*
* @param increment the value to add.
* @param value The increment amount. MUST be non-negative.
* @param attributes A set of attributes to associate with the count.
* @param context The explicit context to associate with this measurement.
*/
void add(double increment);
void add(double value, Attributes attributes, Context context);
@Override
BoundDoubleCounter bind(Labels labels);
/**
* Constructs a bound version of this instrument where all recorded values use the given
* attributes.
*/
BoundDoubleCounter bind(Attributes attributes);
}

View File

@ -5,14 +5,42 @@
package io.opentelemetry.api.metrics;
import java.util.function.Consumer;
/** Builder class for {@link DoubleCounter}. */
public interface DoubleCounterBuilder extends SynchronousInstrumentBuilder {
@Override
public interface DoubleCounterBuilder {
/**
* Sets the description for this instrument.
*
* <p>Description stirngs should follw the instrument description rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-description
*/
DoubleCounterBuilder setDescription(String description);
@Override
/**
* Sets the unit of measure for this instrument.
*
* <p>Unit strings should follow the instrument unit rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-unit
*/
DoubleCounterBuilder setUnit(String unit);
@Override
/** Sets the counter for recording {@code long} values. */
LongCounterBuilder ofLongs();
/**
* Builds and returns a {@code DoubleCounter} with the desired options.
*
* @return a {@code DoubleCounter} with the desired options.
*/
DoubleCounter build();
/**
* Builds this asynchronous insturment with the given callback.
*
* <p>The callback will only be called when the {@link Meter} is being observed.
*
* @param callback A state-capturing callback used to observe values on-demand.
*/
void buildWithCallback(Consumer<ObservableDoubleMeasurement> callback);
}

View File

@ -0,0 +1,39 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import java.util.function.Consumer;
/** A builder for Gauge metric types. These can only be asynchronously collected. */
public interface DoubleGaugeBuilder {
/**
* Sets the description for this instrument.
*
* <p>Description strings should follow the instrument description rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-description
*/
DoubleGaugeBuilder setDescription(String description);
/**
* Sets the unit of measure for this instrument.
*
* <p>Unit strings should follow the instrument unit rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-unit
*/
DoubleGaugeBuilder setUnit(String unit);
/** Sets the gauge for recording {@code long} values. */
LongGaugeBuilder ofLongs();
/**
* Builds this asynchronous instrument with the given callback.
*
* <p>The callback will only be called when the {@link Meter} is being observed.
*
* @param callback A state-capturing callback used to observe values on-demand.
*/
void buildWithCallback(Consumer<ObservableDoubleMeasurement> callback);
}

View File

@ -0,0 +1,51 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.context.Context;
import javax.annotation.concurrent.ThreadSafe;
/** A histogram instrument that records {@code long} values. */
@ThreadSafe
public interface DoubleHistogram {
/**
* Records a value.
*
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param value The amount of the measurement.
*/
void record(double value);
/**
* Records a value with a set of attributes.
*
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param value The amount of the measurement.
* @param attributes A set of attributes to associate with the count.
*/
void record(double value, Attributes attributes);
/**
* Records a value with a set of attributes.
*
* @param value The amount of the measurement.
* @param attributes A set of attributes to associate with the count.
* @param context The explicit context to associate with this measurement.
*/
void record(double value, Attributes attributes, Context context);
/**
* Constructs a bound version of this instrument where all recorded values use the given
* attributes.
*/
BoundDoubleHistogram bind(Attributes attributes);
}

View File

@ -0,0 +1,36 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
/** Builder class for {@link DoubleHistogram}. */
public interface DoubleHistogramBuilder {
/**
* Sets the description for this instrument.
*
* <p>Description strings should follow the instrument description rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-description
*/
DoubleHistogramBuilder setDescription(String description);
/**
* Sets the unit of measure for this instrument.
*
* <p>Unit strings should follow the instrument unit rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-unit
*/
DoubleHistogramBuilder setUnit(String unit);
/** Sets the counter for recording {@code long} values. */
LongHistogramBuilder ofLongs();
/**
* Builds and returns a {@code DoubleHistogram} with the desired options.
*
* @return a {@code DoubleHistogram} with the desired options.
*/
DoubleHistogram build();
}

View File

@ -1,49 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import javax.annotation.concurrent.ThreadSafe;
/**
* {@code SumObserver} is the asynchronous instrument corresponding to Counter, used to capture a
* monotonic sum with Observe(sum).
*
* <p>"Sum" appears in the name to remind that it is used to capture sums directly. Use a
* SumObserver to capture any value that starts at zero and rises throughout the process lifetime
* and never falls.
*
* <p>A {@code SumObserver} is a good choice in situations where a measurement is expensive to
* compute, such that it would be wasteful to compute on every request.
*
* <p>Example:
*
* <pre>{@code
* // class YourClass {
* //
* // private static final Meter meter = OpenTelemetry.getMeterProvider().get("my_library_name");
* // private static final DoubleSumObserver cpuObserver =
* // meter.
* // .doubleSumObserverBuilder("cpu_time")
* // .setDescription("System CPU usage")
* // .setUnit("ms")
* // .build();
* //
* // void init() {
* // cpuObserver.setUpdater(
* // new DoubleSumObserver.Callback<DoubleResult>() {
* // @Override
* // public void update(DoubleResult result) {
* // // Get system cpu usage
* // result.observe(cpuIdle, "state", "idle");
* // result.observe(cpuUser, "state", "user");
* // }
* // });
* // }
* // }
* }</pre>
*/
@ThreadSafe
public interface DoubleSumObserver extends AsynchronousInstrument {}

View File

@ -1,24 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import java.util.function.Consumer;
/** Builder class for {@link DoubleSumObserver}. */
public interface DoubleSumObserverBuilder
extends AsynchronousInstrumentBuilder<AsynchronousInstrument.DoubleResult> {
@Override
DoubleSumObserverBuilder setDescription(String description);
@Override
DoubleSumObserverBuilder setUnit(String unit);
@Override
DoubleSumObserverBuilder setUpdater(Consumer<AsynchronousInstrument.DoubleResult> updater);
@Override
DoubleSumObserver build();
}

View File

@ -5,62 +5,46 @@
package io.opentelemetry.api.metrics;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.context.Context;
import javax.annotation.concurrent.ThreadSafe;
/**
* UpDownCounter is a synchronous instrument and very similar to Counter except that Add(increment)
* supports negative increments. This makes UpDownCounter not useful for computing a rate
* aggregation. The default aggregation is `Sum`, only the sum is non-monotonic. It is generally
* useful for capturing changes in an amount of resources used, or any quantity that rises and falls
* during a request.
*
* <p>Example:
*
* <pre>{@code
* class YourClass {
* private static final Meter meter = OpenTelemetry.getMeterProvider().get("my_library_name");
* private static final DoubleUpDownCounter upDownCounter =
* meter.
* .doubleUpDownCounterBuilder("resource_usage")
* .setDescription("Current resource usage")
* .setUnit("1")
* .build();
*
* // It is recommended that the API user keep references to a Bound Counters.
* private static final BoundDoubleUpDownCounter someWorkBound =
* upDownCounter.bind("work_name", "some_work");
*
* void doSomeWork() {
* someWorkBound.add(10.2); // Resources needed for this task.
* // Your code here.
* someWorkBound.add(-10.0);
* }
* }
* }</pre>
*/
/** An up-down-counter instrument that records {@code double} values. */
@ThreadSafe
public interface DoubleUpDownCounter extends SynchronousInstrument<BoundDoubleUpDownCounter> {
public interface DoubleUpDownCounter {
/**
* Records a value.
*
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param value The increment amount. May be positive, negative or zero.
*/
void add(double value);
/**
* Adds the given {@code increment} to the current value.
* Records a value with a set of attributes.
*
* <p>The value added is associated with the current {@code Context} and provided set of labels.
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param increment the value to add.
* @param labels the labels to be associated to this recording.
* @param value The increment amount. May be positive, negative or zero.
* @param attributes A set of attributes to associate with the count.
*/
void add(double increment, Labels labels);
void add(double value, Attributes attributes);
/**
* Adds the given {@code increment} to the current value.
* Records a value with a set of attributes.
*
* <p>The value added is associated with the current {@code Context} and empty labels.
*
* @param increment the value to add.
* @param value The increment amount. May be positive, negative or zero.
* @param attributes A set of attributes to associate with the count.
* @param context The explicit context to associate with this measurement.
*/
void add(double increment);
void add(double value, Attributes attributes, Context context);
@Override
BoundDoubleUpDownCounter bind(Labels labels);
/**
* Constructs a bound version of this instrument where all recorded values use the given
* attributes.
*/
BoundDoubleUpDownCounter bind(Attributes attributes);
}

View File

@ -5,14 +5,42 @@
package io.opentelemetry.api.metrics;
import java.util.function.Consumer;
/** Builder class for {@link DoubleUpDownCounter}. */
public interface DoubleUpDownCounterBuilder extends SynchronousInstrumentBuilder {
@Override
public interface DoubleUpDownCounterBuilder {
/**
* Sets the description for this instrument.
*
* <p>Description strings should follow the instrument description rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-description
*/
DoubleUpDownCounterBuilder setDescription(String description);
@Override
/**
* Sets the unit of measure for this instrument.
*
* <p>Unit strings should follow the instrument unit rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-unit
*/
DoubleUpDownCounterBuilder setUnit(String unit);
@Override
/** Sets the counter for recording {@code long} values. */
LongUpDownCounterBuilder ofLongs();
/**
* Builds and returns a {@code DoubleUpDownCounter} with the desired options.
*
* @return a {@code DoubleUpDownCounter} with the desired options.
*/
DoubleUpDownCounter build();
/**
* Builds this asynchronous instrument with the given callback.
*
* <p>The callback will only be called when the {@link Meter} is being observed.
*
* @param callback A state-capturing callback used to observe values on-demand.
*/
void buildWithCallback(Consumer<ObservableDoubleMeasurement> callback);
}

View File

@ -1,49 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import javax.annotation.concurrent.ThreadSafe;
/**
* UpDownSumObserver is the asynchronous instrument corresponding to UpDownCounter, used to capture
* a non-monotonic count with Observe(sum).
*
* <p>"Sum" appears in the name to remind that it is used to capture sums directly. Use a
* UpDownSumObserver to capture any value that starts at zero and rises or falls throughout the
* process lifetime.
*
* <p>A {@code UpDownSumObserver} is a good choice in situations where a measurement is expensive to
* compute, such that it would be wasteful to compute on every request.
*
* <p>Example:
*
* <pre>{@code
* // class YourClass {
* //
* // private static final Meter meter = OpenTelemetry.getMeterProvider().get("my_library_name");
* // private static final DoubleUpDownSumObserver memoryObserver =
* // meter.
* // .doubleUpDownSumObserverBuilder("memory_usage")
* // .setDescription("System memory usage")
* // .setUnit("by")
* // .build();
* //
* // void init() {
* // memoryObserver.setUpdater(
* // new DoubleUpDownSumObserver.Callback<DoubleResult>() {
* // @Override
* // public void update(DoubleResult result) {
* // // Get system memory usage
* // result.observe(memoryUsed, "state", "used");
* // result.observe(memoryFree, "state", "free");
* // }
* // });
* // }
* // }
* }</pre>
*/
@ThreadSafe
public interface DoubleUpDownSumObserver extends AsynchronousInstrument {}

View File

@ -1,24 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import java.util.function.Consumer;
/** Builder class for {@link DoubleUpDownSumObserver}. */
public interface DoubleUpDownSumObserverBuilder
extends AsynchronousInstrumentBuilder<AsynchronousInstrument.DoubleResult> {
@Override
DoubleUpDownSumObserverBuilder setDescription(String description);
@Override
DoubleUpDownSumObserverBuilder setUnit(String unit);
@Override
DoubleUpDownSumObserverBuilder setUpdater(Consumer<AsynchronousInstrument.DoubleResult> updater);
@Override
DoubleUpDownSumObserver build();
}

View File

@ -1,45 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import javax.annotation.concurrent.ThreadSafe;
/**
* {@code ValueObserver} is the asynchronous instrument corresponding to ValueRecorder, used to
* capture values that are treated as individual observations, recorded with the observe(value)
* method.
*
* <p>A {@code ValueObserver} is a good choice in situations where a measurement is expensive to
* compute, such that it would be wasteful to compute on every request.
*
* <p>Example:
*
* <pre>{@code
* // class YourClass {
* //
* // private static final Meter meter = OpenTelemetry.getMeterProvider().get("my_library_name");
* // private static final DoubleValueObserver cpuObserver =
* // meter.
* // .doubleValueObserverBuilder("cpu_temperature")
* // .setDescription("System CPU temperature")
* // .setUnit("ms")
* // .build();
* //
* // void init() {
* // cpuObserver.setUpdater(
* // new DoubleValueObserver.Callback<DoubleResult>() {
* // @Override
* // public void update(DoubleResult result) {
* // // Get system cpu temperature
* // result.observe(cpuTemperature);
* // }
* // });
* // }
* // }
* }</pre>
*/
@ThreadSafe
public interface DoubleValueObserver extends AsynchronousInstrument {}

View File

@ -1,24 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import java.util.function.Consumer;
/** Builder class for {@link DoubleValueObserver}. */
public interface DoubleValueObserverBuilder
extends AsynchronousInstrumentBuilder<AsynchronousInstrument.DoubleResult> {
@Override
DoubleValueObserverBuilder setDescription(String description);
@Override
DoubleValueObserverBuilder setUnit(String unit);
@Override
DoubleValueObserverBuilder setUpdater(Consumer<AsynchronousInstrument.DoubleResult> updater);
@Override
DoubleValueObserver build();
}

View File

@ -1,74 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import io.opentelemetry.api.metrics.common.Labels;
import javax.annotation.concurrent.ThreadSafe;
/**
* ValueRecorder is a synchronous instrument useful for recording any number, positive or negative.
* Values captured by a Record(value) are treated as individual events belonging to a distribution
* that is being summarized.
*
* <p>ValueRecorder should be chosen either when capturing measurements that do not contribute
* meaningfully to a sum, or when capturing numbers that are additive in nature, but where the
* distribution of individual increments is considered interesting.
*
* <p>One of the most common uses for ValueRecorder is to capture latency measurements. Latency
* measurements are not additive in the sense that there is little need to know the latency-sum of
* all processed requests. We use a ValueRecorder instrument to capture latency measurements
* typically because we are interested in knowing mean, median, and other summary statistics about
* individual events.
*
* <p>Example:
*
* <pre>{@code
* class YourClass {
*
* private static final Meter meter = OpenTelemetry.getMeterProvider().get("my_library_name");
* private static final DoubleValueRecorder valueRecorder =
* meter.
* .doubleValueRecorderBuilder("doWork_latency")
* .setDescription("gRPC Latency")
* .setUnit("ms")
* .build();
*
* // It is recommended that the API user keep references to a Bound Counters.
* private static final BoundDoubleValueRecorder someWorkBound =
* valueRecorder.bind("work_name", "some_work");
*
* void doWork() {
* long startTime = System.nanoTime();
* // Your code here.
* someWorkBound.record((System.nanoTime() - startTime) / 1e6);
* }
* }
* }</pre>
*/
@ThreadSafe
public interface DoubleValueRecorder extends SynchronousInstrument<BoundDoubleValueRecorder> {
/**
* Records the given measurement, associated with the current {@code Context} and provided set of
* labels.
*
* @param value the measurement to record.
* @param labels the set of labels to be associated to this recording
* @throws IllegalArgumentException if value is negative.
*/
void record(double value, Labels labels);
/**
* Records the given measurement, associated with the current {@code Context} and empty labels.
*
* @param value the measurement to record.
* @throws IllegalArgumentException if value is negative.
*/
void record(double value);
@Override
BoundDoubleValueRecorder bind(Labels labels);
}

View File

@ -1,18 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
/** Builder class for {@link DoubleValueRecorder}. */
public interface DoubleValueRecorderBuilder extends SynchronousInstrumentBuilder {
@Override
DoubleValueRecorderBuilder setDescription(String description);
@Override
DoubleValueRecorderBuilder setUnit(String unit);
@Override
DoubleValueRecorder build();
}

View File

@ -5,29 +5,17 @@
package io.opentelemetry.api.metrics;
import java.util.concurrent.atomic.AtomicReference;
import io.opentelemetry.api.metrics.internal.NoopMeterProvider;
/**
* IMPORTANT: This is a temporary class, and solution for the metrics package until it will be
* marked as stable.
*/
public final class GlobalMeterProvider {
private static final Object mutex = new Object();
private static final AtomicReference<MeterProvider> globalMeterProvider = new AtomicReference<>();
/** This class is a temporary solution until metrics SDK is marked stable. */
public class GlobalMeterProvider {
private static volatile MeterProvider globalMeterProvider = NoopMeterProvider.getInstance();
private GlobalMeterProvider() {}
/** Returns the globally registered {@link MeterProvider}. */
public static MeterProvider get() {
MeterProvider meterProvider = globalMeterProvider.get();
if (meterProvider == null) {
synchronized (mutex) {
if (globalMeterProvider.get() == null) {
return MeterProvider.noop();
}
}
}
return meterProvider;
return globalMeterProvider;
}
/**
@ -36,50 +24,7 @@ public final class GlobalMeterProvider {
* early as possible in your application initialization logic, often in a {@code static} block in
* your main class.
*/
public static void set(MeterProvider meterProvider) {
globalMeterProvider.set(meterProvider);
}
/**
* Gets or creates a named meter instance from the globally registered {@link MeterProvider}.
*
* <p>This is a shortcut method for {@code getGlobalMeterProvider().get(instrumentationName)}
*
* @param instrumentationName The name of the instrumentation library, not the name of the
* instrument*ed* library.
* @return a tracer instance.
*/
public static Meter getMeter(String instrumentationName) {
return get().get(instrumentationName);
}
/**
* Gets or creates a named and versioned meter instance from the globally registered {@link
* MeterProvider}.
*
* <p>This is a shortcut method for {@code getGlobalMeterProvider().get(instrumentationName,
* instrumentationVersion)}
*
* @param instrumentationName The name of the instrumentation library, not the name of the
* instrument*ed* library.
* @param instrumentationVersion The version of the instrumentation library.
* @return a tracer instance.
*/
public static Meter getMeter(String instrumentationName, String instrumentationVersion) {
return get().get(instrumentationName, instrumentationVersion);
}
/**
* Creates a {@link MeterBuilder} for a named meter instance.
*
* <p>This is a shortcut method for {@code get().meterBuilder(instrumentationName)}
*
* @param instrumentationName The name of the instrumentation library, not the name of the
* instrument*ed* library.
* @return a MeterBuilder instance.
* @since 1.4.0
*/
public static MeterBuilder meterBuilder(String instrumentationName) {
return get().meterBuilder(instrumentationName);
public static void set(MeterProvider provider) {
globalMeterProvider = (provider == null) ? NoopMeterProvider.getInstance() : provider;
}
}

View File

@ -1,13 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import javax.annotation.concurrent.ThreadSafe;
/** Base interface for all metrics defined in this package. */
@ThreadSafe
@SuppressWarnings("InterfaceWithOnlyStatics")
public interface Instrument {}

View File

@ -1,36 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
/** The {@code Builder} class for the {@code Instrument}. */
public interface InstrumentBuilder {
/**
* Sets the description of the {@code Instrument}.
*
* <p>Default value is {@code ""}.
*
* @param description the description of the Instrument.
* @return this.
*/
InstrumentBuilder setDescription(String description);
/**
* Sets the unit of the {@code Instrument}.
*
* <p>Default value is {@code "1"}.
*
* @param unit the unit of the Instrument.
* @return this.
*/
InstrumentBuilder setUnit(String unit);
/**
* Builds and returns a {@code Instrument} with the desired options.
*
* @return a {@code Instrument} with the desired options.
*/
Instrument build();
}

View File

@ -5,59 +5,47 @@
package io.opentelemetry.api.metrics;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.context.Context;
import javax.annotation.concurrent.ThreadSafe;
/**
* Counter is the most common synchronous instrument. This instrument supports an {@link #add(long,
* Labels)}` function for reporting an increment, and is restricted to non-negative increments. The
* default aggregation is `Sum`.
*
* <p>Example:
*
* <pre>{@code
* class YourClass {
* private static final Meter meter = OpenTelemetry.getMeterProvider().get("my_library_name");
* private static final LongCounter counter =
* meter.
* .longCounterBuilder("processed_jobs")
* .setDescription("Processed jobs")
* .setUnit("1")
* .build();
*
* // It is recommended that the API user keep a reference to a Bound Counter.
* private static final BoundLongCounter someWorkBound =
* counter.bind("work_name", "some_work");
*
* void doSomeWork() {
* // Your code here.
* someWorkBound.add(10);
* }
* }
* }</pre>
*/
/** A counter instrument that records {@code long} values. */
@ThreadSafe
public interface LongCounter extends SynchronousInstrument<BoundLongCounter> {
public interface LongCounter {
/**
* Adds the given {@code increment} to the current value. The values cannot be negative.
* Records a value.
*
* <p>The value added is associated with the current {@code Context} and provided set of labels.
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param increment the value to add.
* @param labels the set of labels to be associated to this recording.
* @param value The increment amount. MUST be non-negative.
*/
void add(long increment, Labels labels);
void add(long value);
/**
* Adds the given {@code increment} to the current value. The values cannot be negative.
* Records a value with a set of attributes.
*
* <p>The value added is associated with the current {@code Context} and empty labels.
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param increment the value to add.
* @param value The increment amount. MUST be non-negative.
* @param attributes A set of attributes to associate with the count.
*/
void add(long increment);
void add(long value, Attributes attributes);
@Override
BoundLongCounter bind(Labels labels);
/**
* Records a value with a set of attributes.
*
* @param value The increment amount. MUST be non-negative.
* @param attributes A set of attributes to associate with the count.
* @param context The explicit context to associate with this measurement.
*/
void add(long value, Attributes attributes, Context context);
/**
* Constructs a bound version of this instrument where all recorded values use the given
* attributes.
*/
BoundLongCounter bind(Attributes attributes);
}

View File

@ -5,14 +5,43 @@
package io.opentelemetry.api.metrics;
import java.util.function.Consumer;
/** Builder class for {@link LongCounter}. */
public interface LongCounterBuilder extends SynchronousInstrumentBuilder {
@Override
public interface LongCounterBuilder {
/**
* Sets the description for this instrument.
*
* <p>Description strings should follow the instrument description rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-description
*/
LongCounterBuilder setDescription(String description);
@Override
/**
* Sets the unit of measure for this instrument.
*
* <p>Unit strings should follow the instrument unit rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-unit
*/
LongCounterBuilder setUnit(String unit);
@Override
/** Sets the counter for recording {@code double} values. */
DoubleCounterBuilder ofDoubles();
/**
* Builds and returns a {@code LongCounter} with the desired options.
*
* @return a {@code LongCounter} with the desired options.
*/
LongCounter build();
/**
* Builds this asynchronous instrument with the given callback.
*
* <p>The callback will only be called when the {@link Meter} is being observed.
*
* @param callback A state-capturing callback used to observe values on-demand.
*/
void buildWithCallback(Consumer<ObservableLongMeasurement> callback);
}

View File

@ -0,0 +1,39 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import java.util.function.Consumer;
/** A builder for Gauge metric types. These can only be asynchronously collected. */
public interface LongGaugeBuilder {
/**
* Sets the description for this instrument.
*
* <p>Description strings should follow the instrument description rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-description
*/
public LongGaugeBuilder setDescription(String description);
/**
* Sets the unit of measure for this instrument.
*
* <p>Unit strings should follow the instrument unit rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-unit
*/
LongGaugeBuilder setUnit(String unit);
/** Sets the gauge for recording {@code double} values. */
DoubleGaugeBuilder ofDoubles();
/**
* Builds this asynchronous insturment with the given callback.
*
* <p>The callback will only be called when the {@link Meter} is being observed.
*
* @param callback A state-capturing callback used to observe values on-demand.
*/
void buildWithCallback(Consumer<ObservableLongMeasurement> callback);
}

View File

@ -0,0 +1,51 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.context.Context;
import javax.annotation.concurrent.ThreadSafe;
/** A histogram instrument that records {@code long} values. */
@ThreadSafe
public interface LongHistogram {
/**
* Records a value.
*
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param value The amount of the measurement.
*/
void record(long value);
/**
* Records a value with a set of attributes.
*
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param value The amount of the measurement.
* @param attributes A set of attributes to associate with the count.
*/
void record(long value, Attributes attributes);
/**
* Records a value with a set of attributes.
*
* @param value The amount of the measurement.
* @param attributes A set of attributes to associate with the count.
* @param context The explicit context to associate with this measurement.
*/
void record(long value, Attributes attributes, Context context);
/**
* Construct a bound version of this instrument where all recorded values use the given
* attributes.
*/
BoundLongHistogram bind(Attributes attributes);
}

View File

@ -0,0 +1,35 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
/** Builder class for {@link LongHistogram}. */
public interface LongHistogramBuilder {
/**
* Sets the description for this instrument.
*
* <p>Description strings should follow the instrument description rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-description
*/
LongHistogramBuilder setDescription(String description);
/**
* Sets the unit of measure for this instrument.
*
* <p>Unit strings should follow the instrument unit rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-unit
*/
LongHistogramBuilder setUnit(String unit);
/** Sets the histogram for recording {@code double} values. */
DoubleHistogramBuilder ofDoubles();
/**
* Builds and returns a {@code LongHistogram} with the desired options.
*
* @return a {@code LongHistogram} with the desired options.
*/
LongHistogram build();
}

View File

@ -1,49 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import javax.annotation.concurrent.ThreadSafe;
/**
* {@code SumObserver} is the asynchronous instrument corresponding to Counter, used to capture a
* monotonic sum with Observe(sum).
*
* <p>"Sum" appears in the name to remind that it is used to capture sums directly. Use a
* SumObserver to capture any value that starts at zero and rises throughout the process lifetime
* and never falls.
*
* <p>A {@code SumObserver} is a good choice in situations where a measurement is expensive to
* compute, such that it would be wasteful to compute on every request.
*
* <p>Example:
*
* <pre>{@code
* // class YourClass {
* //
* // private static final Meter meter = OpenTelemetry.getMeterProvider().get("my_library_name");
* // private static final LongSumObserver cpuObserver =
* // meter.
* // .longSumObserverBuilder("cpu_time")
* // .setDescription("System CPU usage")
* // .setUnit("ms")
* // .build();
* //
* // void init() {
* // cpuObserver.setUpdater(
* // new LongSumObserver.Callback<LongResult>() {
* // @Override
* // public void update(LongResult result) {
* // // Get system cpu usage
* // result.observe(cpuIdle, "state", "idle");
* // result.observe(cpuUser, "state", "user");
* // }
* // });
* // }
* // }
* }</pre>
*/
@ThreadSafe
public interface LongSumObserver extends AsynchronousInstrument {}

View File

@ -1,24 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import java.util.function.Consumer;
/** Builder class for {@link LongSumObserver}. */
public interface LongSumObserverBuilder
extends AsynchronousInstrumentBuilder<AsynchronousInstrument.LongResult> {
@Override
LongSumObserverBuilder setDescription(String description);
@Override
LongSumObserverBuilder setUnit(String unit);
@Override
LongSumObserverBuilder setUpdater(Consumer<AsynchronousInstrument.LongResult> updater);
@Override
LongSumObserver build();
}

View File

@ -5,62 +5,46 @@
package io.opentelemetry.api.metrics;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.context.Context;
import javax.annotation.concurrent.ThreadSafe;
/**
* UpDownCounter is a synchronous instrument and very similar to Counter except that Add(increment)
* supports negative increments. This makes UpDownCounter not useful for computing a rate
* aggregation. The default aggregation is `Sum`, only the sum is non-monotonic. It is generally
* useful for capturing changes in an amount of resources used, or any quantity that rises and falls
* during a request.
*
* <p>Example:
*
* <pre>{@code
* class YourClass {
* private static final Meter meter = OpenTelemetry.getMeterProvider().get("my_library_name");
* private static final LongUpDownCounter upDownCounter =
* meter.
* .longUpDownCounterBuilder("active_tasks")
* .setDescription("Number of active tasks")
* .setUnit("1")
* .build();
*
* // It is recommended that the API user keep a reference to a Bound Counter.
* private static final BoundLongUpDownCounter someWorkBound =
* upDownCounter.bind("work_name", "some_work");
*
* void doSomeWork() {
* someWorkBound.add(1);
* // Your code here.
* someWorkBound.add(-1);
* }
* }
* }</pre>
*/
/** An up-down-counter instrument that records {@code long} values. */
@ThreadSafe
public interface LongUpDownCounter extends SynchronousInstrument<BoundLongUpDownCounter> {
public interface LongUpDownCounter {
/**
* Records a value.
*
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param value The increment amount. May be positive, negative or zero.
*/
void add(long value);
/**
* Adds the given {@code increment} to the current value.
* Record a value with a set of attributes.
*
* <p>The value added is associated with the current {@code Context} and provided set of labels.
* <p>Note: This may use {@code Context.current()} to pull the context associated with this
* measurement.
*
* @param increment the value to add.
* @param labels the set of labels to be associated to this recording.
* @param value The increment amount. May be positive, negative or zero.
* @param attributes A set of attributes to associate with the count.
*/
void add(long increment, Labels labels);
void add(long value, Attributes attributes);
/**
* Adds the given {@code increment} to the current value.
* Records a value with a set of attributes.
*
* <p>The value added is associated with the current {@code Context} and empty labels.
*
* @param increment the value to add.
* @param value The increment amount. May be positive, negative or zero.
* @param attributes A set of attributes to associate with the count.
* @param context The explicit context to associate with this measurement.
*/
void add(long increment);
void add(long value, Attributes attributes, Context context);
@Override
BoundLongUpDownCounter bind(Labels labels);
/**
* Construct a bound version of this instrument where all recorded values use the given
* attributes.
*/
BoundLongUpDownCounter bind(Attributes attributes);
}

View File

@ -5,14 +5,42 @@
package io.opentelemetry.api.metrics;
import java.util.function.Consumer;
/** Builder class for {@link LongUpDownCounter}. */
public interface LongUpDownCounterBuilder extends SynchronousInstrumentBuilder {
@Override
public interface LongUpDownCounterBuilder {
/**
* Sets the description for this instrument.
*
* <p>Description strings should follow the instrument description rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-description
*/
LongUpDownCounterBuilder setDescription(String description);
@Override
/**
* Sets the unit of measure for this instrument.
*
* <p>Unit strings should follow the instrument unit rules:
* https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument-unit
*/
LongUpDownCounterBuilder setUnit(String unit);
@Override
/** Sets the counter for recording {@code double} values. */
DoubleUpDownCounterBuilder ofDoubles();
/**
* Builds and returns a {@code LongUpDownCounter} with the desired options.
*
* @return a {@code LongUpDownCounter} with the desired options.
*/
LongUpDownCounter build();
/**
* Builds this asynchronous instrument with the given callback.
*
* <p>The callback will only be called when the {@link Meter} is being observed.
*
* @param callback A state-capturing callback used to observe values on-demand.
*/
void buildWithCallback(Consumer<ObservableLongMeasurement> callback);
}

View File

@ -1,49 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import javax.annotation.concurrent.ThreadSafe;
/**
* UpDownSumObserver is the asynchronous instrument corresponding to UpDownCounter, used to capture
* a non-monotonic count with Observe(sum).
*
* <p>"Sum" appears in the name to remind that it is used to capture sums directly. Use a
* UpDownSumObserver to capture any value that starts at zero and rises or falls throughout the
* process lifetime.
*
* <p>A {@code UpDownSumObserver} is a good choice in situations where a measurement is expensive to
* compute, such that it would be wasteful to compute on every request.
*
* <p>Example:
*
* <pre>{@code
* // class YourClass {
* //
* // private static final Meter meter = OpenTelemetry.getMeterProvider().get("my_library_name");
* // private static final LongUpDownSumObserver memoryObserver =
* // meter.
* // .longUpDownSumObserverBuilder("memory_usage")
* // .setDescription("System memory usage")
* // .setUnit("by")
* // .build();
* //
* // void init() {
* // memoryObserver.setUpdater(
* // new LongUpDownSumObserver.Callback<LongResult>() {
* // @Override
* // public void update(LongResult result) {
* // // Get system memory usage
* // result.observe(memoryUsed, "state", "used");
* // result.observe(memoryFree, "state", "free");
* // }
* // });
* // }
* // }
* }</pre>
*/
@ThreadSafe
public interface LongUpDownSumObserver extends AsynchronousInstrument {}

View File

@ -1,24 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import java.util.function.Consumer;
/** Builder class for {@link LongUpDownSumObserver}. */
public interface LongUpDownSumObserverBuilder
extends AsynchronousInstrumentBuilder<AsynchronousInstrument.LongResult> {
@Override
LongUpDownSumObserverBuilder setDescription(String description);
@Override
LongUpDownSumObserverBuilder setUnit(String unit);
@Override
LongUpDownSumObserverBuilder setUpdater(Consumer<AsynchronousInstrument.LongResult> updater);
@Override
LongUpDownSumObserver build();
}

View File

@ -1,45 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import javax.annotation.concurrent.ThreadSafe;
/**
* {@code ValueObserver} is the asynchronous instrument corresponding to ValueRecorder, used to
* capture values that are treated as individual observations, recorded with the observe(value)
* method.
*
* <p>A {@code ValueObserver} is a good choice in situations where a measurement is expensive to
* compute, such that it would be wasteful to compute on every request.
*
* <p>Example:
*
* <pre>{@code
* // class YourClass {
* //
* // private static final Meter meter = OpenTelemetry.getMeterProvider().get("my_library_name");
* // private static final LongValueObserver cpuObserver =
* // meter.
* // .longValueObserverBuilder("cpu_fan_speed")
* // .setDescription("System CPU fan speed")
* // .setUnit("ms")
* // .build();
* //
* // void init() {
* // cpuObserver.setUpdater(
* // new LongValueObserver.Callback<LongResult>() {
* // @Override
* // public void update(LongResult result) {
* // // Get system cpu fan speed
* // result.observe(cpuFanSpeed);
* // }
* // });
* // }
* // }
* }</pre>
*/
@ThreadSafe
public interface LongValueObserver extends AsynchronousInstrument {}

View File

@ -1,24 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import java.util.function.Consumer;
/** Builder class for {@link LongValueObserver}. */
public interface LongValueObserverBuilder
extends AsynchronousInstrumentBuilder<AsynchronousInstrument.LongResult> {
@Override
LongValueObserverBuilder setDescription(String description);
@Override
LongValueObserverBuilder setUnit(String unit);
@Override
LongValueObserverBuilder setUpdater(Consumer<AsynchronousInstrument.LongResult> updater);
@Override
LongValueObserver build();
}

View File

@ -1,74 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import io.opentelemetry.api.metrics.common.Labels;
import javax.annotation.concurrent.ThreadSafe;
/**
* ValueRecorder is a synchronous instrument useful for recording any number, positive or negative.
* Values captured by a Record(value) are treated as individual events belonging to a distribution
* that is being summarized.
*
* <p>ValueRecorder should be chosen either when capturing measurements that do not contribute
* meaningfully to a sum, or when capturing numbers that are additive in nature, but where the
* distribution of individual increments is considered interesting.
*
* <p>One of the most common uses for ValueRecorder is to capture latency measurements. Latency
* measurements are not additive in the sense that there is little need to know the latency-sum of
* all processed requests. We use a ValueRecorder instrument to capture latency measurements
* typically because we are interested in knowing mean, median, and other summary statistics about
* individual events.
*
* <p>Example:
*
* <pre>{@code
* class YourClass {
*
* private static final Meter meter = OpenTelemetry.getMeterProvider().get("my_library_name");
* private static final LongValueRecorder valueRecorder =
* meter.
* .longValueRecorderBuilder("doWork_latency")
* .setDescription("gRPC Latency")
* .setUnit("ns")
* .build();
*
* // It is recommended that the API user keep a reference to a Bound Counter.
* private static final BoundLongValueRecorder someWorkBound =
* valueRecorder.bind("work_name", "some_work");
*
* void doWork() {
* long startTime = System.nanoTime();
* // Your code here.
* someWorkBound.record(System.nanoTime() - startTime);
* }
* }
* }</pre>
*/
@ThreadSafe
public interface LongValueRecorder extends SynchronousInstrument<BoundLongValueRecorder> {
/**
* Records the given measurement, associated with the current {@code Context} and provided set of
* labels.
*
* @param value the measurement to record.
* @param labels the set of labels to be associated to this recording
* @throws IllegalArgumentException if value is negative.
*/
void record(long value, Labels labels);
/**
* Records the given measurement, associated with the current {@code Context} and empty labels.
*
* @param value the measurement to record.
* @throws IllegalArgumentException if value is negative.
*/
void record(long value);
@Override
BoundLongValueRecorder bind(Labels labels);
}

View File

@ -1,18 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
/** Builder class for {@link LongValueRecorder}. */
public interface LongValueRecorderBuilder extends SynchronousInstrumentBuilder {
@Override
LongValueRecorderBuilder setDescription(String description);
@Override
LongValueRecorderBuilder setUnit(String unit);
@Override
LongValueRecorder build();
}

View File

@ -8,174 +8,53 @@ package io.opentelemetry.api.metrics;
import javax.annotation.concurrent.ThreadSafe;
/**
* Meter is a simple, interface that allows users to record measurements (metrics).
* Provides instruments used to produce metrics.
*
* <p>There are two ways to record measurements:
* <p>Instruments are obtained through builders provided by this interface. Each builder has a
* default "type" associated with recordings that may be changed.
*
* <ul>
* <li>Record raw measurements, and defer defining the aggregation and the labels for the exported
* Instrument. This should be used in libraries like gRPC to record measurements like
* "server_latency" or "received_bytes".
* <li>Record pre-defined aggregation data (or already aggregated data). This should be used to
* report cpu/memory usage, or simple metrics like "queue_length".
* </ul>
*
* <p>TODO: Update comment.
* <p>A Meter is generally associated with an instrumentation library, e.g. "I monitor apache
* httpclient".
*/
@ThreadSafe
public interface Meter {
/**
* Constructs a counter instrument.
*
* <p>This is used to build both synchronous (in-context) instruments and asynchronous (callback)
* instruments.
*
* @param name the name used for the counter.
* @return a builder for configuring a new Counter instrument. Defaults to recording long values,
* but may be changed.
*/
LongCounterBuilder counterBuilder(String name);
/**
* Returns a builder for a {@link DoubleCounter}.
* Constructs an up-down-counter instrument.
*
* @param name the name of the instrument. Should be a ASCII string with a length no greater than
* 255 characters.
* @return a {@code DoubleCounter.Builder}.
* @throws NullPointerException if {@code name} is null.
* @throws IllegalArgumentException if different metric with the same name already registered.
* @throws IllegalArgumentException if the {@code name} does not match the requirements.
* <p>This is used to build both synchronous (in-context) instruments and asynchronous (callback)
* instruments.
*
* @param name the name used for the counter.
* @return a builder for configuring a new Counter synchronous instrument. Defaults to recording
* long values, but may be changed.
*/
DoubleCounterBuilder doubleCounterBuilder(String name);
LongUpDownCounterBuilder upDownCounterBuilder(String name);
/**
* Returns a builder for a {@link LongCounter}.
* Constructs a Histogram instrument.
*
* @param name the name of the instrument. Should be a ASCII string with a length no greater than
* 255 characters.
* @return a {@code LongCounter.Builder}.
* @throws NullPointerException if {@code name} is null.
* @throws IllegalArgumentException if different metric with the same name already registered.
* @throws IllegalArgumentException if the {@code name} does not match the requirements.
* @param name the name used for the counter.
* @return a builder for configuring a new Histogram synchronous instrument. Defaults to recording
* double values, but may be changed.
*/
LongCounterBuilder longCounterBuilder(String name);
DoubleHistogramBuilder histogramBuilder(String name);
/**
* Returns a builder for a {@link DoubleUpDownCounter}.
* Constructs an asynchronous gauge.
*
* @param name the name of the instrument. Should be a ASCII string with a length no greater than
* 255 characters.
* @return a {@code DoubleCounter.Builder}.
* @throws NullPointerException if {@code name} is null.
* @throws IllegalArgumentException if different metric with the same name already registered.
* @throws IllegalArgumentException if the {@code name} does not match the requirements.
* @return a builder used for configuring how to report gauge measurements on demand.
*/
DoubleUpDownCounterBuilder doubleUpDownCounterBuilder(String name);
/**
* Returns a builder for a {@link LongUpDownCounter}.
*
* @param name the name of the instrument. Should be a ASCII string with a length no greater than
* 255 characters.
* @return a {@code LongCounter.Builder}.
* @throws NullPointerException if {@code name} is null.
* @throws IllegalArgumentException if different metric with the same name already registered.
* @throws IllegalArgumentException if the {@code name} does not match the requirements.
*/
LongUpDownCounterBuilder longUpDownCounterBuilder(String name);
/**
* Returns a new builder for a {@link DoubleValueRecorder}.
*
* @param name the name of the instrument. Should be a ASCII string with a length no greater than
* 255 characters.
* @return a new builder for a {@code DoubleValueRecorder}.
* @throws NullPointerException if {@code name} is null.
* @throws IllegalArgumentException if different metric with the same name already registered.
* @throws IllegalArgumentException if the {@code name} does not match the requirements.
*/
DoubleValueRecorderBuilder doubleValueRecorderBuilder(String name);
/**
* Returns a new builder for a {@link LongValueRecorder}.
*
* @param name the name of the instrument. Should be a ASCII string with a length no greater than
* 255 characters.
* @return a new builder for a {@code LongValueRecorder}.
* @throws NullPointerException if {@code name} is null.
* @throws IllegalArgumentException if different metric with the same name already registered.
* @throws IllegalArgumentException if the {@code name} does not match the requirements.
*/
LongValueRecorderBuilder longValueRecorderBuilder(String name);
/**
* Returns a new builder for a {@link DoubleSumObserver}.
*
* @param name the name of the instrument. Should be a ASCII string with a length no greater than
* 255 characters.
* @return a new builder for a {@code DoubleSumObserver}.
* @throws NullPointerException if {@code name} is null.
* @throws IllegalArgumentException if different metric with the same name already registered.
* @throws IllegalArgumentException if the {@code name} does not match the requirements.
*/
DoubleSumObserverBuilder doubleSumObserverBuilder(String name);
/**
* Returns a new builder for a {@link LongSumObserver}.
*
* @param name the name of the instrument. Should be a ASCII string with a length no greater than
* 255 characters.
* @return a new builder for a {@code LongSumObserver}.
* @throws NullPointerException if {@code name} is null.
* @throws IllegalArgumentException if different metric with the same name already registered.
* @throws IllegalArgumentException if the {@code name} does not match the requirements.
*/
LongSumObserverBuilder longSumObserverBuilder(String name);
/**
* Returns a new builder for a {@link DoubleUpDownSumObserver}.
*
* @param name the name of the instrument. Should be a ASCII string with a length no greater than
* 255 characters.
* @return a new builder for a {@code DoubleUpDownObserver}.
* @throws NullPointerException if {@code name} is null.
* @throws IllegalArgumentException if different metric with the same name already registered.
* @throws IllegalArgumentException if the {@code name} does not match the requirements.
*/
DoubleUpDownSumObserverBuilder doubleUpDownSumObserverBuilder(String name);
/**
* Returns a new builder for a {@link LongUpDownSumObserver}.
*
* @param name the name of the instrument. Should be a ASCII string with a length no greater than
* 255 characters.
* @return a new builder for a {@code LongUpDownSumObserver}.
* @throws NullPointerException if {@code name} is null.
* @throws IllegalArgumentException if different metric with the same name already registered.
* @throws IllegalArgumentException if the {@code name} does not match the requirements.
*/
LongUpDownSumObserverBuilder longUpDownSumObserverBuilder(String name);
/**
* Returns a new builder for a {@link DoubleValueObserver}.
*
* @param name the name of the instrument. Should be a ASCII string with a length no greater than
* 255 characters.
* @return a new builder for a {@code DoubleValueObserver}.
* @throws NullPointerException if {@code name} is null.
* @throws IllegalArgumentException if different metric with the same name already registered.
* @throws IllegalArgumentException if the {@code name} does not match the requirements.
*/
DoubleValueObserverBuilder doubleValueObserverBuilder(String name);
/**
* Returns a new builder for a {@link LongValueObserver}.
*
* @param name the name of the instrument. Should be a ASCII string with a length no greater than
* 255 characters.
* @return a new builder for a {@code LongValueObserver}.
* @throws NullPointerException if {@code name} is null.
* @throws IllegalArgumentException if different metric with the same name already registered.
* @throws IllegalArgumentException if the {@code name} does not match the requirements.
*/
LongValueObserverBuilder longValueObserverBuilder(String name);
/**
* Utility method that allows users to atomically record measurements to a set of Instruments with
* a common set of labels.
*
* @param keyValuePairs The set of labels to associate with this recorder and all it's recordings.
* @return a {@code MeasureBatchRecorder} that can be use to atomically record a set of
* measurements associated with different Measures.
*/
BatchRecorder newBatchRecorder(String... keyValuePairs);
DoubleGaugeBuilder gaugeBuilder(String name);
}

View File

@ -13,7 +13,7 @@ package io.opentelemetry.api.metrics;
public interface MeterBuilder {
/**
* Assign an OpenTelemetry schema URL to the resulting Meter.
* Assigns an OpenTelemetry schema URL to the resulting Meter.
*
* @param schemaUrl The URL of the OpenTelemetry schema being used by this instrumentation
* library.
@ -22,7 +22,7 @@ public interface MeterBuilder {
MeterBuilder setSchemaUrl(String schemaUrl);
/**
* Assign a version to the instrumentation library that is using the resulting Meter.
* Assigns a version to the instrumentation library that is using the resulting Meter.
*
* @param instrumentationVersion The version of the instrumentation library.
* @return this

View File

@ -5,33 +5,32 @@
package io.opentelemetry.api.metrics;
import io.opentelemetry.api.metrics.internal.NoopMeterProvider;
import javax.annotation.concurrent.ThreadSafe;
/**
* A registry for creating named {@link Meter}s. The name <i>Provider</i> is for consistency with
* other languages and it is <b>NOT</b> loaded using reflection.
* A registry for creating named {@link Meter}s.
*
* <p>A MeterProvider represents a configured (or noop) Metric collection system that can be used to
* instrument code.
*
* <p>The name <i>Provider</i> is for consistency with other languages and it is <b>NOT</b> loaded
* using reflection.
*
* @see io.opentelemetry.api.metrics.Meter
*/
@ThreadSafe
public interface MeterProvider {
/**
* Returns a {@link MeterProvider} that only creates no-op {@link Instrument}s that neither record
* nor are emitted.
*/
static MeterProvider noop() {
return DefaultMeterProvider.getInstance();
}
/**
* Gets or creates a named meter instance.
* Gets or creates a named and versioned meter instance.
*
* @param instrumentationName The name of the instrumentation library, not the name of the
* instrument*ed* library.
* @return a tracer instance.
* @return a meter instance.
*/
Meter get(String instrumentationName);
default Meter get(String instrumentationName) {
return meterBuilder(instrumentationName).build();
}
/**
* Gets or creates a named and versioned meter instance.
@ -39,9 +38,15 @@ public interface MeterProvider {
* @param instrumentationName The name of the instrumentation library, not the name of the
* instrument*ed* library.
* @param instrumentationVersion The version of the instrumentation library.
* @return a tracer instance.
* @param schemaUrl Specifies the Schema URL that should be recorded in the emitted metrics.
* @return a meter instance.
*/
Meter get(String instrumentationName, String instrumentationVersion);
default Meter get(String instrumentationName, String instrumentationVersion, String schemaUrl) {
return meterBuilder(instrumentationName)
.setInstrumentationVersion(instrumentationVersion)
.setSchemaUrl(schemaUrl)
.build();
}
/**
* Creates a MeterBuilder for a named meter instance.
@ -51,7 +56,10 @@ public interface MeterProvider {
* @return a MeterBuilder instance.
* @since 1.4.0
*/
default MeterBuilder meterBuilder(String instrumentationName) {
return DefaultMeterBuilder.getInstance();
MeterBuilder meterBuilder(String instrumentationName);
/** Returns a MeterProvider that does nothing. */
public static MeterProvider noop() {
return NoopMeterProvider.getInstance();
}
}

View File

@ -0,0 +1,26 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import io.opentelemetry.api.common.Attributes;
/** An interface for observing measurements with {@code double} values. */
public interface ObservableDoubleMeasurement extends ObservableMeasurement {
/**
* Records a measurement.
*
* @param value The measurement amount. MUST be non-negative.
*/
void observe(double value);
/**
* Records a measurement with a set of attributes.
*
* @param value The measurement amount. MUST be non-negative.
* @param attributes A set of attributes to associate with the count.
*/
void observe(double value, Attributes attributes);
}

View File

@ -0,0 +1,26 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import io.opentelemetry.api.common.Attributes;
/** An interface for observing measurements with {@code long} values. */
public interface ObservableLongMeasurement extends ObservableMeasurement {
/**
* Records a measurement.
*
* @param value The measurement amount. MUST be non-negative.
*/
void observe(long value);
/**
* Records a measurement with a set of attributes.
*
* @param value The measurement amount. MUST be non-negative.
* @param attributes A set of attributes to associate with the count.
*/
void observe(long value, Attributes attributes);
}

View File

@ -0,0 +1,13 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
/**
* A mechanism for observing measurments.
*
* <p>see {@link ObservableDoubleMeasurement} or {@link ObservableLongMeasurement}.
*/
public interface ObservableMeasurement {}

View File

@ -1,34 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import io.opentelemetry.api.metrics.common.Labels;
import javax.annotation.concurrent.ThreadSafe;
/**
* SynchronousInstrument is an interface that defines a type of instruments that are used to report
* measurements synchronously. That is, when the user reports individual measurements as they occur.
*
* <p>Synchronous instrument events additionally have a Context associated with them, describing
* properties of the associated trace and distributed correlation values.
*
* @param <B> the specific type of Bound Instrument this instrument can provide.
*/
@ThreadSafe
public interface SynchronousInstrument<B extends BoundSynchronousInstrument> extends Instrument {
/**
* Returns a {@code Bound Instrument} associated with the specified labels. Multiples requests
* with the same set of labels may return the same {@code Bound Instrument} instance.
*
* <p>It is recommended that callers keep a reference to the Bound Instrument instead of always
* calling this method for every operation.
*
* @param labels the set of labels, as key-value pairs.
* @return a {@code Bound Instrument}
* @throws NullPointerException if {@code labelValues} is null.
*/
B bind(Labels labels);
}

View File

@ -1,12 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
/** Builder class for {@link SynchronousInstrument}. */
public interface SynchronousInstrumentBuilder extends InstrumentBuilder {
@Override
SynchronousInstrument<?> build();
}

View File

@ -1,31 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics.common;
import io.opentelemetry.api.internal.ImmutableKeyValuePairs;
import javax.annotation.concurrent.Immutable;
@Immutable
final class ArrayBackedLabels extends ImmutableKeyValuePairs<String, String> implements Labels {
private static final Labels EMPTY = Labels.builder().build();
static Labels empty() {
return EMPTY;
}
private ArrayBackedLabels(Object[] data) {
super(data);
}
static Labels sortAndFilterToLabels(Object... data) {
return new ArrayBackedLabels(data);
}
@Override
public LabelsBuilder toBuilder() {
return new ArrayBackedLabelsBuilder(data());
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics.common;
import java.util.ArrayList;
import java.util.List;
class ArrayBackedLabelsBuilder implements LabelsBuilder {
private final List<Object> data;
ArrayBackedLabelsBuilder() {
data = new ArrayList<>();
}
ArrayBackedLabelsBuilder(List<Object> data) {
this.data = new ArrayList<>(data);
}
@Override
public Labels build() {
return ArrayBackedLabels.sortAndFilterToLabels(data.toArray());
}
@Override
public LabelsBuilder put(String key, String value) {
data.add(key);
data.add(value);
return this;
}
}

View File

@ -1,122 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics.common;
import static io.opentelemetry.api.metrics.common.ArrayBackedLabels.sortAndFilterToLabels;
import java.util.Map;
import java.util.function.BiConsumer;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
* An immutable container for labels, which are key-value pairs of {@link String}s.
*
* <p>Implementations of this interface *must* be immutable and have well-defined value-based
* equals/hashCode implementations. If an implementation does not strictly conform to these
* requirements, behavior of the OpenTelemetry APIs and default SDK cannot be guaranteed.
*
* <p>For this reason, it is strongly suggested that you use the implementation that is provided
* here via the factory methods and the {@link ArrayBackedLabelsBuilder}.
*/
@Immutable
public interface Labels {
/** Returns a {@link Labels} instance with no attributes. */
static Labels empty() {
return ArrayBackedLabels.empty();
}
/** Creates a new {@link LabelsBuilder} instance for creating arbitrary {@link Labels}. */
static LabelsBuilder builder() {
return new ArrayBackedLabelsBuilder();
}
/** Returns a {@link Labels} instance with a single key-value pair. */
static Labels of(String key, String value) {
return sortAndFilterToLabels(key, value);
}
/**
* Returns a {@link Labels} instance with two key-value pairs. Order of the keys is not preserved.
* Duplicate keys will be removed.
*/
static Labels of(String key1, String value1, String key2, String value2) {
return sortAndFilterToLabels(key1, value1, key2, value2);
}
/**
* Returns a {@link Labels} instance with three key-value pairs. Order of the keys is not
* preserved. Duplicate keys will be removed.
*/
static Labels of(
String key1, String value1, String key2, String value2, String key3, String value3) {
return sortAndFilterToLabels(key1, value1, key2, value2, key3, value3);
}
/**
* Returns a {@link Labels} instance with four key-value pairs. Order of the keys is not
* preserved. Duplicate keys will be removed.
*/
static Labels of(
String key1,
String value1,
String key2,
String value2,
String key3,
String value3,
String key4,
String value4) {
return sortAndFilterToLabels(key1, value1, key2, value2, key3, value3, key4, value4);
}
/**
* Returns a {@link Labels} instance with five key-value pairs. Order of the keys is not
* preserved. Duplicate keys will be removed.
*/
static Labels of(
String key1,
String value1,
String key2,
String value2,
String key3,
String value3,
String key4,
String value4,
String key5,
String value5) {
return sortAndFilterToLabels(
key1, value1,
key2, value2,
key3, value3,
key4, value4,
key5, value5);
}
/** Returns a {@link Labels} instance with the provided {@code keyValueLabelPairs}. */
static Labels of(String... keyValueLabelPairs) {
return sortAndFilterToLabels((Object[]) keyValueLabelPairs);
}
/** Iterates over all the key-value pairs of labels contained by this instance. */
void forEach(BiConsumer<? super String, ? super String> consumer);
/** The number of key-value pairs of labels in this instance. */
int size();
/** Returns the value for the given {@code key}, or {@code null} if the key is not present. */
@Nullable
String get(String key);
/** Returns whether this instance is empty (contains no labels). */
boolean isEmpty();
/** Returns a read-only view of these {@link Labels} as a {@link Map}. */
Map<String, String> asMap();
/** Create a {@link LabelsBuilder} pre-populated with the contents of this Labels instance. */
LabelsBuilder toBuilder();
}

View File

@ -1,19 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics.common;
/** A builder of {@link Labels} supporting an arbitrary number of key-value pairs. */
public interface LabelsBuilder {
/** Create the {@link Labels} from this. */
Labels build();
/**
* Puts a single label into this Builder.
*
* @return this Builder
*/
LabelsBuilder put(String key, String value);
}

View File

@ -1,31 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics.internal;
import javax.annotation.concurrent.Immutable;
/** Internal utility methods for working with attribute keys, attribute values, and metric names. */
@Immutable
public final class MetricsStringUtils {
public static final int METRIC_NAME_MAX_LENGTH = 255;
/**
* Determines whether the metric name contains a valid metric name.
*
* @param metricName the metric name to be validated.
* @return whether the metricName contains a valid name.
*/
public static boolean isValidMetricName(String metricName) {
if (metricName.isEmpty() || metricName.length() > METRIC_NAME_MAX_LENGTH) {
return false;
}
String pattern = "[aA-zZ][aA-zZ0-9_\\-.]*";
return metricName.matches(pattern);
}
private MetricsStringUtils() {}
}

View File

@ -0,0 +1,434 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics.internal;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.BoundDoubleCounter;
import io.opentelemetry.api.metrics.BoundDoubleHistogram;
import io.opentelemetry.api.metrics.BoundDoubleUpDownCounter;
import io.opentelemetry.api.metrics.BoundLongCounter;
import io.opentelemetry.api.metrics.BoundLongHistogram;
import io.opentelemetry.api.metrics.BoundLongUpDownCounter;
import io.opentelemetry.api.metrics.DoubleCounter;
import io.opentelemetry.api.metrics.DoubleCounterBuilder;
import io.opentelemetry.api.metrics.DoubleGaugeBuilder;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.DoubleHistogramBuilder;
import io.opentelemetry.api.metrics.DoubleUpDownCounter;
import io.opentelemetry.api.metrics.DoubleUpDownCounterBuilder;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.LongCounterBuilder;
import io.opentelemetry.api.metrics.LongGaugeBuilder;
import io.opentelemetry.api.metrics.LongHistogram;
import io.opentelemetry.api.metrics.LongHistogramBuilder;
import io.opentelemetry.api.metrics.LongUpDownCounter;
import io.opentelemetry.api.metrics.LongUpDownCounterBuilder;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
import io.opentelemetry.context.Context;
import java.util.function.Consumer;
import javax.annotation.concurrent.ThreadSafe;
/**
* No-op implementations of {@link Meter}.
*
* <p>This implementation should induce as close to zero overhead as possible.
*
* <p>A few notes from the specificaiton on allowed behaviors leading to this deasign [<a
* href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/api.md#instrument">Instrument
* Spec</a>]:
*
* <ul>
* <li>Multiple Insturments with the same name under the same Meter MUST return an error
* <li>Different Meters MUST be treated as separate namespaces
* <li>Implementations MUST NOT require users to repeatedly obtain a Meter again with the same
* name+version+schema_url to pick up configuration changes. This can be achieved either by
* allowing to work with an outdated configuration or by ensuring that new configuration
* applies also to previously returned Meters.
* <li>A MeterProvider could also return a no-op Meter here if application owners configure the
* SDK to suppress telemetry produced by this library
* <li>In case an invalid name (null or empty string) is specified, a working Meter implementation
* MUST be returned as a fallback rather than returning null or throwing an exception,
* </ul>
*/
@ThreadSafe
public class NoopMeter implements Meter {
private static final NoopMeter INSTANCE = new NoopMeter();
public static Meter getInstance() {
return INSTANCE;
}
@Override
public LongCounterBuilder counterBuilder(String name) {
return new NoopLongCounterBuilder();
}
@Override
public LongUpDownCounterBuilder upDownCounterBuilder(String name) {
return new NoopLongUpDownCounterBuilder();
}
@Override
public DoubleHistogramBuilder histogramBuilder(String name) {
return new NoopDoubleHistogramBuilder();
}
@Override
public DoubleGaugeBuilder gaugeBuilder(String name) {
return new NoopDoubleObservableInstrumentBuilder();
}
private NoopMeter() {}
private static class NoopLongCounter implements LongCounter {
@Override
public void add(long value, Attributes attributes, Context context) {}
@Override
public void add(long value, Attributes attributes) {}
@Override
public void add(long value) {}
@Override
public BoundLongCounter bind(Attributes attributes) {
return new NoopBoundLongCounter();
}
}
private static class NoopBoundLongCounter implements BoundLongCounter {
@Override
public void add(long value) {}
@Override
public void add(long value, Context context) {}
@Override
public void unbind() {}
}
private static class NoopDoubleCounter implements DoubleCounter {
@Override
public void add(double value, Attributes attributes, Context context) {}
@Override
public void add(double value, Attributes attributes) {}
@Override
public void add(double value) {}
@Override
public BoundDoubleCounter bind(Attributes attributes) {
return new NoopBoundDoubleCounter();
}
}
private static class NoopBoundDoubleCounter implements BoundDoubleCounter {
@Override
public void add(double value) {}
@Override
public void add(double value, Context context) {}
@Override
public void unbind() {}
}
private static class NoopLongCounterBuilder implements LongCounterBuilder {
@Override
public LongCounterBuilder setDescription(String description) {
return this;
}
@Override
public LongCounterBuilder setUnit(String unit) {
return this;
}
@Override
public DoubleCounterBuilder ofDoubles() {
return new NoopDoubleCounterBuilder();
}
@Override
public LongCounter build() {
return new NoopLongCounter();
}
@Override
public void buildWithCallback(Consumer<ObservableLongMeasurement> callback) {}
}
private static class NoopDoubleCounterBuilder implements DoubleCounterBuilder {
@Override
public DoubleCounterBuilder setDescription(String description) {
return this;
}
@Override
public DoubleCounterBuilder setUnit(String unit) {
return this;
}
@Override
public LongCounterBuilder ofLongs() {
return new NoopLongCounterBuilder();
}
@Override
public DoubleCounter build() {
return new NoopDoubleCounter();
}
@Override
public void buildWithCallback(Consumer<ObservableDoubleMeasurement> callback) {}
}
private static class NoopLongUpDownCounter implements LongUpDownCounter {
@Override
public void add(long value, Attributes attributes, Context context) {}
@Override
public void add(long value, Attributes attributes) {}
@Override
public void add(long value) {}
@Override
public BoundLongUpDownCounter bind(Attributes attributes) {
return new NoopBoundLongUpDownCounter();
}
}
private static class NoopBoundLongUpDownCounter implements BoundLongUpDownCounter {
@Override
public void add(long value, Context context) {}
@Override
public void add(long value) {}
@Override
public void unbind() {}
}
private static class NoopDoubleUpDownCounter implements DoubleUpDownCounter {
@Override
public void add(double value, Attributes attributes, Context context) {}
@Override
public void add(double value, Attributes attributes) {}
@Override
public void add(double value) {}
@Override
public BoundDoubleUpDownCounter bind(Attributes attributes) {
return new NoopBoundDoubleUpDownCounter();
}
}
private static class NoopBoundDoubleUpDownCounter implements BoundDoubleUpDownCounter {
@Override
public void add(double value, Context context) {}
@Override
public void add(double value) {}
@Override
public void unbind() {}
}
private static class NoopLongUpDownCounterBuilder implements LongUpDownCounterBuilder {
@Override
public LongUpDownCounterBuilder setDescription(String description) {
return this;
}
@Override
public LongUpDownCounterBuilder setUnit(String unit) {
return this;
}
@Override
public DoubleUpDownCounterBuilder ofDoubles() {
return new NoopDoubleUpDownCounterBuilder();
}
@Override
public LongUpDownCounter build() {
return new NoopLongUpDownCounter();
}
@Override
public void buildWithCallback(Consumer<ObservableLongMeasurement> callback) {}
}
private static class NoopDoubleUpDownCounterBuilder implements DoubleUpDownCounterBuilder {
@Override
public DoubleUpDownCounterBuilder setDescription(String description) {
return this;
}
@Override
public DoubleUpDownCounterBuilder setUnit(String unit) {
return this;
}
@Override
public LongUpDownCounterBuilder ofLongs() {
return new NoopLongUpDownCounterBuilder();
}
@Override
public DoubleUpDownCounter build() {
return new NoopDoubleUpDownCounter();
}
@Override
public void buildWithCallback(Consumer<ObservableDoubleMeasurement> callback) {}
}
public static class NoopDoubleHistogram implements DoubleHistogram {
@Override
public void record(double value, Attributes attributes, Context context) {}
@Override
public void record(double value, Attributes attributes) {}
@Override
public void record(double value) {}
@Override
public BoundDoubleHistogram bind(Attributes attributes) {
return new NoopBoundDoubleHistogram();
}
}
public static class NoopBoundDoubleHistogram implements BoundDoubleHistogram {
@Override
public void record(double value, Context context) {}
@Override
public void record(double value) {}
@Override
public void unbind() {}
}
public static class NoopLongHistogram implements LongHistogram {
@Override
public void record(long value, Attributes attributes, Context context) {}
@Override
public void record(long value, Attributes attributes) {}
@Override
public void record(long value) {}
@Override
public BoundLongHistogram bind(Attributes attributes) {
return new NoopBoundLongHistogram();
}
}
public static class NoopBoundLongHistogram implements BoundLongHistogram {
@Override
public void record(long value, Context context) {}
@Override
public void record(long value) {}
@Override
public void unbind() {}
}
public static class NoopDoubleHistogramBuilder implements DoubleHistogramBuilder {
@Override
public DoubleHistogramBuilder setDescription(String description) {
return this;
}
@Override
public DoubleHistogramBuilder setUnit(String unit) {
return this;
}
@Override
public LongHistogramBuilder ofLongs() {
return new NoopLongHistogramBuilder();
}
@Override
public DoubleHistogram build() {
return new NoopDoubleHistogram();
}
}
public static class NoopLongHistogramBuilder implements LongHistogramBuilder {
@Override
public LongHistogramBuilder setDescription(String description) {
return this;
}
@Override
public LongHistogramBuilder setUnit(String unit) {
return this;
}
@Override
public DoubleHistogramBuilder ofDoubles() {
return new NoopDoubleHistogramBuilder();
}
@Override
public LongHistogram build() {
return new NoopLongHistogram();
}
}
public static class NoopDoubleObservableInstrumentBuilder implements DoubleGaugeBuilder {
@Override
public DoubleGaugeBuilder setDescription(String description) {
return this;
}
@Override
public DoubleGaugeBuilder setUnit(String unit) {
return this;
}
@Override
public LongGaugeBuilder ofLongs() {
return new NoopLongObservableInstrumentBuilder();
}
@Override
public void buildWithCallback(Consumer<ObservableDoubleMeasurement> callback) {}
}
public static class NoopLongObservableInstrumentBuilder implements LongGaugeBuilder {
@Override
public LongGaugeBuilder setDescription(String description) {
return this;
}
@Override
public LongGaugeBuilder setUnit(String unit) {
return this;
}
@Override
public DoubleGaugeBuilder ofDoubles() {
return new NoopDoubleObservableInstrumentBuilder();
}
@Override
public void buildWithCallback(Consumer<ObservableLongMeasurement> callback) {}
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics.internal;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.MeterBuilder;
import io.opentelemetry.api.metrics.MeterProvider;
/** A {@link MeterProvider} that does nothing. */
public class NoopMeterProvider implements MeterProvider {
@Override
public MeterBuilder meterBuilder(String instrumentationName) {
return BUILDER_INSTANCE;
}
private static final NoopMeterProvider INSTANCE = new NoopMeterProvider();
private static final MeterBuilder BUILDER_INSTANCE = new NoopMeterBuilder();
public static MeterProvider getInstance() {
return INSTANCE;
}
private NoopMeterProvider() {}
private static class NoopMeterBuilder implements MeterBuilder {
@Override
public MeterBuilder setSchemaUrl(String schemaUrl) {
return this;
}
@Override
public MeterBuilder setInstrumentationVersion(String instrumentationVersion) {
return this;
}
@Override
public Meter build() {
return NoopMeter.getInstance();
}
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
/**
* Interfaces and implementations that are internal to OpenTelemetry.
*
* <p>All the content under this package and its subpackages are considered not part of the public
* API, and must not be used by users of the OpenTelemetry library.
*/
@ParametersAreNonnullByDefault
package io.opentelemetry.api.metrics.internal;
import javax.annotation.ParametersAreNonnullByDefault;

View File

@ -1,103 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.junit.jupiter.api.Test;
class BatchRecorderTest {
private static final Meter meter = DefaultMeter.getInstance();
@Test
void testNewBatchRecorder_WrongNumberOfLabels() {
assertThatThrownBy(() -> meter.newBatchRecorder("key"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("key/value");
}
@Test
void testNewBatchRecorder_NullLabelKey() {
assertThatThrownBy(() -> meter.newBatchRecorder(null, "value"))
.isInstanceOf(NullPointerException.class)
.hasMessageContaining("null keys");
}
@Test
void preventNull_MeasureLong() {
assertThatThrownBy(() -> meter.newBatchRecorder().put((LongValueRecorder) null, 5L).record())
.isInstanceOf(NullPointerException.class)
.hasMessage("valueRecorder");
}
@Test
void preventNull_MeasureDouble() {
assertThatThrownBy(() -> meter.newBatchRecorder().put((DoubleValueRecorder) null, 5L).record())
.isInstanceOf(NullPointerException.class)
.hasMessage("valueRecorder");
}
@Test
void preventNull_LongCounter() {
assertThatThrownBy(() -> meter.newBatchRecorder().put((LongCounter) null, 5L).record())
.isInstanceOf(NullPointerException.class)
.hasMessage("counter");
}
@Test
void preventNull_DoubleCounter() {
assertThatThrownBy(() -> meter.newBatchRecorder().put((DoubleCounter) null, 5L).record())
.isInstanceOf(NullPointerException.class)
.hasMessage("counter");
}
@Test
void preventNull_LongUpDownCounter() {
assertThatThrownBy(() -> meter.newBatchRecorder().put((LongUpDownCounter) null, 5L).record())
.isInstanceOf(NullPointerException.class)
.hasMessage("upDownCounter");
}
@Test
void preventNull_DoubleUpDownCounter() {
assertThatThrownBy(() -> meter.newBatchRecorder().put((DoubleUpDownCounter) null, 5L).record())
.isInstanceOf(NullPointerException.class)
.hasMessage("upDownCounter");
}
@Test
void doesNotThrow() {
BatchRecorder batchRecorder = meter.newBatchRecorder();
batchRecorder.put(meter.longValueRecorderBuilder("longValueRecorder").build(), 44L);
batchRecorder.put(meter.longValueRecorderBuilder("negativeLongValueRecorder").build(), -44L);
batchRecorder.put(meter.doubleValueRecorderBuilder("doubleValueRecorder").build(), 77.556d);
batchRecorder.put(
meter.doubleValueRecorderBuilder("negativeDoubleValueRecorder").build(), -77.556d);
batchRecorder.put(meter.longCounterBuilder("longCounter").build(), 44L);
batchRecorder.put(meter.doubleCounterBuilder("doubleCounter").build(), 77.556d);
batchRecorder.put(meter.longUpDownCounterBuilder("longUpDownCounter").build(), -44L);
batchRecorder.put(meter.doubleUpDownCounterBuilder("doubleUpDownCounter").build(), -77.556d);
batchRecorder.record();
}
@Test
void negativeValue_DoubleCounter() {
BatchRecorder batchRecorder = meter.newBatchRecorder();
assertThatThrownBy(
() -> batchRecorder.put(meter.doubleCounterBuilder("doubleCounter").build(), -77.556d))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Counters can only increase");
}
@Test
void negativeValue_LongCounter() {
BatchRecorder batchRecorder = meter.newBatchRecorder();
assertThatThrownBy(
() -> batchRecorder.put(meter.longCounterBuilder("longCounter").build(), -44L))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Counters can only increase");
}
}

View File

@ -1,26 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
class DefaultMeterTest {
@Test
void expectDefaultMeter() {
assertThat(MeterProvider.noop().get("test")).isInstanceOf(DefaultMeter.class);
assertThat(MeterProvider.noop().get("test")).isSameAs(DefaultMeter.getInstance());
assertThat(MeterProvider.noop().get("test", "0.1.0")).isSameAs(DefaultMeter.getInstance());
assertThat(
MeterProvider.noop()
.meterBuilder("test")
.setInstrumentationVersion("0.1.0")
.setSchemaUrl("http://url")
.build())
.isSameAs(DefaultMeter.getInstance());
}
}

View File

@ -1,120 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.api.metrics.internal.MetricsStringUtils;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class DoubleCounterTest {
private static final String NAME = "name";
private static final String DESCRIPTION = "description";
private static final String UNIT = "1";
private static final Meter meter = DefaultMeter.getInstance();
@Test
void preventNull_Name() {
assertThatThrownBy(() -> meter.doubleCounterBuilder(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("name");
}
@Test
void preventEmpty_Name() {
assertThatThrownBy(() -> meter.doubleCounterBuilder("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNonPrintableName() {
assertThatThrownBy(() -> meter.doubleCounterBuilder("\2").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventTooLongName() {
char[] chars = new char[MetricsStringUtils.METRIC_NAME_MAX_LENGTH + 1];
Arrays.fill(chars, 'a');
String longName = String.valueOf(chars);
assertThatThrownBy(() -> meter.doubleCounterBuilder(longName).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNull_Description() {
assertThatThrownBy(() -> meter.doubleCounterBuilder("metric").setDescription(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("description");
}
@Test
void preventNull_Unit() {
assertThatThrownBy(() -> meter.doubleCounterBuilder("metric").setUnit(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("unit");
}
@Test
void add_preventNullLabels() {
assertThatThrownBy(() -> meter.doubleCounterBuilder("metric").build().add(1.0, null))
.isInstanceOf(NullPointerException.class)
.hasMessage("labels");
}
@Test
void add_DoesNotThrow() {
DoubleCounter doubleCounter =
meter.doubleCounterBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
doubleCounter.add(1.0, Labels.empty());
doubleCounter.add(1.0);
}
@Test
void add_PreventNegativeValue() {
DoubleCounter doubleCounter =
meter.doubleCounterBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
assertThatThrownBy(() -> doubleCounter.add(-1.0, Labels.empty()))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Counters can only increase");
}
@Test
void bound_PreventNullLabels() {
assertThatThrownBy(() -> meter.doubleCounterBuilder("metric").build().bind(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("labels");
}
@Test
void bound_DoesNotThrow() {
DoubleCounter doubleCounter =
meter.doubleCounterBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
BoundDoubleCounter bound = doubleCounter.bind(Labels.empty());
bound.add(1.0);
bound.unbind();
}
@Test
void bound_PreventNegativeValue() {
DoubleCounter doubleCounter =
meter.doubleCounterBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
BoundDoubleCounter bound = doubleCounter.bind(Labels.empty());
try {
assertThatThrownBy(() -> bound.add(-1.0))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Counters can only increase");
} finally {
bound.unbind();
}
}
}

View File

@ -1,80 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.metrics.internal.MetricsStringUtils;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class DoubleSumObserverTest {
private static final String NAME = "name";
private static final String DESCRIPTION = "description";
private static final String UNIT = "1";
private static final Meter meter = DefaultMeter.getInstance();
@Test
void preventNull_Name() {
assertThatThrownBy(() -> meter.doubleSumObserverBuilder(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("name");
}
@Test
void preventEmpty_Name() {
assertThatThrownBy(() -> meter.doubleSumObserverBuilder("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNonPrintableName() {
assertThatThrownBy(() -> meter.doubleSumObserverBuilder("\2").build())
.isInstanceOf(IllegalArgumentException.class);
}
@Test
void preventTooLongName() {
char[] chars = new char[MetricsStringUtils.METRIC_NAME_MAX_LENGTH + 1];
Arrays.fill(chars, 'a');
String longName = String.valueOf(chars);
assertThatThrownBy(() -> meter.doubleSumObserverBuilder(longName).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNull_Description() {
assertThatThrownBy(() -> meter.doubleSumObserverBuilder("metric").setDescription(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("description");
}
@Test
void preventNull_Unit() {
assertThatThrownBy(() -> meter.doubleSumObserverBuilder("metric").setUnit(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("unit");
}
@Test
void preventNull_Callback() {
assertThatThrownBy(() -> meter.doubleSumObserverBuilder("metric").setUpdater(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("callback");
}
@Test
void doesNotThrow() {
meter
.doubleSumObserverBuilder(NAME)
.setDescription(DESCRIPTION)
.setUnit(UNIT)
.setUpdater(result -> {})
.build();
}
}

View File

@ -1,101 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.api.metrics.internal.MetricsStringUtils;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class DoubleUpDownCounterTest {
private static final String NAME = "name";
private static final String DESCRIPTION = "description";
private static final String UNIT = "1";
private static final Meter meter = DefaultMeter.getInstance();
@Test
void preventNull_Name() {
assertThatThrownBy(() -> meter.doubleUpDownCounterBuilder(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("name");
}
@Test
void preventEmpty_Name() {
assertThatThrownBy(() -> meter.doubleUpDownCounterBuilder("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNonPrintableName() {
assertThatThrownBy(() -> meter.doubleUpDownCounterBuilder("\2").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventTooLongName() {
char[] chars = new char[MetricsStringUtils.METRIC_NAME_MAX_LENGTH + 1];
Arrays.fill(chars, 'a');
String longName = String.valueOf(chars);
assertThatThrownBy(() -> meter.doubleUpDownCounterBuilder(longName).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNull_Description() {
assertThatThrownBy(
() -> meter.doubleUpDownCounterBuilder("metric").setDescription(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("description");
}
@Test
void preventNull_Unit() {
assertThatThrownBy(() -> meter.doubleUpDownCounterBuilder("metric").setUnit(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("unit");
}
@Test
void add_preventNullLabels() {
assertThatThrownBy(() -> meter.doubleUpDownCounterBuilder("metric").build().bind(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("labels");
}
@Test
void add_DoesNotThrow() {
DoubleUpDownCounter doubleUpDownCounter =
meter.doubleUpDownCounterBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
doubleUpDownCounter.add(1.0, Labels.empty());
doubleUpDownCounter.add(-1.0, Labels.empty());
doubleUpDownCounter.add(1.0);
doubleUpDownCounter.add(-1.0);
}
@Test
void bound_PreventNullLabels() {
assertThatThrownBy(() -> meter.doubleUpDownCounterBuilder("metric").build().bind(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("labels");
}
@Test
void bound_DoesNotThrow() {
DoubleUpDownCounter doubleUpDownCounter =
meter.doubleUpDownCounterBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
BoundDoubleUpDownCounter bound = doubleUpDownCounter.bind(Labels.empty());
bound.add(1.0);
bound.add(-1.0);
bound.unbind();
}
}

View File

@ -1,83 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.metrics.internal.MetricsStringUtils;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class DoubleUpDownSumObserverTest {
private static final String NAME = "name";
private static final String DESCRIPTION = "description";
private static final String UNIT = "1";
private static final Meter meter = DefaultMeter.getInstance();
@Test
void preventNull_Name() {
assertThatThrownBy(() -> meter.doubleUpDownSumObserverBuilder(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("name");
}
@Test
void preventEmpty_Name() {
assertThatThrownBy(() -> meter.doubleUpDownSumObserverBuilder("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNonPrintableName() {
assertThatThrownBy(() -> meter.doubleUpDownSumObserverBuilder("\2").build())
.isInstanceOf(IllegalArgumentException.class);
}
@Test
void preventTooLongName() {
char[] chars = new char[MetricsStringUtils.METRIC_NAME_MAX_LENGTH + 1];
Arrays.fill(chars, 'a');
String longName = String.valueOf(chars);
assertThatThrownBy(() -> meter.doubleUpDownSumObserverBuilder(longName).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNull_Description() {
assertThatThrownBy(
() -> meter.doubleUpDownSumObserverBuilder("metric").setDescription(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("description");
}
@Test
void preventNull_Unit() {
assertThatThrownBy(() -> meter.doubleUpDownSumObserverBuilder("metric").setUnit(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("unit");
}
@Test
void preventNull_Callback() {
assertThatThrownBy(
() -> meter.doubleUpDownSumObserverBuilder("metric").setUpdater(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("callback");
}
@Test
void doesNotThrow() {
meter
.doubleUpDownSumObserverBuilder(NAME)
.setDescription(DESCRIPTION)
.setUnit(UNIT)
.setUpdater(result -> {})
.build();
}
}

View File

@ -1,82 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.metrics.internal.MetricsStringUtils;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class DoubleValueObserverTest {
private static final String NAME = "name";
private static final String DESCRIPTION = "description";
private static final String UNIT = "1";
private static final Meter meter = DefaultMeter.getInstance();
@Test
void preventNull_Name() {
assertThatThrownBy(() -> meter.doubleValueObserverBuilder(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("name");
}
@Test
void preventEmpty_Name() {
assertThatThrownBy(() -> meter.doubleValueObserverBuilder("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNonPrintableName() {
assertThatThrownBy(() -> meter.doubleValueObserverBuilder("\2").build())
.isInstanceOf(IllegalArgumentException.class);
}
@Test
void preventTooLongName() {
char[] chars = new char[MetricsStringUtils.METRIC_NAME_MAX_LENGTH + 1];
Arrays.fill(chars, 'a');
String longName = String.valueOf(chars);
assertThatThrownBy(() -> meter.doubleValueObserverBuilder(longName).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNull_Description() {
assertThatThrownBy(
() -> meter.doubleValueObserverBuilder("metric").setDescription(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("description");
}
@Test
void preventNull_Unit() {
assertThatThrownBy(() -> meter.doubleValueObserverBuilder("metric").setUnit(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("unit");
}
@Test
void preventNull_Callback() {
assertThatThrownBy(() -> meter.doubleValueObserverBuilder("metric").setUpdater(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("callback");
}
@Test
void doesNotThrow() {
meter
.doubleValueObserverBuilder(NAME)
.setDescription(DESCRIPTION)
.setUnit(UNIT)
.setUpdater(result -> {})
.build();
}
}

View File

@ -1,101 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.api.metrics.internal.MetricsStringUtils;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class DoubleValueRecorderTest {
private static final String NAME = "name";
private static final String DESCRIPTION = "description";
private static final String UNIT = "1";
private static final Meter meter = DefaultMeter.getInstance();
@Test
void preventNull_Name() {
assertThatThrownBy(() -> meter.doubleValueRecorderBuilder(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("name");
}
@Test
void preventEmpty_Name() {
assertThatThrownBy(() -> meter.doubleValueRecorderBuilder("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNonPrintableName() {
assertThatThrownBy(() -> meter.doubleValueRecorderBuilder("\2").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventTooLongName() {
char[] chars = new char[MetricsStringUtils.METRIC_NAME_MAX_LENGTH + 1];
Arrays.fill(chars, 'a');
String longName = String.valueOf(chars);
assertThatThrownBy(() -> meter.doubleValueRecorderBuilder(longName).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNull_Description() {
assertThatThrownBy(
() -> meter.doubleValueRecorderBuilder("metric").setDescription(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("description");
}
@Test
void preventNull_Unit() {
assertThatThrownBy(() -> meter.doubleValueRecorderBuilder("metric").setUnit(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("unit");
}
@Test
void record_PreventNullLabels() {
assertThatThrownBy(() -> meter.doubleValueRecorderBuilder("metric").build().record(1.0, null))
.isInstanceOf(NullPointerException.class)
.hasMessage("labels");
}
@Test
void record_DoesNotThrow() {
DoubleValueRecorder doubleValueRecorder =
meter.doubleValueRecorderBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
doubleValueRecorder.record(5.0, Labels.empty());
doubleValueRecorder.record(-5.0, Labels.empty());
doubleValueRecorder.record(5.0);
doubleValueRecorder.record(-5.0);
}
@Test
void bound_PreventNullLabels() {
assertThatThrownBy(() -> meter.doubleValueRecorderBuilder("metric").build().bind(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("labels");
}
@Test
void bound_DoesNotThrow() {
DoubleValueRecorder doubleValueRecorder =
meter.doubleValueRecorderBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
BoundDoubleValueRecorder bound = doubleValueRecorder.bind(Labels.empty());
bound.record(5.0);
bound.record(-5.0);
bound.unbind();
}
}

View File

@ -1,120 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.api.metrics.internal.MetricsStringUtils;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class LongCounterTest {
private static final String NAME = "name";
private static final String DESCRIPTION = "description";
private static final String UNIT = "1";
private static final Meter meter = DefaultMeter.getInstance();
@Test
void preventNull_Name() {
assertThatThrownBy(() -> meter.longCounterBuilder(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("name");
}
@Test
void preventEmpty_Name() {
assertThatThrownBy(() -> meter.longCounterBuilder("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNonPrintableName() {
assertThatThrownBy(() -> meter.longCounterBuilder("\2").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventTooLongName() {
char[] chars = new char[MetricsStringUtils.METRIC_NAME_MAX_LENGTH + 1];
Arrays.fill(chars, 'a');
String longName = String.valueOf(chars);
assertThatThrownBy(() -> meter.longCounterBuilder(longName).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNull_Description() {
assertThatThrownBy(() -> meter.longCounterBuilder("metric").setDescription(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("description");
}
@Test
void preventNull_Unit() {
assertThatThrownBy(() -> meter.longCounterBuilder("metric").setUnit(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("unit");
}
@Test
void add_PreventNullLabels() {
assertThatThrownBy(() -> meter.longCounterBuilder("metric").build().add(1, null))
.isInstanceOf(NullPointerException.class)
.hasMessage("labels");
}
@Test
void add_DoesNotThrow() {
LongCounter longCounter =
meter.longCounterBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
longCounter.add(1, Labels.empty());
longCounter.add(1);
}
@Test
void add_PreventNegativeValue() {
LongCounter longCounter =
meter.longCounterBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
assertThatThrownBy(() -> longCounter.add(-1, Labels.empty()))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Counters can only increase");
}
@Test
void bound_PreventNullLabels() {
assertThatThrownBy(() -> meter.longCounterBuilder("metric").build().bind(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("labels");
}
@Test
void bound_DoesNotThrow() {
LongCounter longCounter =
meter.longCounterBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
BoundLongCounter bound = longCounter.bind(Labels.empty());
bound.add(1);
bound.unbind();
}
@Test
void bound_PreventNegativeValue() {
LongCounter longCounter =
meter.longCounterBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
BoundLongCounter bound = longCounter.bind(Labels.empty());
try {
assertThatThrownBy(() -> bound.add(-1))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Counters can only increase");
} finally {
bound.unbind();
}
}
}

View File

@ -1,82 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.metrics.internal.MetricsStringUtils;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class LongSumObserverTest {
private static final String NAME = "name";
private static final String DESCRIPTION = "description";
private static final String UNIT = "1";
private static final Meter meter = DefaultMeter.getInstance();
@Test
void preventNull_Name() {
assertThatThrownBy(() -> meter.longSumObserverBuilder(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("name");
}
@Test
void preventEmpty_Name() {
assertThatThrownBy(() -> meter.longSumObserverBuilder("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNonPrintableName() {
assertThatThrownBy(() -> meter.longSumObserverBuilder("\2").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventTooLongName() {
char[] chars = new char[MetricsStringUtils.METRIC_NAME_MAX_LENGTH + 1];
Arrays.fill(chars, 'a');
String longName = String.valueOf(chars);
assertThatThrownBy(() -> meter.longSumObserverBuilder(longName).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNull_Description() {
assertThatThrownBy(() -> meter.longSumObserverBuilder("metric").setDescription(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("description");
}
@Test
void preventNull_Unit() {
assertThatThrownBy(() -> meter.longSumObserverBuilder("metric").setUnit(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("unit");
}
@Test
void preventNull_Callback() {
assertThatThrownBy(() -> meter.longSumObserverBuilder("metric").setUpdater(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("callback");
}
@Test
void doesNotThrow() {
meter
.longSumObserverBuilder(NAME)
.setDescription(DESCRIPTION)
.setUnit(UNIT)
.setUpdater(result -> {})
.build();
}
}

View File

@ -1,100 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.api.metrics.internal.MetricsStringUtils;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class LongUpDownCounterTest {
private static final String NAME = "name";
private static final String DESCRIPTION = "description";
private static final String UNIT = "1";
private static final Meter meter = DefaultMeter.getInstance();
@Test
void preventNull_Name() {
assertThatThrownBy(() -> meter.longUpDownCounterBuilder(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("name");
}
@Test
void preventEmpty_Name() {
assertThatThrownBy(() -> meter.longUpDownCounterBuilder("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNonPrintableName() {
assertThatThrownBy(() -> meter.longUpDownCounterBuilder("\2").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventTooLongName() {
char[] chars = new char[MetricsStringUtils.METRIC_NAME_MAX_LENGTH + 1];
Arrays.fill(chars, 'a');
String longName = String.valueOf(chars);
assertThatThrownBy(() -> meter.longUpDownCounterBuilder(longName).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNull_Description() {
assertThatThrownBy(() -> meter.longUpDownCounterBuilder("metric").setDescription(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("description");
}
@Test
void preventNull_Unit() {
assertThatThrownBy(() -> meter.longUpDownCounterBuilder("metric").setUnit(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("unit");
}
@Test
void add_PreventNullLabels() {
assertThatThrownBy(() -> meter.longUpDownCounterBuilder("metric").build().add(1, null))
.isInstanceOf(NullPointerException.class)
.hasMessage("labels");
}
@Test
void add_DoesNotThrow() {
LongUpDownCounter longUpDownCounter =
meter.longUpDownCounterBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
longUpDownCounter.add(1, Labels.empty());
longUpDownCounter.add(-1, Labels.empty());
longUpDownCounter.add(1);
longUpDownCounter.add(-1);
}
@Test
void bound_PreventNullLabels() {
assertThatThrownBy(() -> meter.longUpDownCounterBuilder("metric").build().bind(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("labels");
}
@Test
void bound_DoesNotThrow() {
LongUpDownCounter longUpDownCounter =
meter.longUpDownCounterBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
BoundLongUpDownCounter bound = longUpDownCounter.bind(Labels.empty());
bound.add(1);
bound.add(-1);
bound.unbind();
}
}

View File

@ -1,83 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.metrics.internal.MetricsStringUtils;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class LongUpDownSumObserverTest {
private static final String NAME = "name";
private static final String DESCRIPTION = "description";
private static final String UNIT = "1";
private static final Meter meter = DefaultMeter.getInstance();
@Test
void preventNull_Name() {
assertThatThrownBy(() -> meter.longUpDownSumObserverBuilder(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("name");
}
@Test
void preventEmpty_Name() {
assertThatThrownBy(() -> meter.longUpDownSumObserverBuilder("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNonPrintableName() {
assertThatThrownBy(() -> meter.longUpDownSumObserverBuilder("\2").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventTooLongName() {
char[] chars = new char[MetricsStringUtils.METRIC_NAME_MAX_LENGTH + 1];
Arrays.fill(chars, 'a');
String longName = String.valueOf(chars);
assertThatThrownBy(() -> meter.longUpDownSumObserverBuilder(longName).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(DefaultMeter.ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNull_Description() {
assertThatThrownBy(
() -> meter.longUpDownSumObserverBuilder("metric").setDescription(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("description");
}
@Test
void preventNull_Unit() {
assertThatThrownBy(() -> meter.longUpDownSumObserverBuilder("metric").setUnit(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("unit");
}
@Test
void preventNull_Callback() {
assertThatThrownBy(() -> meter.longUpDownSumObserverBuilder("metric").setUpdater(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("callback");
}
@Test
void doesNotThrow() {
meter
.longUpDownSumObserverBuilder(NAME)
.setDescription(DESCRIPTION)
.setUnit(UNIT)
.setUpdater(result -> {})
.build();
}
}

View File

@ -1,84 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import static io.opentelemetry.api.metrics.DefaultMeter.ERROR_MESSAGE_INVALID_NAME;
import static java.util.Arrays.fill;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.metrics.internal.MetricsStringUtils;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link LongValueObserver}. */
class LongValueObserverTest {
private static final String NAME = "name";
private static final String DESCRIPTION = "description";
private static final String UNIT = "1";
private static final Meter meter = DefaultMeter.getInstance();
@Test
void preventNull_Name() {
assertThatThrownBy(() -> meter.longValueObserverBuilder(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("name");
}
@Test
void preventEmpty_Name() {
assertThatThrownBy(() -> meter.longValueObserverBuilder("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNonPrintableName() {
assertThatThrownBy(() -> meter.longValueObserverBuilder("\2").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventTooLongName() {
char[] chars = new char[MetricsStringUtils.METRIC_NAME_MAX_LENGTH + 1];
fill(chars, 'a');
String longName = String.valueOf(chars);
assertThatThrownBy(() -> meter.longValueObserverBuilder(longName).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNull_Description() {
assertThatThrownBy(() -> meter.longValueObserverBuilder("metric").setDescription(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("description");
}
@Test
void preventNull_Unit() {
assertThatThrownBy(() -> meter.longValueObserverBuilder("metric").setUnit(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("unit");
}
@Test
void preventNull_Callback() {
assertThatThrownBy(() -> meter.longValueObserverBuilder("metric").setUpdater(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("callback");
}
@Test
void doesNotThrow() {
meter
.longValueObserverBuilder(NAME)
.setDescription(DESCRIPTION)
.setUnit(UNIT)
.setUpdater(result -> {})
.build();
}
}

View File

@ -1,102 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics;
import static io.opentelemetry.api.metrics.DefaultMeter.ERROR_MESSAGE_INVALID_NAME;
import static java.util.Arrays.fill;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.api.metrics.internal.MetricsStringUtils;
import org.junit.jupiter.api.Test;
/** Tests for {@link LongValueRecorder}. */
public final class LongValueRecorderTest {
private static final String NAME = "name";
private static final String DESCRIPTION = "description";
private static final String UNIT = "1";
private static final Meter meter = DefaultMeter.getInstance();
@Test
void preventNull_Name() {
assertThatThrownBy(() -> meter.longValueRecorderBuilder(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("name");
}
@Test
void preventEmpty_Name() {
assertThatThrownBy(() -> meter.longValueRecorderBuilder("").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNonPrintableMeasureName() {
assertThatThrownBy(() -> meter.longValueRecorderBuilder("\2").build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventTooLongName() {
char[] chars = new char[MetricsStringUtils.METRIC_NAME_MAX_LENGTH + 1];
fill(chars, 'a');
String longName = String.valueOf(chars);
assertThatThrownBy(() -> meter.longValueRecorderBuilder(longName).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(ERROR_MESSAGE_INVALID_NAME);
}
@Test
void preventNull_Description() {
assertThatThrownBy(() -> meter.longValueRecorderBuilder("metric").setDescription(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("description");
}
@Test
void preventNull_Unit() {
assertThatThrownBy(() -> meter.longValueRecorderBuilder("metric").setUnit(null).build())
.isInstanceOf(NullPointerException.class)
.hasMessage("unit");
}
@Test
void record_PreventNullLabels() {
assertThatThrownBy(() -> meter.longValueRecorderBuilder("metric").build().record(1, null))
.isInstanceOf(NullPointerException.class)
.hasMessage("labels");
}
@Test
void record_DoesNotThrow() {
LongValueRecorder longValueRecorder =
meter.longValueRecorderBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
longValueRecorder.record(5, Labels.empty());
longValueRecorder.record(-5, Labels.empty());
longValueRecorder.record(5);
longValueRecorder.record(-5);
}
@Test
void bound_PreventNullLabels() {
assertThatThrownBy(() -> meter.longValueRecorderBuilder("metric").build().bind(null))
.isInstanceOf(NullPointerException.class)
.hasMessage("labels");
}
@Test
void bound_DoesNotThrow() {
LongValueRecorder longValueRecorder =
meter.longValueRecorderBuilder(NAME).setDescription(DESCRIPTION).setUnit(UNIT).build();
BoundLongValueRecorder bound = longValueRecorder.bind(Labels.empty());
bound.record(5);
bound.record(-5);
bound.unbind();
}
}

View File

@ -1,151 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics.common;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.jupiter.api.Test;
class LabelsTest {
@Test
void forEach() {
final Map<String, String> entriesSeen = new LinkedHashMap<>();
Labels labels =
Labels.of(
"key1", "value1",
"key2", "value2");
labels.forEach(entriesSeen::put);
assertThat(entriesSeen).containsExactly(entry("key1", "value1"), entry("key2", "value2"));
}
@Test
void asMap() {
Labels labels =
Labels.of(
"key1", "value1",
"key2", "value2");
assertThat(labels.asMap()).containsExactly(entry("key1", "value1"), entry("key2", "value2"));
}
@Test
void forEach_singleAttribute() {
final Map<String, String> entriesSeen = new HashMap<>();
Labels labels = Labels.of("key", "value");
labels.forEach(entriesSeen::put);
assertThat(entriesSeen).containsExactly(entry("key", "value"));
}
@Test
void forEach_empty() {
final AtomicBoolean sawSomething = new AtomicBoolean(false);
Labels emptyLabels = Labels.empty();
emptyLabels.forEach((key, value) -> sawSomething.set(true));
assertThat(sawSomething.get()).isFalse();
}
@Test
void orderIndependentEquality() {
Labels one =
Labels.of(
"key3", "value3",
"key1", "value1",
"key2", "value2");
Labels two =
Labels.of(
"key2", "value2",
"key3", "value3",
"key1", "value1");
assertThat(one).isEqualTo(two);
}
@Test
void nullValueEquivalentWithMissing() {
Labels one =
Labels.of(
"key3", "value3",
"key4", null,
"key1", "value1",
"key2", "value2");
Labels two =
Labels.of(
"key2", "value2",
"key3", "value3",
"key1", "value1");
assertThat(one).isEqualTo(two);
}
@Test
void deduplication() {
Labels one =
Labels.of(
"key1", "valueX",
"key1", "value1");
Labels two = Labels.of("key1", "value1");
assertThat(one).isEqualTo(two);
}
@Test
void threeLabels() {
Labels one =
Labels.of(
"key1", "value1",
"key3", "value3",
"key2", "value2");
assertThat(one).isNotNull();
}
@Test
void fourLabels() {
Labels one =
Labels.of(
"key1", "value1",
"key2", "value2",
"key3", "value3",
"key4", "value4");
assertThat(one).isNotNull();
}
@Test
void builder() {
Labels labels =
Labels.builder()
.put("key1", "duplicateShouldBeIgnored")
.put("key1", "value1")
.put("key2", "value2")
.build();
assertThat(labels)
.isEqualTo(
Labels.of(
"key1", "value1",
"key2", "value2"));
}
@Test
void toBuilder() {
Labels initial = Labels.of("one", "a");
Labels second = initial.toBuilder().put("two", "b").build();
assertThat(initial.size()).isEqualTo(1);
assertThat(second.size()).isEqualTo(2);
assertThat(initial).isEqualTo(Labels.of("one", "a"));
assertThat(second).isEqualTo(Labels.of("one", "a", "two", "b"));
}
}

View File

@ -1,27 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics.internal;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
class MetricsStringUtilsTest {
@Test
void isValidMetricName() {
assertThat(MetricsStringUtils.isValidMetricName("")).isFalse();
assertThat(
MetricsStringUtils.isValidMetricName(
String.valueOf(new char[MetricsStringUtils.METRIC_NAME_MAX_LENGTH + 1])))
.isFalse();
assertThat(MetricsStringUtils.isValidMetricName("abcd")).isTrue();
assertThat(MetricsStringUtils.isValidMetricName("ab.cd")).isTrue();
assertThat(MetricsStringUtils.isValidMetricName("ab12cd")).isTrue();
assertThat(MetricsStringUtils.isValidMetricName("1abcd")).isFalse();
assertThat(MetricsStringUtils.isValidMetricName("ab*cd")).isFalse();
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics.internal;
import io.opentelemetry.api.metrics.MeterProvider;
import org.junit.jupiter.api.Test;
public class NoopMeterProviderTest {
@Test
void noopMeterProvider_getDoesNotThrow() {
MeterProvider provider = MeterProvider.noop();
provider.get("user-instrumentation");
provider.get("schema-instrumentation", "1.0", "myschema://url");
}
@Test
void noopMeterProvider_builderDoesNotThrow() {
MeterProvider provider = MeterProvider.noop();
provider.meterBuilder("user-instrumentation").build();
provider.meterBuilder("advanced-instrumetnation").setInstrumentationVersion("1.0").build();
provider.meterBuilder("schema-instrumentation").setSchemaUrl("myschema://url").build();
provider
.meterBuilder("schema-instrumentation")
.setInstrumentationVersion("1.0")
.setSchemaUrl("myschema://url")
.build();
}
}

View File

@ -0,0 +1,268 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.metrics.internal;
import static io.opentelemetry.api.common.AttributeKey.stringKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.BoundDoubleCounter;
import io.opentelemetry.api.metrics.BoundDoubleHistogram;
import io.opentelemetry.api.metrics.BoundDoubleUpDownCounter;
import io.opentelemetry.api.metrics.BoundLongCounter;
import io.opentelemetry.api.metrics.BoundLongHistogram;
import io.opentelemetry.api.metrics.BoundLongUpDownCounter;
import io.opentelemetry.api.metrics.DoubleCounter;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.DoubleUpDownCounter;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.LongHistogram;
import io.opentelemetry.api.metrics.LongUpDownCounter;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.context.Context;
import org.junit.jupiter.api.Test;
public class NoopMeterTest {
private static final Meter meter = NoopMeter.getInstance();
@Test
void noopLongCounter_doesNotThrow() {
LongCounter counter =
meter.counterBuilder("size").setDescription("The size I'm measuring").setUnit("1").build();
counter.add(1);
counter.add(1, Attributes.of(stringKey("thing"), "car"));
counter.add(1, Attributes.of(stringKey("thing"), "car"), Context.current());
}
@Test
void noopBoundLongCounter_doesNotThrow() {
BoundLongCounter counter =
meter
.counterBuilder("size")
.setDescription("The size I'm measuring")
.setUnit("1")
.build()
.bind(Attributes.of(stringKey("thing"), "car"));
counter.add(1);
counter.add(1, Context.current());
}
@Test
void noopDoubleCounter_doesNotThrow() {
DoubleCounter counter =
meter
.counterBuilder("size")
.ofDoubles()
.setDescription("The size I'm measuring")
.setUnit("1")
.build();
counter.add(1.2);
counter.add(2.5, Attributes.of(stringKey("thing"), "car"));
counter.add(2.5, Attributes.of(stringKey("thing"), "car"), Context.current());
}
@Test
void noopBoundDoubleCounter_doesNotThrow() {
BoundDoubleCounter counter =
meter
.counterBuilder("size")
.ofDoubles()
.setDescription("The size I'm measuring")
.setUnit("1")
.build()
.bind(Attributes.of(stringKey("thing"), "car"));
counter.add(1.2);
counter.add(2.5, Context.current());
}
@Test
void noopLongUpDownCounter_doesNotThrow() {
LongUpDownCounter counter =
meter
.upDownCounterBuilder("size")
.setDescription("The size I'm measuring")
.setUnit("1")
.build();
counter.add(-1);
counter.add(1, Attributes.of(stringKey("thing"), "car"));
counter.add(1, Attributes.of(stringKey("thing"), "car"), Context.current());
}
@Test
void noopBoundLongUpDownCounter_doesNotThrow() {
BoundLongUpDownCounter counter =
meter
.upDownCounterBuilder("size")
.setDescription("The size I'm measuring")
.setUnit("1")
.build()
.bind(Attributes.of(stringKey("thing"), "car"));
counter.add(-1);
counter.add(1, Context.current());
}
@Test
void noopDoubleUpDownCounter_doesNotThrow() {
DoubleUpDownCounter counter =
meter
.upDownCounterBuilder("size")
.ofDoubles()
.setDescription("The size I'm measuring")
.setUnit("1")
.build();
counter.add(-2e4);
counter.add(1.0e-1, Attributes.of(stringKey("thing"), "car"));
counter.add(1.0e-1, Attributes.of(stringKey("thing"), "car"), Context.current());
}
@Test
void noopBoundDoubleUpDownCounter_doesNotThrow() {
BoundDoubleUpDownCounter counter =
meter
.upDownCounterBuilder("size")
.ofDoubles()
.setDescription("The size I'm measuring")
.setUnit("1")
.build()
.bind(Attributes.of(stringKey("thing"), "car"));
counter.add(-2e4);
counter.add(1.0e-1, Context.current());
}
@Test
void noopLongHistogram_doesNotThrow() {
LongHistogram histogram =
meter
.histogramBuilder("size")
.ofLongs()
.setDescription("The size I'm measuring")
.setUnit("1")
.build();
histogram.record(-1);
histogram.record(1, Attributes.of(stringKey("thing"), "car"));
histogram.record(1, Attributes.of(stringKey("thing"), "car"), Context.current());
}
@Test
void noopBoundLongHistogram_doesNotThrow() {
BoundLongHistogram histogram =
meter
.histogramBuilder("size")
.ofLongs()
.setDescription("The size I'm measuring")
.setUnit("1")
.build()
.bind(Attributes.of(stringKey("thing"), "car"));
histogram.record(-1);
histogram.record(1, Context.current());
}
@Test
void noopDoubleHistogram_doesNotThrow() {
DoubleHistogram histogram =
meter
.histogramBuilder("size")
.setDescription("The size I'm measuring")
.setUnit("1")
.build();
histogram.record(-2e4);
histogram.record(1.0e-1, Attributes.of(stringKey("thing"), "car"));
histogram.record(1.0e-1, Attributes.of(stringKey("thing"), "car"), Context.current());
}
@Test
void noopBoundDoubleHistogram_doesNotThrow() {
BoundDoubleHistogram histogram =
meter
.histogramBuilder("size")
.setDescription("The size I'm measuring")
.setUnit("1")
.build()
.bind(Attributes.of(stringKey("thing"), "car"));
histogram.record(-2e4);
histogram.record(1.0e-1, Context.current());
}
@Test
void noopObservableLongGauage_doesNotThrow() {
meter
.gaugeBuilder("temperature")
.ofLongs()
.setDescription("The current temperature")
.setUnit("C")
.buildWithCallback(
m -> {
m.observe(1);
m.observe(2, Attributes.of(stringKey("thing"), "engine"));
});
}
@Test
void noopObservableDoubleGauage_doesNotThrow() {
meter
.gaugeBuilder("temperature")
.setDescription("The current temperature")
.setUnit("C")
.buildWithCallback(
m -> {
m.observe(1.0e1);
m.observe(-27.4, Attributes.of(stringKey("thing"), "engine"));
});
}
@Test
void noopObservableLongCounter_doesNotThrow() {
meter
.counterBuilder("temperature")
.setDescription("The current temperature")
.setUnit("C")
.buildWithCallback(
m -> {
m.observe(1);
m.observe(2, Attributes.of(stringKey("thing"), "engine"));
});
}
@Test
void noopObservableDoubleCounter_doesNotThrow() {
meter
.counterBuilder("temperature")
.ofDoubles()
.setDescription("The current temperature")
.setUnit("C")
.buildWithCallback(
m -> {
m.observe(1.0e1);
m.observe(-27.4, Attributes.of(stringKey("thing"), "engine"));
});
}
@Test
void noopObservableLongUpDownCounter_doesNotThrow() {
meter
.upDownCounterBuilder("temperature")
.setDescription("The current temperature")
.setUnit("C")
.buildWithCallback(
m -> {
m.observe(1);
m.observe(2, Attributes.of(stringKey("thing"), "engine"));
});
}
@Test
void noopObservableDoubleUpDownCounter_doesNotThrow() {
meter
.upDownCounterBuilder("temperature")
.ofDoubles()
.setDescription("The current temperature")
.setUnit("C")
.buildWithCallback(
m -> {
m.observe(1.0e1);
m.observe(-27.4, Attributes.of(stringKey("thing"), "engine"));
});
}
}

View File

@ -7,11 +7,11 @@ package io.opentelemetry.exporter.otlp.http.trace;
import com.google.rpc.Code;
import com.google.rpc.Status;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.BoundLongCounter;
import io.opentelemetry.api.metrics.GlobalMeterProvider;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.exporter.otlp.internal.SpanAdapter;
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
import io.opentelemetry.sdk.common.CompletableResultCode;
@ -41,11 +41,12 @@ import okio.Okio;
public final class OtlpHttpSpanExporter implements SpanExporter {
private static final String EXPORTER_NAME = OtlpHttpSpanExporter.class.getSimpleName();
private static final Labels EXPORTER_NAME_LABELS = Labels.of("exporter", EXPORTER_NAME);
private static final Labels EXPORT_SUCCESS_LABELS =
Labels.of("exporter", EXPORTER_NAME, "success", "true");
private static final Labels EXPORT_FAILURE_LABELS =
Labels.of("exporter", EXPORTER_NAME, "success", "false");
private static final Attributes EXPORTER_NAME_LABELS =
Attributes.builder().put("exporter", EXPORTER_NAME).build();
private static final Attributes EXPORT_SUCCESS_LABELS =
Attributes.builder().put("exporter", EXPORTER_NAME).put("success", true).build();
private static final Attributes EXPORT_FAILURE_LABELS =
Attributes.builder().put("exporter", EXPORTER_NAME).put("success", false).build();
private static final MediaType PROTOBUF_MEDIA_TYPE = MediaType.parse("application/x-protobuf");
@ -63,10 +64,9 @@ public final class OtlpHttpSpanExporter implements SpanExporter {
OtlpHttpSpanExporter(
OkHttpClient client, String endpoint, Headers headers, boolean isCompressionEnabled) {
Meter meter = GlobalMeterProvider.getMeter("io.opentelemetry.exporters.otlp-http");
this.spansSeen =
meter.longCounterBuilder("spansSeenByExporter").build().bind(EXPORTER_NAME_LABELS);
LongCounter spansExportedCounter = meter.longCounterBuilder("spansExportedByExporter").build();
Meter meter = GlobalMeterProvider.get().get("io.opentelemetry.exporters.otlp-http");
this.spansSeen = meter.counterBuilder("spansSeenByExporter").build().bind(EXPORTER_NAME_LABELS);
LongCounter spansExportedCounter = meter.counterBuilder("spansExportedByExporter").build();
this.spansExportedSuccess = spansExportedCounter.bind(EXPORT_SUCCESS_LABELS);
this.spansExportedFailure = spansExportedCounter.bind(EXPORT_FAILURE_LABELS);

View File

@ -11,11 +11,12 @@ import com.google.common.util.concurrent.MoreExecutors;
import io.grpc.ConnectivityState;
import io.grpc.ManagedChannel;
import io.grpc.Status;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.BoundLongCounter;
import io.opentelemetry.api.metrics.GlobalMeterProvider;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.exporter.otlp.internal.SpanAdapter;
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse;
@ -35,13 +36,15 @@ import javax.annotation.concurrent.ThreadSafe;
/** Exports spans using OTLP via gRPC, using OpenTelemetry's protobuf model. */
@ThreadSafe
public final class OtlpGrpcSpanExporter implements SpanExporter {
private static final AttributeKey<String> EXPORTER_KEY = AttributeKey.stringKey("exporter");
private static final AttributeKey<String> SUCCESS_KEY = AttributeKey.stringKey("success");
private static final String EXPORTER_NAME = OtlpGrpcSpanExporter.class.getSimpleName();
private static final Labels EXPORTER_NAME_LABELS = Labels.of("exporter", EXPORTER_NAME);
private static final Labels EXPORT_SUCCESS_LABELS =
Labels.of("exporter", EXPORTER_NAME, "success", "true");
private static final Labels EXPORT_FAILURE_LABELS =
Labels.of("exporter", EXPORTER_NAME, "success", "false");
private static final Attributes EXPORTER_NAME_Attributes =
Attributes.of(EXPORTER_KEY, EXPORTER_NAME);
private static final Attributes EXPORT_SUCCESS_ATTRIBUTES =
Attributes.of(EXPORTER_KEY, EXPORTER_NAME, SUCCESS_KEY, "true");
private static final Attributes EXPORT_FAILURE_ATTRIBUTES =
Attributes.of(EXPORTER_KEY, EXPORTER_NAME, SUCCESS_KEY, "false");
private final ThrottlingLogger logger =
new ThrottlingLogger(Logger.getLogger(OtlpGrpcSpanExporter.class.getName()));
@ -62,12 +65,13 @@ public final class OtlpGrpcSpanExporter implements SpanExporter {
* 0 or to a negative value, the exporter will wait indefinitely.
*/
OtlpGrpcSpanExporter(ManagedChannel channel, long timeoutNanos) {
Meter meter = GlobalMeterProvider.getMeter("io.opentelemetry.exporters.otlp");
// TODO: telemetry schema version.
Meter meter = GlobalMeterProvider.get().meterBuilder("io.opentelemetry.exporters.otlp").build();
this.spansSeen =
meter.longCounterBuilder("spansSeenByExporter").build().bind(EXPORTER_NAME_LABELS);
LongCounter spansExportedCounter = meter.longCounterBuilder("spansExportedByExporter").build();
this.spansExportedSuccess = spansExportedCounter.bind(EXPORT_SUCCESS_LABELS);
this.spansExportedFailure = spansExportedCounter.bind(EXPORT_FAILURE_LABELS);
meter.counterBuilder("spansSeenByExporter").build().bind(EXPORTER_NAME_Attributes);
LongCounter spansExportedCounter = meter.counterBuilder("spansExportedByExporter").build();
this.spansExportedSuccess = spansExportedCounter.bind(EXPORT_SUCCESS_ATTRIBUTES);
this.spansExportedFailure = spansExportedCounter.bind(EXPORT_FAILURE_ATTRIBUTES);
this.managedChannel = channel;
this.timeoutNanos = timeoutNanos;

View File

@ -9,8 +9,8 @@ import static org.assertj.core.api.Assertions.assertThat;
import com.linecorp.armeria.client.WebClient;
import com.linecorp.armeria.common.AggregatedHttpResponse;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.GlobalMeterProvider;
import io.opentelemetry.api.metrics.common.Labels;
import java.io.IOException;
import java.net.ServerSocket;
import org.junit.jupiter.api.Test;
@ -37,9 +37,9 @@ class PrometheusTest {
GlobalMeterProvider.get()
.get("test")
.longValueObserverBuilder("test")
.setUpdater(result -> result.observe(2, Labels.empty()))
.build();
.gaugeBuilder("test")
.ofLongs()
.buildWithCallback(result -> result.observe(2, Attributes.empty()));
WebClient client = WebClient.of("http://127.0.0.1:" + port);
AggregatedHttpResponse response = client.get("/metrics").aggregate().join();

View File

@ -5,11 +5,12 @@
package io.opentelemetry.sdk.logging.export;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.BoundLongCounter;
import io.opentelemetry.api.metrics.GlobalMeterProvider;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.internal.DaemonThreadFactory;
import io.opentelemetry.sdk.logging.LogProcessor;
@ -66,19 +67,23 @@ public final class BatchLogProcessor implements LogProcessor {
private static class Worker implements Runnable {
static {
Meter meter = GlobalMeterProvider.getMeter("io.opentelemetry.sdk.logging");
// TODO: As of Specification 1.4, this should have a telemetry schema version.
Meter meter = GlobalMeterProvider.get().meterBuilder("io.opentelemetry.sdk.trace").build();
LongCounter logRecordsProcessed =
meter
.longCounterBuilder("logRecordsProcessed")
.counterBuilder("logRecordsProcessed")
.setUnit("1")
.setDescription("Number of records processed")
.build();
successCounter = logRecordsProcessed.bind(Labels.of("result", "success"));
AttributeKey<String> resultKey = AttributeKey.stringKey("result");
AttributeKey<String> causeKey = AttributeKey.stringKey("cause");
successCounter = logRecordsProcessed.bind(Attributes.of(resultKey, "success"));
exporterFailureCounter =
logRecordsProcessed.bind(
Labels.of("result", "dropped record", "cause", "exporter failure"));
Attributes.of(resultKey, "dropped record", causeKey, "exporter failure"));
queueFullRecordCounter =
logRecordsProcessed.bind(Labels.of("result", "dropped record", "cause", "queue full"));
logRecordsProcessed.bind(
Attributes.of(resultKey, "dropped record", causeKey, "queue full"));
}
private static final BoundLongCounter exporterFailureCounter;

View File

@ -7,6 +7,7 @@ package io.opentelemetry.sdk.extension.incubator.trace;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.export.MetricProducer;
import io.opentelemetry.sdk.trace.ReadableSpan;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.SpanExporter;
@ -37,7 +38,7 @@ public class ExecutorServiceSpanProcessorCpuBenchmark {
@State(Scope.Benchmark)
public static class BenchmarkState {
private SdkMeterProvider sdkMeterProvider;
private MetricProducer collector;
private ExecutorServiceSpanProcessor processor;
private Tracer tracer;
private int numThreads = 1;
@ -50,7 +51,9 @@ public class ExecutorServiceSpanProcessorCpuBenchmark {
@Setup(Level.Iteration)
public final void setup() {
sdkMeterProvider = SdkMeterProvider.builder().buildAndRegisterGlobal();
final SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder().buildAndRegisterGlobal();
// Note: these will (likely) no longer be the same in future SDK.
collector = sdkMeterProvider;
SpanExporter exporter = new DelayingSpanExporter(delayMs);
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
processor = ExecutorServiceSpanProcessor.builder(exporter, executor, true).build();
@ -61,7 +64,7 @@ public class ExecutorServiceSpanProcessorCpuBenchmark {
@TearDown(Level.Iteration)
public final void recordMetrics() {
BatchSpanProcessorMetrics metrics =
new BatchSpanProcessorMetrics(sdkMeterProvider.collectAllMetrics(), numThreads);
new BatchSpanProcessorMetrics(collector.collectAllMetrics(), numThreads);
exportedSpans = metrics.exportedSpans();
droppedSpans = metrics.droppedSpans();
}

View File

@ -7,6 +7,7 @@ package io.opentelemetry.sdk.extension.incubator.trace;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.export.MetricProducer;
import io.opentelemetry.sdk.trace.ReadableSpan;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.SpanExporter;
@ -30,7 +31,7 @@ public class ExecutorServiceSpanProcessorDroppedSpansBenchmark {
@State(Scope.Benchmark)
public static class BenchmarkState {
private SdkMeterProvider sdkMeterProvider;
private MetricProducer collector;
private ExecutorServiceSpanProcessor processor;
private Tracer tracer;
private double dropRatio;
@ -40,7 +41,9 @@ public class ExecutorServiceSpanProcessorDroppedSpansBenchmark {
@Setup(Level.Iteration)
public final void setup() {
sdkMeterProvider = SdkMeterProvider.builder().buildAndRegisterGlobal();
final SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder().buildAndRegisterGlobal();
// Note: these will (likely) no longer be the same in future SDK.
collector = sdkMeterProvider;
SpanExporter exporter = new DelayingSpanExporter(0);
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
processor = ExecutorServiceSpanProcessor.builder(exporter, executor, true).build();
@ -51,7 +54,7 @@ public class ExecutorServiceSpanProcessorDroppedSpansBenchmark {
@TearDown(Level.Iteration)
public final void recordMetrics() {
BatchSpanProcessorMetrics metrics =
new BatchSpanProcessorMetrics(sdkMeterProvider.collectAllMetrics(), numThreads);
new BatchSpanProcessorMetrics(collector.collectAllMetrics(), numThreads);
dropRatio = metrics.dropRatio();
exportedSpans = metrics.exportedSpans();
droppedSpans = metrics.droppedSpans();

View File

@ -7,6 +7,7 @@ package io.opentelemetry.sdk.extension.incubator.trace;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.export.MetricProducer;
import io.opentelemetry.sdk.trace.ReadableSpan;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.SpanExporter;
@ -34,7 +35,7 @@ public class ExecutorServiceSpanProcessorMultiThreadBenchmark {
@State(Scope.Benchmark)
public static class BenchmarkState {
private SdkMeterProvider sdkMeterProvider;
private MetricProducer collector;
private ExecutorServiceSpanProcessor processor;
private Tracer tracer;
private int numThreads = 1;
@ -47,7 +48,9 @@ public class ExecutorServiceSpanProcessorMultiThreadBenchmark {
@Setup(Level.Iteration)
public final void setup() {
sdkMeterProvider = SdkMeterProvider.builder().buildAndRegisterGlobal();
final SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder().buildAndRegisterGlobal();
// Note: these will (likely) no longer be the same in future SDK.
collector = sdkMeterProvider;
SpanExporter exporter = new DelayingSpanExporter(delayMs);
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
processor = ExecutorServiceSpanProcessor.builder(exporter, executor, true).build();
@ -58,7 +61,7 @@ public class ExecutorServiceSpanProcessorMultiThreadBenchmark {
@TearDown(Level.Iteration)
public final void recordMetrics() {
BatchSpanProcessorMetrics metrics =
new BatchSpanProcessorMetrics(sdkMeterProvider.collectAllMetrics(), numThreads);
new BatchSpanProcessorMetrics(collector.collectAllMetrics(), numThreads);
exportedSpans = metrics.exportedSpans();
droppedSpans = metrics.droppedSpans();
}

View File

@ -5,11 +5,12 @@
package io.opentelemetry.sdk.extension.incubator.trace;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.BoundLongCounter;
import io.opentelemetry.api.metrics.GlobalMeterProvider;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.common.Labels;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.ReadWriteSpan;
@ -35,15 +36,17 @@ import org.jctools.queues.MpscArrayQueue;
@SuppressWarnings("FutureReturnValueIgnored")
public final class ExecutorServiceSpanProcessor implements SpanProcessor {
private static final String SPAN_PROCESSOR_TYPE_LABEL = "spanProcessorType";
private static final AttributeKey<String> SPAN_PROCESSOR_TYPE_KEY =
AttributeKey.stringKey("spanProcessorType");
private static final AttributeKey<Boolean> DROPPED_KEY = AttributeKey.booleanKey("dropped");
private static final String SPAN_PROCESSOR_TYPE_VALUE =
ExecutorServiceSpanProcessor.class.getSimpleName();
private static final Labels SPAN_PROCESSOR_LABELS =
Labels.of(SPAN_PROCESSOR_TYPE_LABEL, SPAN_PROCESSOR_TYPE_VALUE);
private static final Labels SPAN_PROCESSOR_DROPPED_LABELS =
Labels.of(SPAN_PROCESSOR_TYPE_LABEL, SPAN_PROCESSOR_TYPE_VALUE, "dropped", "true");
private static final Labels SPAN_PROCESSOR_EXPORTED_LABELS =
Labels.of(SPAN_PROCESSOR_TYPE_LABEL, SPAN_PROCESSOR_TYPE_VALUE, "dropped", "false");
private static final Attributes SPAN_PROCESSOR_LABELS =
Attributes.of(SPAN_PROCESSOR_TYPE_KEY, SPAN_PROCESSOR_TYPE_VALUE);
private static final Attributes SPAN_PROCESSOR_DROPPED_LABELS =
Attributes.of(SPAN_PROCESSOR_TYPE_KEY, SPAN_PROCESSOR_TYPE_VALUE, DROPPED_KEY, true);
private static final Attributes SPAN_PROCESSOR_EXPORTED_LABELS =
Attributes.of(SPAN_PROCESSOR_TYPE_KEY, SPAN_PROCESSOR_TYPE_VALUE, DROPPED_KEY, false);
private final Worker worker;
private final AtomicBoolean isShutdown = new AtomicBoolean(false);
@ -163,16 +166,17 @@ public final class ExecutorServiceSpanProcessor implements SpanProcessor {
ScheduledExecutorService executorService,
AtomicBoolean isShutdown,
long workerScheduleIntervalNanos) {
Meter meter = GlobalMeterProvider.getMeter("io.opentelemetry.sdk.trace");
// TODO: As of Specification 1.4, this should have a telemetry schema version.
Meter meter = GlobalMeterProvider.get().meterBuilder("io.opentelemetry.sdk.trace").build();
meter
.longValueObserverBuilder("queueSize")
.gaugeBuilder("queueSize")
.ofLongs()
.setDescription("The number of spans queued")
.setUnit("1")
.setUpdater(result -> result.observe(queue.size(), SPAN_PROCESSOR_LABELS))
.build();
.buildWithCallback(result -> result.observe(queue.size(), SPAN_PROCESSOR_LABELS));
LongCounter processedSpansCounter =
meter
.longCounterBuilder("processedSpans")
.counterBuilder("processedSpans")
.setUnit("1")
.setDescription(
"The number of spans processed by the BatchSpanProcessor. "

View File

@ -0,0 +1,29 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.testing.assertj.metrics;
import io.opentelemetry.sdk.metrics.data.DoubleSummaryData;
import io.opentelemetry.sdk.metrics.data.DoubleSummaryPointData;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractIterableAssert;
import org.assertj.core.api.Assertions;
/** Assert on a {@link DoubleSummaryData} metric. */
public class DoubleSummaryDataAssert
extends AbstractAssert<DoubleSummaryDataAssert, DoubleSummaryData> {
protected DoubleSummaryDataAssert(DoubleSummaryData actual) {
super(actual, DoubleSummaryDataAssert.class);
}
/** Returns convenience API to assert against the {@code points} field. */
public AbstractIterableAssert<
?, ? extends Iterable<? extends DoubleSummaryPointData>, DoubleSummaryPointData, ?>
points() {
isNotNull();
return Assertions.assertThat(actual.getPoints());
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.testing.assertj.metrics;
import io.opentelemetry.sdk.metrics.data.DoubleSummaryPointData;
import io.opentelemetry.sdk.metrics.data.ValueAtPercentile;
import org.assertj.core.api.Assertions;
/** Asserts for (deprecated) Summary points. */
public class DoubleSummaryPointDataAssert
extends AbstractPointDataAssert<DoubleSummaryPointDataAssert, DoubleSummaryPointData> {
protected DoubleSummaryPointDataAssert(DoubleSummaryPointData actual) {
super(actual, DoubleSummaryPointDataAssert.class);
}
/** Ensure the summary has seen the expected count of measurements. */
public DoubleSummaryPointDataAssert hasCount(long expected) {
isNotNull();
Assertions.assertThat(actual.getCount()).as("count").isEqualTo(expected);
return this;
}
/** Ensure the summary has the expected sum across all observed measurements. */
public DoubleSummaryPointDataAssert hasSum(double expected) {
isNotNull();
Assertions.assertThat(actual.getSum()).as("sum").isEqualTo(expected);
return this;
}
/** Ensure the summary has exactly, in any order, the given percentile values. */
public DoubleSummaryPointDataAssert hasPercentileValues(ValueAtPercentile... percentiles) {
isNotNull();
Assertions.assertThat(actual.getPercentileValues()).containsExactlyInAnyOrder(percentiles);
return this;
}
}

View File

@ -10,6 +10,8 @@ import io.opentelemetry.sdk.metrics.data.DoubleHistogramData;
import io.opentelemetry.sdk.metrics.data.DoubleHistogramPointData;
import io.opentelemetry.sdk.metrics.data.DoublePointData;
import io.opentelemetry.sdk.metrics.data.DoubleSumData;
import io.opentelemetry.sdk.metrics.data.DoubleSummaryData;
import io.opentelemetry.sdk.metrics.data.DoubleSummaryPointData;
import io.opentelemetry.sdk.metrics.data.LongGaugeData;
import io.opentelemetry.sdk.metrics.data.LongPointData;
import io.opentelemetry.sdk.metrics.data.LongSumData;
@ -33,11 +35,21 @@ public final class MetricAssertions extends Assertions {
return new DoubleHistogramAssert(metric);
}
/** Returns an assertion for {@link DoubleSummaryData}. */
public static DoubleSummaryDataAssert assertThat(DoubleSummaryData metric) {
return new DoubleSummaryDataAssert(metric);
}
/** Returns an assertion for {@link DoubleHistogramPointData}. */
public static DoubleHistogramPointDataAssert assertThat(DoubleHistogramPointData point) {
return new DoubleHistogramPointDataAssert(point);
}
/** Returns an assertion for {@link DoubleSummaryPointData}. */
public static DoubleSummaryPointDataAssert assertThat(DoubleSummaryPointData point) {
return new DoubleSummaryPointDataAssert(point);
}
/** Returns an assertion for {@link DoublePointData}. */
public static DoublePointDataAssert assertThat(DoublePointData point) {
return new DoublePointDataAssert(point);

View File

@ -180,4 +180,22 @@ public class MetricDataAssert extends AbstractAssert<MetricDataAssert, MetricDat
}
return new LongSumDataAssert(actual.getLongSumData());
}
/**
* Ensures this {@link MetricData} is a {@code DoubleSummaryData}.
*
* @return convenience API to assert against the {@code DoubleSummaryData}.
*/
public DoubleSummaryDataAssert hasDoubleSummary() {
isNotNull();
if (actual.getType() != MetricDataType.SUMMARY) {
failWithActualExpectedAndMessage(
actual,
"type: SUMMARY",
"Exepcted MetricData to have type <%s> but found <%s>",
MetricDataType.SUMMARY,
actual.getType());
}
return new DoubleSummaryDataAssert(actual.getDoubleSummaryData());
}
}

View File

@ -17,11 +17,14 @@ import io.opentelemetry.sdk.metrics.data.DoubleGaugeData;
import io.opentelemetry.sdk.metrics.data.DoubleHistogramData;
import io.opentelemetry.sdk.metrics.data.DoublePointData;
import io.opentelemetry.sdk.metrics.data.DoubleSumData;
import io.opentelemetry.sdk.metrics.data.DoubleSummaryData;
import io.opentelemetry.sdk.metrics.data.DoubleSummaryPointData;
import io.opentelemetry.sdk.metrics.data.LongExemplar;
import io.opentelemetry.sdk.metrics.data.LongGaugeData;
import io.opentelemetry.sdk.metrics.data.LongPointData;
import io.opentelemetry.sdk.metrics.data.LongSumData;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.metrics.data.ValueAtPercentile;
import io.opentelemetry.sdk.resources.Resource;
import java.util.Collections;
import org.junit.jupiter.api.Test;
@ -55,6 +58,17 @@ public class MetricAssertionsTest {
// Points
Collections.emptyList()));
private static final MetricData DOUBLE_SUMMARY_METRIC =
MetricData.createDoubleSummary(
RESOURCE,
INSTRUMENTATION_LIBRARY_INFO,
/* name= */ "summary",
/* description= */ "description",
/* unit= */ "unit",
DoubleSummaryData.create(
// Points
Collections.emptyList()));
private static final MetricData DOUBLE_GAUGE_METRIC =
MetricData.createDoubleGauge(
RESOURCE,
@ -148,6 +162,12 @@ public class MetricAssertionsTest {
private static final LongPointData LONG_POINT_DATA_WITH_EXEMPLAR =
LongPointData.create(1, 2, Attributes.empty(), 3, Collections.singletonList(LONG_EXEMPLAR));
private static final ValueAtPercentile PERCENTILE_VALUE = ValueAtPercentile.create(0, 1);
private static final DoubleSummaryPointData DOUBLE_SUMMARY_POINT_DATA =
DoubleSummaryPointData.create(
1, 2, Attributes.empty(), 1, 2, Collections.singletonList(PERCENTILE_VALUE));
@Test
void metric_passing() {
assertThat(HISTOGRAM_METRIC)
@ -197,6 +217,17 @@ public class MetricAssertionsTest {
.isInstanceOf(AssertionError.class);
}
@Test
void summary_passing() {
assertThat(DOUBLE_SUMMARY_METRIC).hasDoubleSummary();
}
@Test
void sumamry_failing() {
assertThatThrownBy(() -> assertThat(DOUBLE_GAUGE_METRIC).hasDoubleSummary())
.isInstanceOf(AssertionError.class);
}
@Test
void doubleGauge_passing() {
assertThat(DOUBLE_GAUGE_METRIC).hasDoubleGauge();
@ -335,4 +366,30 @@ public class MetricAssertionsTest {
assertThatThrownBy(() -> assertThat(HISTOGRAM_DELTA_METRIC).hasLongGauge())
.isInstanceOf(AssertionError.class);
}
@Test
void doubleSummaryPointData_passing() {
assertThat(DOUBLE_SUMMARY_POINT_DATA)
.hasCount(1)
.hasSum(2)
.hasEpochNanos(2)
.hasStartEpochNanos(1)
.hasAttributes(Attributes.empty())
.hasPercentileValues(PERCENTILE_VALUE);
}
@Test
void doubleSummaryPointData_failing() {
assertThatThrownBy(() -> assertThat(DOUBLE_SUMMARY_POINT_DATA).hasCount(2))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(() -> assertThat(DOUBLE_SUMMARY_POINT_DATA).hasSum(1))
.isInstanceOf(AssertionError.class);
assertThatThrownBy(
() ->
assertThat(DOUBLE_SUMMARY_POINT_DATA)
.hasPercentileValues(ValueAtPercentile.create(1, 1)))
.isInstanceOf(AssertionError.class);
}
}

15
sdk/metrics/README.md Normal file
View File

@ -0,0 +1,15 @@
# OpenTelemetry Metrics SDK
The code in this directory is currently the legacy impelmentation of the previous experimental metrics SDK specification.
The following set of known issues will be fixed aas the new SDK specification stabilizes:
- The names of SDK insturments do not line up with API instruments.
- Baggage / Context are not available to metrics / views.
- The View API still uses the term LabelsProcessor.
- Only one exporter is allowed.
- Histograms are generating summaries.
- Exemplars are not sampled
- The set of Aggregators goes well beyond the expected "stable" list and (likely) will have some moved to extensions.
- There is no exposed `MetricProcessor` interface.

View File

@ -5,8 +5,8 @@
package io.opentelemetry.sdk.metrics;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.common.Labels;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
@ -37,14 +37,15 @@ public class MetricsBenchmarks {
@Param MetricsTestOperationBuilder opBuilder;
MetricsTestOperationBuilder.Operation op;
final Labels sharedLabelSet = Labels.of("KEY", "VALUE");
Labels threadUniqueLabelSet;
final Attributes sharedLabelSet = Attributes.builder().put("KEY", "VALUE").build();
Attributes threadUniqueLabelSet;
@Setup
public void setup(ThreadParams threadParams) {
Meter meter = sdk.getMeter();
op = opBuilder.build(meter);
threadUniqueLabelSet = Labels.of("KEY", String.valueOf(threadParams.getThreadIndex()));
threadUniqueLabelSet =
Attributes.builder().put("KEY", String.valueOf(threadParams.getThreadIndex())).build();
}
}

View File

@ -5,16 +5,16 @@
package io.opentelemetry.sdk.metrics;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.BoundDoubleCounter;
import io.opentelemetry.api.metrics.BoundDoubleValueRecorder;
import io.opentelemetry.api.metrics.BoundDoubleHistogram;
import io.opentelemetry.api.metrics.BoundLongCounter;
import io.opentelemetry.api.metrics.BoundLongValueRecorder;
import io.opentelemetry.api.metrics.BoundLongHistogram;
import io.opentelemetry.api.metrics.DoubleCounter;
import io.opentelemetry.api.metrics.DoubleValueRecorder;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.LongCounter;
import io.opentelemetry.api.metrics.LongValueRecorder;
import io.opentelemetry.api.metrics.LongHistogram;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.common.Labels;
/**
* This enum allows for iteration over all of the operations that we want to benchmark. To ensure
@ -27,15 +27,15 @@ public enum MetricsTestOperationBuilder {
LongCounterAdd(
meter -> {
return new Operation() {
final LongCounter metric = meter.longCounterBuilder("long_counter").build();
final LongCounter metric = meter.counterBuilder("long_counter").build();
final BoundLongCounter boundMetric =
meter
.longCounterBuilder("bound_long_counter")
.counterBuilder("bound_long_counter")
.build()
.bind(Labels.of("KEY", "VALUE"));
.bind(Attributes.builder().put("KEY", "VALUE").build());
@Override
public void perform(Labels labels) {
public void perform(Attributes labels) {
metric.add(5L, labels);
}
@ -48,15 +48,16 @@ public enum MetricsTestOperationBuilder {
DoubleCounterAdd(
meter -> {
return new Operation() {
final DoubleCounter metric = meter.doubleCounterBuilder("double_counter").build();
final DoubleCounter metric = meter.counterBuilder("double_counter").ofDoubles().build();
final BoundDoubleCounter boundMetric =
meter
.doubleCounterBuilder("bound_double_counter")
.counterBuilder("bound_double_counter")
.ofDoubles()
.build()
.bind(Labels.of("KEY", "VALUE"));
.bind(Attributes.builder().put("KEY", "VALUE").build());
@Override
public void perform(Labels labels) {
public void perform(Attributes labels) {
metric.add(5.0d, labels);
}
@ -66,19 +67,19 @@ public enum MetricsTestOperationBuilder {
}
};
}),
DoubleValueRecorderRecord(
DoubleHistogramRecord(
meter -> {
return new Operation() {
final DoubleValueRecorder metric =
meter.doubleValueRecorderBuilder("double_value_recorder").build();
final BoundDoubleValueRecorder boundMetric =
final DoubleHistogram metric =
meter.histogramBuilder("double_histogram_recorder").build();
final BoundDoubleHistogram boundMetric =
meter
.doubleValueRecorderBuilder("bound_double_value_recorder")
.histogramBuilder("bound_double_histogram_recorder")
.build()
.bind(Labels.of("KEY", "VALUE"));
.bind(Attributes.builder().put("KEY", "VALUE").build());
@Override
public void perform(Labels labels) {
public void perform(Attributes labels) {
metric.record(5.0d, labels);
}
@ -88,41 +89,20 @@ public enum MetricsTestOperationBuilder {
}
};
}),
DoubleHistogramRecorderRecord(
LongHistogramRecord(
meter -> {
return new Operation() {
final DoubleValueRecorder metric =
meter.doubleValueRecorderBuilder("double_histogram_recorder").build();
final BoundDoubleValueRecorder boundMetric =
final LongHistogram metric =
meter.histogramBuilder("long_value_recorder").ofLongs().build();
final BoundLongHistogram boundMetric =
meter
.doubleValueRecorderBuilder("bound_double_histogram_recorder")
.histogramBuilder("bound_long_value_recorder")
.ofLongs()
.build()
.bind(Labels.of("KEY", "VALUE"));
.bind(Attributes.builder().put("KEY", "VALUE").build());
@Override
public void perform(Labels labels) {
metric.record(5.0d, labels);
}
@Override
public void performBound() {
boundMetric.record(5.0d);
}
};
}),
LongValueRecorderRecord(
meter -> {
return new Operation() {
final LongValueRecorder metric =
meter.longValueRecorderBuilder("long_value_recorder").build();
final BoundLongValueRecorder boundMetric =
meter
.longValueRecorderBuilder("bound_long_value_recorder")
.build()
.bind(Labels.of("KEY", "VALUE"));
@Override
public void perform(Labels labels) {
public void perform(Attributes labels) {
metric.record(5L, labels);
}
@ -148,7 +128,7 @@ public enum MetricsTestOperationBuilder {
}
interface Operation {
void perform(Labels labels);
void perform(Attributes labels);
void performBound();
}

Some files were not shown because too many files have changed in this diff Show More