Skip to content

Commit a53b31b

Browse files
committed
Clean up telemetry messages. Add more profiling flare data.
1 parent c68b54c commit a53b31b

File tree

15 files changed

+437
-325
lines changed

15 files changed

+437
-325
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1162,7 +1162,7 @@ private static void initializeCrashTracking(boolean delayed, boolean checkNative
11621162
SEND_TELEMETRY, "Crashtracking failed to initialize. No additional details available.");
11631163
}
11641164
} catch (Throwable t) {
1165-
log.debug(SEND_TELEMETRY, "Unable to initialize crashtracking", t);
1165+
log.debug(SEND_TELEMETRY, "Unable to initialize crashtracking");
11661166
}
11671167
}
11681168

dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/Initializer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public static boolean initialize(boolean forceJmx) {
103103
initializeOOMENotifier(access);
104104
return true;
105105
} catch (Throwable t) {
106-
LOG.debug(SEND_TELEMETRY, "Failed to initialize crash tracking: " + t.getMessage(), t);
106+
LOG.debug("Failed to initialize crash tracking: " + t.getMessage(), t);
107107
}
108108
return false;
109109
}

dd-java-agent/agent-profiling/profiling-controller-openjdk/src/main/java/com/datadog/profiling/controller/openjdk/events/SmapEntryCache.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.datadog.profiling.controller.openjdk.events;
22

3-
import static datadog.trace.api.telemetry.LogCollector.SEND_TELEMETRY;
4-
53
import datadog.environment.JavaVirtualMachine;
64
import de.thetaphi.forbiddenapis.SuppressForbidden;
75
import java.io.BufferedReader;
@@ -296,7 +294,7 @@ private static Map<Long, String> getAnnotatedRegions() {
296294
}
297295
return annotatedRegions;
298296
} catch (Exception e) {
299-
log.debug(SEND_TELEMETRY, "Failed to get annotated regions", e);
297+
log.debug("Failed to get annotated regions", e);
300298
}
301299
return Collections.emptyMap();
302300
}
@@ -311,9 +309,9 @@ private void collectEvents(List<SmapEntryEvent> events) {
311309
}
312310
log.debug("Collected {} smap entry events.", events.size());
313311
} catch (IOException e) {
314-
log.debug(SEND_TELEMETRY, "Failed to read smap file", e);
312+
log.debug("Failed to read smap file", e);
315313
} catch (Exception e) {
316-
log.debug(SEND_TELEMETRY, "Failed to parse smap file", e);
314+
log.debug("Failed to parse smap file", e);
317315
}
318316
}
319317
}

dd-java-agent/agent-profiling/profiling-controller-openjdk/src/main/java/com/datadog/profiling/controller/openjdk/events/SmapEntryFactory.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
package com.datadog.profiling.controller.openjdk.events;
22

3-
import static datadog.trace.api.telemetry.LogCollector.SEND_TELEMETRY;
4-
53
import datadog.environment.JavaVirtualMachine;
64
import datadog.environment.OperatingSystem;
5+
import datadog.trace.api.profiling.ProfilerFlareLogger;
76
import datadog.trace.bootstrap.instrumentation.jfr.JfrHelper;
87
import java.lang.management.ManagementFactory;
98
import java.time.Duration;
@@ -62,9 +61,8 @@ public static void registerEvents() {
6261
log.debug("Smap entry events registered successfully");
6362
}
6463
} catch (Exception e) {
65-
log.debug(
66-
SEND_TELEMETRY,
67-
"Smap entry events could not be registered due to missing systemMap operation");
64+
ProfilerFlareLogger.getInstance()
65+
.log("Smap entry events could not be registered due to missing systemMap operation", e);
6866
}
6967
}
7068
}
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
package com.datadog.profiling.controller;
2+
3+
import datadog.environment.JavaVirtualMachine;
4+
import datadog.environment.OperatingSystem;
5+
import datadog.environment.SystemProperties;
6+
import de.thetaphi.forbiddenapis.SuppressForbidden;
7+
import java.io.File;
8+
import java.io.IOException;
9+
import java.net.URL;
10+
import java.nio.file.FileSystems;
11+
import java.nio.file.FileVisitResult;
12+
import java.nio.file.FileVisitor;
13+
import java.nio.file.Files;
14+
import java.nio.file.Path;
15+
import java.nio.file.Paths;
16+
import java.nio.file.attribute.BasicFileAttributes;
17+
import java.nio.file.attribute.PosixFilePermissions;
18+
import java.util.Set;
19+
import java.util.function.Supplier;
20+
import java.util.jar.JarFile;
21+
22+
public final class EnvironmentChecker {
23+
private static void appendLine(String line, StringBuilder sb) {
24+
sb.append(line).append(System.lineSeparator());
25+
}
26+
27+
private static void appendLine(Supplier<StringBuilder> sbSupplier) {
28+
sbSupplier.get().append(System.lineSeparator());
29+
}
30+
31+
@SuppressForbidden
32+
public static boolean checkEnvironment(String temp, StringBuilder sb) {
33+
if (!JavaVirtualMachine.isJavaVersionAtLeast(8)) {
34+
appendLine("Profiler requires Java 8 or newer", sb);
35+
return false;
36+
}
37+
appendLine(
38+
() ->
39+
sb.append("Using Java version: ")
40+
.append(JavaVirtualMachine.getRuntimeVersion())
41+
.append(" (")
42+
.append(SystemProperties.getOrDefault("java.home", "unknown"))
43+
.append(")"));
44+
appendLine(
45+
() ->
46+
sb.append("Running as user: ")
47+
.append(SystemProperties.getOrDefault("user.name", "unknown")));
48+
boolean result = false;
49+
result |= checkJFR(sb);
50+
result |= checkDdprof(sb);
51+
if (!result) {;
52+
appendLine("Profiler is not supported on this JVM.", sb);
53+
return false;
54+
} else {
55+
appendLine("Profiler is supported on this JVM.", sb);
56+
}
57+
sb.append(System.lineSeparator());
58+
if (!checkTempLocation(temp, sb)) {
59+
appendLine("Profiler will not work properly due to issues with temp directory location.", sb);
60+
return false;
61+
} else {
62+
if (!temp.equals(SystemProperties.get("java.io.tmpdir"))) {
63+
appendLine(
64+
() ->
65+
sb.append("! Make sure to add '-Ddd.profiling.tempdir=")
66+
.append(temp)
67+
.append("' to your JVM command line !"));
68+
}
69+
}
70+
appendLine("Profiler is ready to be used.", sb);
71+
return true;
72+
}
73+
74+
@SuppressForbidden
75+
private static boolean checkJFR(StringBuilder sb) {
76+
if (JavaVirtualMachine.isOracleJDK8()) {
77+
appendLine(
78+
"JFR is commercial feature in Oracle JDK 8. Make sure you have the right license.", sb);
79+
return true;
80+
} else if (JavaVirtualMachine.isJ9()) {
81+
appendLine("JFR is not supported on J9 JVM.", sb);
82+
return false;
83+
} else {
84+
appendLine(
85+
() -> sb.append("JFR is supported on ").append(JavaVirtualMachine.getRuntimeVersion()));
86+
return true;
87+
}
88+
}
89+
90+
@SuppressForbidden
91+
private static boolean checkDdprof(StringBuilder sb) {
92+
if (!OperatingSystem.isLinux()) {
93+
appendLine("Datadog profiler is only supported on Linux.", sb);
94+
return false;
95+
} else {
96+
appendLine(
97+
() ->
98+
sb.append("Datadog profiler is supported on ")
99+
.append(JavaVirtualMachine.getRuntimeVersion()));
100+
return true;
101+
}
102+
}
103+
104+
@SuppressForbidden
105+
private static boolean checkTempLocation(String temp, StringBuilder sb) {
106+
// Check if the temp directory is writable
107+
if (temp == null || temp.isEmpty()) {
108+
appendLine("Temp directory is not specified.", sb);
109+
return false;
110+
}
111+
112+
appendLine(() -> sb.append("Checking temporary directory: ").append(temp));
113+
114+
Path base = Paths.get(temp);
115+
if (!Files.exists(base)) {
116+
appendLine(() -> sb.append("Temporary directory does not exist: ").append(base));
117+
return false;
118+
}
119+
Path target = base.resolve("dd-profiler").normalize();
120+
boolean rslt = true;
121+
Set<String> supportedViews = FileSystems.getDefault().supportedFileAttributeViews();
122+
boolean isPosix = supportedViews.contains("posix");
123+
try {
124+
if (isPosix) {
125+
Files.createDirectories(
126+
target,
127+
PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwx------")));
128+
} else {
129+
// non-posix, eg. Windows - let's rely on the created folders being world-writable
130+
Files.createDirectories(target);
131+
}
132+
appendLine(() -> sb.append("Temporary directory is writable: ").append(target));
133+
rslt &= checkCreateTempFile(target, sb);
134+
rslt &= checkLoadLibrary(target, sb);
135+
} catch (Exception e) {
136+
appendLine(() -> sb.append("Unable to create temp directory in location ").append(temp));
137+
if (isPosix) {
138+
appendLine(
139+
() ->
140+
sb.append("Base dir: ")
141+
.append(base)
142+
.append(" [")
143+
.append(getPermissionsStringSafe(base))
144+
.append("]"));
145+
}
146+
appendLine(() -> sb.append("Error: ").append(e));
147+
} finally {
148+
if (Files.exists(target)) {
149+
try {
150+
Files.walkFileTree(
151+
target,
152+
new FileVisitor<Path>() {
153+
@Override
154+
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
155+
throws IOException {
156+
return FileVisitResult.CONTINUE;
157+
}
158+
159+
@Override
160+
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
161+
throws IOException {
162+
Files.delete(file);
163+
return FileVisitResult.CONTINUE;
164+
}
165+
166+
@Override
167+
public FileVisitResult visitFileFailed(Path file, IOException exc)
168+
throws IOException {
169+
return FileVisitResult.CONTINUE;
170+
}
171+
172+
@Override
173+
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
174+
throws IOException {
175+
Files.delete(dir);
176+
return FileVisitResult.CONTINUE;
177+
}
178+
});
179+
} catch (IOException ignored) {
180+
// should never happen
181+
}
182+
}
183+
}
184+
return rslt;
185+
}
186+
187+
private static String getPermissionsStringSafe(Path file) {
188+
try {
189+
return PosixFilePermissions.toString(Files.getPosixFilePermissions(file));
190+
} catch (IOException ignored) {
191+
return "<unavailable>";
192+
}
193+
}
194+
195+
@SuppressForbidden
196+
private static boolean checkCreateTempFile(Path target, StringBuilder sb) {
197+
// create a file to check if the directory is writable
198+
try {
199+
appendLine(() -> sb.append("Attempting to create a test file in: ").append(target));
200+
Path testFile = target.resolve("testfile");
201+
Files.createFile(testFile);
202+
appendLine(() -> sb.append("Test file created: ").append(testFile));
203+
return true;
204+
} catch (Exception e) {
205+
appendLine(() -> sb.append("Unable to create test file in temp directory ").append(target));
206+
appendLine(() -> sb.append("Error: ").append(e));
207+
}
208+
return false;
209+
}
210+
211+
@SuppressForbidden
212+
private static boolean checkLoadLibrary(Path target, StringBuilder sb) {
213+
if (!OperatingSystem.isLinux()) {
214+
// we are loading the native library only on linux
215+
appendLine("Skipping native library check on non-linux platform", sb);
216+
return true;
217+
}
218+
boolean rslt = true;
219+
try {
220+
rslt &= extractSoFromJar(target, sb);
221+
if (rslt) {
222+
Path libFile = target.resolve("libjavaProfiler.so");
223+
appendLine(() -> sb.append("Attempting to load native library from: ").append(libFile));
224+
System.load(libFile.toString());
225+
appendLine("Native library loaded successfully", sb);
226+
}
227+
return true;
228+
} catch (Throwable t) {
229+
appendLine(
230+
() -> sb.append("Unable to load native library in temp directory ").append(target));
231+
appendLine(() -> sb.append("Error: ").append(t));
232+
return false;
233+
}
234+
}
235+
236+
@SuppressForbidden
237+
private static boolean extractSoFromJar(Path target, StringBuilder sb) throws Exception {
238+
URL jarUrl = EnvironmentChecker.class.getProtectionDomain().getCodeSource().getLocation();
239+
try (JarFile jarFile = new JarFile(new File(jarUrl.toURI()))) {
240+
return jarFile.stream()
241+
.filter(e -> e.getName().contains("libjavaProfiler.so"))
242+
.filter(
243+
e ->
244+
e.getName()
245+
.contains(OperatingSystem.isAarch64() ? "/linux-arm64/" : "/linux-x64/")
246+
&& (!OperatingSystem.isMusl() || e.getName().contains("-musl")))
247+
.findFirst()
248+
.map(
249+
e -> {
250+
try {
251+
Path soFile = target.resolve("libjavaProfiler.so");
252+
Files.createDirectories(soFile.getParent());
253+
Files.copy(jarFile.getInputStream(e), soFile);
254+
appendLine(() -> sb.append("Native library extracted to: ").append(soFile));
255+
return true;
256+
} catch (Throwable t) {
257+
appendLine("Failed to extract or load native library", sb);
258+
appendLine(() -> sb.append("Error: ").append(t));
259+
}
260+
return false;
261+
})
262+
.orElse(Boolean.FALSE);
263+
}
264+
}
265+
}

dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/ProfilerFlareReporter.java renamed to dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerFlareReporter.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
package com.datadog.profiling.agent;
1+
package com.datadog.profiling.controller;
22

3-
import com.datadog.profiling.controller.ProfilingSupport;
43
import datadog.trace.api.Config;
54
import datadog.trace.api.config.ProfilingConfig;
65
import datadog.trace.api.flare.TracerFlare;
@@ -15,14 +14,14 @@
1514

1615
public final class ProfilerFlareReporter implements TracerFlare.Reporter {
1716
private static final ProfilerFlareReporter INSTANCE = new ProfilerFlareReporter();
18-
private static Exception profilerInitializationException;
17+
private volatile Exception profilerInitializationException;
1918

2019
public static void register() {
2120
TracerFlare.addReporter(INSTANCE);
2221
}
2322

2423
public static void reportInitializationException(Exception e) {
25-
profilerInitializationException = e;
24+
INSTANCE.profilerInitializationException = e;
2625
}
2726

2827
@Override
@@ -40,6 +39,12 @@ public void addReportToFlare(ZipOutputStream zip) throws IOException {
4039
// no-op, ignore if we can't read the template override file
4140
}
4241
}
42+
43+
StringBuilder envCheck = new StringBuilder();
44+
String tempDir = ConfigProvider.getInstance().getString(ProfilingConfig.PROFILING_TEMP_DIR);
45+
EnvironmentChecker.checkEnvironment(
46+
tempDir != null ? tempDir : System.getProperty("java.io.tmpdir"), envCheck);
47+
TracerFlare.addText(zip, "profiler_env.txt", envCheck.toString());
4348
}
4449

4550
private String getProfilerConfig() {

dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerSettingsSupport.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,6 @@ protected ProfilerSettingsSupport(
189189
// usually set via DD_INSTRUMENTATION_INSTALL_TYPE env var
190190
configProvider.getString("instrumentation.install.type");
191191
this.profilerActivationSetting = getProfilerActivation(configProvider);
192-
193-
logger.debug(
194-
SEND_TELEMETRY,
195-
"Profiler settings: " + this); // telemetry receiver does not recognize formatting
196192
}
197193

198194
private static int getStackDepth() {
@@ -212,8 +208,7 @@ private static int getStackDepth() {
212208
try {
213209
return Integer.parseInt(value.substring(start, end));
214210
} catch (NumberFormatException e) {
215-
logger.debug(
216-
SEND_TELEMETRY, "Failed to parse stack depth from JFR options: {}", value, e);
211+
logger.debug(SEND_TELEMETRY, "Failed to parse stack depth from JFR options");
217212
}
218213
}
219214
}

0 commit comments

Comments
 (0)