Fix flaky micrometer retries in javaagent test (#5168)
* Fix flaky micrometer retries in javaagent test * remove comment * add clarifying comment
This commit is contained in:
parent
f6c520a062
commit
1ecf493332
|
@ -3,15 +3,13 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
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;
|
||||
package io.opentelemetry.instrumentation.api.internal;
|
||||
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.metrics.Meter;
|
||||
import io.opentelemetry.api.metrics.ObservableDoubleMeasurement;
|
||||
import io.opentelemetry.api.metrics.ObservableLongMeasurement;
|
||||
import io.opentelemetry.instrumentation.api.cache.Cache;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -20,15 +18,35 @@ import java.util.function.ToDoubleFunction;
|
|||
import java.util.function.ToLongFunction;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
// this class must live in the bootstrap classloader - in case different metrics instrumentations
|
||||
// (micrometer) get applied to classes in different classloaders, we want them to share the same
|
||||
// async instrument registry - because the underlying OTel Meter is shared too. There is only one
|
||||
// OTel SDK in the agent, and therefore there must be only one AsyncInstrumentRegistry too -
|
||||
// otherwise some async metrics would get lost because of duplicate instrument registrations.
|
||||
|
||||
// TODO: refactor this class, there's too much copy-paste here
|
||||
final class AsyncInstrumentRegistry {
|
||||
public final class AsyncInstrumentRegistry {
|
||||
|
||||
// we need to re-use instrument registries per OpenTelemetry instance so that async instruments
|
||||
// that were created by other OpenTelemetryMeterRegistries can be reused; otherwise the SDK will
|
||||
// start logging errors and async measurements will not be recorded
|
||||
private static final Cache<Meter, AsyncInstrumentRegistry> asyncInstrumentRegistries =
|
||||
Cache.weak();
|
||||
|
||||
/**
|
||||
* Returns the {@link AsyncInstrumentRegistry} for the passed {@link Meter}. There is at most one
|
||||
* {@link AsyncInstrumentRegistry} created for each OpenTelemetry {@link Meter}.
|
||||
*/
|
||||
public static AsyncInstrumentRegistry getOrCreate(Meter meter) {
|
||||
return asyncInstrumentRegistries.computeIfAbsent(meter, AsyncInstrumentRegistry::new);
|
||||
}
|
||||
|
||||
// using a weak ref so that the AsyncInstrumentRegistry (which is stored in a static maps) does
|
||||
// not hold strong references to Meter (and thus make it impossible to collect Meter garbage).
|
||||
// in practice this should never return null - OpenTelemetryMeterRegistry maintains a strong
|
||||
// reference to both Meter and AsyncInstrumentRegistry; if the meter registry is GC'd then its
|
||||
// corresponding AsyncInstrumentRegistry cannot possibly be used; and Meter cannot be GC'd until
|
||||
// OpentelemetryMeterRegistry is GC'd
|
||||
// OpenTelemetryMeterRegistry is GC'd
|
||||
private final WeakReference<Meter> meter;
|
||||
|
||||
// values from the maps below are never removed - that is because the underlying OpenTelemetry
|
||||
|
@ -47,16 +65,7 @@ final class AsyncInstrumentRegistry {
|
|||
this.meter = new WeakReference<>(meter);
|
||||
}
|
||||
|
||||
<T> AsyncMeasurementHandle buildGauge(
|
||||
io.micrometer.core.instrument.Meter.Id meterId,
|
||||
Attributes attributes,
|
||||
@Nullable T obj,
|
||||
ToDoubleFunction<T> objMetric) {
|
||||
return buildGauge(
|
||||
meterId.getName(), description(meterId), baseUnit(meterId), attributes, obj, objMetric);
|
||||
}
|
||||
|
||||
<T> AsyncMeasurementHandle buildGauge(
|
||||
public <T> AsyncMeasurementHandle buildGauge(
|
||||
String name,
|
||||
String description,
|
||||
String baseUnit,
|
||||
|
@ -81,16 +90,7 @@ final class AsyncInstrumentRegistry {
|
|||
return new AsyncMeasurementHandle(recorder, attributes);
|
||||
}
|
||||
|
||||
<T> AsyncMeasurementHandle buildDoubleCounter(
|
||||
io.micrometer.core.instrument.Meter.Id meterId,
|
||||
Attributes attributes,
|
||||
T obj,
|
||||
ToDoubleFunction<T> objMetric) {
|
||||
return buildDoubleCounter(
|
||||
meterId.getName(), description(meterId), baseUnit(meterId), attributes, obj, objMetric);
|
||||
}
|
||||
|
||||
<T> AsyncMeasurementHandle buildDoubleCounter(
|
||||
public <T> AsyncMeasurementHandle buildDoubleCounter(
|
||||
String name,
|
||||
String description,
|
||||
String baseUnit,
|
||||
|
@ -116,7 +116,7 @@ final class AsyncInstrumentRegistry {
|
|||
return new AsyncMeasurementHandle(recorder, attributes);
|
||||
}
|
||||
|
||||
<T> AsyncMeasurementHandle buildLongCounter(
|
||||
public <T> AsyncMeasurementHandle buildLongCounter(
|
||||
String name,
|
||||
String description,
|
||||
String baseUnit,
|
||||
|
@ -141,7 +141,7 @@ final class AsyncInstrumentRegistry {
|
|||
return new AsyncMeasurementHandle(recorder, attributes);
|
||||
}
|
||||
|
||||
<T> AsyncMeasurementHandle buildUpDownDoubleCounter(
|
||||
public <T> AsyncMeasurementHandle buildUpDownDoubleCounter(
|
||||
String name,
|
||||
String description,
|
||||
String baseUnit,
|
||||
|
@ -251,7 +251,7 @@ final class AsyncInstrumentRegistry {
|
|||
}
|
||||
}
|
||||
|
||||
static final class AsyncMeasurementHandle {
|
||||
public static final class AsyncMeasurementHandle {
|
||||
|
||||
private final MeasurementsRecorder<?> measurementsRecorder;
|
||||
private final Attributes attributes;
|
||||
|
@ -261,7 +261,7 @@ final class AsyncInstrumentRegistry {
|
|||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
void remove() {
|
||||
public void remove() {
|
||||
measurementsRecorder.removeMeasurement(attributes);
|
||||
}
|
||||
}
|
|
@ -5,12 +5,15 @@
|
|||
|
||||
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.tagsAsAttributes;
|
||||
|
||||
import io.micrometer.core.instrument.FunctionCounter;
|
||||
import io.micrometer.core.instrument.Measurement;
|
||||
import io.micrometer.core.instrument.util.MeterEquivalence;
|
||||
import io.opentelemetry.instrumentation.micrometer.v1_5.AsyncInstrumentRegistry.AsyncMeasurementHandle;
|
||||
import io.opentelemetry.instrumentation.api.internal.AsyncInstrumentRegistry;
|
||||
import io.opentelemetry.instrumentation.api.internal.AsyncInstrumentRegistry.AsyncMeasurementHandle;
|
||||
import java.util.Collections;
|
||||
import java.util.function.ToDoubleFunction;
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -29,7 +32,8 @@ final class OpenTelemetryFunctionCounter<T> implements FunctionCounter, Removabl
|
|||
this.id = id;
|
||||
|
||||
countMeasurementHandle =
|
||||
asyncInstrumentRegistry.buildDoubleCounter(id, tagsAsAttributes(id), obj, countFunction);
|
||||
asyncInstrumentRegistry.buildDoubleCounter(
|
||||
id.getName(), description(id), baseUnit(id), tagsAsAttributes(id), obj, countFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,7 +15,8 @@ import io.micrometer.core.instrument.Statistic;
|
|||
import io.micrometer.core.instrument.util.MeterEquivalence;
|
||||
import io.micrometer.core.instrument.util.TimeUtils;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.instrumentation.micrometer.v1_5.AsyncInstrumentRegistry.AsyncMeasurementHandle;
|
||||
import io.opentelemetry.instrumentation.api.internal.AsyncInstrumentRegistry;
|
||||
import io.opentelemetry.instrumentation.api.internal.AsyncInstrumentRegistry.AsyncMeasurementHandle;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.ToDoubleFunction;
|
||||
|
|
|
@ -5,12 +5,15 @@
|
|||
|
||||
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.tagsAsAttributes;
|
||||
|
||||
import io.micrometer.core.instrument.Gauge;
|
||||
import io.micrometer.core.instrument.Measurement;
|
||||
import io.micrometer.core.instrument.util.MeterEquivalence;
|
||||
import io.opentelemetry.instrumentation.micrometer.v1_5.AsyncInstrumentRegistry.AsyncMeasurementHandle;
|
||||
import io.opentelemetry.instrumentation.api.internal.AsyncInstrumentRegistry;
|
||||
import io.opentelemetry.instrumentation.api.internal.AsyncInstrumentRegistry.AsyncMeasurementHandle;
|
||||
import java.util.Collections;
|
||||
import java.util.function.ToDoubleFunction;
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -29,7 +32,8 @@ final class OpenTelemetryGauge<T> implements Gauge, RemovableMeter {
|
|||
this.id = id;
|
||||
|
||||
gaugeMeasurementHandle =
|
||||
asyncInstrumentRegistry.buildGauge(id, tagsAsAttributes(id), obj, objMetric);
|
||||
asyncInstrumentRegistry.buildGauge(
|
||||
id.getName(), description(id), baseUnit(id), tagsAsAttributes(id), obj, objMetric);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -14,7 +14,8 @@ import io.micrometer.core.instrument.Measurement;
|
|||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.util.MeterEquivalence;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.instrumentation.micrometer.v1_5.AsyncInstrumentRegistry.AsyncMeasurementHandle;
|
||||
import io.opentelemetry.instrumentation.api.internal.AsyncInstrumentRegistry;
|
||||
import io.opentelemetry.instrumentation.api.internal.AsyncInstrumentRegistry.AsyncMeasurementHandle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
|
|
@ -20,7 +20,7 @@ import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
|
|||
import io.micrometer.core.instrument.distribution.HistogramGauges;
|
||||
import io.micrometer.core.instrument.distribution.pause.PauseDetector;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.api.cache.Cache;
|
||||
import io.opentelemetry.instrumentation.api.internal.AsyncInstrumentRegistry;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.ToDoubleFunction;
|
||||
import java.util.function.ToLongFunction;
|
||||
|
@ -49,20 +49,13 @@ public final class OpenTelemetryMeterRegistry extends MeterRegistry {
|
|||
return new OpenTelemetryMeterRegistryBuilder(openTelemetry);
|
||||
}
|
||||
|
||||
// we need to re-use instrument registries per OpenTelemetry instance so that async instruments
|
||||
// that were created by other OpenTelemetryMeterRegistries can be reused; otherwise the SDK will
|
||||
// start logging errors and async measurements will not be recorded
|
||||
private static final Cache<io.opentelemetry.api.metrics.Meter, AsyncInstrumentRegistry>
|
||||
asyncInstrumentRegistries = Cache.weak();
|
||||
|
||||
private final io.opentelemetry.api.metrics.Meter otelMeter;
|
||||
private final AsyncInstrumentRegistry asyncInstrumentRegistry;
|
||||
|
||||
OpenTelemetryMeterRegistry(Clock clock, io.opentelemetry.api.metrics.Meter otelMeter) {
|
||||
super(clock);
|
||||
this.otelMeter = otelMeter;
|
||||
this.asyncInstrumentRegistry =
|
||||
asyncInstrumentRegistries.computeIfAbsent(otelMeter, AsyncInstrumentRegistry::new);
|
||||
this.asyncInstrumentRegistry = AsyncInstrumentRegistry.getOrCreate(otelMeter);
|
||||
this.config().onMeterRemoved(OpenTelemetryMeterRegistry::onMeterRemoved);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue