Change the way Micrometer LongTaskTimer is bridged (#5338)
This commit is contained in:
parent
cc60ffb6e0
commit
6774ce5791
|
@ -64,6 +64,8 @@ public final class AsyncInstrumentRegistry {
|
||||||
private final Map<String, LongMeasurementsRecorder> longCounters = new ConcurrentHashMap<>();
|
private final Map<String, LongMeasurementsRecorder> longCounters = new ConcurrentHashMap<>();
|
||||||
private final Map<String, DoubleMeasurementsRecorder> upDownDoubleCounters =
|
private final Map<String, DoubleMeasurementsRecorder> upDownDoubleCounters =
|
||||||
new ConcurrentHashMap<>();
|
new ConcurrentHashMap<>();
|
||||||
|
private final Map<String, LongMeasurementsRecorder> upDownLongCounters =
|
||||||
|
new ConcurrentHashMap<>();
|
||||||
|
|
||||||
AsyncInstrumentRegistry(Meter meter) {
|
AsyncInstrumentRegistry(Meter meter) {
|
||||||
this.meter = new WeakReference<>(meter);
|
this.meter = new WeakReference<>(meter);
|
||||||
|
@ -150,7 +152,7 @@ public final class AsyncInstrumentRegistry {
|
||||||
String description,
|
String description,
|
||||||
String baseUnit,
|
String baseUnit,
|
||||||
Attributes attributes,
|
Attributes attributes,
|
||||||
T obj,
|
@Nullable T obj,
|
||||||
ToDoubleFunction<T> objMetric) {
|
ToDoubleFunction<T> objMetric) {
|
||||||
|
|
||||||
DoubleMeasurementsRecorder recorder =
|
DoubleMeasurementsRecorder recorder =
|
||||||
|
@ -171,6 +173,31 @@ public final class AsyncInstrumentRegistry {
|
||||||
return new AsyncMeasurementHandle(recorder, attributes);
|
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() {
|
private Meter otelMeter() {
|
||||||
Meter otelMeter = meter.get();
|
Meter otelMeter = meter.get();
|
||||||
if (otelMeter == null) {
|
if (otelMeter == null) {
|
||||||
|
|
|
@ -33,11 +33,7 @@ final class Bridging {
|
||||||
}
|
}
|
||||||
|
|
||||||
static String name(Meter.Id id, NamingConvention namingConvention) {
|
static String name(Meter.Id id, NamingConvention namingConvention) {
|
||||||
return name(id.getName(), id, namingConvention);
|
return namingConvention.name(id.getName(), id.getType(), id.getBaseUnit());
|
||||||
}
|
|
||||||
|
|
||||||
private static String name(String name, Meter.Id id, NamingConvention namingConvention) {
|
|
||||||
return namingConvention.name(name, id.getType(), id.getBaseUnit());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static String description(Meter.Id id) {
|
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
|
// use "total_time" instead of "total" to avoid clashing with Statistic.TOTAL
|
||||||
String statisticStr =
|
String statisticStr =
|
||||||
statistic == Statistic.TOTAL_TIME ? "total_time" : statistic.getTagValueRepresentation();
|
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() {}
|
private Bridging() {}
|
||||||
|
|
|
@ -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.baseUnit;
|
||||||
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.description;
|
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.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.Bridging.tagsAsAttributes;
|
||||||
|
|
||||||
import io.micrometer.core.instrument.AbstractDistributionSummary;
|
import io.micrometer.core.instrument.AbstractDistributionSummary;
|
||||||
import io.micrometer.core.instrument.Clock;
|
import io.micrometer.core.instrument.Clock;
|
||||||
import io.micrometer.core.instrument.DistributionSummary;
|
import io.micrometer.core.instrument.DistributionSummary;
|
||||||
import io.micrometer.core.instrument.Measurement;
|
import io.micrometer.core.instrument.Measurement;
|
||||||
import io.micrometer.core.instrument.Statistic;
|
|
||||||
import io.micrometer.core.instrument.config.NamingConvention;
|
import io.micrometer.core.instrument.config.NamingConvention;
|
||||||
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
|
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
|
||||||
import io.micrometer.core.instrument.distribution.NoopHistogram;
|
import io.micrometer.core.instrument.distribution.NoopHistogram;
|
||||||
|
@ -59,15 +57,17 @@ final class OpenTelemetryDistributionSummary extends AbstractDistributionSummary
|
||||||
max = new TimeWindowMax(clock, distributionStatisticConfig);
|
max = new TimeWindowMax(clock, distributionStatisticConfig);
|
||||||
|
|
||||||
this.attributes = tagsAsAttributes(id, namingConvention);
|
this.attributes = tagsAsAttributes(id, namingConvention);
|
||||||
|
|
||||||
|
String conventionName = name(id, namingConvention);
|
||||||
this.otelHistogram =
|
this.otelHistogram =
|
||||||
otelMeter
|
otelMeter
|
||||||
.histogramBuilder(name(id, namingConvention))
|
.histogramBuilder(conventionName)
|
||||||
.setDescription(description(id))
|
.setDescription(description(id))
|
||||||
.setUnit(baseUnit(id))
|
.setUnit(baseUnit(id))
|
||||||
.build();
|
.build();
|
||||||
this.maxHandle =
|
this.maxHandle =
|
||||||
asyncInstrumentRegistry.buildGauge(
|
asyncInstrumentRegistry.buildGauge(
|
||||||
statisticInstrumentName(id, Statistic.MAX, namingConvention),
|
conventionName + ".max",
|
||||||
description(id),
|
description(id),
|
||||||
baseUnit(id),
|
baseUnit(id),
|
||||||
attributes,
|
attributes,
|
||||||
|
|
|
@ -6,13 +6,12 @@
|
||||||
package io.opentelemetry.instrumentation.micrometer.v1_5;
|
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.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.Bridging.tagsAsAttributes;
|
||||||
import static io.opentelemetry.instrumentation.micrometer.v1_5.TimeUnitHelper.getUnitString;
|
import static io.opentelemetry.instrumentation.micrometer.v1_5.TimeUnitHelper.getUnitString;
|
||||||
|
|
||||||
import io.micrometer.core.instrument.FunctionTimer;
|
import io.micrometer.core.instrument.FunctionTimer;
|
||||||
import io.micrometer.core.instrument.Measurement;
|
import io.micrometer.core.instrument.Measurement;
|
||||||
import io.micrometer.core.instrument.Statistic;
|
|
||||||
import io.micrometer.core.instrument.config.NamingConvention;
|
import io.micrometer.core.instrument.config.NamingConvention;
|
||||||
import io.micrometer.core.instrument.util.MeterEquivalence;
|
import io.micrometer.core.instrument.util.MeterEquivalence;
|
||||||
import io.micrometer.core.instrument.util.TimeUtils;
|
import io.micrometer.core.instrument.util.TimeUtils;
|
||||||
|
@ -46,8 +45,8 @@ final class OpenTelemetryFunctionTimer<T> implements FunctionTimer, RemovableMet
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.baseTimeUnit = baseTimeUnit;
|
this.baseTimeUnit = baseTimeUnit;
|
||||||
|
|
||||||
String countMeterName = statisticInstrumentName(id, Statistic.COUNT, namingConvention);
|
String countMeterName = name(id, namingConvention) + ".count";
|
||||||
String totalTimeMeterName = statisticInstrumentName(id, Statistic.TOTAL_TIME, namingConvention);
|
String totalTimeMeterName = name(id, namingConvention) + ".sum";
|
||||||
Attributes attributes = tagsAsAttributes(id, namingConvention);
|
Attributes attributes = tagsAsAttributes(id, namingConvention);
|
||||||
|
|
||||||
countMeasurementHandle =
|
countMeasurementHandle =
|
||||||
|
|
|
@ -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.description;
|
||||||
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.name;
|
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.Bridging.tagsAsAttributes;
|
||||||
import static io.opentelemetry.instrumentation.micrometer.v1_5.TimeUnitHelper.getUnitString;
|
import static io.opentelemetry.instrumentation.micrometer.v1_5.TimeUnitHelper.getUnitString;
|
||||||
|
|
||||||
import io.micrometer.core.instrument.Clock;
|
import io.micrometer.core.instrument.Clock;
|
||||||
import io.micrometer.core.instrument.Measurement;
|
import io.micrometer.core.instrument.Measurement;
|
||||||
import io.micrometer.core.instrument.Statistic;
|
|
||||||
import io.micrometer.core.instrument.config.NamingConvention;
|
import io.micrometer.core.instrument.config.NamingConvention;
|
||||||
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
|
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
|
||||||
import io.micrometer.core.instrument.internal.DefaultLongTaskTimer;
|
import io.micrometer.core.instrument.internal.DefaultLongTaskTimer;
|
||||||
import io.micrometer.core.instrument.util.TimeUtils;
|
|
||||||
import io.opentelemetry.api.common.Attributes;
|
import io.opentelemetry.api.common.Attributes;
|
||||||
import io.opentelemetry.api.metrics.DoubleHistogram;
|
import io.opentelemetry.instrumentation.api.internal.AsyncInstrumentRegistry;
|
||||||
import io.opentelemetry.api.metrics.LongUpDownCounter;
|
import io.opentelemetry.instrumentation.api.internal.AsyncInstrumentRegistry.AsyncMeasurementHandle;
|
||||||
import io.opentelemetry.api.metrics.Meter;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
final class OpenTelemetryLongTaskTimer extends DefaultLongTaskTimer implements RemovableMeter {
|
final class OpenTelemetryLongTaskTimer extends DefaultLongTaskTimer implements RemovableMeter {
|
||||||
|
|
||||||
private final TimeUnit baseTimeUnit;
|
|
||||||
private final DistributionStatisticConfig distributionStatisticConfig;
|
private final DistributionStatisticConfig distributionStatisticConfig;
|
||||||
// TODO: use bound instruments when they're available
|
private final AsyncMeasurementHandle activeTasksHandle;
|
||||||
private final DoubleHistogram otelHistogram;
|
private final AsyncMeasurementHandle durationHandle;
|
||||||
private final LongUpDownCounter otelActiveTasksCounter;
|
|
||||||
private final Attributes attributes;
|
|
||||||
|
|
||||||
private volatile boolean removed = false;
|
|
||||||
|
|
||||||
OpenTelemetryLongTaskTimer(
|
OpenTelemetryLongTaskTimer(
|
||||||
Id id,
|
Id id,
|
||||||
|
@ -42,37 +33,29 @@ final class OpenTelemetryLongTaskTimer extends DefaultLongTaskTimer implements R
|
||||||
Clock clock,
|
Clock clock,
|
||||||
TimeUnit baseTimeUnit,
|
TimeUnit baseTimeUnit,
|
||||||
DistributionStatisticConfig distributionStatisticConfig,
|
DistributionStatisticConfig distributionStatisticConfig,
|
||||||
Meter otelMeter) {
|
AsyncInstrumentRegistry asyncInstrumentRegistry) {
|
||||||
super(id, clock, baseTimeUnit, distributionStatisticConfig, false);
|
super(id, clock, baseTimeUnit, distributionStatisticConfig, false);
|
||||||
|
|
||||||
this.baseTimeUnit = baseTimeUnit;
|
|
||||||
this.distributionStatisticConfig = distributionStatisticConfig;
|
this.distributionStatisticConfig = distributionStatisticConfig;
|
||||||
|
|
||||||
this.otelHistogram =
|
String conventionName = name(id, namingConvention);
|
||||||
otelMeter
|
Attributes attributes = tagsAsAttributes(id, namingConvention);
|
||||||
.histogramBuilder(name(id, namingConvention))
|
this.activeTasksHandle =
|
||||||
.setDescription(description(id))
|
asyncInstrumentRegistry.buildUpDownLongCounter(
|
||||||
.setUnit(getUnitString(baseTimeUnit))
|
conventionName + ".active",
|
||||||
.build();
|
description(id),
|
||||||
this.otelActiveTasksCounter =
|
"tasks",
|
||||||
otelMeter
|
attributes,
|
||||||
.upDownCounterBuilder(
|
this,
|
||||||
statisticInstrumentName(id, Statistic.ACTIVE_TASKS, namingConvention))
|
DefaultLongTaskTimer::activeTasks);
|
||||||
.setDescription(description(id))
|
this.durationHandle =
|
||||||
.setUnit("tasks")
|
asyncInstrumentRegistry.buildUpDownDoubleCounter(
|
||||||
.build();
|
conventionName + ".duration",
|
||||||
this.attributes = tagsAsAttributes(id, namingConvention);
|
description(id),
|
||||||
}
|
getUnitString(baseTimeUnit),
|
||||||
|
attributes,
|
||||||
@Override
|
this,
|
||||||
public Sample start() {
|
t -> t.duration(baseTimeUnit));
|
||||||
Sample original = super.start();
|
|
||||||
if (removed) {
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
|
|
||||||
otelActiveTasksCounter.add(1, attributes);
|
|
||||||
return new OpenTelemetrySample(original);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -83,41 +66,12 @@ final class OpenTelemetryLongTaskTimer extends DefaultLongTaskTimer implements R
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRemove() {
|
public void onRemove() {
|
||||||
removed = true;
|
activeTasksHandle.remove();
|
||||||
|
durationHandle.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isUsingMicrometerHistograms() {
|
boolean isUsingMicrometerHistograms() {
|
||||||
return distributionStatisticConfig.isPublishingPercentiles()
|
return distributionStatisticConfig.isPublishingPercentiles()
|
||||||
|| distributionStatisticConfig.isPublishingHistogram();
|
|| 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ public final class OpenTelemetryMeterRegistry extends MeterRegistry {
|
||||||
clock,
|
clock,
|
||||||
getBaseTimeUnit(),
|
getBaseTimeUnit(),
|
||||||
distributionStatisticConfig,
|
distributionStatisticConfig,
|
||||||
otelMeter);
|
asyncInstrumentRegistry);
|
||||||
if (timer.isUsingMicrometerHistograms()) {
|
if (timer.isUsingMicrometerHistograms()) {
|
||||||
HistogramGauges.registerWithCommonFormat(timer, this);
|
HistogramGauges.registerWithCommonFormat(timer, this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.description;
|
||||||
import static io.opentelemetry.instrumentation.micrometer.v1_5.Bridging.name;
|
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.Bridging.tagsAsAttributes;
|
||||||
import static io.opentelemetry.instrumentation.micrometer.v1_5.TimeUnitHelper.getUnitString;
|
import static io.opentelemetry.instrumentation.micrometer.v1_5.TimeUnitHelper.getUnitString;
|
||||||
|
|
||||||
import io.micrometer.core.instrument.AbstractTimer;
|
import io.micrometer.core.instrument.AbstractTimer;
|
||||||
import io.micrometer.core.instrument.Clock;
|
import io.micrometer.core.instrument.Clock;
|
||||||
import io.micrometer.core.instrument.Measurement;
|
import io.micrometer.core.instrument.Measurement;
|
||||||
import io.micrometer.core.instrument.Statistic;
|
|
||||||
import io.micrometer.core.instrument.config.NamingConvention;
|
import io.micrometer.core.instrument.config.NamingConvention;
|
||||||
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
|
import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
|
||||||
import io.micrometer.core.instrument.distribution.NoopHistogram;
|
import io.micrometer.core.instrument.distribution.NoopHistogram;
|
||||||
|
@ -62,15 +60,17 @@ final class OpenTelemetryTimer extends AbstractTimer implements RemovableMeter {
|
||||||
|
|
||||||
this.baseTimeUnit = baseTimeUnit;
|
this.baseTimeUnit = baseTimeUnit;
|
||||||
this.attributes = tagsAsAttributes(id, namingConvention);
|
this.attributes = tagsAsAttributes(id, namingConvention);
|
||||||
|
|
||||||
|
String conventionName = name(id, namingConvention);
|
||||||
this.otelHistogram =
|
this.otelHistogram =
|
||||||
otelMeter
|
otelMeter
|
||||||
.histogramBuilder(name(id, namingConvention))
|
.histogramBuilder(conventionName)
|
||||||
.setDescription(description(id))
|
.setDescription(description(id))
|
||||||
.setUnit(getUnitString(baseTimeUnit))
|
.setUnit(getUnitString(baseTimeUnit))
|
||||||
.build();
|
.build();
|
||||||
this.maxHandle =
|
this.maxHandle =
|
||||||
asyncInstrumentRegistry.buildGauge(
|
asyncInstrumentRegistry.buildGauge(
|
||||||
statisticInstrumentName(id, Statistic.MAX, namingConvention),
|
conventionName + ".max",
|
||||||
description(id),
|
description(id),
|
||||||
getUnitString(baseTimeUnit),
|
getUnitString(baseTimeUnit),
|
||||||
attributes,
|
attributes,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attri
|
||||||
|
|
||||||
import io.micrometer.core.instrument.Counter;
|
import io.micrometer.core.instrument.Counter;
|
||||||
import io.micrometer.core.instrument.DistributionSummary;
|
import io.micrometer.core.instrument.DistributionSummary;
|
||||||
|
import io.micrometer.core.instrument.LongTaskTimer;
|
||||||
import io.micrometer.core.instrument.Meter;
|
import io.micrometer.core.instrument.Meter;
|
||||||
import io.micrometer.core.instrument.MeterRegistry;
|
import io.micrometer.core.instrument.MeterRegistry;
|
||||||
import io.micrometer.core.instrument.Metrics;
|
import io.micrometer.core.instrument.Metrics;
|
||||||
|
@ -178,7 +179,7 @@ class NamingConventionTest {
|
||||||
.containsOnly(attributeEntry("test.tag", "test.value")))));
|
.containsOnly(attributeEntry("test.tag", "test.value")))));
|
||||||
testing.waitAndAssertMetrics(
|
testing.waitAndAssertMetrics(
|
||||||
INSTRUMENTATION_NAME,
|
INSTRUMENTATION_NAME,
|
||||||
"test.renamedFunctionTimer.total_time",
|
"test.renamedFunctionTimer.sum",
|
||||||
metrics ->
|
metrics ->
|
||||||
metrics.anySatisfy(
|
metrics.anySatisfy(
|
||||||
metric ->
|
metric ->
|
||||||
|
@ -214,6 +215,43 @@ class NamingConventionTest {
|
||||||
.containsOnly(attributeEntry("test.tag", "test.value")))));
|
.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
|
@Test
|
||||||
void renameTimer() {
|
void renameTimer() {
|
||||||
// when
|
// when
|
||||||
|
|
|
@ -31,7 +31,7 @@ public abstract class AbstractFunctionTimerSecondsTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testFunctionCounterWithBaseUnitSeconds() throws InterruptedException {
|
void testFunctionTimerWithBaseUnitSeconds() throws InterruptedException {
|
||||||
// given
|
// given
|
||||||
FunctionTimer functionTimer =
|
FunctionTimer functionTimer =
|
||||||
FunctionTimer.builder(
|
FunctionTimer.builder(
|
||||||
|
@ -70,7 +70,7 @@ public abstract class AbstractFunctionTimerSecondsTest {
|
||||||
testing()
|
testing()
|
||||||
.waitAndAssertMetrics(
|
.waitAndAssertMetrics(
|
||||||
INSTRUMENTATION_NAME,
|
INSTRUMENTATION_NAME,
|
||||||
"testFunctionTimerSeconds.total_time",
|
"testFunctionTimerSeconds.sum",
|
||||||
metrics ->
|
metrics ->
|
||||||
metrics.anySatisfy(
|
metrics.anySatisfy(
|
||||||
metric ->
|
metric ->
|
||||||
|
@ -100,8 +100,6 @@ public abstract class AbstractFunctionTimerSecondsTest {
|
||||||
AbstractIterableAssert::isEmpty);
|
AbstractIterableAssert::isEmpty);
|
||||||
testing()
|
testing()
|
||||||
.waitAndAssertMetrics(
|
.waitAndAssertMetrics(
|
||||||
INSTRUMENTATION_NAME,
|
INSTRUMENTATION_NAME, "testFunctionTimerSeconds.sum", AbstractIterableAssert::isEmpty);
|
||||||
"testFunctionTimerSeconds.total_time",
|
|
||||||
AbstractIterableAssert::isEmpty);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ public abstract class AbstractFunctionTimerTest {
|
||||||
testing()
|
testing()
|
||||||
.waitAndAssertMetrics(
|
.waitAndAssertMetrics(
|
||||||
INSTRUMENTATION_NAME,
|
INSTRUMENTATION_NAME,
|
||||||
"testFunctionTimer.total_time",
|
"testFunctionTimer.sum",
|
||||||
metrics ->
|
metrics ->
|
||||||
metrics.anySatisfy(
|
metrics.anySatisfy(
|
||||||
metric ->
|
metric ->
|
||||||
|
@ -100,7 +100,7 @@ public abstract class AbstractFunctionTimerTest {
|
||||||
INSTRUMENTATION_NAME, "testFunctionTimer.count", AbstractIterableAssert::isEmpty);
|
INSTRUMENTATION_NAME, "testFunctionTimer.count", AbstractIterableAssert::isEmpty);
|
||||||
testing()
|
testing()
|
||||||
.waitAndAssertMetrics(
|
.waitAndAssertMetrics(
|
||||||
INSTRUMENTATION_NAME, "testFunctionTimer.total_time", AbstractIterableAssert::isEmpty);
|
INSTRUMENTATION_NAME, "testFunctionTimer.sum", AbstractIterableAssert::isEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -121,7 +121,7 @@ public abstract class AbstractFunctionTimerTest {
|
||||||
testing()
|
testing()
|
||||||
.waitAndAssertMetrics(
|
.waitAndAssertMetrics(
|
||||||
INSTRUMENTATION_NAME,
|
INSTRUMENTATION_NAME,
|
||||||
"testNanoFunctionTimer.total_time",
|
"testNanoFunctionTimer.sum",
|
||||||
metrics ->
|
metrics ->
|
||||||
metrics.anySatisfy(
|
metrics.anySatisfy(
|
||||||
metric ->
|
metric ->
|
||||||
|
@ -162,7 +162,7 @@ public abstract class AbstractFunctionTimerTest {
|
||||||
testing()
|
testing()
|
||||||
.waitAndAssertMetrics(
|
.waitAndAssertMetrics(
|
||||||
INSTRUMENTATION_NAME,
|
INSTRUMENTATION_NAME,
|
||||||
"testFunctionTimerWithTags.total_time",
|
"testFunctionTimerWithTags.sum",
|
||||||
metrics ->
|
metrics ->
|
||||||
metrics.anySatisfy(
|
metrics.anySatisfy(
|
||||||
metric ->
|
metric ->
|
||||||
|
|
|
@ -12,6 +12,7 @@ import io.micrometer.core.instrument.LongTaskTimer;
|
||||||
import io.micrometer.core.instrument.Metrics;
|
import io.micrometer.core.instrument.Metrics;
|
||||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.assertj.core.api.AbstractIterableAssert;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -58,31 +59,33 @@ public abstract class AbstractLongTaskTimerSecondsTest {
|
||||||
.hasValue(1)
|
.hasValue(1)
|
||||||
.attributes()
|
.attributes()
|
||||||
.containsOnly(attributeEntry("tag", "value")))));
|
.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
|
// when
|
||||||
TimeUnit.MILLISECONDS.sleep(100);
|
TimeUnit.MILLISECONDS.sleep(100);
|
||||||
sample.stop();
|
sample.stop();
|
||||||
|
|
||||||
// then
|
// 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()
|
testing()
|
||||||
.waitAndAssertMetrics(
|
.waitAndAssertMetrics(
|
||||||
INSTRUMENTATION_NAME,
|
INSTRUMENTATION_NAME,
|
||||||
|
@ -99,46 +102,38 @@ public abstract class AbstractLongTaskTimerSecondsTest {
|
||||||
.hasValue(0)
|
.hasValue(0)
|
||||||
.attributes()
|
.attributes()
|
||||||
.containsOnly(attributeEntry("tag", "value")))));
|
.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();
|
testing().clearData();
|
||||||
|
|
||||||
// when timer is removed from the registry
|
// when timer is removed from the registry
|
||||||
Metrics.globalRegistry.remove(timer);
|
Metrics.globalRegistry.remove(timer);
|
||||||
sample = timer.start();
|
timer.start();
|
||||||
|
|
||||||
// then no tasks are active after starting a new sample
|
// then no tasks are active after starting a new sample
|
||||||
testing()
|
testing()
|
||||||
.waitAndAssertMetrics(
|
.waitAndAssertMetrics(
|
||||||
INSTRUMENTATION_NAME,
|
INSTRUMENTATION_NAME,
|
||||||
"testLongTaskTimerSeconds.active",
|
"testLongTaskTimerSeconds.active",
|
||||||
metrics ->
|
AbstractIterableAssert::isEmpty);
|
||||||
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
|
|
||||||
testing()
|
testing()
|
||||||
.waitAndAssertMetrics(
|
.waitAndAssertMetrics(
|
||||||
INSTRUMENTATION_NAME,
|
INSTRUMENTATION_NAME,
|
||||||
"testLongTaskTimerSeconds",
|
"testLongTaskTimerSeconds.duration",
|
||||||
metrics ->
|
AbstractIterableAssert::isEmpty);
|
||||||
metrics.allSatisfy(
|
|
||||||
metric ->
|
|
||||||
assertThat(metric)
|
|
||||||
.hasDoubleHistogram()
|
|
||||||
.points()
|
|
||||||
.noneSatisfy(
|
|
||||||
point -> assertThat(point).hasSumGreaterThan(0.2).hasCount(2))));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import io.micrometer.core.instrument.LongTaskTimer;
|
||||||
import io.micrometer.core.instrument.Metrics;
|
import io.micrometer.core.instrument.Metrics;
|
||||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.assertj.core.api.AbstractIterableAssert;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -58,31 +59,33 @@ public abstract class AbstractLongTaskTimerTest {
|
||||||
.hasValue(1)
|
.hasValue(1)
|
||||||
.attributes()
|
.attributes()
|
||||||
.containsOnly(attributeEntry("tag", "value")))));
|
.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
|
// when
|
||||||
TimeUnit.MILLISECONDS.sleep(100);
|
TimeUnit.MILLISECONDS.sleep(100);
|
||||||
sample.stop();
|
sample.stop();
|
||||||
|
|
||||||
// then
|
// 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()
|
testing()
|
||||||
.waitAndAssertMetrics(
|
.waitAndAssertMetrics(
|
||||||
INSTRUMENTATION_NAME,
|
INSTRUMENTATION_NAME,
|
||||||
|
@ -99,76 +102,34 @@ public abstract class AbstractLongTaskTimerTest {
|
||||||
.hasValue(0)
|
.hasValue(0)
|
||||||
.attributes()
|
.attributes()
|
||||||
.containsOnly(attributeEntry("tag", "value")))));
|
.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();
|
testing().clearData();
|
||||||
|
|
||||||
// when timer is removed from the registry
|
// when timer is removed from the registry
|
||||||
Metrics.globalRegistry.remove(timer);
|
Metrics.globalRegistry.remove(timer);
|
||||||
sample = timer.start();
|
timer.start();
|
||||||
|
|
||||||
// then no tasks are active after starting a new sample
|
// then no tasks are active after starting a new sample
|
||||||
testing()
|
testing()
|
||||||
.waitAndAssertMetrics(
|
.waitAndAssertMetrics(
|
||||||
INSTRUMENTATION_NAME,
|
INSTRUMENTATION_NAME, "testLongTaskTimer.active", AbstractIterableAssert::isEmpty);
|
||||||
"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
|
|
||||||
testing()
|
testing()
|
||||||
.waitAndAssertMetrics(
|
.waitAndAssertMetrics(
|
||||||
INSTRUMENTATION_NAME,
|
INSTRUMENTATION_NAME, "testLongTaskTimer.duration", AbstractIterableAssert::isEmpty);
|
||||||
"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))));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue