From af947556ee1725b7132bc3ebfb12c0916905c7cb Mon Sep 17 00:00:00 2001 From: David Date: Sat, 15 Aug 2026 21:12:34 +0200 Subject: [PATCH 1/3] Find and use first error message in tracked errors --- .../src/main/java/dev/faststats/ErrorHelper.java | 14 +++++++++++--- .../java/dev/faststats/ErrorTrackerTest.java | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/dev/faststats/ErrorHelper.java b/core/src/main/java/dev/faststats/ErrorHelper.java index e1c0b864..bcd299b6 100644 --- a/core/src/main/java/dev/faststats/ErrorHelper.java +++ b/core/src/main/java/dev/faststats/ErrorHelper.java @@ -36,7 +36,7 @@ private static JsonObject compileAll(final TrackedError trackedError, @Nullable @Nullable final Attributes defaultAttributes) { final var error = trackedError.error(); final var report = new JsonObject(); - final var message = getAnonymizedMessage(error, customPatterns); + final var message = anonymize(findFirstMessage(error, null), customPatterns); final var stacktrace = new JsonArray(); final var header = message != null @@ -75,7 +75,7 @@ private static void appendCauseChain(@Nullable Throwable cause, final ListnewSetFromMap(new IdentityHashMap<>()); while (cause != null && visited.add(cause)) { - final var causeMessage = getAnonymizedMessage(cause, customPatterns); + final var causeMessage = anonymize(cause.getMessage(), customPatterns); final var header = causeMessage != null ? "Caused by: " + cause.getClass().getName() + ": " + causeMessage : "Caused by: " + cause.getClass().getName(); @@ -213,8 +213,16 @@ private static boolean isSameClassLoader(final ClassLoader classLoader, final Cl return loader == current; } - private static @Nullable String getAnonymizedMessage(final Throwable error, final List> customPatterns) { + private static @Nullable String findFirstMessage(@Nullable final Throwable error, @Nullable Set visited) { + if (error == null) return null; final var message = error.getMessage(); + if (message != null) return message; + if (visited == null) visited = Collections.newSetFromMap(new IdentityHashMap<>()); + if (!visited.add(error)) return null; + return findFirstMessage(error.getCause(), visited); + } + + private static @Nullable String anonymize(@Nullable final String message, final List> customPatterns) { if (message == null) return null; var truncated = message.length() > MAX_MESSAGE_LENGTH ? message.substring(0, MAX_MESSAGE_LENGTH) + "..." diff --git a/core/src/test/java/dev/faststats/ErrorTrackerTest.java b/core/src/test/java/dev/faststats/ErrorTrackerTest.java index 91e6a3a6..70e5e4fe 100644 --- a/core/src/test/java/dev/faststats/ErrorTrackerTest.java +++ b/core/src/test/java/dev/faststats/ErrorTrackerTest.java @@ -165,6 +165,22 @@ public void nullMessagesAreNotSerializedAsMessageProperty() { assertEquals("java.lang.RuntimeException", report.getAsJsonArray("stack").get(0).getAsString()); } + @Test + public void messageFallsBackToCauseMessage() { + final var cause = new IllegalArgumentException("cause message"); + final var error = new RuntimeException(null, cause); + + tracker.trackError(error); + + final var report = tracker.getFullData().get(0).getAsJsonObject(); + final var stack = report.getAsJsonArray("stack"); + assertEquals("cause message", report.get("message").getAsString()); + assertEquals("java.lang.RuntimeException: cause message", stack.get(0).getAsString()); + assertTrue(stack.asList().stream() + .anyMatch(line -> line.getAsString() + .equals("Caused by: java.lang.IllegalArgumentException: cause message"))); + } + @Test public void nestedCausesAreSerializedInOrder() { final var root = new IllegalArgumentException("root secret 172.16.0.9"); From 22ecd7bd752c8dc308bb06ba9371b87aad0fbbde Mon Sep 17 00:00:00 2001 From: David Date: Sat, 15 Aug 2026 22:02:05 +0200 Subject: [PATCH 2/3] Only use first message in root message field --- core/src/main/java/dev/faststats/ErrorHelper.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/dev/faststats/ErrorHelper.java b/core/src/main/java/dev/faststats/ErrorHelper.java index bcd299b6..34f9f56a 100644 --- a/core/src/main/java/dev/faststats/ErrorHelper.java +++ b/core/src/main/java/dev/faststats/ErrorHelper.java @@ -36,7 +36,7 @@ private static JsonObject compileAll(final TrackedError trackedError, @Nullable @Nullable final Attributes defaultAttributes) { final var error = trackedError.error(); final var report = new JsonObject(); - final var message = anonymize(findFirstMessage(error, null), customPatterns); + final var message = anonymize(error.getMessage(), customPatterns); final var stacktrace = new JsonArray(); final var header = message != null @@ -54,7 +54,8 @@ private static JsonObject compileAll(final TrackedError trackedError, @Nullable appendCauseChain(error.getCause(), stack, suppress, stacktrace, customPatterns); report.addProperty("error", error.getClass().getName()); - if (message != null) report.addProperty("message", message); + final var first = anonymize(findFirstMessage(error, null), customPatterns); + if (first != null) report.addProperty("message", first); report.add("stack", stacktrace); report.addProperty("handled", trackedError.handled()); From b78940767d0c85e93e1748e477c4e5ca126dc4d0 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 15 Aug 2026 22:04:51 +0200 Subject: [PATCH 3/3] Fix test to reflect latest changes --- core/src/test/java/dev/faststats/ErrorTrackerTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/src/test/java/dev/faststats/ErrorTrackerTest.java b/core/src/test/java/dev/faststats/ErrorTrackerTest.java index 70e5e4fe..aa5ad741 100644 --- a/core/src/test/java/dev/faststats/ErrorTrackerTest.java +++ b/core/src/test/java/dev/faststats/ErrorTrackerTest.java @@ -175,10 +175,6 @@ public void messageFallsBackToCauseMessage() { final var report = tracker.getFullData().get(0).getAsJsonObject(); final var stack = report.getAsJsonArray("stack"); assertEquals("cause message", report.get("message").getAsString()); - assertEquals("java.lang.RuntimeException: cause message", stack.get(0).getAsString()); - assertTrue(stack.asList().stream() - .anyMatch(line -> line.getAsString() - .equals("Caused by: java.lang.IllegalArgumentException: cause message"))); } @Test