diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/AsyncInstrumentRegistry.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/AsyncInstrumentRegistry.java index 65c6aae0b6..cc99ca42a6 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/AsyncInstrumentRegistry.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/AsyncInstrumentRegistry.java @@ -64,6 +64,8 @@ public final class AsyncInstrumentRegistry { private final Map longCounters = new ConcurrentHashMap<>(); private final Map upDownDoubleCounters = new ConcurrentHashMap<>(); + private final Map 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 objMetric) { DoubleMeasurementsRecorder recorder = @@ -171,6 +173,31 @@ public final class AsyncInstrumentRegistry { return new AsyncMeasurementHandle(recorder, attributes); } + public AsyncMeasurementHandle buildUpDownLongCounter( + String name, + String description, + String baseUnit, + Attributes attributes, + @Nullable T obj, + ToLongFunction 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) { diff --git a/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/Bridging.java b/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/Bridging.java index b6292385d3..90e1465e2d 100644 --- a/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/Bridging.java +++ b/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() {} diff --git a/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryDistributionSummary.java b/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryDistributionSummary.java index aa0c4d869c..dd63c0103c 100644 --- a/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryDistributionSummary.java +++ b/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, diff --git a/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryFunctionTimer.java b/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryFunctionTimer.java index fd7f352468..3bec29f495 100644 --- a/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryFunctionTimer.java +++ b/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryFunctionTimer.java @@ -6,13 +6,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.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 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 = diff --git a/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryLongTaskTimer.java b/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryLongTaskTimer.java index e8fd8f0fb7..6ab2aec665 100644 --- a/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryLongTaskTimer.java +++ b/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); - } - } } diff --git a/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryMeterRegistry.java b/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryMeterRegistry.java index fb0c3570b8..5fdb3d7994 100644 --- a/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryMeterRegistry.java +++ b/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); } diff --git a/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryTimer.java b/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryTimer.java index d4596a1a21..e7538853a6 100644 --- a/instrumentation/micrometer/micrometer-1.5/library/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/OpenTelemetryTimer.java +++ b/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, diff --git a/instrumentation/micrometer/micrometer-1.5/library/src/test/java/io/opentelemetry/instrumentation/micrometer/v1_5/NamingConventionTest.java b/instrumentation/micrometer/micrometer-1.5/library/src/test/java/io/opentelemetry/instrumentation/micrometer/v1_5/NamingConventionTest.java index 603d180dc0..85d82f79ef 100644 --- a/instrumentation/micrometer/micrometer-1.5/library/src/test/java/io/opentelemetry/instrumentation/micrometer/v1_5/NamingConventionTest.java +++ b/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 diff --git a/instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractFunctionTimerSecondsTest.java b/instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractFunctionTimerSecondsTest.java index 86f9f5bfa1..9093ee539a 100644 --- a/instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractFunctionTimerSecondsTest.java +++ b/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); } } diff --git a/instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractFunctionTimerTest.java b/instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractFunctionTimerTest.java index 5c44e86396..9ff79c802c 100644 --- a/instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractFunctionTimerTest.java +++ b/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 -> diff --git a/instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractLongTaskTimerSecondsTest.java b/instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractLongTaskTimerSecondsTest.java index 658de0ab2e..43d8ecd279 100644 --- a/instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractLongTaskTimerSecondsTest.java +++ b/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"))))); + testing() + .waitAndAssertMetrics( + INSTRUMENTATION_NAME, + "testLongTaskTimerSeconds.duration", + metrics -> + metrics.anySatisfy( + metric -> + assertThat(metric) + .hasDescription("This is a test long task timer") + .hasUnit("s") + .hasDoubleSum() + .isNotMonotonic() + .points() + .satisfiesExactly( + point -> { + assertThat(point) + .attributes() + .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, - "testLongTaskTimerSeconds", - metrics -> - metrics.anySatisfy( - metric -> - assertThat(metric) - .hasDescription("This is a test long task timer") - .hasUnit("s") - .hasDoubleHistogram() - .points() - .satisfiesExactly( - point -> - assertThat(point) - .hasSumGreaterThan(0.1) - .hasCount(1) - .attributes() - .containsOnly(attributeEntry("tag", "value"))))); testing() .waitAndAssertMetrics( INSTRUMENTATION_NAME, @@ -99,46 +102,38 @@ public abstract class AbstractLongTaskTimerSecondsTest { .hasValue(0) .attributes() .containsOnly(attributeEntry("tag", "value"))))); + testing() + .waitAndAssertMetrics( + INSTRUMENTATION_NAME, + "testLongTaskTimerSeconds.duration", + metrics -> + metrics.anySatisfy( + metric -> + assertThat(metric) + .hasDoubleSum() + .points() + .satisfiesExactly( + point -> + assertThat(point) + .hasValue(0) + .attributes() + .containsOnly(attributeEntry("tag", "value"))))); testing().clearData(); // when timer is removed from the registry Metrics.globalRegistry.remove(timer); - sample = timer.start(); + timer.start(); // then no tasks are active after starting a new sample testing() .waitAndAssertMetrics( INSTRUMENTATION_NAME, "testLongTaskTimerSeconds.active", - metrics -> - metrics.anySatisfy( - metric -> - assertThat(metric) - .hasLongSum() - .points() - .satisfiesExactly( - point -> - assertThat(point) - .hasValue(0) - .attributes() - .containsOnly(attributeEntry("tag", "value"))))); - - // when - TimeUnit.MILLISECONDS.sleep(100); - sample.stop(); - - // then sample of a removed timer does not record any data + AbstractIterableAssert::isEmpty); testing() .waitAndAssertMetrics( INSTRUMENTATION_NAME, - "testLongTaskTimerSeconds", - metrics -> - metrics.allSatisfy( - metric -> - assertThat(metric) - .hasDoubleHistogram() - .points() - .noneSatisfy( - point -> assertThat(point).hasSumGreaterThan(0.2).hasCount(2)))); + "testLongTaskTimerSeconds.duration", + AbstractIterableAssert::isEmpty); } } diff --git a/instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractLongTaskTimerTest.java b/instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractLongTaskTimerTest.java index b01ab4f554..d35778091e 100644 --- a/instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractLongTaskTimerTest.java +++ b/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"))))); + testing() + .waitAndAssertMetrics( + INSTRUMENTATION_NAME, + "testLongTaskTimer.duration", + metrics -> + metrics.anySatisfy( + metric -> + assertThat(metric) + .hasDescription("This is a test long task timer") + .hasUnit("ms") + .hasDoubleSum() + .isNotMonotonic() + .points() + .satisfiesExactly( + point -> { + assertThat(point) + .attributes() + .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, - "testLongTaskTimer", - metrics -> - metrics.anySatisfy( - metric -> - assertThat(metric) - .hasDescription("This is a test long task timer") - .hasUnit("ms") - .hasDoubleHistogram() - .points() - .satisfiesExactly( - point -> - assertThat(point) - .hasSumGreaterThan(100) - .hasCount(1) - .attributes() - .containsOnly(attributeEntry("tag", "value"))))); testing() .waitAndAssertMetrics( INSTRUMENTATION_NAME, @@ -99,76 +102,34 @@ public abstract class AbstractLongTaskTimerTest { .hasValue(0) .attributes() .containsOnly(attributeEntry("tag", "value"))))); + testing() + .waitAndAssertMetrics( + INSTRUMENTATION_NAME, + "testLongTaskTimer.duration", + metrics -> + metrics.anySatisfy( + metric -> + assertThat(metric) + .hasDoubleSum() + .points() + .satisfiesExactly( + point -> + assertThat(point) + .hasValue(0) + .attributes() + .containsOnly(attributeEntry("tag", "value"))))); testing().clearData(); // when timer is removed from the registry Metrics.globalRegistry.remove(timer); - sample = timer.start(); + timer.start(); // then no tasks are active after starting a new sample testing() .waitAndAssertMetrics( - INSTRUMENTATION_NAME, - "testLongTaskTimer.active", - metrics -> - metrics.anySatisfy( - metric -> - assertThat(metric) - .hasLongSum() - .points() - .satisfiesExactly( - point -> - assertThat(point) - .hasValue(0) - .attributes() - .containsOnly(attributeEntry("tag", "value"))))); - - // when - TimeUnit.MILLISECONDS.sleep(100); - sample.stop(); - - // then sample of a removed timer does not record any data + INSTRUMENTATION_NAME, "testLongTaskTimer.active", AbstractIterableAssert::isEmpty); 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 - 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); } }