From b117ab3ab7b1a447de3ac3c78d545998051a8e46 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Fri, 19 Jun 2026 14:57:46 +0200 Subject: [PATCH] Improve crash report message when signal is absent --- .../parsers/HotspotCrashLogParser.java | 7 +++++-- .../parsers/J9JavacoreParser.java | 4 ++-- .../parsers/HotspotCrashLogParserTest.java | 21 +++++++++++++++++++ .../parsers/J9JavacoreParserTest.java | 18 ++++++++++++++++ 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java index 33985ebc65c..0c01f6b57a9 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java @@ -550,9 +550,12 @@ public CrashLog parse(String uuid, String crashLog) { if (oomMessage != null) { kind = "OutOfMemory"; message = oomMessage; - } else { - kind = sigInfo != null && sigInfo.name != null ? sigInfo.name : "UNKNOWN"; + } else if (sigInfo != null && sigInfo.name != null) { + kind = sigInfo.name; message = "Process terminated by signal " + kind; + } else { + kind = "InternalError"; + message = "Process terminated by Internal error"; } final List enrichedFrames = new ArrayList<>(frames.size()); diff --git a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/J9JavacoreParser.java b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/J9JavacoreParser.java index 1d7214dde6d..f13896b0dca 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/J9JavacoreParser.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/J9JavacoreParser.java @@ -257,8 +257,8 @@ public CrashLog parse(String uuid, String javacoreContent) { : eventType.toUpperCase(Locale.ROOT); message = "Process terminated by signal " + kind; } else { - kind = "UNKNOWN"; - message = "Unknown crash event"; + kind = "InternalError"; + message = "Process terminated by Internal error"; } // Enrich frames with build IDs (best effort) diff --git a/dd-java-agent/agent-crashtracking/src/test/java/datadog/crashtracking/parsers/HotspotCrashLogParserTest.java b/dd-java-agent/agent-crashtracking/src/test/java/datadog/crashtracking/parsers/HotspotCrashLogParserTest.java index 0abe9c8921d..2008ac78e05 100644 --- a/dd-java-agent/agent-crashtracking/src/test/java/datadog/crashtracking/parsers/HotspotCrashLogParserTest.java +++ b/dd-java-agent/agent-crashtracking/src/test/java/datadog/crashtracking/parsers/HotspotCrashLogParserTest.java @@ -49,6 +49,8 @@ public void testIncompleteParsing() throws Exception { assertNotNull(crashLog.error.stack); assertNotNull(crashLog.error.stack.frames); assertEquals(0, crashLog.error.stack.frames.length); + assertEquals("InternalError", crashLog.error.kind); + assertEquals("Process terminated by Internal error", crashLog.error.message); } /** macOS aarch64 uses lowercase register names: x0-x28, fp, lr, sp, pc, cpsr */ @@ -335,6 +337,25 @@ public void testParseCurrentThreadName(String line, String expected) { HotspotCrashLogParser.parseCurrentThreadName(line)); } + @Test + public void testNoSignalProducesInternalError() throws Exception { + // A crash log that reaches the PROCESS section but has no siginfo line + String crashLog = + "# A fatal error has been detected by the Java Runtime Environment:\n" + + "#\n" + + "# Core dump will be written.\n" + + "--------------- T H R E A D ---------------\n" + + "Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)\n" + + "--------------- P R O C E S S ---------------\n"; + + CrashLog result = new HotspotCrashLogParser().parse(UUID.randomUUID().toString(), crashLog); + + assertNotNull(result); + assertFalse(result.incomplete); + assertEquals("InternalError", result.error.kind); + assertEquals("Process terminated by Internal error", result.error.message); + } + private String readFileAsString(String resource) throws IOException { try (InputStream stream = getClass().getClassLoader().getResourceAsStream(resource)) { return new BufferedReader( diff --git a/dd-java-agent/agent-crashtracking/src/test/java/datadog/crashtracking/parsers/J9JavacoreParserTest.java b/dd-java-agent/agent-crashtracking/src/test/java/datadog/crashtracking/parsers/J9JavacoreParserTest.java index 63ffe0fbe10..cab2a9a457e 100644 --- a/dd-java-agent/agent-crashtracking/src/test/java/datadog/crashtracking/parsers/J9JavacoreParserTest.java +++ b/dd-java-agent/agent-crashtracking/src/test/java/datadog/crashtracking/parsers/J9JavacoreParserTest.java @@ -212,6 +212,24 @@ public void testDateTimeParsing() throws Exception { "Expected ISO-8601 format, got: " + crashLog.timestamp); } + @Test + public void testNoSignalProducesInternalError() throws Exception { + // A javacore with a THREADS section but no 1TISIGINFO line + String javacoreContent = + "0SECTION TITLE subcomponent dump routine\n" + + "NULL ===============================\n" + + "1TICHARSET UTF-8\n" + + "NULL ------------------------------------------------------------------------\n" + + "0SECTION THREADS subcomponent dump routine\n" + + "NULL =================================\n"; + + CrashLog result = new J9JavacoreParser().parse(UUID.randomUUID().toString(), javacoreContent); + + assertNotNull(result); + assertEquals("InternalError", result.error.kind); + assertEquals("Process terminated by Internal error", result.error.message); + } + private String readFileAsString(String resource) throws IOException { try (InputStream stream = getClass().getClassLoader().getResourceAsStream(resource)) { return new BufferedReader(