-
Notifications
You must be signed in to change notification settings - Fork 299
/
Copy pathScriptInitializer.java
165 lines (151 loc) · 5.91 KB
/
ScriptInitializer.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package com.datadog.crashtracking;
import static datadog.trace.util.AgentThreadFactory.AGENT_THREAD_GROUP;
import static java.util.Comparator.reverseOrder;
import static java.util.Locale.ROOT;
import com.sun.management.HotSpotDiagnosticMXBean;
import datadog.trace.api.Platform;
import datadog.trace.util.PidHelper;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class ScriptInitializer {
static final Logger LOG = LoggerFactory.getLogger(ScriptInitializer.class);
static final String PID_PREFIX = "_pid";
static final String RWXRWXRWX = "rwxrwxrwx";
static final String R_XR_XR_X = "r-xr-xr-x";
public static void initialize() {
// this is HotSpot specific implementation (eg. will not work for IBM J9)
HotSpotDiagnosticMXBean diagBean =
ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
initializeCrashUploader(diagBean);
initializeOOMENotifier(diagBean);
}
static InputStream getCrashUploaderTemplate() {
String name = Platform.isWindows() ? "upload_crash.bat" : "upload_crash.sh";
return CrashUploader.class.getResourceAsStream(name);
}
static InputStream getOomeNotifierTemplate() {
String name = Platform.isWindows() ? "notify_oome.bat" : "notify_oome.sh";
return OOMENotifier.class.getResourceAsStream(name);
}
static String findAgentJar() {
String agentPath = null;
String classResourceName = CrashUploader.class.getName().replace('.', '/') + ".class";
URL classResource = CrashUploader.class.getClassLoader().getResource(classResourceName);
String selfClass = classResource == null ? "null" : classResource.toString();
if (selfClass.startsWith("jar:file:")) {
int idx = selfClass.lastIndexOf(".jar");
if (idx > -1) {
agentPath = selfClass.substring(9, idx + 4);
}
}
// test harness env is different; use the known project structure to locate the agent jar
else if (selfClass.startsWith("file:")) {
int idx = selfClass.lastIndexOf("dd-java-agent");
if (idx > -1) {
Path libsPath = Paths.get(selfClass.substring(5, idx + 13), "build", "libs");
try (Stream<Path> files = Files.walk(libsPath)) {
Predicate<Path> isJarFile =
p -> p.getFileName().toString().toLowerCase(ROOT).endsWith(".jar");
agentPath =
files
.sorted(reverseOrder())
.filter(isJarFile)
.findFirst()
.map(Path::toString)
.orElse(null);
} catch (IOException ignored) {
// Ignore failure to get agent path
}
}
}
return agentPath;
}
static void writeConfig(Path scriptPath, String... entries) {
String cfgFileName = getBaseName(scriptPath) + PID_PREFIX + PidHelper.getPid() + ".cfg";
Path cfgPath = scriptPath.resolveSibling(cfgFileName);
LOG.debug("Writing config file: {}", cfgPath);
try (BufferedWriter bw = Files.newBufferedWriter(cfgPath)) {
for (int i = 0; i < entries.length; i += 2) {
bw.write(entries[i]);
bw.write('=');
bw.write(entries[i + 1]);
bw.newLine();
}
bw.write("java_home=" + System.getProperty("java.home"));
bw.newLine();
Runtime.getRuntime()
.addShutdownHook(
new Thread(
AGENT_THREAD_GROUP,
() -> {
try {
LOG.debug("Deleting config file: {}", cfgPath);
Files.deleteIfExists(cfgPath);
} catch (IOException e) {
LOG.warn("Failed deleting config file: {}", cfgPath, e);
}
}));
LOG.debug("Config file written: {}", cfgPath);
} catch (IOException e) {
LOG.warn("Failed writing config file: {}", cfgPath);
try {
Files.deleteIfExists(cfgPath);
} catch (IOException ignored) {
// ignore
}
}
}
private static String getBaseName(Path path) {
String filename = path.getFileName().toString();
int dotIndex = filename.lastIndexOf('.');
if (dotIndex == -1) {
return filename;
}
return filename.substring(0, dotIndex);
}
/**
* If the value of `-XX:OnError` JVM argument is referring to `dd_crash_uploader.sh` or
* `dd_crash_uploader.bat` and the script does not exist it will be created and prefilled with
* code ensuring the error log upload will be triggered on JVM crash.
*/
private static void initializeCrashUploader(HotSpotDiagnosticMXBean diagBean) {
try {
String onErrorVal = diagBean.getVMOption("OnError").getValue();
String onErrorFile = diagBean.getVMOption("ErrorFile").getValue();
CrashUploaderScriptInitializer.initialize(onErrorVal, onErrorFile);
} catch (Throwable t) {
logInitializationError(
"Unexpected exception while creating custom crash upload script. Crash tracking will not work properly.",
t);
}
}
private static void initializeOOMENotifier(HotSpotDiagnosticMXBean diagBean) {
try {
String onOutOfMemoryVal = diagBean.getVMOption("OnOutOfMemoryError").getValue();
OOMENotifierScriptInitializer.initialize(onOutOfMemoryVal);
} catch (Throwable t) {
logInitializationError(
"Unexpected exception while initializing OOME notifier. OOMEs will not be tracked.", t);
}
}
private static void logInitializationError(String msg, Throwable t) {
if (LOG.isDebugEnabled()) {
LOG.warn("{}", msg, t);
} else {
LOG.warn(
"{} [{}] (Change the logging level to debug to see the full stacktrace)",
msg,
t.getMessage());
}
}
}