Remove LongAdder and ClassValue usages from instrumentation-api
MODIFY
instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/RuntimeVirtualFieldSupplier.java
instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/RuntimeVirtualFieldSupplier.java
@@ -7,8 +7,6 @@ package io.opentelemetry.instrumentation.api.internal;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.field.VirtualField;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,18 +37,17 @@ public final class RuntimeVirtualFieldSupplier {
return instance;
}
- private static final class CacheBasedVirtualFieldSupplier
- extends ClassValue<Map<Class<?>, VirtualField<?, ?>>> implements VirtualFieldSupplier {
+ private static final class CacheBasedVirtualFieldSupplier implements VirtualFieldSupplier {
+
+ private final Cache<Class<?>, Cache<Class<?>, VirtualField<?, ?>>>
+ ownerToFieldToImplementationMap = Cache.builder().setWeakKeys().build();
@Override
public <U extends T, T, F> VirtualField<U, F> find(Class<T> type, Class<F> fieldType) {
return (VirtualField<U, F>)
- get(type).computeIfAbsent(fieldType, k -> new CacheBasedVirtualField<>());
- }
-
- @Override
- protected Map<Class<?>, VirtualField<?, ?>> computeValue(Class<?> type) {
- return new ConcurrentHashMap<>();
+ ownerToFieldToImplementationMap
+ .computeIfAbsent(type, c -> Cache.builder().setWeakKeys().build())
+ .computeIfAbsent(fieldType, c -> new CacheBasedVirtualField<>());
}
}

MODIFY
instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/SupportabilityMetrics.java
instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/SupportabilityMetrics.java
@@ -11,7 +11,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.LongAdder;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -22,7 +22,7 @@ public final class SupportabilityMetrics {
private final Consumer<String> reporter;
private final ConcurrentMap<String, KindCounters> suppressionCounters = new ConcurrentHashMap<>();
- private final ConcurrentMap<String, LongAdder> counters = new ConcurrentHashMap<>();
+ private final ConcurrentMap<String, AtomicLong> counters = new ConcurrentHashMap<>();
private static final SupportabilityMetrics INSTANCE =
new SupportabilityMetrics(Config.get(), logger::debug).start();
@@ -52,7 +52,7 @@ public final class SupportabilityMetrics {
return;
}
- counters.computeIfAbsent(counterName, k -> new LongAdder()).increment();
+ counters.computeIfAbsent(counterName, k -> new AtomicLong()).incrementAndGet();
}
// visible for testing
@@ -69,7 +69,7 @@ public final class SupportabilityMetrics {
});
counters.forEach(
(counterName, counter) -> {
- long value = counter.sumThenReset();
+ long value = counter.getAndSet(0);
if (value > 0) {
reporter.accept("Counter '" + counterName + "' : " + value);
}
@@ -100,28 +100,28 @@ public final class SupportabilityMetrics {
// this class is threadsafe.
private static class KindCounters {
- private final LongAdder server = new LongAdder();
- private final LongAdder client = new LongAdder();
- private final LongAdder internal = new LongAdder();
- private final LongAdder consumer = new LongAdder();
- private final LongAdder producer = new LongAdder();
+ private final AtomicLong server = new AtomicLong();
+ private final AtomicLong client = new AtomicLong();
+ private final AtomicLong internal = new AtomicLong();
+ private final AtomicLong consumer = new AtomicLong();
+ private final AtomicLong producer = new AtomicLong();
void increment(SpanKind kind) {
switch (kind) {
case INTERNAL:
- internal.increment();
+ internal.incrementAndGet();
break;
case SERVER:
- server.increment();
+ server.incrementAndGet();
break;
case CLIENT:
- client.increment();
+ client.incrementAndGet();
break;
case PRODUCER:
- producer.increment();
+ producer.incrementAndGet();
break;
case CONSUMER:
- consumer.increment();
+ consumer.incrementAndGet();
break;
}
}
@@ -129,15 +129,15 @@ public final class SupportabilityMetrics {
long getAndReset(SpanKind kind) {
switch (kind) {
case INTERNAL:
- return internal.sumThenReset();
+ return internal.getAndSet(0);
case SERVER:
- return server.sumThenReset();
+ return server.getAndSet(0);
case CLIENT:
- return client.sumThenReset();
+ return client.getAndSet(0);
case PRODUCER:
- return producer.sumThenReset();
+ return producer.getAndSet(0);
case CONSUMER:
- return consumer.sumThenReset();
+ return consumer.getAndSet(0);
}
return 0;
}

MODIFY
instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/ClassNames.java
instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/ClassNames.java
package io.opentelemetry.instrumentation.api.tracer;
+import io.opentelemetry.instrumentation.api.caching.Cache;
+
public final class ClassNames {
- private static final ClassValue<String> simpleNames =
- new ClassValue<String>() {
- @Override
- protected String computeValue(Class<?> type) {
+ private static final Cache<Class<?>, String> simpleNames = Cache.builder().setWeakKeys().build();
+
+ /**
+ * This method is used to generate a simple name based on a given class reference, e.g. for use in
+ * span names and span attributes. Anonymous classes are named based on their parent.
+ */
+ public static String simpleName(Class<?> type) {
+ return simpleNames.computeIfAbsent(type, ClassNames::computeSimpleName);
+ }
+
+ private static String computeSimpleName(Class<?> type) {
if (!type.isAnonymousClass()) {
return type.getSimpleName();
}
@@ -23,15 +32,6 @@ public final class ClassNames {
}
return className;
}
- };
-
- /**
- * This method is used to generate a simple name based on a given class reference, e.g. for use in
- * span names and span attributes. Anonymous classes are named based on their parent.
- */
- public static String simpleName(Class<?> type) {
- return simpleNames.get(type);
- }
private ClassNames() {}
}

MODIFY
instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/SpanNames.java
instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/SpanNames.java
package io.opentelemetry.instrumentation.api.tracer;
+import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.util.ClassAndMethod;
import java.lang.reflect.Method;
import java.util.Map;
@@ -13,14 +14,8 @@ import javax.annotation.Nullable;
public final class SpanNames {
- private static final ClassValue<Map<String, String>> spanNameCaches =
- new ClassValue<Map<String, String>>() {
- @Override
- protected Map<String, String> computeValue(Class<?> clazz) {
- // the cache is naturally bounded by the number of methods in a class
- return new ConcurrentHashMap<>();
- }
- };
+ private static final Cache<Class<?>, Map<String, String>> spanNameCaches =
+ Cache.builder().setWeakKeys().build();
/**
* This method is used to generate a span name based on a method. Anonymous classes are named
@@ -51,7 +46,10 @@ public final class SpanNames {
* based on their parent.
*/
public static String fromMethod(Class<?> clazz, String methodName) {
- Map<String, String> spanNameCache = spanNameCaches.get(clazz);
+ // the cache (ConcurrentHashMap) is naturally bounded by the number of methods in a class
+ Map<String, String> spanNameCache =
+ spanNameCaches.computeIfAbsent(clazz, c -> new ConcurrentHashMap<>());
+
// not using computeIfAbsent, because it would require a capturing (allocating) lambda
String spanName = spanNameCache.get(methodName);
if (spanName != null) {

Remove LongAdder and ClassValue usages from instrumentation-api (#4671)