Drop micrometer shim (#4735)

* Drop micrometer shim

* Remove remnants of micrometer-shim
This commit is contained in:
jack-berg 2022-09-08 11:39:06 -05:00 committed by GitHub
parent c3a9f68ec8
commit 1046253f3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 0 additions and 3570 deletions

View File

@ -47,7 +47,6 @@ This project contains the following top level components:
* [sdk-extensions](sdk-extensions/) defines additional SDK extensions, which are not part of the core SDK.
* [OpenTracing shim](opentracing-shim/) defines a bridge layer from OpenTracing to the OpenTelemetry API.
* [OpenCensus shim](opencensus-shim/) defines a bridge layer from OpenCensus to the OpenTelemetry API.
* [Micrometer shim](micrometer1-shim/) defines a bridge layer from Micrometer to the OpenTelemetry API.
This project publishes a lot of artifacts, listed in [releases](#releases).
[`opentelemetry-bom`](https://mvnrepository.com/artifact/io.opentelemetry/opentelemetry-bom) (BOM =
@ -280,7 +279,6 @@ dependency as follows, replacing `{{artifact-id}}` with the value from the "Arti
| Component | Description | Artifact ID | Version |
|----------------------------------------|--------------------------------------------------------------|----------------------------------|-------------------------------------------------------------|
| [Micrometer Shim](./micrometer1-shim) | Bridge micrometer metrics into the OpenTelemetry metrics API | `opentelemetry-micrometer1-shim` | <!--VERSION_UNSTABLE-->1.17.0-alpha<!--/VERSION_UNSTABLE--> |
| [OpenCensus Shim](./opencensus-shim) | Bridge opencensus metrics into the OpenTelemetry metrics SDK | `opentelemetry-opencensus-shim` | <!--VERSION_UNSTABLE-->1.17.0-alpha<!--/VERSION_UNSTABLE--> |
| [OpenTracing Shim](./opentracing-shim) | Bridge opentracing spans into the OpenTelemetry trace API | `opentelemetry-opentracing-shim` | <!--VERSION_UNSTABLE-->1.17.0-alpha<!--/VERSION_UNSTABLE--> |

View File

@ -18,7 +18,6 @@ val DEPENDENCY_BOMS = listOf(
"com.linecorp.armeria:armeria-bom:1.18.0",
"com.squareup.okhttp3:okhttp-bom:4.10.0",
"io.grpc:grpc-bom:1.49.0",
"io.micrometer:micrometer-bom:1.9.3",
"io.zipkin.brave:brave-bom:5.13.11",
"io.zipkin.reporter2:zipkin-reporter-bom:2.16.3",
"org.junit:junit-bom:5.9.0",

View File

@ -1,51 +0,0 @@
plugins {
id("otel.java-conventions")
id("otel.publish-conventions")
}
description = "OpenTelemetry Micrometer Bridge"
otelJava.moduleName.set("io.opentelemetry.micrometer1shim")
dependencies {
api(project(":api:all"))
api("io.micrometer:micrometer-core")
testImplementation(project(":sdk:testing"))
}
testing {
suites {
// Test older LTS versions
val testMicrometer15 by registering(JvmTestSuite::class) {
sources {
java {
setSrcDirs(listOf("src/test/java"))
}
}
dependencies {
implementation(project(":sdk:testing"))
implementation(project.dependencies.enforcedPlatform("io.micrometer:micrometer-bom:1.5.17"))
}
}
val testMicrometer16 by registering(JvmTestSuite::class) {
sources {
java {
setSrcDirs(listOf("src/test/java"))
}
}
dependencies {
implementation(project(":sdk:testing"))
implementation(project.dependencies.enforcedPlatform("io.micrometer:micrometer-bom:1.6.13"))
}
}
}
}
tasks {
check {
dependsOn(testing.suites)
}
}

View File

@ -1 +0,0 @@
otel.release=alpha

View File

@ -1,63 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.Statistic;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.config.NamingConvention;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
final class Bridging {
private static final ConcurrentMap<String, String> descriptionsCache = new ConcurrentHashMap<>();
static Attributes tagsAsAttributes(Meter.Id id, NamingConvention namingConvention) {
Iterable<Tag> tags = id.getTagsAsIterable();
if (!tags.iterator().hasNext()) {
return Attributes.empty();
}
AttributesBuilder builder = Attributes.builder();
for (Tag tag : tags) {
String tagKey = namingConvention.tagKey(tag.getKey());
String tagValue = namingConvention.tagValue(tag.getValue());
builder.put(tagKey, tagValue);
}
return builder.build();
}
static String name(Meter.Id id, NamingConvention namingConvention) {
return namingConvention.name(id.getName(), id.getType(), id.getBaseUnit());
}
static String description(Meter.Id id) {
return descriptionsCache.computeIfAbsent(
id.getName(),
n -> {
String description = id.getDescription();
return description != null ? description : "";
});
}
static String baseUnit(Meter.Id id) {
String baseUnit = id.getBaseUnit();
return baseUnit == null ? "1" : baseUnit;
}
static String statisticInstrumentName(
Meter.Id id, Statistic statistic, NamingConvention namingConvention) {
String prefix = id.getName() + ".";
// use "total_time" instead of "total" to avoid clashing with Statistic.TOTAL
String statisticStr =
statistic == Statistic.TOTAL_TIME ? "total_time" : statistic.getTagValueRepresentation();
return namingConvention.name(prefix + statisticStr, id.getType(), id.getBaseUnit());
}
private Bridging() {}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
import java.lang.ref.WeakReference;
import java.util.function.Consumer;
import java.util.function.ToDoubleFunction;
import javax.annotation.Nullable;
final class DoubleMeasurementRecorder<T> implements Consumer<ObservableDoubleMeasurement> {
// using a weak reference here so that the existence of the micrometer Meter does not block the
// measured object from being GC'd; e.g. a Gauge (or any other async instrument) must not block
// garbage collection of the object that it measures
private final WeakReference<T> objWeakRef;
private final ToDoubleFunction<T> metricFunction;
private final Attributes attributes;
DoubleMeasurementRecorder(
@Nullable T obj, ToDoubleFunction<T> metricFunction, Attributes attributes) {
this.objWeakRef = new WeakReference<>(obj);
this.metricFunction = metricFunction;
this.attributes = attributes;
}
@Override
public void accept(ObservableDoubleMeasurement measurement) {
T obj = objWeakRef.get();
if (obj != null) {
measurement.record(metricFunction.applyAsDouble(obj), attributes);
}
}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
import java.lang.ref.WeakReference;
import java.util.function.Consumer;
import java.util.function.ToLongFunction;
import javax.annotation.Nullable;
final class LongMeasurementRecorder<T> implements Consumer<ObservableLongMeasurement> {
// using a weak reference here so that the existence of the micrometer Meter does not block the
// measured object from being GC'd; e.g. a Gauge (or any other async instrument) must not block
// garbage collection of the object that it measures
private final WeakReference<T> objWeakRef;
private final ToLongFunction<T> metricFunction;
private final Attributes attributes;
LongMeasurementRecorder(
@Nullable T obj, ToLongFunction<T> metricFunction, Attributes attributes) {
this.objWeakRef = new WeakReference<>(obj);
this.metricFunction = metricFunction;
this.attributes = attributes;
}
@Override
public void accept(ObservableLongMeasurement measurement) {
T obj = objWeakRef.get();
if (obj != null) {
measurement.record(metricFunction.applyAsLong(obj), attributes);
}
}
}

View File

@ -1,67 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.Bridging.baseUnit;
import static io.opentelemetry.micrometer1shim.Bridging.name;
import static io.opentelemetry.micrometer1shim.Bridging.tagsAsAttributes;
import io.micrometer.core.instrument.AbstractMeter;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Measurement;
import io.micrometer.core.instrument.config.NamingConvention;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleCounter;
import io.opentelemetry.api.metrics.Meter;
import java.util.Collections;
final class OpenTelemetryCounter extends AbstractMeter implements Counter, RemovableMeter {
// TODO: use bound instruments when they're available
private final DoubleCounter otelCounter;
private final Attributes attributes;
private volatile boolean removed = false;
OpenTelemetryCounter(Id id, NamingConvention namingConvention, Meter otelMeter) {
super(id);
this.attributes = tagsAsAttributes(id, namingConvention);
String conventionName = name(id, namingConvention);
this.otelCounter =
otelMeter
.counterBuilder(conventionName)
.setDescription(Bridging.description(id))
.setUnit(baseUnit(id))
.ofDoubles()
.build();
}
@Override
public void increment(double v) {
if (removed) {
return;
}
otelCounter.add(v, attributes);
}
@Override
public double count() {
UnsupportedReadLogger.logWarning();
return Double.NaN;
}
@Override
public Iterable<Measurement> measure() {
UnsupportedReadLogger.logWarning();
return Collections.emptyList();
}
@Override
public void onRemove() {
removed = true;
}
}

View File

@ -1,165 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.Bridging.baseUnit;
import static io.opentelemetry.micrometer1shim.Bridging.name;
import static io.opentelemetry.micrometer1shim.Bridging.tagsAsAttributes;
import io.micrometer.core.instrument.AbstractDistributionSummary;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.Measurement;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
import io.micrometer.core.instrument.distribution.NoopHistogram;
import io.micrometer.core.instrument.distribution.TimeWindowMax;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.ObservableDoubleGauge;
import java.util.Collections;
import java.util.concurrent.atomic.DoubleAdder;
import java.util.concurrent.atomic.LongAdder;
final class OpenTelemetryDistributionSummary extends AbstractDistributionSummary
implements RemovableMeter {
private final Measurements measurements;
private final TimeWindowMax max;
// TODO: use bound instruments when they're available
private final DoubleHistogram otelHistogram;
private final Attributes attributes;
private final ObservableDoubleGauge observableMax;
private volatile boolean removed = false;
OpenTelemetryDistributionSummary(
Id id,
NamingConvention namingConvention,
Clock clock,
DistributionStatisticConfig distributionStatisticConfig,
double scale,
Meter otelMeter) {
super(id, clock, distributionStatisticConfig, scale, false);
if (isUsingMicrometerHistograms()) {
measurements = new MicrometerHistogramMeasurements();
} else {
measurements = NoopMeasurements.INSTANCE;
}
max = new TimeWindowMax(clock, distributionStatisticConfig);
this.attributes = tagsAsAttributes(id, namingConvention);
String name = name(id, namingConvention);
this.otelHistogram =
otelMeter
.histogramBuilder(name)
.setDescription(Bridging.description(id))
.setUnit(baseUnit(id))
.build();
this.observableMax =
otelMeter
.gaugeBuilder(name + ".max")
.setDescription(Bridging.description(id))
.setUnit(baseUnit(id))
.buildWithCallback(
new DoubleMeasurementRecorder<>(max, TimeWindowMax::poll, attributes));
}
boolean isUsingMicrometerHistograms() {
return histogram != NoopHistogram.INSTANCE;
}
@Override
protected void recordNonNegative(double amount) {
if (!removed) {
otelHistogram.record(amount, attributes);
measurements.record(amount);
max.record(amount);
}
}
@Override
public long count() {
return measurements.count();
}
@Override
public double totalAmount() {
return measurements.totalAmount();
}
@Override
public double max() {
return max.poll();
}
@Override
public Iterable<Measurement> measure() {
UnsupportedReadLogger.logWarning();
return Collections.emptyList();
}
@Override
public void onRemove() {
removed = true;
observableMax.close();
}
private interface Measurements {
void record(double amount);
long count();
double totalAmount();
}
// if micrometer histograms are not being used then there's no need to keep any local state
// OpenTelemetry metrics bridge does not support reading measurements
enum NoopMeasurements implements Measurements {
INSTANCE;
@Override
public void record(double amount) {}
@Override
public long count() {
UnsupportedReadLogger.logWarning();
return 0;
}
@Override
public double totalAmount() {
UnsupportedReadLogger.logWarning();
return Double.NaN;
}
}
// calculate count and totalAmount value for the use of micrometer histograms
// kinda similar to how DropwizardDistributionSummary does that
private static final class MicrometerHistogramMeasurements implements Measurements {
private final LongAdder count = new LongAdder();
private final DoubleAdder totalAmount = new DoubleAdder();
@Override
public void record(double amount) {
count.increment();
totalAmount.add(amount);
}
@Override
public long count() {
return count.sum();
}
@Override
public double totalAmount() {
return totalAmount.sum();
}
}
}

View File

@ -1,62 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.Bridging.baseUnit;
import static io.opentelemetry.micrometer1shim.Bridging.name;
import static io.opentelemetry.micrometer1shim.Bridging.tagsAsAttributes;
import io.micrometer.core.instrument.AbstractMeter;
import io.micrometer.core.instrument.FunctionCounter;
import io.micrometer.core.instrument.Measurement;
import io.micrometer.core.instrument.config.NamingConvention;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.ObservableDoubleCounter;
import java.util.Collections;
import java.util.function.ToDoubleFunction;
final class OpenTelemetryFunctionCounter<T> extends AbstractMeter
implements FunctionCounter, RemovableMeter {
private final ObservableDoubleCounter observableCount;
OpenTelemetryFunctionCounter(
Id id,
NamingConvention namingConvention,
T obj,
ToDoubleFunction<T> countFunction,
Meter otelMeter) {
super(id);
String name = name(id, namingConvention);
observableCount =
otelMeter
.counterBuilder(name)
.ofDoubles()
.setDescription(Bridging.description(id))
.setUnit(baseUnit(id))
.buildWithCallback(
new DoubleMeasurementRecorder<>(
obj, countFunction, tagsAsAttributes(id, namingConvention)));
}
@Override
public double count() {
UnsupportedReadLogger.logWarning();
return Double.NaN;
}
@Override
public Iterable<Measurement> measure() {
UnsupportedReadLogger.logWarning();
return Collections.emptyList();
}
@Override
public void onRemove() {
observableCount.close();
}
}

View File

@ -1,101 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import io.micrometer.core.instrument.AbstractMeter;
import io.micrometer.core.instrument.FunctionTimer;
import io.micrometer.core.instrument.Measurement;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.instrument.util.TimeUtils;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.ObservableDoubleCounter;
import io.opentelemetry.api.metrics.ObservableLongCounter;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.function.ToDoubleFunction;
import java.util.function.ToLongFunction;
final class OpenTelemetryFunctionTimer<T> extends AbstractMeter
implements FunctionTimer, RemovableMeter {
private final TimeUnit baseTimeUnit;
private final ObservableLongCounter observableCount;
private final ObservableDoubleCounter observableTotalTime;
OpenTelemetryFunctionTimer(
Id id,
NamingConvention namingConvention,
T obj,
ToLongFunction<T> countFunction,
ToDoubleFunction<T> totalTimeFunction,
TimeUnit totalTimeFunctionUnit,
TimeUnit baseTimeUnit,
Meter otelMeter) {
super(id);
this.baseTimeUnit = baseTimeUnit;
String name = Bridging.name(id, namingConvention);
Attributes attributes = Bridging.tagsAsAttributes(id, namingConvention);
this.observableCount =
otelMeter
.counterBuilder(name + ".count")
.setDescription(Bridging.description(id))
.setUnit("1")
.buildWithCallback(new LongMeasurementRecorder<>(obj, countFunction, attributes));
this.observableTotalTime =
otelMeter
.counterBuilder(name + ".sum")
.ofDoubles()
.setDescription(Bridging.description(id))
.setUnit(TimeUnitHelper.getUnitString(baseTimeUnit))
.buildWithCallback(
new DoubleMeasurementRecorder<>(
obj,
val ->
TimeUtils.convert(
totalTimeFunction.applyAsDouble(val),
totalTimeFunctionUnit,
baseTimeUnit),
attributes));
}
@Override
public double count() {
UnsupportedReadLogger.logWarning();
return Double.NaN;
}
@Override
public double totalTime(TimeUnit unit) {
UnsupportedReadLogger.logWarning();
return Double.NaN;
}
@Override
public double mean(TimeUnit unit) {
UnsupportedReadLogger.logWarning();
return Double.NaN;
}
@Override
public TimeUnit baseTimeUnit() {
return baseTimeUnit;
}
@Override
public Iterable<Measurement> measure() {
UnsupportedReadLogger.logWarning();
return Collections.emptyList();
}
@Override
public void onRemove() {
observableCount.close();
observableTotalTime.close();
}
}

View File

@ -1,61 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.Bridging.baseUnit;
import static io.opentelemetry.micrometer1shim.Bridging.name;
import static io.opentelemetry.micrometer1shim.Bridging.tagsAsAttributes;
import io.micrometer.core.instrument.AbstractMeter;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.Measurement;
import io.micrometer.core.instrument.config.NamingConvention;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.ObservableDoubleGauge;
import java.util.Collections;
import java.util.function.ToDoubleFunction;
import javax.annotation.Nullable;
final class OpenTelemetryGauge<T> extends AbstractMeter implements Gauge, RemovableMeter {
private final ObservableDoubleGauge observableGauge;
OpenTelemetryGauge(
Id id,
NamingConvention namingConvention,
@Nullable T obj,
ToDoubleFunction<T> objMetric,
Meter otelMeter) {
super(id);
String name = name(id, namingConvention);
observableGauge =
otelMeter
.gaugeBuilder(name)
.setDescription(Bridging.description(id))
.setUnit(baseUnit(id))
.buildWithCallback(
new DoubleMeasurementRecorder<>(
obj, objMetric, tagsAsAttributes(id, namingConvention)));
}
@Override
public double value() {
UnsupportedReadLogger.logWarning();
return Double.NaN;
}
@Override
public Iterable<Measurement> measure() {
UnsupportedReadLogger.logWarning();
return Collections.emptyList();
}
@Override
public void onRemove() {
observableGauge.close();
}
}

View File

@ -1,77 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.Bridging.name;
import static io.opentelemetry.micrometer1shim.Bridging.tagsAsAttributes;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.Measurement;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
import io.micrometer.core.instrument.internal.DefaultLongTaskTimer;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.ObservableDoubleUpDownCounter;
import io.opentelemetry.api.metrics.ObservableLongUpDownCounter;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
final class OpenTelemetryLongTaskTimer extends DefaultLongTaskTimer implements RemovableMeter {
private final DistributionStatisticConfig distributionStatisticConfig;
private final ObservableLongUpDownCounter observableActiveTasks;
private final ObservableDoubleUpDownCounter observableDuration;
OpenTelemetryLongTaskTimer(
Id id,
NamingConvention namingConvention,
Clock clock,
TimeUnit baseTimeUnit,
DistributionStatisticConfig distributionStatisticConfig,
Meter otelMeter) {
super(id, clock, baseTimeUnit, distributionStatisticConfig, false);
this.distributionStatisticConfig = distributionStatisticConfig;
String name = name(id, namingConvention);
Attributes attributes = tagsAsAttributes(id, namingConvention);
this.observableActiveTasks =
otelMeter
.upDownCounterBuilder(name + ".active")
.setDescription(Bridging.description(id))
.setUnit("tasks")
.buildWithCallback(
new LongMeasurementRecorder<>(this, DefaultLongTaskTimer::activeTasks, attributes));
this.observableDuration =
otelMeter
.upDownCounterBuilder(name + ".duration")
.ofDoubles()
.setDescription(Bridging.description(id))
.setUnit(TimeUnitHelper.getUnitString(baseTimeUnit))
.buildWithCallback(
new DoubleMeasurementRecorder<>(
this, t -> t.duration(t.baseTimeUnit()), attributes));
}
@Override
public Iterable<Measurement> measure() {
UnsupportedReadLogger.logWarning();
return Collections.emptyList();
}
@Override
public void onRemove() {
observableActiveTasks.close();
observableDuration.close();
}
boolean isUsingMicrometerHistograms() {
return distributionStatisticConfig.isPublishingPercentiles()
|| distributionStatisticConfig.isPublishingHistogram();
}
}

View File

@ -1,98 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.Bridging.baseUnit;
import static io.opentelemetry.micrometer1shim.Bridging.statisticInstrumentName;
import static io.opentelemetry.micrometer1shim.Bridging.tagsAsAttributes;
import io.micrometer.core.instrument.AbstractMeter;
import io.micrometer.core.instrument.Measurement;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.config.NamingConvention;
import io.opentelemetry.api.common.Attributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
final class OpenTelemetryMeter extends AbstractMeter implements Meter, RemovableMeter {
private final List<AutoCloseable> observableInstruments;
OpenTelemetryMeter(
Id id,
NamingConvention namingConvention,
Iterable<Measurement> measurements,
io.opentelemetry.api.metrics.Meter otelMeter) {
super(id);
Attributes attributes = tagsAsAttributes(id, namingConvention);
List<AutoCloseable> observableInstruments = new ArrayList<>();
for (Measurement measurement : measurements) {
String name = statisticInstrumentName(id, measurement.getStatistic(), namingConvention);
String description = Bridging.description(id);
String baseUnit = baseUnit(id);
DoubleMeasurementRecorder<Measurement> callback =
new DoubleMeasurementRecorder<>(measurement, Measurement::getValue, attributes);
switch (measurement.getStatistic()) {
case TOTAL:
// fall through
case TOTAL_TIME:
case COUNT:
observableInstruments.add(
otelMeter
.counterBuilder(name)
.ofDoubles()
.setDescription(description)
.setUnit(baseUnit)
.buildWithCallback(callback));
break;
case ACTIVE_TASKS:
observableInstruments.add(
otelMeter
.upDownCounterBuilder(name)
.ofDoubles()
.setDescription(description)
.setUnit(baseUnit)
.buildWithCallback(callback));
break;
case DURATION:
// fall through
case MAX:
case VALUE:
case UNKNOWN:
observableInstruments.add(
otelMeter
.gaugeBuilder(name)
.setDescription(description)
.setUnit(baseUnit)
.buildWithCallback(callback));
break;
}
}
this.observableInstruments = observableInstruments;
}
@Override
public Iterable<Measurement> measure() {
UnsupportedReadLogger.logWarning();
return Collections.emptyList();
}
@Override
public void onRemove() {
try {
for (AutoCloseable observableInstrument : observableInstruments) {
observableInstrument.close();
}
} catch (Exception e) {
throw new IllegalStateException("SDK instruments should never throw on close()", e);
}
}
}

View File

@ -1,173 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.FunctionCounter;
import io.micrometer.core.instrument.FunctionTimer;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.LongTaskTimer;
import io.micrometer.core.instrument.Measurement;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
import io.micrometer.core.instrument.distribution.HistogramGauges;
import io.micrometer.core.instrument.distribution.pause.PauseDetector;
import io.opentelemetry.api.OpenTelemetry;
import java.util.concurrent.TimeUnit;
import java.util.function.ToDoubleFunction;
import java.util.function.ToLongFunction;
import javax.annotation.Nullable;
/**
* A {@link MeterRegistry} implementation that forwards all the captured metrics to the {@linkplain
* io.opentelemetry.api.metrics.Meter OpenTelemetry Meter} obtained from the passed {@link
* OpenTelemetry} instance.
*/
public final class OpenTelemetryMeterRegistry extends MeterRegistry {
/**
* Returns a new {@link OpenTelemetryMeterRegistry} configured with the given {@link
* OpenTelemetry}.
*/
public static MeterRegistry create(OpenTelemetry openTelemetry) {
return builder(openTelemetry).build();
}
/**
* Returns a new {@link OpenTelemetryMeterRegistryBuilder} configured with the given {@link
* OpenTelemetry}.
*/
public static OpenTelemetryMeterRegistryBuilder builder(OpenTelemetry openTelemetry) {
return new OpenTelemetryMeterRegistryBuilder(openTelemetry);
}
private final TimeUnit baseTimeUnit;
private final io.opentelemetry.api.metrics.Meter otelMeter;
OpenTelemetryMeterRegistry(
Clock clock,
TimeUnit baseTimeUnit,
NamingConvention namingConvention,
io.opentelemetry.api.metrics.Meter otelMeter) {
super(clock);
this.baseTimeUnit = baseTimeUnit;
this.otelMeter = otelMeter;
this.config()
.namingConvention(namingConvention)
.onMeterRemoved(OpenTelemetryMeterRegistry::onMeterRemoved);
}
@Override
protected <T> Gauge newGauge(Meter.Id id, @Nullable T obj, ToDoubleFunction<T> valueFunction) {
return new OpenTelemetryGauge<>(id, config().namingConvention(), obj, valueFunction, otelMeter);
}
@Override
protected Counter newCounter(Meter.Id id) {
return new OpenTelemetryCounter(id, config().namingConvention(), otelMeter);
}
@Override
protected LongTaskTimer newLongTaskTimer(
Meter.Id id, DistributionStatisticConfig distributionStatisticConfig) {
OpenTelemetryLongTaskTimer timer =
new OpenTelemetryLongTaskTimer(
id,
config().namingConvention(),
clock,
getBaseTimeUnit(),
distributionStatisticConfig,
otelMeter);
if (timer.isUsingMicrometerHistograms()) {
HistogramGauges.registerWithCommonFormat(timer, this);
}
return timer;
}
@Override
protected Timer newTimer(
Meter.Id id,
DistributionStatisticConfig distributionStatisticConfig,
PauseDetector pauseDetector) {
OpenTelemetryTimer timer =
new OpenTelemetryTimer(
id,
config().namingConvention(),
clock,
distributionStatisticConfig,
pauseDetector,
getBaseTimeUnit(),
otelMeter);
if (timer.isUsingMicrometerHistograms()) {
HistogramGauges.registerWithCommonFormat(timer, this);
}
return timer;
}
@Override
protected DistributionSummary newDistributionSummary(
Meter.Id id, DistributionStatisticConfig distributionStatisticConfig, double scale) {
OpenTelemetryDistributionSummary distributionSummary =
new OpenTelemetryDistributionSummary(
id, config().namingConvention(), clock, distributionStatisticConfig, scale, otelMeter);
if (distributionSummary.isUsingMicrometerHistograms()) {
HistogramGauges.registerWithCommonFormat(distributionSummary, this);
}
return distributionSummary;
}
@Override
protected Meter newMeter(Meter.Id id, Meter.Type type, Iterable<Measurement> measurements) {
return new OpenTelemetryMeter(id, config().namingConvention(), measurements, otelMeter);
}
@Override
protected <T> FunctionTimer newFunctionTimer(
Meter.Id id,
T obj,
ToLongFunction<T> countFunction,
ToDoubleFunction<T> totalTimeFunction,
TimeUnit totalTimeFunctionUnit) {
return new OpenTelemetryFunctionTimer<>(
id,
config().namingConvention(),
obj,
countFunction,
totalTimeFunction,
totalTimeFunctionUnit,
getBaseTimeUnit(),
otelMeter);
}
@Override
protected <T> FunctionCounter newFunctionCounter(
Meter.Id id, T obj, ToDoubleFunction<T> countFunction) {
return new OpenTelemetryFunctionCounter<>(
id, config().namingConvention(), obj, countFunction, otelMeter);
}
@Override
protected TimeUnit getBaseTimeUnit() {
return baseTimeUnit;
}
@Override
protected DistributionStatisticConfig defaultHistogramConfig() {
return DistributionStatisticConfig.DEFAULT;
}
private static void onMeterRemoved(Meter meter) {
if (meter instanceof RemovableMeter) {
((RemovableMeter) meter).onRemove();
}
}
}

View File

@ -1,69 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.config.NamingConvention;
import io.opentelemetry.api.OpenTelemetry;
import java.util.concurrent.TimeUnit;
/** A builder of {@link OpenTelemetryMeterRegistry}. */
public final class OpenTelemetryMeterRegistryBuilder {
// Visible for testing
static final String INSTRUMENTATION_NAME = "io.opentelemetry.micrometer1shim";
private final OpenTelemetry openTelemetry;
private Clock clock = Clock.SYSTEM;
private TimeUnit baseTimeUnit = TimeUnit.MILLISECONDS;
private boolean prometheusMode = false;
OpenTelemetryMeterRegistryBuilder(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
}
/** Sets a custom {@link Clock}. Useful for testing. */
public OpenTelemetryMeterRegistryBuilder setClock(Clock clock) {
this.clock = clock;
return this;
}
/** Sets the base time unit. */
public OpenTelemetryMeterRegistryBuilder setBaseTimeUnit(TimeUnit baseTimeUnit) {
this.baseTimeUnit = baseTimeUnit;
return this;
}
/**
* Enables the "Prometheus mode" - this will simulate the behavior of Micrometer's {@code
* PrometheusMeterRegistry}. The instruments will be renamed to match Micrometer instrument
* naming, and the base time unit will be set to seconds.
*
* <p>Set this to {@code true} if you are using the Prometheus metrics exporter.
*/
public OpenTelemetryMeterRegistryBuilder setPrometheusMode(boolean prometheusMode) {
this.prometheusMode = prometheusMode;
return this;
}
/**
* Returns a new {@link OpenTelemetryMeterRegistry} with the settings of this {@link
* OpenTelemetryMeterRegistryBuilder}.
*/
public MeterRegistry build() {
// prometheus mode overrides any unit settings with SECONDS
TimeUnit baseTimeUnit = prometheusMode ? TimeUnit.SECONDS : this.baseTimeUnit;
NamingConvention namingConvention =
prometheusMode ? PrometheusModeNamingConvention.INSTANCE : NamingConvention.identity;
return new OpenTelemetryMeterRegistry(
clock,
baseTimeUnit,
namingConvention,
openTelemetry.getMeterProvider().get(INSTRUMENTATION_NAME));
}
}

View File

@ -1,171 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.Bridging.name;
import static io.opentelemetry.micrometer1shim.Bridging.tagsAsAttributes;
import io.micrometer.core.instrument.AbstractTimer;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.Measurement;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
import io.micrometer.core.instrument.distribution.NoopHistogram;
import io.micrometer.core.instrument.distribution.TimeWindowMax;
import io.micrometer.core.instrument.distribution.pause.PauseDetector;
import io.micrometer.core.instrument.util.TimeUtils;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.ObservableDoubleGauge;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.DoubleAdder;
import java.util.concurrent.atomic.LongAdder;
final class OpenTelemetryTimer extends AbstractTimer implements RemovableMeter {
private final Measurements measurements;
private final TimeWindowMax max;
private final TimeUnit baseTimeUnit;
// TODO: use bound instruments when they're available
private final DoubleHistogram otelHistogram;
private final Attributes attributes;
private final ObservableDoubleGauge observableMax;
private volatile boolean removed = false;
OpenTelemetryTimer(
Id id,
NamingConvention namingConvention,
Clock clock,
DistributionStatisticConfig distributionStatisticConfig,
PauseDetector pauseDetector,
TimeUnit baseTimeUnit,
Meter otelMeter) {
super(id, clock, distributionStatisticConfig, pauseDetector, TimeUnit.MILLISECONDS, false);
if (isUsingMicrometerHistograms()) {
measurements = new MicrometerHistogramMeasurements();
} else {
measurements = NoopMeasurements.INSTANCE;
}
max = new TimeWindowMax(clock, distributionStatisticConfig);
this.baseTimeUnit = baseTimeUnit;
this.attributes = tagsAsAttributes(id, namingConvention);
String name = name(id, namingConvention);
this.otelHistogram =
otelMeter
.histogramBuilder(name)
.setDescription(Bridging.description(id))
.setUnit(TimeUnitHelper.getUnitString(baseTimeUnit))
.build();
this.observableMax =
otelMeter
.gaugeBuilder(name + ".max")
.setDescription(Bridging.description(id))
.setUnit(TimeUnitHelper.getUnitString(baseTimeUnit))
.buildWithCallback(
new DoubleMeasurementRecorder<>(max, m -> m.poll(baseTimeUnit), attributes));
}
boolean isUsingMicrometerHistograms() {
return histogram != NoopHistogram.INSTANCE;
}
@Override
protected void recordNonNegative(long amount, TimeUnit unit) {
if (!removed) {
double nanos = (double) unit.toNanos(amount);
double time = TimeUtils.nanosToUnit(nanos, baseTimeUnit);
otelHistogram.record(time, attributes);
measurements.record(nanos);
max.record(nanos, TimeUnit.NANOSECONDS);
}
}
@Override
public long count() {
return measurements.count();
}
@Override
public double totalTime(TimeUnit unit) {
return measurements.totalTime(unit);
}
@Override
public double max(TimeUnit unit) {
return max.poll(unit);
}
@Override
public Iterable<Measurement> measure() {
UnsupportedReadLogger.logWarning();
return Collections.emptyList();
}
@Override
public void onRemove() {
removed = true;
observableMax.close();
}
private interface Measurements {
void record(double nanos);
long count();
double totalTime(TimeUnit unit);
}
// if micrometer histograms are not being used then there's no need to keep any local state
// OpenTelemetry metrics bridge does not support reading measurements
enum NoopMeasurements implements Measurements {
INSTANCE;
@Override
public void record(double nanos) {}
@Override
public long count() {
UnsupportedReadLogger.logWarning();
return 0;
}
@Override
public double totalTime(TimeUnit unit) {
UnsupportedReadLogger.logWarning();
return Double.NaN;
}
}
// calculate count and totalTime value for the use of micrometer histograms
// kinda similar to how DropwizardTimer does that
private static final class MicrometerHistogramMeasurements implements Measurements {
private final LongAdder count = new LongAdder();
private final DoubleAdder totalTime = new DoubleAdder();
@Override
public void record(double nanos) {
count.increment();
totalTime.add(nanos);
}
@Override
public long count() {
return count.sum();
}
@Override
public double totalTime(TimeUnit unit) {
return TimeUtils.nanosToUnit(totalTime.sum(), unit);
}
}
}

View File

@ -1,36 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.config.NamingConvention;
import javax.annotation.Nullable;
// This naming strategy does not replace '.' with '_', and it does not append '_total' to counter
// names - the reason behind it is that this is already done by the Prometheus exporter; see the
// io.opentelemetry.exporter.prometheus.MetricAdapter class
enum PrometheusModeNamingConvention implements NamingConvention {
INSTANCE;
@Override
public String name(String name, Meter.Type type, @Nullable String baseUnit) {
if (type == Meter.Type.COUNTER
|| type == Meter.Type.DISTRIBUTION_SUMMARY
|| type == Meter.Type.GAUGE) {
if (baseUnit != null && !name.endsWith("." + baseUnit)) {
name = name + "." + baseUnit;
}
}
if (type == Meter.Type.LONG_TASK_TIMER || type == Meter.Type.TIMER) {
if (!name.endsWith(".seconds")) {
name = name + ".seconds";
}
}
return name;
}
}

View File

@ -1,11 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
interface RemovableMeter {
void onRemove();
}

View File

@ -1,33 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import java.util.concurrent.TimeUnit;
final class TimeUnitHelper {
static String getUnitString(TimeUnit unit) {
switch (unit) {
case NANOSECONDS:
return "ns";
case MICROSECONDS:
return "us";
case MILLISECONDS:
return "ms";
case SECONDS:
return "s";
case MINUTES:
return "min";
case HOURS:
return "h";
case DAYS:
return "d";
}
throw new IllegalStateException("Should not ever happen");
}
private TimeUnitHelper() {}
}

View File

@ -1,23 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import java.util.logging.Level;
import java.util.logging.Logger;
final class UnsupportedReadLogger {
static {
Logger logger = Logger.getLogger(OpenTelemetryMeterRegistry.class.getName());
logger.log(Level.WARNING, "OpenTelemetry metrics bridge does not support reading measurements");
}
static void logWarning() {
// do nothing; the warning will be logged exactly once when this class is loaded
}
private UnsupportedReadLogger() {}
}

View File

@ -1,64 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistryBuilder.INSTRUMENTATION_NAME;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Metrics;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class CounterTest {
@RegisterExtension
static final MicrometerTestingExtension testing = new MicrometerTestingExtension();
@Test
void testCounter() {
Counter counter =
Counter.builder("testCounter")
.description("This is a test counter")
.tags("tag", "value")
.baseUnit("items")
.register(Metrics.globalRegistry);
counter.increment();
counter.increment(2);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testCounter")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test counter")
.hasUnit("items")
.hasDoubleSumSatisfying(
sum ->
sum.isMonotonic()
.hasPointsSatisfying(
point ->
point
.hasValue(3)
.hasAttributes(attributeEntry("tag", "value")))));
Metrics.globalRegistry.remove(counter);
counter.increment();
// Synchronous instruments will continue to report previous value after removal
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testCounter")
.hasDoubleSumSatisfying(
sum -> sum.hasPointsSatisfying(point -> point.hasValue(3))));
}
}

View File

@ -1,217 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistryBuilder.INSTRUMENTATION_NAME;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.Metrics;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class DistributionSummaryTest {
@RegisterExtension
static final MicrometerTestingExtension testing = new MicrometerTestingExtension();
@Test
void testMicrometerDistributionSummary() {
DistributionSummary summary =
DistributionSummary.builder("testSummary")
.description("This is a test distribution summary")
.baseUnit("things")
.tags("tag", "value")
.register(Metrics.globalRegistry);
summary.record(1);
summary.record(2);
summary.record(4);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testSummary")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test distribution summary")
.hasUnit("things")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(7)
.hasCount(3)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testSummary.max")
.hasDescription("This is a test distribution summary")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(4)
.hasAttributes(attributeEntry("tag", "value")))));
Metrics.globalRegistry.remove(summary);
// Histogram is synchronous and returns previous value after removal, max is asynchronous and is
// removed completely.
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testSummary")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(7)
.hasCount(3)
.hasAttributes(attributeEntry("tag", "value")))));
}
@Test
void testMicrometerHistogram() {
DistributionSummary summary =
DistributionSummary.builder("testSummary")
.description("This is a test distribution summary")
.baseUnit("things")
.tags("tag", "value")
.serviceLevelObjectives(1, 10, 100, 1000)
.distributionStatisticBufferLength(10)
.register(Metrics.globalRegistry);
summary.record(0.5);
summary.record(5);
summary.record(50);
summary.record(500);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testSummary")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test distribution summary")
.hasUnit("things")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
points ->
points
.hasSum(555.5)
.hasCount(4)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testSummary.max")
.hasDescription("This is a test distribution summary")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(500)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testSummary.histogram")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(1)
.hasAttributes(
attributeEntry("le", "1"),
attributeEntry("tag", "value")),
point ->
point
.hasValue(2)
.hasAttributes(
attributeEntry("le", "10"),
attributeEntry("tag", "value")),
point ->
point
.hasValue(3)
.hasAttributes(
attributeEntry("le", "100"),
attributeEntry("tag", "value")),
point ->
point
.hasValue(4)
.hasAttributes(
attributeEntry("le", "1000"),
attributeEntry("tag", "value")))));
}
@Test
void testMicrometerPercentiles() {
DistributionSummary summary =
DistributionSummary.builder("testSummary")
.description("This is a test distribution summary")
.baseUnit("things")
.tags("tag", "value")
.publishPercentiles(0.5, 0.95, 0.99)
.register(Metrics.globalRegistry);
summary.record(50);
summary.record(100);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testSummary")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test distribution summary")
.hasUnit("things")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(150)
.hasCount(2)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testSummary.max")
.hasDescription("This is a test distribution summary")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(100)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testSummary.percentile")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasAttributes(
attributeEntry("phi", "0.5"),
attributeEntry("tag", "value")),
point ->
point.hasAttributes(
attributeEntry("phi", "0.95"),
attributeEntry("tag", "value")),
point ->
point.hasAttributes(
attributeEntry("phi", "0.99"),
attributeEntry("tag", "value")))));
}
}

View File

@ -1,92 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistryBuilder.INSTRUMENTATION_NAME;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import io.micrometer.core.instrument.FunctionCounter;
import io.micrometer.core.instrument.Metrics;
import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import io.opentelemetry.sdk.metrics.internal.state.MetricStorageRegistry;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class FunctionCounterTest {
@RegisterExtension
static final MicrometerTestingExtension testing = new MicrometerTestingExtension();
final AtomicLong num = new AtomicLong(12);
final AtomicLong anotherNum = new AtomicLong(13);
@Test
void testFunctionCounter() {
FunctionCounter counter =
FunctionCounter.builder("testFunctionCounter", num, AtomicLong::get)
.description("This is a test function counter")
.tags("tag", "value")
.baseUnit("items")
.register(Metrics.globalRegistry);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testFunctionCounter")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test function counter")
.hasUnit("items")
.hasDoubleSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point
.hasValue(12)
.hasAttributes(attributeEntry("tag", "value")))));
Metrics.globalRegistry.remove(counter);
assertThat(testing.collectAllMetrics()).isEmpty();
}
@Test
@SuppressLogger(MetricStorageRegistry.class)
void functionCountersWithSameNameAndDifferentTags() {
FunctionCounter.builder("testFunctionCounterWithTags", num, AtomicLong::get)
.description("First description")
.tags("tag", "1")
.baseUnit("items")
.register(Metrics.globalRegistry);
FunctionCounter.builder("testFunctionCounterWithTags", anotherNum, AtomicLong::get)
.description("ignored")
.tags("tag", "2")
.baseUnit("items")
.register(Metrics.globalRegistry);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testFunctionCounterWithTags")
.hasDescription("First description")
.hasUnit("items")
.hasDoubleSumSatisfying(
sum ->
sum.isMonotonic()
.hasPointsSatisfying(
point ->
point
.hasValue(12)
.hasAttributes(attributeEntry("tag", "1")),
point ->
point
.hasValue(13)
.hasAttributes(attributeEntry("tag", "2")))));
}
}

View File

@ -1,88 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistryBuilder.INSTRUMENTATION_NAME;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import io.micrometer.core.instrument.FunctionTimer;
import io.micrometer.core.instrument.Metrics;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class FunctionTimerSecondsTest {
@RegisterExtension
static final MicrometerTestingExtension testing =
new MicrometerTestingExtension() {
@Override
OpenTelemetryMeterRegistryBuilder configureOtelRegistry(
OpenTelemetryMeterRegistryBuilder registry) {
return registry.setBaseTimeUnit(TimeUnit.SECONDS);
}
};
final TestTimer timerObj = new TestTimer();
@BeforeEach
void cleanupTimer() {
timerObj.reset();
}
@Test
void testFunctionTimerWithBaseUnitSeconds() {
FunctionTimer functionTimer =
FunctionTimer.builder(
"testFunctionTimerSeconds",
timerObj,
TestTimer::getCount,
TestTimer::getTotalTimeNanos,
TimeUnit.NANOSECONDS)
.description("This is a test function timer")
.tags("tag", "value")
.register(Metrics.globalRegistry);
timerObj.add(42, TimeUnit.SECONDS);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testFunctionTimerSeconds.count")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test function timer")
.hasUnit("1")
.hasLongSumSatisfying(
sum ->
sum.isMonotonic()
.hasPointsSatisfying(
point ->
point
.hasValue(1)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testFunctionTimerSeconds.sum")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test function timer")
.hasUnit("s")
.hasDoubleSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point
.hasValue(42)
.hasAttributes(attributeEntry("tag", "value")))));
Metrics.globalRegistry.remove(functionTimer);
assertThat(testing.collectAllMetrics()).isEmpty();
}
}

View File

@ -1,149 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistryBuilder.INSTRUMENTATION_NAME;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import io.micrometer.core.instrument.FunctionTimer;
import io.micrometer.core.instrument.Metrics;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class FunctionTimerTest {
@RegisterExtension
static final MicrometerTestingExtension testing = new MicrometerTestingExtension();
final TestTimer timerObj = new TestTimer();
final TestTimer anotherTimerObj = new TestTimer();
@BeforeEach
void cleanupTimers() {
timerObj.reset();
anotherTimerObj.reset();
}
@Test
void testFunctionTimer() throws InterruptedException {
FunctionTimer functionTimer =
FunctionTimer.builder(
"testFunctionTimer",
timerObj,
TestTimer::getCount,
TestTimer::getTotalTimeNanos,
TimeUnit.NANOSECONDS)
.description("This is a test function timer")
.tags("tag", "value")
.register(Metrics.globalRegistry);
timerObj.add(42, TimeUnit.SECONDS);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testFunctionTimer.count")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test function timer")
.hasUnit("1")
.hasLongSumSatisfying(
sum ->
sum.isMonotonic()
.hasPointsSatisfying(
point ->
point
.hasValue(1)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testFunctionTimer.sum")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test function timer")
.hasUnit("ms")
.hasDoubleSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point
.hasValue(42_000)
.hasAttributes(attributeEntry("tag", "value")))));
Metrics.globalRegistry.remove(functionTimer);
assertThat(testing.collectAllMetrics()).isEmpty();
}
@Test
void testNanoPrecision() {
FunctionTimer.builder(
"testNanoFunctionTimer",
timerObj,
TestTimer::getCount,
TestTimer::getTotalTimeNanos,
TimeUnit.NANOSECONDS)
.register(Metrics.globalRegistry);
timerObj.add(1_234_000, TimeUnit.NANOSECONDS);
assertThat(testing.collectAllMetrics())
.anySatisfy(
metric ->
assertThat(metric)
.hasName("testNanoFunctionTimer.sum")
.hasUnit("ms")
.hasDoubleSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point -> point.hasValue(1.234).hasAttributes(Attributes.empty()))));
}
@Test
void functionTimersWithSameNameAndDifferentTags() {
FunctionTimer.builder(
"testFunctionTimerWithTags",
timerObj,
TestTimer::getCount,
TestTimer::getTotalTimeNanos,
TimeUnit.NANOSECONDS)
.tags("tag", "1")
.register(Metrics.globalRegistry);
FunctionTimer.builder(
"testFunctionTimerWithTags",
anotherTimerObj,
TestTimer::getCount,
TestTimer::getTotalTimeNanos,
TimeUnit.NANOSECONDS)
.tags("tag", "2")
.register(Metrics.globalRegistry);
timerObj.add(12, TimeUnit.SECONDS);
anotherTimerObj.add(42, TimeUnit.SECONDS);
assertThat(testing.collectAllMetrics())
.anySatisfy(
metric ->
assertThat(metric)
.hasName("testFunctionTimerWithTags.sum")
.hasUnit("ms")
.hasDoubleSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point
.hasValue(12_000)
.hasAttributes(attributeEntry("tag", "1")),
point ->
point
.hasValue(42_000)
.hasAttributes(attributeEntry("tag", "2")))));
}
}

View File

@ -1,117 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistryBuilder.INSTRUMENTATION_NAME;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.Metrics;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import java.lang.ref.WeakReference;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class GaugeTest {
@RegisterExtension
static final MicrometerTestingExtension testing = new MicrometerTestingExtension();
@Test
void testGauge() {
// when
Gauge gauge =
Gauge.builder("testGauge", () -> 42)
.description("This is a test gauge")
.tags("tag", "value")
.baseUnit("items")
.register(Metrics.globalRegistry);
// then
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testGauge")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test gauge")
.hasUnit("items")
.hasDoubleGaugeSatisfying(
doubleGauge ->
doubleGauge.hasPointsSatisfying(
point ->
point
.hasValue(42)
.hasAttributes(attributeEntry("tag", "value")))));
// when
Metrics.globalRegistry.remove(gauge);
assertThat(testing.collectAllMetrics()).isEmpty();
}
@Test
void gaugesWithSameNameAndDifferentTags() {
Gauge.builder("testGaugeWithTags", () -> 12)
.description("First description wins")
.baseUnit("items")
.tags("tag", "1")
.register(Metrics.globalRegistry);
Gauge.builder("testGaugeWithTags", () -> 42)
.description("ignored")
.baseUnit("items")
.tags("tag", "2")
.register(Metrics.globalRegistry);
assertThat(testing.collectAllMetrics())
.satisfiesExactly(
metric ->
assertThat(metric)
.hasName("testGaugeWithTags")
.hasDescription("First description wins")
.hasUnit("items")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasValue(12).hasAttributes(attributeEntry("tag", "1")),
point ->
point.hasValue(42).hasAttributes(attributeEntry("tag", "2")))));
}
@Test
void testWeakRefGauge() throws InterruptedException {
AtomicLong num = new AtomicLong(42);
Gauge.builder("testWeakRefGauge", num, AtomicLong::get)
.strongReference(false)
.register(Metrics.globalRegistry);
assertThat(testing.collectAllMetrics())
.satisfiesExactly(
metric ->
assertThat(metric)
.hasName("testWeakRefGauge")
.hasDoubleGaugeSatisfying(
gauge -> gauge.hasPointsSatisfying(point -> point.hasValue(42))));
WeakReference<AtomicLong> numWeakRef = new WeakReference<>(num);
num = null;
awaitGc(numWeakRef);
assertThat(testing.collectAllMetrics()).isEmpty();
}
private static void awaitGc(WeakReference<?> ref) throws InterruptedException {
while (ref.get() != null) {
if (Thread.interrupted()) {
throw new InterruptedException();
}
System.gc();
System.runFinalization();
}
}
}

View File

@ -1,138 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistryBuilder.INSTRUMENTATION_NAME;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import io.micrometer.core.instrument.LongTaskTimer;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.MockClock;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class LongTaskTimerHistogramTest {
static MockClock clock = new MockClock();
@RegisterExtension
static final MicrometerTestingExtension testing =
new MicrometerTestingExtension() {
@Override
OpenTelemetryMeterRegistryBuilder configureOtelRegistry(
OpenTelemetryMeterRegistryBuilder registry) {
return registry.setClock(clock);
}
};
@Test
void testMicrometerHistogram() {
LongTaskTimer timer =
LongTaskTimer.builder("testLongTaskTimerHistogram")
.description("This is a test timer")
.serviceLevelObjectives(Duration.ofMillis(100), Duration.ofMillis(1000))
.distributionStatisticBufferLength(10)
.register(Metrics.globalRegistry);
LongTaskTimer.Sample sample1 = timer.start();
// only active tasks count
timer.start().stop();
clock.add(Duration.ofMillis(100));
LongTaskTimer.Sample sample2 = timer.start();
LongTaskTimer.Sample sample3 = timer.start();
clock.add(Duration.ofMillis(10));
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testLongTaskTimerHistogram.active")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test timer")
.hasUnit("tasks")
.hasLongSumSatisfying(
sum ->
sum.isNotMonotonic()
.hasPointsSatisfying(
point -> point.hasValue(3).hasAttributes(Attributes.empty()))),
metric ->
assertThat(metric)
.hasName("testLongTaskTimerHistogram.duration")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test timer")
.hasUnit("ms")
.hasDoubleSumSatisfying(
sum ->
sum.isNotMonotonic()
.hasPointsSatisfying(
point ->
point
.hasAttributes(Attributes.empty())
.satisfies(
pointData ->
assertThat(pointData.getValue())
.isPositive()))),
metric ->
assertThat(metric)
.hasName("testLongTaskTimerHistogram.histogram")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasAttributes(attributeEntry("le", "100")).hasValue(2),
point ->
point
.hasAttributes(attributeEntry("le", "1000"))
.hasValue(3))));
sample1.stop();
sample2.stop();
sample3.stop();
// Continues to report 0 after stopped.
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testLongTaskTimerHistogram.active")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test timer")
.hasUnit("tasks")
.hasLongSumSatisfying(
sum ->
sum.isNotMonotonic()
.hasPointsSatisfying(
point -> point.hasValue(0).hasAttributes(Attributes.empty()))),
metric ->
assertThat(metric)
.hasName("testLongTaskTimerHistogram.duration")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test timer")
.hasUnit("ms")
.hasDoubleSumSatisfying(
sum ->
sum.isNotMonotonic()
.hasPointsSatisfying(
point -> point.hasValue(0).hasAttributes(Attributes.empty()))),
metric ->
assertThat(metric)
.hasName("testLongTaskTimerHistogram.histogram")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasValue(0).hasAttributes(attributeEntry("le", "100")),
point ->
point
.hasValue(0)
.hasAttributes(attributeEntry("le", "1000")))));
}
}

View File

@ -1,114 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistryBuilder.INSTRUMENTATION_NAME;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import io.micrometer.core.instrument.LongTaskTimer;
import io.micrometer.core.instrument.Metrics;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class LongTaskTimerSecondsTest {
@RegisterExtension
static final MicrometerTestingExtension testing =
new MicrometerTestingExtension() {
@Override
OpenTelemetryMeterRegistryBuilder configureOtelRegistry(
OpenTelemetryMeterRegistryBuilder registry) {
return registry.setBaseTimeUnit(TimeUnit.SECONDS);
}
};
@Test
void testLongTaskTimerWithBaseUnitSeconds() throws InterruptedException {
// given
LongTaskTimer timer =
LongTaskTimer.builder("testLongTaskTimerSeconds")
.description("This is a test long task timer")
.tags("tag", "value")
.register(Metrics.globalRegistry);
// when
LongTaskTimer.Sample sample = timer.start();
// then
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testLongTaskTimerSeconds.active")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test long task timer")
.hasUnit("tasks")
.hasLongSumSatisfying(
sum ->
sum.isNotMonotonic()
.hasPointsSatisfying(
point ->
point
.hasValue(1)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testLongTaskTimerSeconds.duration")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test long task timer")
.hasUnit("s")
.hasDoubleSumSatisfying(
sum ->
sum.isNotMonotonic()
.hasPointsSatisfying(
point ->
point
.hasAttributes(attributeEntry("tag", "value"))
.satisfies(
pointData ->
assertThat(pointData.getValue())
.isPositive()))));
// when
TimeUnit.MILLISECONDS.sleep(100);
sample.stop();
// then
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testLongTaskTimerSeconds.active")
.hasLongSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point
.hasValue(0)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testLongTaskTimerSeconds.duration")
.hasDoubleSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point
.hasValue(0)
.hasAttributes(attributeEntry("tag", "value")))));
// when timer is removed from the registry
Metrics.globalRegistry.remove(timer);
timer.start();
// then no tasks are active after starting a new sample
assertThat(testing.collectAllMetrics()).isEmpty();
}
}

View File

@ -1,102 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistryBuilder.INSTRUMENTATION_NAME;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import io.micrometer.core.instrument.LongTaskTimer;
import io.micrometer.core.instrument.Metrics;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class LongTaskTimerTest {
@RegisterExtension
static final MicrometerTestingExtension testing = new MicrometerTestingExtension();
@Test
void testLongTaskTimer() throws InterruptedException {
LongTaskTimer timer =
LongTaskTimer.builder("testLongTaskTimer")
.description("This is a test long task timer")
.tags("tag", "value")
.register(Metrics.globalRegistry);
LongTaskTimer.Sample sample = timer.start();
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testLongTaskTimer.active")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test long task timer")
.hasUnit("tasks")
.hasLongSumSatisfying(
sum ->
sum.isNotMonotonic()
.hasPointsSatisfying(
point ->
point
.hasValue(1)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testLongTaskTimer.duration")
.hasDescription("This is a test long task timer")
.hasUnit("ms")
.hasDoubleSumSatisfying(
sum ->
sum.isNotMonotonic()
.hasPointsSatisfying(
point ->
point
.hasAttributes(attributeEntry("tag", "value"))
.satisfies(
pointData ->
assertThat(pointData.getValue())
.isPositive()))));
// when
TimeUnit.MILLISECONDS.sleep(100);
sample.stop();
// then
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testLongTaskTimer.active")
.hasLongSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point
.hasValue(0)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testLongTaskTimer.duration")
.hasDoubleSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point
.hasValue(0)
.hasAttributes(attributeEntry("tag", "value")))));
// when timer is removed from the registry
Metrics.globalRegistry.remove(timer);
timer.start();
// then no tasks are active after starting a new sample
assertThat(testing.collectAllMetrics()).isEmpty();
}
}

View File

@ -1,158 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistryBuilder.INSTRUMENTATION_NAME;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import io.micrometer.core.instrument.Measurement;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Statistic;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class MeterTest {
@RegisterExtension
static final MicrometerTestingExtension testing = new MicrometerTestingExtension();
@Test
void testMeter() {
AtomicReference<Double> number = new AtomicReference<>(12345.0);
List<Measurement> measurements =
Arrays.asList(
new Measurement(number::get, Statistic.TOTAL),
new Measurement(number::get, Statistic.TOTAL_TIME),
new Measurement(number::get, Statistic.COUNT),
new Measurement(number::get, Statistic.ACTIVE_TASKS),
new Measurement(number::get, Statistic.DURATION),
new Measurement(number::get, Statistic.MAX),
new Measurement(number::get, Statistic.VALUE),
new Measurement(number::get, Statistic.UNKNOWN));
Meter meter =
Meter.builder("testMeter", Meter.Type.OTHER, measurements)
.description("This is a test meter")
.baseUnit("things")
.tag("tag", "value")
.register(Metrics.globalRegistry);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testMeter.total")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test meter")
.hasUnit("things")
.hasDoubleSumSatisfying(
sum ->
sum.isMonotonic()
.hasPointsSatisfying(
point ->
point
.hasValue(12345)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testMeter.total_time")
.hasDescription("This is a test meter")
.hasUnit("things")
.hasDoubleSumSatisfying(
sum ->
sum.isMonotonic()
.hasPointsSatisfying(
point ->
point
.hasValue(12345)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testMeter.count")
.hasDescription("This is a test meter")
.hasUnit("things")
.hasDoubleSumSatisfying(
sum ->
sum.isMonotonic()
.hasPointsSatisfying(
point ->
point
.hasValue(12345)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testMeter.active")
.hasDescription("This is a test meter")
.hasUnit("things")
.hasDoubleSumSatisfying(
sum ->
sum.isNotMonotonic()
.hasPointsSatisfying(
point ->
point
.hasValue(12345)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testMeter.duration")
.hasDescription("This is a test meter")
.hasUnit("things")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(12345)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testMeter.max")
.hasDescription("This is a test meter")
.hasUnit("things")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(12345)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testMeter.value")
.hasDescription("This is a test meter")
.hasUnit("things")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(12345)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testMeter.unknown")
.hasDescription("This is a test meter")
.hasUnit("things")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(12345)
.hasAttributes(attributeEntry("tag", "value")))));
// when
Metrics.globalRegistry.remove(meter);
assertThat(testing.collectAllMetrics()).isEmpty();
}
}

View File

@ -1,70 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Metrics;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader;
import java.util.Collection;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
class MicrometerTestingExtension implements AfterEachCallback, BeforeEachCallback {
private static final ExtensionContext.Namespace NAMESPACE =
ExtensionContext.Namespace.create(MicrometerTestingExtension.class);
private InMemoryMetricReader metricReader;
Collection<MetricData> collectAllMetrics() {
return metricReader.collectAllMetrics();
}
@Override
public void beforeEach(ExtensionContext context) {
ExtensionContext.Store store = context.getStore(NAMESPACE);
metricReader = InMemoryMetricReader.create();
SdkMeterProvider meterProvider =
SdkMeterProvider.builder().registerMetricReader(metricReader).build();
MeterRegistry otelMeterRegistry =
configureOtelRegistry(
OpenTelemetryMeterRegistry.builder(
OpenTelemetrySdk.builder().setMeterProvider(meterProvider).build()))
.build();
configureMeterRegistry(otelMeterRegistry);
store.put(SdkMeterProvider.class, meterProvider);
store.put(MeterRegistry.class, otelMeterRegistry);
Metrics.addRegistry(otelMeterRegistry);
}
@Override
public void afterEach(ExtensionContext context) {
ExtensionContext.Store store = context.getStore(NAMESPACE);
MeterRegistry otelMeterRegistry = store.get(MeterRegistry.class, MeterRegistry.class);
SdkMeterProvider meterProvider = store.get(SdkMeterProvider.class, SdkMeterProvider.class);
Metrics.removeRegistry(otelMeterRegistry);
meterProvider.close();
Metrics.globalRegistry.forEachMeter(Metrics.globalRegistry::remove);
}
OpenTelemetryMeterRegistryBuilder configureOtelRegistry(
OpenTelemetryMeterRegistryBuilder registry) {
return registry;
}
MeterRegistry configureMeterRegistry(MeterRegistry registry) {
return registry;
}
}

View File

@ -1,222 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistryBuilder.INSTRUMENTATION_NAME;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.LongTaskTimer;
import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.config.NamingConvention;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@SuppressWarnings("PreferJavaTimeOverload")
class NamingConventionTest {
@RegisterExtension
static final MicrometerTestingExtension testing =
new MicrometerTestingExtension() {
@Override
MeterRegistry configureMeterRegistry(MeterRegistry registry) {
registry
.config()
.namingConvention(
new NamingConvention() {
@Override
public String name(String name, Meter.Type type, String baseUnit) {
return "test." + name;
}
@Override
public String tagKey(String key) {
return "test." + key;
}
@Override
public String tagValue(String value) {
return "test." + value;
}
});
return registry;
}
};
final AtomicLong num = new AtomicLong(42);
@Test
void renameCounter() {
Counter counter = Metrics.counter("renamedCounter", "tag", "value");
counter.increment();
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("test.renamedCounter")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDoubleSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point.hasAttributes(
attributeEntry("test.tag", "test.value")))));
}
@Test
void renameDistributionSummary() {
DistributionSummary summary = Metrics.summary("renamedSummary", "tag", "value");
summary.record(42);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("test.renamedSummary")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point.hasAttributes(attributeEntry("test.tag", "test.value")))),
metric ->
assertThat(metric)
.hasName("test.renamedSummary.max")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasAttributes(
attributeEntry("test.tag", "test.value")))));
}
@Test
void renameFunctionCounter() {
Metrics.more().counter("renamedFunctionCounter", Tags.of("tag", "value"), num);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("test.renamedFunctionCounter")
.hasDoubleSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point.hasAttributes(
attributeEntry("test.tag", "test.value")))));
}
@Test
void renameFunctionTimer() {
Metrics.more()
.timer(
"renamedFunctionTimer",
Tags.of("tag", "value"),
num,
AtomicLong::longValue,
AtomicLong::doubleValue,
TimeUnit.SECONDS);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("test.renamedFunctionTimer.count")
.hasLongSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point.hasAttributes(attributeEntry("test.tag", "test.value")))),
metric ->
assertThat(metric)
.hasName("test.renamedFunctionTimer.sum")
.hasDoubleSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point.hasAttributes(
attributeEntry("test.tag", "test.value")))));
}
@Test
void renameGauge() {
Metrics.gauge("renamedGauge", Tags.of("tag", "value"), num);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("test.renamedGauge")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasAttributes(
attributeEntry("test.tag", "test.value")))));
}
@Test
void renameLongTaskTimer() {
LongTaskTimer timer = Metrics.more().longTaskTimer("renamedLongTaskTimer", "tag", "value");
timer.start().stop();
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("test.renamedLongTaskTimer.active")
.hasLongSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point.hasAttributes(attributeEntry("test.tag", "test.value")))),
metric ->
assertThat(metric)
.hasName("test.renamedLongTaskTimer.duration")
.hasDoubleSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point.hasAttributes(
attributeEntry("test.tag", "test.value")))));
}
@Test
void renameTimer() {
Timer timer = Metrics.timer("renamedTimer", "tag", "value");
timer.record(10, TimeUnit.SECONDS);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("test.renamedTimer")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point.hasAttributes(attributeEntry("test.tag", "test.value")))),
metric ->
assertThat(metric)
.hasName("test.renamedTimer.max")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasAttributes(
attributeEntry("test.tag", "test.value")))));
}
}

View File

@ -1,320 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistryBuilder.INSTRUMENTATION_NAME;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.FunctionTimer;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.LongTaskTimer;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Timer;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@SuppressWarnings("PreferJavaTimeOverload")
class PrometheusModeTest {
@RegisterExtension
static final MicrometerTestingExtension testing =
new MicrometerTestingExtension() {
@Override
OpenTelemetryMeterRegistryBuilder configureOtelRegistry(
OpenTelemetryMeterRegistryBuilder registry) {
return registry.setPrometheusMode(true);
}
};
final TestTimer timerObj = new TestTimer();
@BeforeEach
void cleanupMeters() {
Metrics.globalRegistry.forEachMeter(Metrics.globalRegistry::remove);
}
@Test
void testCounter() {
// given
Counter counter =
Counter.builder("testPrometheusCounter")
.description("This is a test counter")
.tags("tag", "value")
.baseUnit("items")
.register(Metrics.globalRegistry);
// when
counter.increment(12);
// then
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testPrometheusCounter.items")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test counter")
.hasUnit("items")
.hasDoubleSumSatisfying(
sum ->
sum.isMonotonic()
.hasPointsSatisfying(
point ->
point
.hasValue(12)
.hasAttributes(attributeEntry("tag", "value")))));
}
@Test
void testDistributionSummary() {
// given
DistributionSummary summary =
DistributionSummary.builder("testPrometheusSummary")
.description("This is a test summary")
.baseUnit("items")
.tag("tag", "value")
.register(Metrics.globalRegistry);
// when
summary.record(12);
summary.record(42);
// then
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testPrometheusSummary.items")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test summary")
.hasUnit("items")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(54)
.hasCount(2)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testPrometheusSummary.items.max")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test summary")
.hasUnit("items")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(42)
.hasAttributes(attributeEntry("tag", "value")))));
}
@Test
void testFunctionTimer() {
// given
FunctionTimer.builder(
"testPrometheusFunctionTimer",
timerObj,
TestTimer::getCount,
TestTimer::getTotalTimeNanos,
TimeUnit.NANOSECONDS)
.description("This is a test function timer")
.tags("tag", "value")
.register(Metrics.globalRegistry);
// when
timerObj.add(42, TimeUnit.SECONDS);
// then
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testPrometheusFunctionTimer.seconds.count")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test function timer")
.hasUnit("1")
.hasLongSumSatisfying(
sum ->
sum.isMonotonic()
.hasPointsSatisfying(
point ->
point
.hasValue(1)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testPrometheusFunctionTimer.seconds.sum")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test function timer")
.hasUnit("s")
.hasDoubleSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point
.hasValue(42)
.hasAttributes(attributeEntry("tag", "value")))));
}
@Test
void testGauge() {
// when
Gauge.builder("testPrometheusGauge", () -> 42)
.description("This is a test gauge")
.tags("tag", "value")
.baseUnit("items")
.register(Metrics.globalRegistry);
// then
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testPrometheusGauge.items")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test gauge")
.hasUnit("items")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(42)
.hasAttributes(attributeEntry("tag", "value")))));
}
@Test
void testLongTaskTimer() throws InterruptedException {
// given
LongTaskTimer timer =
LongTaskTimer.builder("testPrometheusLongTaskTimer")
.description("This is a test long task timer")
.tags("tag", "value")
.register(Metrics.globalRegistry);
// when
LongTaskTimer.Sample sample = timer.start();
// then
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testPrometheusLongTaskTimer.seconds.active")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test long task timer")
.hasUnit("tasks")
.hasLongSumSatisfying(
sum ->
sum.isNotMonotonic()
.hasPointsSatisfying(
point ->
point
.hasValue(1)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testPrometheusLongTaskTimer.seconds.duration")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test long task timer")
.hasUnit("s")
.hasDoubleSumSatisfying(
sum ->
sum.isNotMonotonic()
.hasPointsSatisfying(
point ->
point
.hasAttributes(attributeEntry("tag", "value"))
.satisfies(
pointData ->
assertThat(pointData.getValue())
.isPositive()))));
// when
TimeUnit.MILLISECONDS.sleep(100);
sample.stop();
// then
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testPrometheusLongTaskTimer.seconds.active")
.hasLongSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point
.hasValue(0)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testPrometheusLongTaskTimer.seconds.duration")
.hasDoubleSumSatisfying(
sum ->
sum.hasPointsSatisfying(
point ->
point
.hasValue(0)
.hasAttributes(attributeEntry("tag", "value")))));
}
@Test
void testTimer() {
// given
Timer timer =
Timer.builder("testPrometheusTimer")
.description("This is a test timer")
.tags("tag", "value")
.register(Metrics.globalRegistry);
// when
timer.record(1, TimeUnit.SECONDS);
timer.record(5, TimeUnit.SECONDS);
timer.record(10_789, TimeUnit.MILLISECONDS);
// then
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testPrometheusTimer.seconds")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test timer")
.hasUnit("s")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(16.789)
.hasCount(3)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testPrometheusTimer.seconds.max")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test timer")
.hasUnit("s")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(10.789)
.hasAttributes(attributeEntry("tag", "value")))));
}
}

View File

@ -1,31 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import java.util.concurrent.TimeUnit;
class TestTimer {
int count = 0;
long totalTimeNanos = 0;
void add(long time, TimeUnit unit) {
count++;
totalTimeNanos += unit.toNanos(time);
}
int getCount() {
return count;
}
double getTotalTimeNanos() {
return totalTimeNanos;
}
void reset() {
count = 0;
totalTimeNanos = 0;
}
}

View File

@ -1,94 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistryBuilder.INSTRUMENTATION_NAME;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Timer;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@SuppressWarnings("PreferJavaTimeOverload")
class TimerSecondsTest {
@RegisterExtension
static final MicrometerTestingExtension testing =
new MicrometerTestingExtension() {
@Override
OpenTelemetryMeterRegistryBuilder configureOtelRegistry(
OpenTelemetryMeterRegistryBuilder registry) {
return registry.setBaseTimeUnit(TimeUnit.SECONDS);
}
};
@Test
void testTimerWithBaseUnitSeconds() {
Timer timer =
Timer.builder("testTimerSeconds")
.description("This is a test timer")
.tags("tag", "value")
.register(Metrics.globalRegistry);
timer.record(1, TimeUnit.SECONDS);
timer.record(10, TimeUnit.SECONDS);
timer.record(12_345, TimeUnit.MILLISECONDS);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testTimerSeconds")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test timer")
.hasUnit("s")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(23.345)
.hasCount(3)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testTimerSeconds.max")
.hasDescription("This is a test timer")
.hasUnit("s")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(12.345)
.hasAttributes(attributeEntry("tag", "value")))));
Metrics.globalRegistry.remove(timer);
timer.record(12, TimeUnit.SECONDS);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testTimerSeconds")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test timer")
.hasUnit("s")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(23.345)
.hasCount(3)
.hasAttributes(attributeEntry("tag", "value")))));
}
}

View File

@ -1,252 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.micrometer1shim;
import static io.opentelemetry.micrometer1shim.OpenTelemetryMeterRegistryBuilder.INSTRUMENTATION_NAME;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Timer;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@SuppressWarnings("PreferJavaTimeOverload")
class TimerTest {
@RegisterExtension
static final MicrometerTestingExtension testing = new MicrometerTestingExtension();
@Test
void testTimer() {
Timer timer =
Timer.builder("testTimer")
.description("This is a test timer")
.tags("tag", "value")
.register(Metrics.globalRegistry);
timer.record(42, TimeUnit.SECONDS);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testTimer")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test timer")
.hasUnit("ms")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(42_000)
.hasCount(1)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testTimer.max")
.hasDescription("This is a test timer")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(42_000)
.hasAttributes(attributeEntry("tag", "value")))));
Metrics.globalRegistry.remove(timer);
timer.record(12, TimeUnit.SECONDS);
// Histogram is synchronous and returns previous value after removal, max is asynchronous and is
// removed completely.
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testTimer")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(42_000)
.hasCount(1)
.hasAttributes(attributeEntry("tag", "value")))));
}
@Test
void testNanoPrecision() {
Timer timer = Timer.builder("testNanoTimer").register(Metrics.globalRegistry);
timer.record(1_234_000, TimeUnit.NANOSECONDS);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testNanoTimer")
.hasUnit("ms")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(1.234)
.hasCount(1)
.hasAttributes(Attributes.empty()))),
metric ->
assertThat(metric)
.hasName("testNanoTimer.max")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point -> point.hasValue(1.234).hasAttributes(Attributes.empty()))));
}
@Test
void testMicrometerHistogram() {
// given
Timer timer =
Timer.builder("testTimer")
.description("This is a test timer")
.tags("tag", "value")
.serviceLevelObjectives(
Duration.ofSeconds(1),
Duration.ofSeconds(10),
Duration.ofSeconds(100),
Duration.ofSeconds(1000))
.distributionStatisticBufferLength(10)
.register(Metrics.globalRegistry);
timer.record(500, TimeUnit.MILLISECONDS);
timer.record(5, TimeUnit.SECONDS);
timer.record(50, TimeUnit.SECONDS);
timer.record(500, TimeUnit.SECONDS);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testTimer")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test timer")
.hasUnit("ms")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(555500)
.hasCount(4)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testTimer.max")
.hasDescription("This is a test timer")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(500000)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testTimer.histogram")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(1)
.hasAttributes(
attributeEntry("le", "1000"),
attributeEntry("tag", "value")),
point ->
point
.hasValue(2)
.hasAttributes(
attributeEntry("le", "10000"),
attributeEntry("tag", "value")),
point ->
point
.hasValue(3)
.hasAttributes(
attributeEntry("le", "100000"),
attributeEntry("tag", "value")),
point ->
point
.hasValue(4)
.hasAttributes(
attributeEntry("le", "1000000"),
attributeEntry("tag", "value")))));
}
@Test
void testMicrometerPercentiles() {
// given
Timer timer =
Timer.builder("testTimer")
.description("This is a test timer")
.tags("tag", "value")
.publishPercentiles(0.5, 0.95, 0.99)
.register(Metrics.globalRegistry);
timer.record(50, TimeUnit.MILLISECONDS);
timer.record(100, TimeUnit.MILLISECONDS);
assertThat(testing.collectAllMetrics())
.satisfiesExactlyInAnyOrder(
metric ->
assertThat(metric)
.hasName("testTimer")
.hasInstrumentationScope(InstrumentationScopeInfo.create(INSTRUMENTATION_NAME))
.hasDescription("This is a test timer")
.hasUnit("ms")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasSum(150)
.hasCount(2)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testTimer.max")
.hasDescription("This is a test timer")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point
.hasValue(100)
.hasAttributes(attributeEntry("tag", "value")))),
metric ->
assertThat(metric)
.hasName("testTimer.percentile")
.hasDoubleGaugeSatisfying(
gauge ->
gauge.hasPointsSatisfying(
point ->
point.hasAttributes(
attributeEntry("phi", "0.5"),
attributeEntry("tag", "value")),
point ->
point.hasAttributes(
attributeEntry("phi", "0.95"),
attributeEntry("tag", "value")),
point ->
point.hasAttributes(
attributeEntry("phi", "0.99"),
attributeEntry("tag", "value")))));
}
}

View File

@ -47,7 +47,6 @@ include(":exporters:zipkin")
include(":integration-tests")
include(":integration-tests:otlp")
include(":integration-tests:tracecontext")
include(":micrometer1-shim")
include(":opencensus-shim")
include(":opentracing-shim")
include(":perf-harness")