Change the way Micrometer LongTaskTimer is bridged
MODIFY
instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/AsyncInstrumentRegistry.java
instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/AsyncInstrumentRegistry.java
@@ -64,6 +64,8 @@ public final class AsyncInstrumentRegistry {
private final Map<String, LongMeasurementsRecorder> longCounters = new ConcurrentHashMap<>();
private final Map<String, DoubleMeasurementsRecorder> upDownDoubleCounters =
new ConcurrentHashMap<>();
+ private final Map<String, LongMeasurementsRecorder> upDownLongCounters =
+ new ConcurrentHashMap<>();
AsyncInstrumentRegistry(Meter meter) {
this.meter = new WeakReference<>(meter);
@@ -150,7 +152,7 @@ public final class AsyncInstrumentRegistry {
String description,
String baseUnit,
Attributes attributes,
- T obj,
+ @Nullable T obj,
ToDoubleFunction<T> objMetric) {
DoubleMeasurementsRecorder recorder =
@@ -171,6 +173,31 @@ public final class AsyncInstrumentRegistry {
return new AsyncMeasurementHandle(recorder, attributes);
}
+ public <T> AsyncMeasurementHandle buildUpDownLongCounter(
+ String name,
+ String description,
+ String baseUnit,
+ Attributes attributes,
+ @Nullable T obj,
+ ToLongFunction<T> objMetric) {
+
+ LongMeasurementsRecorder recorder =
+ upDownLongCounters.computeIfAbsent(
+ name,
+ n -> {
+ LongMeasurementsRecorder recorderCallback = new LongMeasurementsRecorder();
+ otelMeter()
+ .upDownCounterBuilder(name)
+ .setDescription(description)
+ .setUnit(baseUnit)
+ .buildWithCallback(recorderCallback);
+ return recorderCallback;
+ });
+ recorder.addMeasurement(attributes, new LongMeasurementSource<>(obj, objMetric));
+
+ return new AsyncMeasurementHandle(recorder, attributes);
+ }
+
private Meter otelMeter() {
Meter otelMeter = meter.get();
if (otelMeter == null) {

MODIFY
instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/Bridging.java
instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/Bridging.java
@@ -33,11 +33,7 @@ final class Bridging {
}
static String name(Meter.Id id, NamingConvention namingConvention) {
- return name(id.getName(), id, namingConvention);
- }
-
- private static String name(String name, Meter.Id id, NamingConvention namingConvention) {
- return namingConvention.name(name, id.getType(), id.getBaseUnit());
+ return namingConvention.name(id.getName(), id.getType(), id.getBaseUnit());
}
static String description(Meter.Id id) {
@@ -56,7 +52,7 @@ final class Bridging {
// use "total_time" instead of "total" to avoid clashing with Statistic.TOTAL
String statisticStr =
statistic == Statistic.TOTAL_TIME ? "total_time" : statistic.getTagValueRepresentation();
- return name(prefix + statisticStr, id, namingConvention);
+ return namingConvention.name(prefix + statisticStr, id.getType(), id.getBaseUnit());
}
private Bridging() {}

MODIFY
instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryDistributionSummary.java
instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryDistributionSummary.java
@@ -8,14 +8,12 @@ package io.opentelemetry.instrumentation.micrometer.v1_5;
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.baseUnit;
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.description;
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.name;
-import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.statisticInstrumentName;
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.tagsAsAttributes;
import io.micrometer.core.instrument.AbstractDistributionSummary;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.Measurement;
-import io.micrometer.core.instrument.Statistic;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
import io.micrometer.core.instrument.distribution.NoopHistogram;
@@ -59,15 +57,17 @@ final class OpenTelemetryDistributionSummary extends AbstractDistributionSummary
max = new TimeWindowMax(clock, distributionStatisticConfig);
this.attributes = tagsAsAttributes(id, namingConvention);
+
+ String conventionName = name(id, namingConvention);
this.otelHistogram =
otelMeter
- .histogramBuilder(name(id, namingConvention))
+ .histogramBuilder(conventionName)
.setDescription(description(id))
.setUnit(baseUnit(id))
.build();
this.maxHandle =
asyncInstrumentRegistry.buildGauge(
- statisticInstrumentName(id, Statistic.MAX, namingConvention),
+ conventionName + ".max",
description(id),
baseUnit(id),
attributes,

MODIFY
instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryFunctionTimer.java
instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryFunctionTimer.java
package io.opentelemetry.instrumentation.micrometer.v1_5;
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.description;
-import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.statisticInstrumentName;
+import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.name;
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.tagsAsAttributes;
import static io.opentelemetry.instrumentation.micrometer.v1_5.TimeUnitHelper.getUnitString;
import io.micrometer.core.instrument.FunctionTimer;
import io.micrometer.core.instrument.Measurement;
-import io.micrometer.core.instrument.Statistic;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.instrument.util.MeterEquivalence;
import io.micrometer.core.instrument.util.TimeUtils;
@@ -46,8 +45,8 @@ final class OpenTelemetryFunctionTimer<T> implements FunctionTimer, RemovableMet
this.id = id;
this.baseTimeUnit = baseTimeUnit;
- String countMeterName = statisticInstrumentName(id, Statistic.COUNT, namingConvention);
- String totalTimeMeterName = statisticInstrumentName(id, Statistic.TOTAL_TIME, namingConvention);
+ String countMeterName = name(id, namingConvention) + ".count";
+ String totalTimeMeterName = name(id, namingConvention) + ".sum";
Attributes attributes = tagsAsAttributes(id, namingConvention);
countMeasurementHandle =

MODIFY
instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryLongTaskTimer.java
instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryLongTaskTimer.java
@@ -7,34 +7,25 @@ package io.opentelemetry.instrumentation.micrometer.v1_5;
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.description;
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.name;
-import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.statisticInstrumentName;
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.tagsAsAttributes;
import static io.opentelemetry.instrumentation.micrometer.v1_5.TimeUnitHelper.getUnitString;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.Measurement;
-import io.micrometer.core.instrument.Statistic;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
import io.micrometer.core.instrument.internal.DefaultLongTaskTimer;
-import io.micrometer.core.instrument.util.TimeUtils;
import io.opentelemetry.api.common.Attributes;
-import io.opentelemetry.api.metrics.DoubleHistogram;
-import io.opentelemetry.api.metrics.LongUpDownCounter;
-import io.opentelemetry.api.metrics.Meter;
+import io.opentelemetry.instrumentation.api.internal.AsyncInstrumentRegistry;
+import io.opentelemetry.instrumentation.api.internal.AsyncInstrumentRegistry.AsyncMeasurementHandle;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
final class OpenTelemetryLongTaskTimer extends DefaultLongTaskTimer implements RemovableMeter {
- private final TimeUnit baseTimeUnit;
private final DistributionStatisticConfig distributionStatisticConfig;
- // TODO: use bound instruments when they're available
- private final DoubleHistogram otelHistogram;
- private final LongUpDownCounter otelActiveTasksCounter;
- private final Attributes attributes;
-
- private volatile boolean removed = false;
+ private final AsyncMeasurementHandle activeTasksHandle;
+ private final AsyncMeasurementHandle durationHandle;
OpenTelemetryLongTaskTimer(
Id id,
@@ -42,37 +33,29 @@ final class OpenTelemetryLongTaskTimer extends DefaultLongTaskTimer implements R
Clock clock,
TimeUnit baseTimeUnit,
DistributionStatisticConfig distributionStatisticConfig,
- Meter otelMeter) {
+ AsyncInstrumentRegistry asyncInstrumentRegistry) {
super(id, clock, baseTimeUnit, distributionStatisticConfig, false);
- this.baseTimeUnit = baseTimeUnit;
this.distributionStatisticConfig = distributionStatisticConfig;
- this.otelHistogram =
- otelMeter
- .histogramBuilder(name(id, namingConvention))
- .setDescription(description(id))
- .setUnit(getUnitString(baseTimeUnit))
- .build();
- this.otelActiveTasksCounter =
- otelMeter
- .upDownCounterBuilder(
- statisticInstrumentName(id, Statistic.ACTIVE_TASKS, namingConvention))
- .setDescription(description(id))
- .setUnit("tasks")
- .build();
- this.attributes = tagsAsAttributes(id, namingConvention);
- }
-
- @Override
- public Sample start() {
- Sample original = super.start();
- if (removed) {
- return original;
- }
-
- otelActiveTasksCounter.add(1, attributes);
- return new OpenTelemetrySample(original);
+ String conventionName = name(id, namingConvention);
+ Attributes attributes = tagsAsAttributes(id, namingConvention);
+ this.activeTasksHandle =
+ asyncInstrumentRegistry.buildUpDownLongCounter(
+ conventionName + ".active",
+ description(id),
+ "tasks",
+ attributes,
+ this,
+ DefaultLongTaskTimer::activeTasks);
+ this.durationHandle =
+ asyncInstrumentRegistry.buildUpDownDoubleCounter(
+ conventionName + ".duration",
+ description(id),
+ getUnitString(baseTimeUnit),
+ attributes,
+ this,
+ t -> t.duration(baseTimeUnit));
}
@Override
@@ -83,41 +66,12 @@ final class OpenTelemetryLongTaskTimer extends DefaultLongTaskTimer implements R
@Override
public void onRemove() {
- removed = true;
+ activeTasksHandle.remove();
+ durationHandle.remove();
}
boolean isUsingMicrometerHistograms() {
return distributionStatisticConfig.isPublishingPercentiles()
|| distributionStatisticConfig.isPublishingHistogram();
}
-
- private final class OpenTelemetrySample extends Sample {
-
- private final Sample original;
- private volatile boolean stopped = false;
-
- private OpenTelemetrySample(Sample original) {
- this.original = original;
- }
-
- @Override
- public long stop() {
- if (stopped) {
- return -1;
- }
- stopped = true;
- long durationNanos = original.stop();
- if (!removed) {
- otelActiveTasksCounter.add(-1, attributes);
- double time = TimeUtils.nanosToUnit(durationNanos, baseTimeUnit);
- otelHistogram.record(time, attributes);
- }
- return durationNanos;
- }
-
- @Override
- public double duration(TimeUnit unit) {
- return stopped ? -1 : original.duration(unit);
- }
- }
}

MODIFY
instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryMeterRegistry.java
instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryMeterRegistry.java
@@ -87,7 +87,7 @@ public final class OpenTelemetryMeterRegistry extends MeterRegistry {
clock,
getBaseTimeUnit(),
distributionStatisticConfig,
- otelMeter);
+ asyncInstrumentRegistry);
if (timer.isUsingMicrometerHistograms()) {
HistogramGauges.registerWithCommonFormat(timer, this);
}

MODIFY
instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryTimer.java
instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryTimer.java
@@ -7,14 +7,12 @@ package io.opentelemetry.instrumentation.micrometer.v1_5;
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.description;
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.name;
-import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.statisticInstrumentName;
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.tagsAsAttributes;
import static io.opentelemetry.instrumentation.micrometer.v1_5.TimeUnitHelper.getUnitString;
import io.micrometer.core.instrument.AbstractTimer;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.Measurement;
-import io.micrometer.core.instrument.Statistic;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
import io.micrometer.core.instrument.distribution.NoopHistogram;
@@ -62,15 +60,17 @@ final class OpenTelemetryTimer extends AbstractTimer implements RemovableMeter {
this.baseTimeUnit = baseTimeUnit;
this.attributes = tagsAsAttributes(id, namingConvention);
+
+ String conventionName = name(id, namingConvention);
this.otelHistogram =
otelMeter
- .histogramBuilder(name(id, namingConvention))
+ .histogramBuilder(conventionName)
.setDescription(description(id))
.setUnit(getUnitString(baseTimeUnit))
.build();
this.maxHandle =
asyncInstrumentRegistry.buildGauge(
- statisticInstrumentName(id, Statistic.MAX, namingConvention),
+ conventionName + ".max",
description(id),
getUnitString(baseTimeUnit),
attributes,

MODIFY
instrumentation/micrometer/micrometer-1.5/library/src/test/java/io/opentelemetry/instrumentation/micrometer/v1_5/NamingConventionTest.java
instrumentation/micrometer/micrometer-1.5/library/src/test/java/io/opentelemetry/instrumentation/micrometer/v1_5/NamingConventionTest.java
@@ -10,6 +10,7 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attri
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;
@@ -178,7 +179,7 @@ class NamingConventionTest {
.containsOnly(attributeEntry("test.tag", "test.value")))));
testing.waitAndAssertMetrics(
INSTRUMENTATION_NAME,
- "test.renamedFunctionTimer.total_time",
+ "test.renamedFunctionTimer.sum",
metrics ->
metrics.anySatisfy(
metric ->
@@ -214,6 +215,43 @@ class NamingConventionTest {
.containsOnly(attributeEntry("test.tag", "test.value")))));
}
+ @Test
+ void renameLongTaskTimer() {
+ // when
+ LongTaskTimer timer = Metrics.more().longTaskTimer("renamedLongTaskTimer", "tag", "value");
+ timer.start().stop();
+
+ // then
+ testing.waitAndAssertMetrics(
+ INSTRUMENTATION_NAME,
+ "test.renamedLongTaskTimer.active",
+ metrics ->
+ metrics.anySatisfy(
+ metric ->
+ assertThat(metric)
+ .hasLongSum()
+ .points()
+ .satisfiesExactly(
+ point ->
+ assertThat(point)
+ .attributes()
+ .containsOnly(attributeEntry("test.tag", "test.value")))));
+ testing.waitAndAssertMetrics(
+ INSTRUMENTATION_NAME,
+ "test.renamedLongTaskTimer.duration",
+ metrics ->
+ metrics.anySatisfy(
+ metric ->
+ assertThat(metric)
+ .hasDoubleSum()
+ .points()
+ .satisfiesExactly(
+ point ->
+ assertThat(point)
+ .attributes()
+ .containsOnly(attributeEntry("test.tag", "test.value")))));
+ }
+
@Test
void renameTimer() {
// when

MODIFY
instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractFunctionTimerSecondsTest.java
instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractFunctionTimerSecondsTest.java
@@ -31,7 +31,7 @@ public abstract class AbstractFunctionTimerSecondsTest {
}
@Test
- void testFunctionCounterWithBaseUnitSeconds() throws InterruptedException {
+ void testFunctionTimerWithBaseUnitSeconds() throws InterruptedException {
// given
FunctionTimer functionTimer =
FunctionTimer.builder(
@@ -70,7 +70,7 @@ public abstract class AbstractFunctionTimerSecondsTest {
testing()
.waitAndAssertMetrics(
INSTRUMENTATION_NAME,
- "testFunctionTimerSeconds.total_time",
+ "testFunctionTimerSeconds.sum",
metrics ->
metrics.anySatisfy(
metric ->
@@ -100,8 +100,6 @@ public abstract class AbstractFunctionTimerSecondsTest {
AbstractIterableAssert::isEmpty);
testing()
.waitAndAssertMetrics(
- INSTRUMENTATION_NAME,
- "testFunctionTimerSeconds.total_time",
- AbstractIterableAssert::isEmpty);
+ INSTRUMENTATION_NAME, "testFunctionTimerSeconds.sum", AbstractIterableAssert::isEmpty);
}
}

MODIFY
instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractFunctionTimerTest.java
instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractFunctionTimerTest.java
@@ -72,7 +72,7 @@ public abstract class AbstractFunctionTimerTest {
testing()
.waitAndAssertMetrics(
INSTRUMENTATION_NAME,
- "testFunctionTimer.total_time",
+ "testFunctionTimer.sum",
metrics ->
metrics.anySatisfy(
metric ->
@@ -100,7 +100,7 @@ public abstract class AbstractFunctionTimerTest {
INSTRUMENTATION_NAME, "testFunctionTimer.count", AbstractIterableAssert::isEmpty);
testing()
.waitAndAssertMetrics(
- INSTRUMENTATION_NAME, "testFunctionTimer.total_time", AbstractIterableAssert::isEmpty);
+ INSTRUMENTATION_NAME, "testFunctionTimer.sum", AbstractIterableAssert::isEmpty);
}
@Test
@@ -121,7 +121,7 @@ public abstract class AbstractFunctionTimerTest {
testing()
.waitAndAssertMetrics(
INSTRUMENTATION_NAME,
- "testNanoFunctionTimer.total_time",
+ "testNanoFunctionTimer.sum",
metrics ->
metrics.anySatisfy(
metric ->
@@ -162,7 +162,7 @@ public abstract class AbstractFunctionTimerTest {
testing()
.waitAndAssertMetrics(
INSTRUMENTATION_NAME,
- "testFunctionTimerWithTags.total_time",
+ "testFunctionTimerWithTags.sum",
metrics ->
metrics.anySatisfy(
metric ->

MODIFY
instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractLongTaskTimerSecondsTest.java
instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractLongTaskTimerSecondsTest.java
@@ -12,6 +12,7 @@ import io.micrometer.core.instrument.LongTaskTimer;
import io.micrometer.core.instrument.Metrics;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import java.util.concurrent.TimeUnit;
+import org.assertj.core.api.AbstractIterableAssert;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -58,31 +59,33 @@ public abstract class AbstractLongTaskTimerSecondsTest {
.hasValue(1)
.attributes()
.containsOnly(attributeEntry("tag", "value")))));
-
- // when
- TimeUnit.MILLISECONDS.sleep(100);
- sample.stop();
-
- // then
testing()
.waitAndAssertMetrics(
INSTRUMENTATION_NAME,
- "testLongTaskTimerSeconds",
+ "testLongTaskTimerSeconds.duration",
metrics ->
metrics.anySatisfy(
metric ->
assertThat(metric)
.hasDescription("This is a test long task timer")
.hasUnit("s")
- .hasDoubleHistogram()
+ .hasDoubleSum()
+ .isNotMonotonic()
.points()
.satisfiesExactly(
- point ->
+ point -> {
assertThat(point)
- .hasSumGreaterThan(0.1)
- .hasCount(1)
.attributes()
- .containsOnly(attributeEntry("tag", "value")))));
+ .containsOnly(attributeEntry("tag", "value"));
+ // any value >0 - duration of currently running tasks
+ assertThat(point.getValue()).isPositive();
+ })));
+
+ // when
+ TimeUnit.MILLISECONDS.sleep(100);
+ sample.stop();
+
+ // then
testing()
.waitAndAssertMetrics(
INSTRUMENTATION_NAME,
@@ -99,22 +102,15 @@ public abstract class AbstractLongTaskTimerSecondsTest {
.hasValue(0)
.attributes()
.containsOnly(attributeEntry("tag", "value")))));
- testing().clearData();
-
- // when timer is removed from the registry
- Metrics.globalRegistry.remove(timer);
- sample = timer.start();
-
- // then no tasks are active after starting a new sample
testing()
.waitAndAssertMetrics(
INSTRUMENTATION_NAME,
- "testLongTaskTimerSeconds.active",
+ "testLongTaskTimerSeconds.duration",
metrics ->
metrics.anySatisfy(
metric ->
assertThat(metric)
- .hasLongSum()
+ .hasDoubleSum()
.points()
.satisfiesExactly(
point ->
@@ -122,23 +118,22 @@ public abstract class AbstractLongTaskTimerSecondsTest {
.hasValue(0)
.attributes()
.containsOnly(attributeEntry("tag", "value")))));
+ testing().clearData();
- // when
- TimeUnit.MILLISECONDS.sleep(100);
- sample.stop();
+ // when timer is removed from the registry
+ Metrics.globalRegistry.remove(timer);
+ timer.start();
- // then sample of a removed timer does not record any data
+ // then no tasks are active after starting a new sample
testing()
.waitAndAssertMetrics(
INSTRUMENTATION_NAME,
- "testLongTaskTimerSeconds",
- metrics ->
- metrics.allSatisfy(
- metric ->
- assertThat(metric)
- .hasDoubleHistogram()
- .points()
- .noneSatisfy(
- point -> assertThat(point).hasSumGreaterThan(0.2).hasCount(2))));
+ "testLongTaskTimerSeconds.active",
+ AbstractIterableAssert::isEmpty);
+ testing()
+ .waitAndAssertMetrics(
+ INSTRUMENTATION_NAME,
+ "testLongTaskTimerSeconds.duration",
+ AbstractIterableAssert::isEmpty);
}
}

MODIFY
instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractLongTaskTimerTest.java
instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractLongTaskTimerTest.java
@@ -12,6 +12,7 @@ import io.micrometer.core.instrument.LongTaskTimer;
import io.micrometer.core.instrument.Metrics;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import java.util.concurrent.TimeUnit;
+import org.assertj.core.api.AbstractIterableAssert;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -58,31 +59,33 @@ public abstract class AbstractLongTaskTimerTest {
.hasValue(1)
.attributes()
.containsOnly(attributeEntry("tag", "value")))));
-
- // when
- TimeUnit.MILLISECONDS.sleep(100);
- sample.stop();
-
- // then
testing()
.waitAndAssertMetrics(
INSTRUMENTATION_NAME,
- "testLongTaskTimer",
+ "testLongTaskTimer.duration",
metrics ->
metrics.anySatisfy(
metric ->
assertThat(metric)
.hasDescription("This is a test long task timer")
.hasUnit("ms")
- .hasDoubleHistogram()
+ .hasDoubleSum()
+ .isNotMonotonic()
.points()
.satisfiesExactly(
- point ->
+ point -> {
assertThat(point)
- .hasSumGreaterThan(100)
- .hasCount(1)
.attributes()
- .containsOnly(attributeEntry("tag", "value")))));
+ .containsOnly(attributeEntry("tag", "value"));
+ // any value >0 - duration of currently running tasks
+ assertThat(point.getValue()).isPositive();
+ })));
+
+ // when
+ TimeUnit.MILLISECONDS.sleep(100);
+ sample.stop();
+
+ // then
testing()
.waitAndAssertMetrics(
INSTRUMENTATION_NAME,
@@ -99,22 +102,15 @@ public abstract class AbstractLongTaskTimerTest {
.hasValue(0)
.attributes()
.containsOnly(attributeEntry("tag", "value")))));
- testing().clearData();
-
- // when timer is removed from the registry
- Metrics.globalRegistry.remove(timer);
- sample = timer.start();
-
- // then no tasks are active after starting a new sample
testing()
.waitAndAssertMetrics(
INSTRUMENTATION_NAME,
- "testLongTaskTimer.active",
+ "testLongTaskTimer.duration",
metrics ->
metrics.anySatisfy(
metric ->
assertThat(metric)
- .hasLongSum()
+ .hasDoubleSum()
.points()
.satisfiesExactly(
point ->
@@ -122,53 +118,18 @@ public abstract class AbstractLongTaskTimerTest {
.hasValue(0)
.attributes()
.containsOnly(attributeEntry("tag", "value")))));
+ testing().clearData();
- // when
- TimeUnit.MILLISECONDS.sleep(100);
- sample.stop();
+ // when timer is removed from the registry
+ Metrics.globalRegistry.remove(timer);
+ timer.start();
- // then sample of a removed timer does not record any data
+ // then no tasks are active after starting a new sample
testing()
.waitAndAssertMetrics(
- INSTRUMENTATION_NAME,
- "testLongTaskTimer",
- metrics ->
- metrics.allSatisfy(
- metric ->
- assertThat(metric)
- .hasDoubleHistogram()
- .points()
- .noneSatisfy(
- point -> assertThat(point).hasSumGreaterThan(200).hasCount(2))));
- }
-
- @Test
- void testMultipleSampleStopCalls() throws InterruptedException {
- // given
- LongTaskTimer timer =
- LongTaskTimer.builder("testLongTaskTimerSampleStop").register(Metrics.globalRegistry);
-
- // when stop() is called multiple times
- LongTaskTimer.Sample sample = timer.start();
-
- TimeUnit.MILLISECONDS.sleep(100);
-
- sample.stop();
- sample.stop();
- sample.stop();
-
- // then only the first time is recorded
+ INSTRUMENTATION_NAME, "testLongTaskTimer.active", AbstractIterableAssert::isEmpty);
testing()
.waitAndAssertMetrics(
- INSTRUMENTATION_NAME,
- "testLongTaskTimerSampleStop",
- metrics ->
- metrics.allSatisfy(
- metric ->
- assertThat(metric)
- .hasDoubleHistogram()
- .points()
- .satisfiesExactly(
- point -> assertThat(point).hasSumGreaterThan(100).hasCount(1))));
+ INSTRUMENTATION_NAME, "testLongTaskTimer.duration", AbstractIterableAssert::isEmpty);
}
}

Change the way Micrometer LongTaskTimer is bridged (#5338)