Skip to content

Commit 8db72c0

Browse files
authored
Add support for non-visitor based class parsing (via dd-instrument-java) (#9894)
1 parent 52fa9c9 commit 8db72c0

File tree

6 files changed

+61
-11
lines changed

6 files changed

+61
-11
lines changed

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/outline/AnnotationOutline.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package datadog.trace.agent.tooling.bytebuddy.outline;
22

3+
import datadog.instrument.classmatch.ClassFile;
34
import java.lang.annotation.Annotation;
45
import java.lang.annotation.ElementType;
56
import java.lang.annotation.RetentionPolicy;
@@ -17,13 +18,19 @@ final class AnnotationOutline extends WithName implements AnnotationDescription
1718
private static final Map<String, AnnotationDescription> annotationOutlines = new HashMap<>();
1819

1920
static void prepareAnnotationOutline(String name) {
20-
String descriptor = 'L' + name.replace('.', '/') + ';';
21-
annotationOutlines.put(descriptor, new AnnotationOutline(name));
21+
String internalName = name.replace('.', '/');
22+
// flag that we want to parse this annotation
23+
ClassFile.annotationOfInterest(internalName);
24+
// only a few annotation outlines get prepared - we register them under
25+
// both their internal name and descriptor to support different callers
26+
AnnotationOutline annotationOutline = new AnnotationOutline(name);
27+
annotationOutlines.put('L' + internalName + ';', annotationOutline);
28+
annotationOutlines.put(internalName, annotationOutline);
2229
}
2330

2431
/** Only provide outlines of annotations of interest used for matching. */
25-
static AnnotationDescription annotationOutline(String descriptor) {
26-
return annotationOutlines.get(descriptor);
32+
static AnnotationDescription annotationOutline(String internalNameOrDescriptor) {
33+
return annotationOutlines.get(internalNameOrDescriptor);
2734
}
2835

2936
private AnnotationOutline(String name) {

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/outline/OutlineTypeParser.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import static net.bytebuddy.jar.asm.ClassReader.SKIP_CODE;
55
import static net.bytebuddy.jar.asm.ClassReader.SKIP_DEBUG;
66

7+
import datadog.instrument.classmatch.ClassFile;
8+
import datadog.trace.api.InstrumenterConfig;
79
import java.lang.annotation.Annotation;
810
import java.lang.reflect.Field;
911
import java.lang.reflect.Method;
@@ -18,13 +20,19 @@
1820

1921
/** Attempts a minimal parse of just the named elements we need for matching. */
2022
final class OutlineTypeParser implements TypeParser {
23+
private static final boolean visitorClassParsing =
24+
InstrumenterConfig.get().isVisitorClassParsing();
2125

2226
@Override
2327
public TypeDescription parse(byte[] bytecode) {
24-
ClassReader classReader = OpenedClassReader.of(bytecode);
25-
OutlineTypeExtractor typeExtractor = new OutlineTypeExtractor();
26-
classReader.accept(typeExtractor, SKIP_CODE | SKIP_DEBUG);
27-
return typeExtractor.typeOutline;
28+
if (visitorClassParsing) {
29+
ClassReader classReader = OpenedClassReader.of(bytecode);
30+
OutlineTypeExtractor typeExtractor = new OutlineTypeExtractor();
31+
classReader.accept(typeExtractor, SKIP_CODE | SKIP_DEBUG);
32+
return typeExtractor.typeOutline;
33+
} else {
34+
return new TypeOutline(ClassFile.outline(bytecode));
35+
}
2836
}
2937

3038
@Override
@@ -39,7 +47,7 @@ public TypeDescription parse(Class<?> loadedType) {
3947
extractTypeNames(loadedType.getInterfaces()));
4048

4149
for (Annotation a : loadedType.getDeclaredAnnotations()) {
42-
typeOutline.declare(annotationOutline(Type.getDescriptor(a.annotationType())));
50+
typeOutline.declare(annotationOutline(Type.getInternalName(a.annotationType())));
4351
}
4452

4553
for (Field field : loadedType.getDeclaredFields()) {
@@ -50,7 +58,7 @@ public TypeDescription parse(Class<?> loadedType) {
5058
field.getName(),
5159
Type.getDescriptor(field.getType()));
5260
for (Annotation a : field.getDeclaredAnnotations()) {
53-
fieldOutline.declare(annotationOutline(Type.getDescriptor(a.annotationType())));
61+
fieldOutline.declare(annotationOutline(Type.getInternalName(a.annotationType())));
5462
}
5563
typeOutline.declare(fieldOutline);
5664
}
@@ -63,7 +71,7 @@ public TypeDescription parse(Class<?> loadedType) {
6371
method.getName(),
6472
Type.getMethodDescriptor(method));
6573
for (Annotation a : method.getDeclaredAnnotations()) {
66-
methodOutline.declare(annotationOutline(Type.getDescriptor(a.annotationType())));
74+
methodOutline.declare(annotationOutline(Type.getInternalName(a.annotationType())));
6775
}
6876
typeOutline.declare(methodOutline);
6977
}

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/outline/TypeOutline.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package datadog.trace.agent.tooling.bytebuddy.outline;
22

3+
import static datadog.trace.agent.tooling.bytebuddy.outline.AnnotationOutline.annotationOutline;
34
import static datadog.trace.agent.tooling.bytebuddy.outline.TypeFactory.findType;
45

6+
import datadog.instrument.classmatch.ClassOutline;
57
import java.util.ArrayList;
68
import java.util.List;
79
import net.bytebuddy.description.annotation.AnnotationDescription;
@@ -42,6 +44,30 @@ final class TypeOutline extends WithName {
4244
this.interfaces = interfaces;
4345
}
4446

47+
/** Adapts simpler {@link ClassOutline} structure to existing {@link TypeOutline}. */
48+
public TypeOutline(ClassOutline outline) {
49+
super(outline.className.replace('/', '.'));
50+
this.modifiers = outline.access & ALLOWED_TYPE_MODIFIERS;
51+
this.superName = outline.superName;
52+
this.interfaces = outline.interfaces;
53+
54+
for (String annotation : outline.annotations) {
55+
declare(annotationOutline(annotation));
56+
}
57+
58+
for (datadog.instrument.classmatch.FieldOutline f : outline.fields) {
59+
declare(new FieldOutline(this, f.access, f.fieldName, f.descriptor));
60+
}
61+
62+
for (datadog.instrument.classmatch.MethodOutline m : outline.methods) {
63+
MethodOutline method = new MethodOutline(this, m.access, m.methodName, m.descriptor);
64+
for (String annotation : m.annotations) {
65+
method.declare(annotationOutline(annotation));
66+
}
67+
declare(method);
68+
}
69+
}
70+
4571
@Override
4672
protected TypeDescription delegate() {
4773
throw new IllegalStateException("Not available in outline for " + name);

dd-trace-api/src/main/java/datadog/trace/api/config/TraceInstrumentationConfig.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ public final class TraceInstrumentationConfig {
162162
public static final String RESOLVER_NAMES_ARE_UNIQUE = "resolver.names.are.unique";
163163

164164
public static final String UNSAFE_CLASS_INJECTION = "unsafe.class.injection";
165+
public static final String VISITOR_CLASS_PARSING = "visitor.class.parsing";
165166

166167
public static final String CASSANDRA_KEYSPACE_STATEMENT_EXTRACTION_ENABLED =
167168
"trace.cassandra.keyspace.statement.extraction.enabled";

internal-api/src/main/java/datadog/trace/api/InstrumenterConfig.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_THREAD_POOL_EXECUTORS_EXCLUDE;
7575
import static datadog.trace.api.config.TraceInstrumentationConfig.TRACE_WEBSOCKET_MESSAGES_ENABLED;
7676
import static datadog.trace.api.config.TraceInstrumentationConfig.UNSAFE_CLASS_INJECTION;
77+
import static datadog.trace.api.config.TraceInstrumentationConfig.VISITOR_CLASS_PARSING;
7778
import static datadog.trace.api.config.UsmConfig.USM_ENABLED;
7879
import static datadog.trace.util.CollectionUtils.tryMakeImmutableList;
7980
import static datadog.trace.util.CollectionUtils.tryMakeImmutableSet;
@@ -162,6 +163,7 @@ public class InstrumenterConfig {
162163
private final boolean resolverUseLoadClass;
163164
private final Boolean resolverUseUrlCaches;
164165
private final int resolverResetInterval;
166+
private final boolean visitorClassParsing;
165167

166168
private final boolean unsafeClassInjection;
167169

@@ -284,6 +286,7 @@ private InstrumenterConfig() {
284286
: configProvider.getInteger(RESOLVER_RESET_INTERVAL, DEFAULT_RESOLVER_RESET_INTERVAL);
285287

286288
unsafeClassInjection = configProvider.getBoolean(UNSAFE_CLASS_INJECTION, false);
289+
visitorClassParsing = configProvider.getBoolean(VISITOR_CLASS_PARSING, false);
287290

288291
runtimeContextFieldInjection =
289292
configProvider.getBoolean(
@@ -514,6 +517,10 @@ public boolean isUnsafeClassInjection() {
514517
return unsafeClassInjection;
515518
}
516519

520+
public boolean isVisitorClassParsing() {
521+
return visitorClassParsing;
522+
}
523+
517524
public String getInstrumentationConfigId() {
518525
return instrumentationConfigId;
519526
}

metadata/supported-configurations.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,7 @@
13431343
"DD_UNSAFE_CLASS_INJECTION": ["A"],
13441344
"DD_USM_ENABLED": ["A"],
13451345
"DD_VERSION": ["A"],
1346+
"DD_VISITOR_CLASS_PARSING": ["A"],
13461347
"DD_WRITER_BAGGAGE_INJECT": ["A"],
13471348
"DD_WRITER_TYPE": ["A"],
13481349
"OTEL_INSTRUMENTATION_HTTP_CLIENT_CAPTURE_REQUEST_HEADERS": ["A"],

0 commit comments

Comments
 (0)