Cache span names derived from class and method names (DataDog/dd-trace-java#1562)
MODIFY
agent-bootstrap/src/main/java/io/opentelemetry/auto/bootstrap/instrumentation/decorator/BaseDecorator.java
agent-bootstrap/src/main/java/io/opentelemetry/auto/bootstrap/instrumentation/decorator/BaseDecorator.java
@@ -29,10 +29,19 @@ import java.io.StringWriter;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.InetSocketAddress;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
public abstract class BaseDecorator {
+ private static final ClassValue<SpanNames> SPAN_NAMES =
+ new ClassValue<SpanNames>() {
+ @Override
+ protected SpanNames computeValue(Class<?> type) {
+ return new SpanNames(getClassName(type));
+ }
+ };
+
protected BaseDecorator() {}
public Span afterStart(final Span span) {
@@ -88,27 +97,75 @@ public abstract class BaseDecorator {
* reference. Anonymous classes are named based on their parent.
*/
public String spanNameForMethod(final Method method) {
- return spanNameForClass(method.getDeclaringClass()) + "." + method.getName();
+ return spanNameForMethod(method.getDeclaringClass(), method);
+ }
+
+ /**
+ * This method is used to generate an acceptable span (operation) name based on a given method
+ * reference. Anonymous classes are named based on their parent.
+ *
+ * @param method the method to get the name from, nullable
+ * @return the span name from the class and method
+ */
+ public String spanNameForMethod(final Class<?> clazz, final Method method) {
+ return spanNameForMethod(clazz, null == method ? null : method.getName());
+ }
+
+ /**
+ * This method is used to generate an acceptable span (operation) name based on a given method
+ * reference. Anonymous classes are named based on their parent.
+ *
+ * @param methodName the name of the method to get the name from, nullable
+ * @return the span name from the class and method
+ */
+ public String spanNameForMethod(final Class<?> clazz, final String methodName) {
+ SpanNames cn = SPAN_NAMES.get(clazz);
+ return null == methodName ? cn.getClassName() : cn.getSpanName(methodName);
}
/**
* This method is used to generate an acceptable span (operation) name based on a given class
* reference. Anonymous classes are named based on their parent.
*/
- public String spanNameForClass(final Class clazz) {
+ public String spanNameForClass(final Class<?> clazz) {
if (!clazz.isAnonymousClass()) {
return clazz.getSimpleName();
}
- String className = clazz.getName();
- if (clazz.getPackage() != null) {
- final String pkgName = clazz.getPackage().getName();
- if (!pkgName.isEmpty()) {
- className = clazz.getName().replace(pkgName, "").substring(1);
+ return SPAN_NAMES.get(clazz).getClassName();
}
+
+ private static class SpanNames {
+ private final String className;
+ private final ConcurrentHashMap<String, String> spanNames = new ConcurrentHashMap<>(1);
+
+ private SpanNames(String className) {
+ this.className = className;
}
+
+ public String getClassName() {
return className;
}
+ public String getSpanName(String methodName) {
+ String spanName = spanNames.get(methodName);
+ if (null == spanName) {
+ spanName = className + "." + methodName;
+ spanNames.putIfAbsent(methodName, spanName);
+ }
+ return spanName;
+ }
+ }
+
+ private static String getClassName(Class<?> clazz) {
+ String name = clazz.getName();
+ int start = name.lastIndexOf('.');
+ if (!clazz.isAnonymousClass()) {
+ int qualifier = name.indexOf('$', start);
+ return name.substring(Math.max(start, qualifier) + 1);
+ }
+ return name.substring(start + 1);
+ }
+
public static <C> SpanContext extract(final C carrier, final HttpTextFormat.Getter<C> getter) {
final Context context =
getPropagators().getHttpTextFormat().extract(Context.current(), carrier, getter);

MODIFY
instrumentation/jaxrs/jaxrs-1.0/src/main/java/io/opentelemetry/auto/instrumentation/jaxrs/v1_0/JaxRsAnnotationsDecorator.java
instrumentation/jaxrs/jaxrs-1.0/src/main/java/io/opentelemetry/auto/instrumentation/jaxrs/v1_0/JaxRsAnnotationsDecorator.java
@@ -48,7 +48,7 @@ public class JaxRsAnnotationsDecorator extends BaseDecorator {
if (isRootScope && !spanName.isEmpty()) {
span.updateName(spanName);
} else {
- span.updateName(DECORATE.spanNameForClass(target) + "." + method.getName());
+ span.updateName(DECORATE.spanNameForMethod(target, method));
}
}

MODIFY
instrumentation/jaxrs/jaxrs-2.0/src/main/java/io/opentelemetry/auto/instrumentation/jaxrs/v2_0/JaxRsAnnotationsDecorator.java
instrumentation/jaxrs/jaxrs-2.0/src/main/java/io/opentelemetry/auto/instrumentation/jaxrs/v2_0/JaxRsAnnotationsDecorator.java
@@ -58,8 +58,7 @@ public class JaxRsAnnotationsDecorator extends BaseDecorator {
if (isRootScope && !spanName.isEmpty()) {
span.updateName(spanName);
} else {
- span.updateName(
- DECORATE.spanNameForClass(target) + (method == null ? "" : "." + method.getName()));
+ span.updateName(DECORATE.spanNameForMethod(target, method));
}
}

MODIFY
instrumentation/rediscala-1.8/src/main/java/io/opentelemetry/auto/instrumentation/rediscala/RediscalaInstrumentation.java
instrumentation/rediscala-1.8/src/main/java/io/opentelemetry/auto/instrumentation/rediscala/RediscalaInstrumentation.java
@@ -61,9 +61,6 @@ public final class RediscalaInstrumentation extends Instrumenter.Default {
public String[] helperClassNames() {
return new String[] {
RediscalaInstrumentation.class.getName() + "$OnCompleteHandler",
- "io.opentelemetry.auto.bootstrap.instrumentation.decorator.BaseDecorator",
- "io.opentelemetry.auto.bootstrap.instrumentation.decorator.ClientDecorator",
- "io.opentelemetry.auto.bootstrap.instrumentation.decorator.DatabaseClientDecorator",
packageName + ".RediscalaClientDecorator",
};
}
@@ -83,10 +80,10 @@ public final class RediscalaInstrumentation extends Instrumenter.Default {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope onEnter(@Advice.Argument(0) final RedisCommand cmd) {
- final Span span =
- TRACER.spanBuilder(cmd.getClass().getName()).setSpanKind(CLIENT).startSpan();
+ String statement = DECORATE.spanNameForClass(cmd.getClass());
+ final Span span = TRACER.spanBuilder(statement).setSpanKind(CLIENT).startSpan();
DECORATE.afterStart(span);
- DECORATE.onStatement(span, cmd.getClass().getName());
+ DECORATE.onStatement(span, statement);
return new SpanWithScope(span, currentContextWith(span));
}

MODIFY
instrumentation/rediscala-1.8/src/test/groovy/RediscalaClientTest.groovy
instrumentation/rediscala-1.8/src/test/groovy/RediscalaClientTest.groovy
@@ -84,11 +84,11 @@ class RediscalaClientTest extends AgentTestRunner {
assertTraces(1) {
trace(0, 1) {
span(0) {
- operationName "redis.api.strings.Set"
+ operationName "Set"
spanKind CLIENT
tags {
"$Tags.DB_TYPE" "redis"
- "$Tags.DB_STATEMENT" "redis.api.strings.Set"
+ "$Tags.DB_STATEMENT" "Set"
}
}
}
@@ -112,21 +112,21 @@ class RediscalaClientTest extends AgentTestRunner {
assertTraces(2) {
trace(0, 1) {
span(0) {
- operationName "redis.api.strings.Set"
+ operationName "Set"
spanKind CLIENT
tags {
"$Tags.DB_TYPE" "redis"
- "$Tags.DB_STATEMENT" "redis.api.strings.Set"
+ "$Tags.DB_STATEMENT" "Set"
}
}
}
trace(1, 1) {
span(0) {
- operationName "redis.api.strings.Get"
+ operationName "Get"
spanKind CLIENT
tags {
"$Tags.DB_TYPE" "redis"
- "$Tags.DB_STATEMENT" "redis.api.strings.Get"
+ "$Tags.DB_STATEMENT" "Get"
}
}
}

MODIFY
instrumentation/spring-webmvc-3.1/src/main/java/io/opentelemetry/auto/instrumentation/springwebmvc/SpringWebMvcDecorator.java
instrumentation/spring-webmvc-3.1/src/main/java/io/opentelemetry/auto/instrumentation/springwebmvc/SpringWebMvcDecorator.java
@@ -75,7 +75,7 @@ public class SpringWebMvcDecorator extends BaseDecorator {
methodName = "<annotation>";
}
- return DECORATE.spanNameForClass(clazz) + "." + methodName;
+ return DECORATE.spanNameForMethod(clazz, methodName);
}
public String spanNameOnRender(final ModelAndView mv) {

Cache span names derived from class and method names (DataDog/dd-trace-java#1562)