Skip to content

Commit a1931a3

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

File tree

6 files changed

+96
-33
lines changed

6 files changed

+96
-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;
+74-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,29 @@
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+
initializeCrashUploader(flags);
46+
initializeOOMENotifier(flags);
3647
}
3748

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

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

205+
private static String getScript(String scriptName) {
206+
return System.getProperty("java.io.tmpdir") + "/" + getScriptFileName(scriptName) + " %p";
207+
}
208+
209+
private static String getScriptFileName(String scriptName) {
210+
return scriptName + "." + (Platform.isWindows() ? "bat" : "sh");
211+
}
212+
155213
private static void logInitializationError(String msg, Throwable t) {
156214
if (LOG.isDebugEnabled()) {
157215
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)