Skip to content

Commit 9d19300

Browse files
committed
Set up crash-tracking JVM flags automatically (for Hotspot)
1 parent de593cc commit 9d19300

File tree

6 files changed

+100
-33
lines changed

6 files changed

+100
-33
lines changed

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,11 @@ public static void start(
198198
injectAgentArgsConfig(agentArgs);
199199
}
200200

201+
// We want to have this enabled as soon as possible
202+
// It entails loading a native library so let's see if it works without regression in startup
203+
// time
204+
initializeErrorTracking();
205+
201206
// Retro-compatibility for the old way to configure CI Visibility
202207
if ("true".equals(ddGetProperty("dd.integration.junit.enabled"))
203208
|| "true".equals(ddGetProperty("dd.integration.testng.enabled"))) {
@@ -759,8 +764,6 @@ private static synchronized void startJmx() {
759764
if (jmxStarting.getAndSet(true)) {
760765
return; // another thread is already in startJmx
761766
}
762-
// error tracking initialization relies on JMX being available
763-
initializeErrorTracking();
764767
if (jmxFetchEnabled) {
765768
startJmxFetch();
766769
}
@@ -1025,7 +1028,7 @@ private static void initializeErrorTracking() {
10251028
return;
10261029
}
10271030
try {
1028-
Class<?> clz = AGENT_CLASSLOADER.loadClass("com.datadog.crashtracking.ScriptInitializer");
1031+
Class<?> clz = AGENT_CLASSLOADER.loadClass("com.datadog.crashtracking.Initializer");
10291032
clz.getMethod("initialize").invoke(null);
10301033
} catch (Throwable t) {
10311034
log.debug("Unable to initialize crash uploader", t);

dd-java-agent/agent-crashtracking/build.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ dependencies {
1717
implementation project(':utils:container-utils')
1818
implementation project(':utils:version-utils')
1919

20+
implementation project.hasProperty('ddprof.jar') ? files(project.getProperty('ddprof.jar')) : libs.ddprof
21+
2022
implementation libs.okhttp
2123
implementation libs.moshi
2224

dd-java-agent/agent-crashtracking/src/main/java/com/datadog/crashtracking/CrashUploaderScriptInitializer.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package com.datadog.crashtracking;
22

3-
import static com.datadog.crashtracking.ScriptInitializer.LOG;
4-
import static com.datadog.crashtracking.ScriptInitializer.RWXRWXRWX;
5-
import static com.datadog.crashtracking.ScriptInitializer.R_XR_XR_X;
6-
import static com.datadog.crashtracking.ScriptInitializer.findAgentJar;
7-
import static com.datadog.crashtracking.ScriptInitializer.getCrashUploaderTemplate;
8-
import static com.datadog.crashtracking.ScriptInitializer.writeConfig;
3+
import static com.datadog.crashtracking.Initializer.LOG;
4+
import static com.datadog.crashtracking.Initializer.RWXRWXRWX;
5+
import static com.datadog.crashtracking.Initializer.R_XR_XR_X;
6+
import static com.datadog.crashtracking.Initializer.findAgentJar;
7+
import static com.datadog.crashtracking.Initializer.getCrashUploaderTemplate;
8+
import static com.datadog.crashtracking.Initializer.writeConfig;
99
import static java.nio.file.attribute.PosixFilePermissions.asFileAttribute;
1010
import static java.nio.file.attribute.PosixFilePermissions.fromString;
1111
import static java.util.Locale.ROOT;
+78-16
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
import static java.util.Comparator.reverseOrder;
55
import static java.util.Locale.ROOT;
66

7-
import com.sun.management.HotSpotDiagnosticMXBean;
7+
import com.datadoghq.profiler.JVMAccess;
88
import datadog.trace.api.Platform;
9+
import datadog.trace.api.config.ProfilingConfig;
10+
import datadog.trace.bootstrap.config.provider.ConfigProvider;
911
import datadog.trace.util.PidHelper;
1012
import java.io.BufferedWriter;
1113
import java.io.IOException;
1214
import java.io.InputStream;
13-
import java.lang.management.ManagementFactory;
1415
import java.net.URL;
1516
import java.nio.file.Files;
1617
import java.nio.file.Path;
@@ -20,19 +21,33 @@
2021
import org.slf4j.Logger;
2122
import org.slf4j.LoggerFactory;
2223

23-
public final class ScriptInitializer {
24-
static final Logger LOG = LoggerFactory.getLogger(ScriptInitializer.class);
24+
public final class Initializer {
25+
static final Logger LOG = LoggerFactory.getLogger(Initializer.class);
2526
static final String PID_PREFIX = "_pid";
2627
static final String RWXRWXRWX = "rwxrwxrwx";
2728
static final String R_XR_XR_X = "r-xr-xr-x";
2829

2930
public static void initialize() {
30-
// this is HotSpot specific implementation (eg. will not work for IBM J9)
31-
HotSpotDiagnosticMXBean diagBean =
32-
ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
31+
ConfigProvider cfgProvider = ConfigProvider.getInstance();
32+
String scratchDir = cfgProvider.getString(ProfilingConfig.PROFILING_DATADOG_PROFILER_SCRATCH);
3333

34-
initializeCrashUploader(diagBean);
35-
initializeOOMENotifier(diagBean);
34+
JVMAccess jvmAccess =
35+
new JVMAccess(
36+
null,
37+
scratchDir,
38+
throwable -> {
39+
logInitializationError(
40+
"Unexpected exception while initializing JVMAccess", throwable);
41+
});
42+
43+
JVMAccess.Flags flags = jvmAccess.flags();
44+
45+
// // this is HotSpot specific implementation (eg. will not work for IBM J9)
46+
// HotSpotDiagnosticMXBean diagBean =
47+
// ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
48+
49+
initializeCrashUploader(flags);
50+
initializeOOMENotifier(flags);
3651
}
3752

3853
static InputStream getCrashUploaderTemplate() {
@@ -130,28 +145,75 @@ private static String getBaseName(Path path) {
130145
* `dd_crash_uploader.bat` and the script does not exist it will be created and prefilled with
131146
* code ensuring the error log upload will be triggered on JVM crash.
132147
*/
133-
private static void initializeCrashUploader(HotSpotDiagnosticMXBean diagBean) {
148+
private static void initializeCrashUploader(JVMAccess.Flags flags) {
134149
try {
135-
String onErrorVal = diagBean.getVMOption("OnError").getValue();
136-
String onErrorFile = diagBean.getVMOption("ErrorFile").getValue();
137-
CrashUploaderScriptInitializer.initialize(onErrorVal, onErrorFile);
150+
String onErrorVal = flags.getStringFlag("OnError");
151+
String onErrorFile = flags.getStringFlag("ErrorFile");
152+
153+
String uploadScript = getScript("dd_crash_uploader");
154+
if (onErrorVal == null || onErrorVal.isEmpty()) {
155+
onErrorVal = uploadScript;
156+
} else if (!onErrorVal.contains("dd_crash_uploader")) {
157+
// we can chain scripts so let's preserve the original value in addition to our crash
158+
// uploader
159+
onErrorVal = uploadScript + "; " + onErrorVal;
160+
}
161+
162+
// set the JVM flag
163+
flags.setStringFlag("OnError", onErrorVal);
164+
if (LOG.isDebugEnabled()) {
165+
String currentVal = flags.getStringFlag("OnError");
166+
if (!currentVal.equals(uploadScript)) {
167+
LOG.debug("Unable to set OnError flag to {}. Crash-tracking may not work.", currentVal);
168+
}
169+
}
170+
171+
CrashUploaderScriptInitializer.initialize(uploadScript, onErrorFile);
138172
} catch (Throwable t) {
139173
logInitializationError(
140174
"Unexpected exception while creating custom crash upload script. Crash tracking will not work properly.",
141175
t);
142176
}
143177
}
144178

145-
private static void initializeOOMENotifier(HotSpotDiagnosticMXBean diagBean) {
179+
private static void initializeOOMENotifier(JVMAccess.Flags flags) {
146180
try {
147-
String onOutOfMemoryVal = diagBean.getVMOption("OnOutOfMemoryError").getValue();
148-
OOMENotifierScriptInitializer.initialize(onOutOfMemoryVal);
181+
String onOutOfMemoryVal = flags.getStringFlag("OnOutOfMemoryError");
182+
String notifierScript = getScript("dd_oome_notifier");
183+
184+
if (onOutOfMemoryVal == null || onOutOfMemoryVal.isEmpty()) {
185+
onOutOfMemoryVal = notifierScript;
186+
} else if (!onOutOfMemoryVal.contains("dd_oome_notifier")) {
187+
// we can chain scripts so let's preserve the original value in addition to our oome tracker
188+
onOutOfMemoryVal = notifierScript + "; " + onOutOfMemoryVal;
189+
}
190+
191+
// set the JVM flag
192+
flags.setStringFlag("OnOutOfMemoryError", onOutOfMemoryVal);
193+
if (LOG.isDebugEnabled()) {
194+
String currentVal = flags.getStringFlag("OnOutOfMemoryError");
195+
if (!currentVal.equals(onOutOfMemoryVal)) {
196+
LOG.debug(
197+
"Unable to set OnOutOfMemoryError flag to {}. OOME tracking may not work.",
198+
currentVal);
199+
}
200+
}
201+
202+
OOMENotifierScriptInitializer.initialize(notifierScript);
149203
} catch (Throwable t) {
150204
logInitializationError(
151205
"Unexpected exception while initializing OOME notifier. OOMEs will not be tracked.", t);
152206
}
153207
}
154208

209+
private static String getScript(String scriptName) {
210+
return System.getProperty("java.io.tmpdir") + "/" + getScriptFileName(scriptName) + " %p";
211+
}
212+
213+
private static String getScriptFileName(String scriptName) {
214+
return scriptName + "." + (Platform.isWindows() ? "bat" : "sh");
215+
}
216+
155217
private static void logInitializationError(String msg, Throwable t) {
156218
if (LOG.isDebugEnabled()) {
157219
LOG.warn("{}", msg, t);

dd-java-agent/agent-crashtracking/src/main/java/com/datadog/crashtracking/OOMENotifierScriptInitializer.java

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package com.datadog.crashtracking;
22

3-
import static com.datadog.crashtracking.ScriptInitializer.LOG;
4-
import static com.datadog.crashtracking.ScriptInitializer.PID_PREFIX;
5-
import static com.datadog.crashtracking.ScriptInitializer.RWXRWXRWX;
6-
import static com.datadog.crashtracking.ScriptInitializer.R_XR_XR_X;
7-
import static com.datadog.crashtracking.ScriptInitializer.findAgentJar;
8-
import static com.datadog.crashtracking.ScriptInitializer.getOomeNotifierTemplate;
9-
import static com.datadog.crashtracking.ScriptInitializer.writeConfig;
3+
import static com.datadog.crashtracking.Initializer.LOG;
4+
import static com.datadog.crashtracking.Initializer.PID_PREFIX;
5+
import static com.datadog.crashtracking.Initializer.RWXRWXRWX;
6+
import static com.datadog.crashtracking.Initializer.R_XR_XR_X;
7+
import static com.datadog.crashtracking.Initializer.findAgentJar;
8+
import static com.datadog.crashtracking.Initializer.getOomeNotifierTemplate;
9+
import static com.datadog.crashtracking.Initializer.writeConfig;
1010
import static java.nio.file.FileVisitResult.CONTINUE;
1111
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
1212
import static java.nio.file.attribute.PosixFilePermissions.asFileAttribute;

gradle/libs.versions.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ moshi = '1.11.0'
2929
testcontainers = '1.20.1'
3030
jmc = "8.1.0"
3131
autoservice = "1.0-rc7"
32-
ddprof = "1.24.0"
32+
ddprof = "1.25.0"
3333
asm = "9.8"
3434
cafe_crypto = "0.1.0"
3535
lz4 = "1.7.1"

0 commit comments

Comments
 (0)