Skip to content

Commit 87823ae

Browse files
committed
chore: Add processor context for hotspot crash tracking
1 parent ea11e60 commit 87823ae

File tree

8 files changed

+115
-14
lines changed

8 files changed

+115
-14
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,18 @@ private RequestBody makeErrorTrackingRequestBody(@Nonnull CrashLog payload, bool
561561
"os.version")); // this has been restructured under OsInfo so taking raw here
562562
writer.endObject();
563563
}
564+
// experimental
565+
if (payload.experimental != null && payload.experimental.ucontext != null) {
566+
writer.name("experimental");
567+
writer.beginObject();
568+
writer.name("ucontext");
569+
writer.beginObject();
570+
for (Map.Entry<String, String> entry : payload.experimental.ucontext.entrySet()) {
571+
writer.name(entry.getKey()).value(entry.getValue());
572+
}
573+
writer.endObject();
574+
writer.endObject();
575+
}
564576
writer.endObject();
565577
}
566578
return RequestBody.create(APPLICATION_JSON, buf.readByteString());

dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/dto/CrashLog.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ public final class CrashLog {
3939
@Json(name = "sig_info")
4040
public final SigInfo sigInfo;
4141

42+
public final Experimental experimental;
43+
4244
public CrashLog(
4345
String uuid,
4446
boolean incomplete,
@@ -49,6 +51,30 @@ public CrashLog(
4951
ProcInfo procInfo,
5052
SigInfo sigInfo,
5153
String dataSchemaVersion) {
54+
this(
55+
uuid,
56+
incomplete,
57+
timestamp,
58+
error,
59+
metadata,
60+
osInfo,
61+
procInfo,
62+
sigInfo,
63+
dataSchemaVersion,
64+
null);
65+
}
66+
67+
public CrashLog(
68+
String uuid,
69+
boolean incomplete,
70+
String timestamp,
71+
ErrorData error,
72+
Metadata metadata,
73+
OSInfo osInfo,
74+
ProcInfo procInfo,
75+
SigInfo sigInfo,
76+
String dataSchemaVersion,
77+
Experimental experimental) {
5278
this.uuid = uuid != null ? uuid : RandomUtils.randomUUID().toString();
5379
this.incomplete = incomplete;
5480
this.timestamp = timestamp;
@@ -58,6 +84,7 @@ public CrashLog(
5884
this.procInfo = procInfo;
5985
this.sigInfo = sigInfo;
6086
this.dataSchemaVersion = dataSchemaVersion;
87+
this.experimental = experimental;
6188
}
6289

6390
public String toJson() {
@@ -85,7 +112,8 @@ public boolean equals(Object o) {
85112
&& Objects.equals(osInfo, crashLog.osInfo)
86113
&& Objects.equals(procInfo, crashLog.procInfo)
87114
&& Objects.equals(sigInfo, crashLog.sigInfo)
88-
&& Objects.equals(dataSchemaVersion, crashLog.dataSchemaVersion);
115+
&& Objects.equals(dataSchemaVersion, crashLog.dataSchemaVersion)
116+
&& Objects.equals(experimental, crashLog.experimental);
89117
}
90118

91119
@Override
@@ -100,7 +128,8 @@ public int hashCode() {
100128
procInfo,
101129
sigInfo,
102130
version,
103-
dataSchemaVersion);
131+
dataSchemaVersion,
132+
experimental);
104133
}
105134

106135
public boolean equalsForTest(Object o) {
@@ -119,6 +148,7 @@ public boolean equalsForTest(Object o) {
119148
&& Objects.equals(error, crashLog.error)
120149
&& Objects.equals(procInfo, crashLog.procInfo)
121150
&& Objects.equals(sigInfo, crashLog.sigInfo)
122-
&& Objects.equals(dataSchemaVersion, crashLog.dataSchemaVersion);
151+
&& Objects.equals(dataSchemaVersion, crashLog.dataSchemaVersion)
152+
&& Objects.equals(experimental, crashLog.experimental);
123153
}
124154
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package datadog.crashtracking.dto;
2+
3+
import java.util.Map;
4+
import java.util.Objects;
5+
6+
public final class Experimental {
7+
public final Map<String, String> ucontext;
8+
9+
public Experimental(Map<String, String> ucontext) {
10+
this.ucontext = ucontext;
11+
}
12+
13+
@Override
14+
public boolean equals(Object o) {
15+
if (!(o instanceof Experimental)) return false;
16+
Experimental that = (Experimental) o;
17+
return Objects.equals(ucontext, that.ucontext);
18+
}
19+
20+
@Override
21+
public int hashCode() {
22+
return Objects.hash(ucontext);
23+
}
24+
}

dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import datadog.crashtracking.buildid.BuildInfo;
88
import datadog.crashtracking.dto.CrashLog;
99
import datadog.crashtracking.dto.ErrorData;
10+
import datadog.crashtracking.dto.Experimental;
1011
import datadog.crashtracking.dto.Metadata;
1112
import datadog.crashtracking.dto.OSInfo;
1213
import datadog.crashtracking.dto.ProcInfo;
@@ -21,8 +22,10 @@
2122
import java.time.format.DateTimeFormatter;
2223
import java.time.format.DateTimeParseException;
2324
import java.util.ArrayList;
25+
import java.util.LinkedHashMap;
2426
import java.util.List;
2527
import java.util.Locale;
28+
import java.util.Map;
2629
import java.util.regex.Matcher;
2730
import java.util.regex.Pattern;
2831

@@ -45,6 +48,7 @@ enum State {
4548
SUMMARY,
4649
THREAD,
4750
STACKTRACE,
51+
REGISTERS,
4852
SEEK_DYNAMIC_LIBRARIES,
4953
DYNAMIC_LIBRARIES,
5054
DONE
@@ -65,6 +69,9 @@ public HotspotCrashLogParser() {
6569
"siginfo:\\s+si_signo:\\s+(\\d+)\\s+\\((\\w+)\\),\\s+si_code:\\s+(\\d+)\\s+\\(([^)]+)\\),\\s+si_addr:\\s+(0x[0-9a-fA-F]+)");
6670
private static final Pattern DYNAMIC_LIBS_PATH_PARSER =
6771
Pattern.compile("^(?:0x)?[0-9a-fA-F]+(?:-[0-9a-fA-F]+)?\\s+(?:[^\\s/\\[]+\\s+)*(.*)$");
72+
// Matches register entries like: RAX=0x..., R8 =0x..., TRAPNO=0x...
73+
private static final Pattern REGISTER_ENTRY_PARSER =
74+
Pattern.compile("([A-Z0-9]+)\\s*=\\s*(0x[0-9a-fA-F]+)");
6875

6976
private StackFrame parseLine(String line) {
7077
if (line == null || line.isEmpty()) {
@@ -84,10 +91,10 @@ private StackFrame parseLine(String line) {
8491
switch (firstChar) {
8592
case 'J':
8693
{
87-
// J 36572 c2 datadog.trace.util.AgentTaskScheduler$PeriodicTask.run()V (25 bytes) @
88-
// 0x00007f2fd0198488 [0x00007f2fd0198420+0x0000000000000068]
89-
// J 3896 c2 java.nio.ByteBuffer.allocate(I)Ljava/nio/ByteBuffer; java.base@21.0.1 (20
90-
// bytes) @ 0x0000000112ad51e8 [0x0000000112ad4fc0+0x0000000000000228]
94+
// spotless:off
95+
// J 36572 c2 datadog.trace.util.AgentTaskScheduler$PeriodicTask.run()V (25 bytes) @ 0x00007f2fd0198488 [0x00007f2fd0198420+0x0000000000000068]
96+
// J 3896 c2 java.nio.ByteBuffer.allocate(I)Ljava/nio/ByteBuffer; java.base@21.0.1 (20 bytes) @ 0x0000000112ad51e8 [0x0000000112ad4fc0+0x0000000000000228]
97+
// spotless:on
9198
String[] parts = SPACE_SPLITTER.split(line);
9299
if (parts.length > 3) {
93100
functionName = parts[3];
@@ -221,6 +228,7 @@ public CrashLog parse(String uuid, String crashLog) {
221228
String datetime = null;
222229
boolean incomplete = false;
223230
String oomMessage = null;
231+
Map<String, String> registers = null;
224232

225233
String[] lines = NEWLINE_SPLITTER.split(crashLog);
226234
outer:
@@ -275,8 +283,9 @@ public CrashLog parse(String uuid, String crashLog) {
275283
break;
276284
case STACKTRACE:
277285
if (line.startsWith("siginfo:")) {
278-
// siginfo: si_signo: 11 (SIGSEGV), si_code: 1 (SEGV_MAPERR), si_addr:
279-
// 0x0000000000000070
286+
// spotless:off
287+
// siginfo: si_signo: 11 (SIGSEGV), si_code: 1 (SEGV_MAPERR), si_addr: 0x0000000000000070
288+
// spotless:on
280289
final Matcher siginfoMatcher = SIGINFO_PARSER.matcher(line);
281290
if (siginfoMatcher.matches()) {
282291
Integer number = safelyParseInt(siginfoMatcher.group(1));
@@ -286,6 +295,9 @@ public CrashLog parse(String uuid, String crashLog) {
286295
String address = siginfoMatcher.group(5);
287296
sigInfo = new SigInfo(number, name, siCode, sigAction, address);
288297
}
298+
} else if (line.startsWith("Registers:")) {
299+
registers = new LinkedHashMap<>();
300+
state = State.REGISTERS;
289301
} else if (line.contains("P R O C E S S")) {
290302
state = State.SEEK_DYNAMIC_LIBRARIES;
291303
} else {
@@ -296,6 +308,18 @@ public CrashLog parse(String uuid, String crashLog) {
296308
}
297309
}
298310
break;
311+
case REGISTERS:
312+
if (!line.isEmpty() && !REGISTER_ENTRY_PARSER.matcher(line).find()) {
313+
// non-empty line with no register entries signals end of section; reprocess in
314+
// STACKTRACE
315+
state = State.STACKTRACE;
316+
} else {
317+
final Matcher m = REGISTER_ENTRY_PARSER.matcher(line);
318+
while (m.find()) {
319+
registers.put(m.group(1), m.group(2));
320+
}
321+
}
322+
break;
299323
case SEEK_DYNAMIC_LIBRARIES:
300324
if (line.startsWith("Dynamic libraries:")) {
301325
state = State.DYNAMIC_LIBRARIES;
@@ -382,8 +406,19 @@ public CrashLog parse(String uuid, String crashLog) {
382406
Metadata metadata = new Metadata("dd-trace-java", VersionInfo.VERSION, "java", null);
383407
Integer parsedPid = safelyParseInt(pid);
384408
ProcInfo procInfo = parsedPid != null ? new ProcInfo(parsedPid) : null;
409+
Experimental experimental =
410+
(registers != null && !registers.isEmpty()) ? new Experimental(registers) : null;
385411
return new CrashLog(
386-
uuid, incomplete, datetime, error, metadata, OSInfo.current(), procInfo, sigInfo, "1.0");
412+
uuid,
413+
incomplete,
414+
datetime,
415+
error,
416+
metadata,
417+
OSInfo.current(),
418+
procInfo,
419+
sigInfo,
420+
"1.0",
421+
experimental);
387422
}
388423

389424
static String dateTimeToISO(String datetime) {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"timestamp":"2024-09-20T13:19:06Z","ddsource":"crashtracker","error":{"is_crash":true,"type":"UNKNOWN","message":"Process terminated by signal UNKNOWN","source_type":"Crashtracking","stack":{"format":"CrashTrackerV1","frames":[{"function":"__pthread_clockjoin_ex+0x255","path":"libpthread.so.0","relative_address":"0x9cd5"}]}}}
1+
{"timestamp":"2024-09-20T13:19:06Z","ddsource":"crashtracker","error":{"is_crash":true,"type":"UNKNOWN","message":"Process terminated by signal UNKNOWN","source_type":"Crashtracking","stack":{"format":"CrashTrackerV1","frames":[{"function":"__pthread_clockjoin_ex+0x255","path":"libpthread.so.0","relative_address":"0x9cd5"}]}},"experimental":{"ucontext":{"RAX":"0x00000000000000ca","RBX":"0x00000000000000ca","RCX":"0x00007f011ab1ccd7","RDX":"0x000000000008ca23","RSP":"0x00007ffeabf89710","RBP":"0x00007ffeabf897b8","RSI":"0x0000000000000000","RDI":"0x00007f01192129d0","R8":"0x0000000000000000","R9":"0x00007f0119212700","R10":"0x0000000000000000","R11":"0x0000000000000246","R12":"0x000000000008ca23","R13":"0x00007f01192129d0","R14":"0x00007ffeabf89840","R15":"0x00007f0119212700","RIP":"0x00007f011ab1ccd5","EFLAGS":"0x0000000000000246","CSGSFS":"0x002b000000000033","ERR":"0x0000000000000000","TRAPNO":"0x0000000000000000"}}}

dd-java-agent/agent-crashtracking/src/test/resources/golden/errortracking/sample-crash-for-telemetry.txt

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"data_schema_version":"1.0","error":{"is_crash":true,"kind":"UNKNOWN","message":"Process terminated by signal UNKNOWN","source_type":"Crashtracking","stack":{"format":"CrashTrackerV1","frames":[{"function":"__pthread_clockjoin_ex+0x255","path":"libpthread.so.0","relative_address":"0x9cd5"}]}},"incomplete":false,"metadata":{"family":"java","library_name":"dd-trace-java","library_version":"1.60.0-SNAPSHOT~cffe9c6085"},"os_info":{"architecture":"aarch64","bitness":"64","os_type":"Mac OS X","version":{"Semantic":[15,7,1]}},"proc_info":{"pid":576034},"timestamp":"2024-09-20T13:19:06Z","uuid":"a4194cd6-8cb3-45fd-9bd9-3af83e0a3ad3","version_id":0}
1+
{"data_schema_version":"1.0","error":{"is_crash":true,"kind":"UNKNOWN","message":"Process terminated by signal UNKNOWN","source_type":"Crashtracking","stack":{"format":"CrashTrackerV1","frames":[{"function":"__pthread_clockjoin_ex+0x255","path":"libpthread.so.0","relative_address":"0x9cd5"}]}},"incomplete":false,"metadata":{"family":"java","library_name":"dd-trace-java","library_version":"1.60.0-SNAPSHOT~cffe9c6085"},"os_info":{"architecture":"aarch64","bitness":"64","os_type":"Mac OS X","version":{"Semantic":[15,7,1]}},"experimental":{"ucontext":{"RAX":"0x00000000000000ca","RBX":"0x00000000000000ca","RCX":"0x00007f011ab1ccd7","RDX":"0x000000000008ca23","RSP":"0x00007ffeabf89710","RBP":"0x00007ffeabf897b8","RSI":"0x0000000000000000","RDI":"0x00007f01192129d0","R8":"0x0000000000000000","R9":"0x00007f0119212700","R10":"0x0000000000000000","R11":"0x0000000000000246","R12":"0x000000000008ca23","R13":"0x00007f01192129d0","R14":"0x00007ffeabf89840","R15":"0x00007f0119212700","RIP":"0x00007f011ab1ccd5","EFLAGS":"0x0000000000000246","CSGSFS":"0x002b000000000033","ERR":"0x0000000000000000","TRAPNO":"0x0000000000000000"}},"proc_info":{"pid":576034},"timestamp":"2024-09-20T13:19:06Z","uuid":"a4194cd6-8cb3-45fd-9bd9-3af83e0a3ad3","version_id":0}

0 commit comments

Comments
 (0)