diff --git a/core/src/main/java/dev/faststats/ErrorHelper.java b/core/src/main/java/dev/faststats/ErrorHelper.java index e1c0b864..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 = getAnonymizedMessage(error, 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()); @@ -75,7 +76,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 +214,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..aa5ad741 100644 --- a/core/src/test/java/dev/faststats/ErrorTrackerTest.java +++ b/core/src/test/java/dev/faststats/ErrorTrackerTest.java @@ -165,6 +165,18 @@ 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()); + } + @Test public void nestedCausesAreSerializedInOrder() { final var root = new IllegalArgumentException("root secret 172.16.0.9");