diff --git a/base/src/main/java/de/staropensource/sosengine/base/Engine.java b/base/src/main/java/de/staropensource/sosengine/base/Engine.java
index 61d741a..8da30c9 100644
--- a/base/src/main/java/de/staropensource/sosengine/base/Engine.java
+++ b/base/src/main/java/de/staropensource/sosengine/base/Engine.java
@@ -225,6 +225,7 @@ public final class Engine implements SubsystemMainClass {
CrashHandler.getCrashContent().put("Java Virtual Machine", crashContentJvm);
CrashHandler.getCrashContent().put("Operating system", crashContentOS);
CrashHandler.getCrashContent().put("Stacktrace", "\n%stacktrace%");
+ CrashHandler.getCrashContent().put("Stacktrace for all threads", "\n%stacktrace_all%");
}
/**
diff --git a/base/src/main/java/de/staropensource/sosengine/base/internal/placeholders/crashhandler/StacktraceAll.java b/base/src/main/java/de/staropensource/sosengine/base/internal/placeholders/crashhandler/StacktraceAll.java
new file mode 100644
index 0000000..f745506
--- /dev/null
+++ b/base/src/main/java/de/staropensource/sosengine/base/internal/placeholders/crashhandler/StacktraceAll.java
@@ -0,0 +1,72 @@
+/*
+ * STAROPENSOURCE ENGINE SOURCE FILE
+ * Copyright (c) 2024 The StarOpenSource Engine Contributors
+ * Licensed under the GNU Affero General Public License v3
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.staropensource.sosengine.base.internal.placeholders.crashhandler;
+
+import de.staropensource.sosengine.base.classes.Placeholder;
+import de.staropensource.sosengine.base.utility.Miscellaneous;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+/**
+ * Implements the {@code stacktrace_all} placeholder.
+ *
+ * @see Placeholder
+ * @since v1-alpha0
+ */
+@SuppressWarnings({ "unused" })
+public final class StacktraceAll implements Placeholder {
+ /**
+ * Constructs this class.
+ *
+ * @since v1-alpha2
+ */
+ public StacktraceAll() {}
+
+ /** {@inheritDoc} */
+ @NotNull
+ @Override
+ public String replace(@NotNull String text) {
+ StringBuilder output = new StringBuilder();
+ Map stacktraces = Thread.getAllStackTraces();
+
+ for (Thread thread : stacktraces.keySet()) {
+ if (!output.isEmpty())
+ output.append("\n\n");
+ output
+ .append(thread.getName())
+ .append(" (id=")
+ .append(thread.threadId())
+ .append(" priority=")
+ .append(thread.getPriority())
+ .append(" group=")
+ .append(thread.getThreadGroup().getName())
+ .append(" state=")
+ .append(thread.getState().name())
+ .append(" daemon=")
+ .append(thread.isDaemon())
+ .append(")")
+ .append("\n")
+ .append(Miscellaneous.stringifyStackTrace(stacktraces.get(thread), false));
+ }
+
+ return text.replace("%stacktrace_all%", output.toString());
+ }
+}
diff --git a/base/src/main/java/de/staropensource/sosengine/base/logging/CrashHandler.java b/base/src/main/java/de/staropensource/sosengine/base/logging/CrashHandler.java
index 0fb2f85..1670c41 100644
--- a/base/src/main/java/de/staropensource/sosengine/base/logging/CrashHandler.java
+++ b/base/src/main/java/de/staropensource/sosengine/base/logging/CrashHandler.java
@@ -136,8 +136,9 @@ public final class CrashHandler {
temporaryPlaceholders.add(new IssuerInfo(logIssuer));
temporaryPlaceholders.add(new IssuerPackage(logIssuer));
temporaryPlaceholders.add(new IssuerPath(logIssuer));
- // etc
+ // stacktrace*
temporaryPlaceholders.add(new Stacktrace(throwable));
+ temporaryPlaceholders.add(new StacktraceAll());
// Replace placeholders
base = PlaceholderEngine.getInstance().process(base, temporaryPlaceholders);
diff --git a/base/src/main/java/de/staropensource/sosengine/base/utility/Miscellaneous.java b/base/src/main/java/de/staropensource/sosengine/base/utility/Miscellaneous.java
index 2b5ca04..bb4a5e4 100644
--- a/base/src/main/java/de/staropensource/sosengine/base/utility/Miscellaneous.java
+++ b/base/src/main/java/de/staropensource/sosengine/base/utility/Miscellaneous.java
@@ -217,4 +217,28 @@ public final class Miscellaneous {
public static boolean onMainThread() {
return Thread.currentThread().threadId() == 1;
}
+
+ /**
+ * Converts an array of {@link StackTraceElement}s into a regular string.
+ *
+ * @param stacktrace array of {@link StackTraceElement}s to convert
+ * @param indent if all lines should be indented with a single {@code \t} character, like in regular stack traces
+ * @return converted stacktrace string
+ * @since v1-alpha2
+ */
+ @NotNull
+ public static String stringifyStackTrace(@NotNull StackTraceElement[] stacktrace, boolean indent) {
+ StringBuilder output = new StringBuilder();
+
+ for (StackTraceElement element : stacktrace) {
+ if (!output.isEmpty())
+ output.append("\n");
+ if (indent)
+ output.append("\t");
+
+ output.append("at ").append(element);
+ }
+
+ return output.toString();
+ }
}
diff --git a/base/src/main/java/de/staropensource/sosengine/base/utility/parser/StackTraceParser.java b/base/src/main/java/de/staropensource/sosengine/base/utility/parser/StackTraceParser.java
index 4bac377..4822edb 100644
--- a/base/src/main/java/de/staropensource/sosengine/base/utility/parser/StackTraceParser.java
+++ b/base/src/main/java/de/staropensource/sosengine/base/utility/parser/StackTraceParser.java
@@ -19,6 +19,7 @@
package de.staropensource.sosengine.base.utility.parser;
+import de.staropensource.sosengine.base.utility.Miscellaneous;
import lombok.AccessLevel;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
@@ -79,13 +80,6 @@ public final class StackTraceParser {
*/
@NotNull
public String getStackTrace() {
- StringBuilder output = new StringBuilder();
-
- for (StackTraceElement element : throwable.getStackTrace()) {
- if (!output.isEmpty()) output.append("\n");
- output.append("\tat ").append(element.toString());
- }
-
- return output.toString();
+ return Miscellaneous.stringifyStackTrace(throwable.getStackTrace(), true);
}
}