Skip to content

Commit 721ee67

Browse files
jbachorikclaude
andcommitted
Load JMXFetch substitutions reflectively, increase native-image heap
Using .class literals causes eager class loading, making @TargetClass annotations visible to GraalVM's annotation processor even when we conditionally skip adding them to the result list. By loading the classes reflectively with Class.forName(), we prevent them from being discovered when JMXFetch is not present. Also increased native-image heap from 4GB to 8GB to avoid OOM during compilation with profiler enabled. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 23ab89c commit 721ee67

2 files changed

Lines changed: 53 additions & 4 deletions

File tree

dd-java-agent/instrumentation/graal/graal-native-image-20.0/src/main/java/datadog/trace/instrumentation/graal/nativeimage/AnnotationSubstitutionProcessorInstrumentation.java

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,58 @@ public static class FindTargetClassesAdvice {
3434
public static void onExit(@Advice.Return(readOnly = false) List<Class<?>> result) {
3535
result.add(Target_com_datadog_profiling_agent_ProcessContext.class);
3636
result.add(Target_datadog_jctools_util_UnsafeRefArrayAccess.class);
37-
result.add(Target_org_datadog_jmxfetch_App.class);
38-
result.add(Target_org_datadog_jmxfetch_Status.class);
39-
result.add(Target_org_datadog_jmxfetch_reporter_JsonReporter.class);
37+
38+
// Only register JMXFetch substitutions if JMXFetch is actually present on the classpath.
39+
//
40+
// NOTE: It's unclear why these substitutions get triggered during native-image compilation
41+
// when JMXFetch classes are not available. In theory, either:
42+
// 1) The substitutions should not be triggered at all (JMXFetch not in use), OR
43+
// 2) JMXFetch classes should be available (if JMXFetch is in use)
44+
//
45+
// However, in practice, adding profiling-scrubber to the agent triggers native-image to
46+
// discover these substitutions even when building applications that don't use JMXFetch,
47+
// causing "Substitution target not loaded" errors.
48+
//
49+
// This runtime check works around the issue for GraalVM 20.0 (which lacks the `onlyWith`
50+
// field in @TargetClass). For GraalVM 21+, the proper fix would be adding:
51+
// @TargetClass(className = "org.datadog.jmxfetch.App", onlyWith = JmxFetchPresent.class)
52+
//
53+
// IMPORTANT: We must load these classes reflectively (not using .class literals) to prevent
54+
// them from being discovered by GraalVM's annotation processor when JMXFetch is not present.
55+
// Using .class literals causes eager loading, making @TargetClass annotations visible even
56+
// if we don't add them to the result list.
57+
if (isJmxFetchPresent()) {
58+
try {
59+
ClassLoader cl = FindTargetClassesAdvice.class.getClassLoader();
60+
result.add(
61+
Class.forName(
62+
"datadog.trace.instrumentation.graal.nativeimage.Target_org_datadog_jmxfetch_App",
63+
false,
64+
cl));
65+
result.add(
66+
Class.forName(
67+
"datadog.trace.instrumentation.graal.nativeimage.Target_org_datadog_jmxfetch_Status",
68+
false,
69+
cl));
70+
result.add(
71+
Class.forName(
72+
"datadog.trace.instrumentation.graal.nativeimage.Target_org_datadog_jmxfetch_reporter_JsonReporter",
73+
false,
74+
cl));
75+
} catch (ClassNotFoundException e) {
76+
// Substitution classes not available, skip them
77+
}
78+
}
79+
}
80+
81+
private static boolean isJmxFetchPresent() {
82+
try {
83+
Class.forName(
84+
"org.datadog.jmxfetch.App", false, FindTargetClassesAdvice.class.getClassLoader());
85+
return true;
86+
} catch (ClassNotFoundException e) {
87+
return false;
88+
}
4089
}
4190
}
4291
}

dd-smoke-tests/spring-boot-3.0-native/application/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ if (hasProperty('agentPath')) {
3838
if (withProfiler && property('profiler') == 'true') {
3939
buildArgs.add("-J-Ddd.profiling.enabled=true")
4040
}
41-
jvmArgs.add("-Xmx4096M")
41+
jvmArgs.add("-Xmx8192M")
4242
}
4343
}
4444
}

0 commit comments

Comments
 (0)