Was ist der einfachste Weg, um das Ergebnis Throwable.getStackTrace()
in eine Zeichenfolge zu konvertieren , die die Stapelverfolgung darstellt?
Was ist der einfachste Weg, um das Ergebnis Throwable.getStackTrace()
in eine Zeichenfolge zu konvertieren , die die Stapelverfolgung darstellt?
Antworten:
Mit der folgenden Methode können Sie einen Exception
Stack-Trace in konvertieren String
. Diese Klasse ist in Apache commons-lang verfügbar, der am häufigsten verwendeten abhängigen Bibliothek mit vielen gängigen Open Source-Quellen
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)
org.apache.commons.lang3.exception.ExceptionUtils
.
Verwenden Sie Throwable.printStackTrace(PrintWriter pw)
diese Option , um den Stack-Trace an einen geeigneten Writer zu senden.
import java.io.StringWriter;
import java.io.PrintWriter;
// ...
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String sStackTrace = sw.toString(); // stack trace as a string
System.out.println(sStackTrace);
StringWriter
und nicht schließen PrintWriter
?
Das sollte funktionieren:
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
printStackTrace
sollte nur eine Zeichenfolge zurückgeben und die Entscheidung darüber, ob sie gedruckt werden soll oder nicht, dem Benutzer
printXXX()
sollte XXX drucken.
Wenn Sie für Android entwickeln, ist dies weitaus einfacher:
import android.util.Log;
String stackTrace = Log.getStackTraceString(exception);
Das Format ist das gleiche wie bei getStacktrace, z
09-24 16:09:07.042: I/System.out(4844): java.lang.NullPointerException 09-24 16:09:07.042: I/System.out(4844): at com.temp.ttscancel.MainActivity.onCreate(MainActivity.java:43) 09-24 16:09:07.042: I/System.out(4844): at android.app.Activity.performCreate(Activity.java:5248) 09-24 16:09:07.043: I/System.out(4844): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110) 09-24 16:09:07.043: I/System.out(4844): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2162) 09-24 16:09:07.043: I/System.out(4844): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257) 09-24 16:09:07.043: I/System.out(4844): at android.app.ActivityThread.access$800(ActivityThread.java:139) 09-24 16:09:07.043: I/System.out(4844): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210) 09-24 16:09:07.043: I/System.out(4844): at android.os.Handler.dispatchMessage(Handler.java:102) 09-24 16:09:07.043: I/System.out(4844): at android.os.Looper.loop(Looper.java:136) 09-24 16:09:07.044: I/System.out(4844): at android.app.ActivityThread.main(ActivityThread.java:5097) 09-24 16:09:07.044: I/System.out(4844): at java.lang.reflect.Method.invokeNative(Native Method) 09-24 16:09:07.044: I/System.out(4844): at java.lang.reflect.Method.invoke(Method.java:515) 09-24 16:09:07.044: I/System.out(4844): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) 09-24 16:09:07.044: I/System.out(4844): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
Log.e("TAG", "My message", new Throwable());
Throwables
KlasseWenn Sie die aktuelle Throwable
Instanz haben, bietet Google GuavaThrowables.getStackTraceAsString()
.
Beispiel:
String s = Throwables.getStackTraceAsString ( myException ) ;
WARNUNG: Enthält keine Ursache (was normalerweise das nützliche Bit ist!)
public String stackTraceToString(Throwable e) {
StringBuilder sb = new StringBuilder();
for (StackTraceElement element : e.getStackTrace()) {
sb.append(element.toString());
sb.append("\n");
}
return sb.toString();
}
String.format("%n")
oder etwas Ähnliches, anstatt "\n"
DOS-Lamers glücklich zu machen.
Für mich war der sauberste und einfachste Weg:
import java.util.Arrays;
Arrays.toString(e.getStackTrace());
public static String getStackTrace(Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
return sw.toString();
}
StringWriter
und PrintWriter
Objekte close
d sein sollten .... (oder ich denke, nur die PrintWriter
müssen geschlossen werden, da das Schließen auch das schließen sollte StringWriter
)
Mit dem folgenden Code können Sie die gesamte stackTrace in einem String
Format abrufen , ohne APIs wie log4J oder sogar zu verwenden java.util.Logger
:
catch (Exception e) {
StackTraceElement[] stack = e.getStackTrace();
String exception = "";
for (StackTraceElement s : stack) {
exception = exception + s.toString() + "\n\t\t";
}
System.out.println(exception);
// then you can send the exception string to a external file.
}
Hier ist eine Version, die direkt in Code kopiert werden kann:
import java.io.StringWriter;
import java.io.PrintWriter;
//Two lines of code to get the exception into a StringWriter
StringWriter sw = new StringWriter();
new Throwable().printStackTrace(new PrintWriter(sw));
//And to actually print it
logger.info("Current stack trace is:\n" + sw.toString());
Oder in einem Fangblock
} catch (Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
logger.info("Current stack trace is:\n" + sw.toString());
}
Throwable
definiert ist, richtig?
Arrays.toString(thrown.getStackTrace())
Ist der einfachste Weg, das Ergebnis in einen String zu konvertieren. Ich verwende dies in meinem Programm, um den Stack-Trace zu drucken
LOGGER.log(Level.SEVERE, "Query Builder Issue Stack Trace : {0} ,Message : {1} objid {2}", new Object[]{Arrays.toString(e.getStackTrace()), e.getMessage(),objId});
Drucken Sie die Stapelverfolgung in a PrintStream
und konvertieren Sie sie dann in a String
:
// ...
catch (Exception e)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(out));
String str = new String(out.toByteArray());
System.out.println(str);
}
Stack-Trace in String drucken
import java.io.PrintWriter;
import java.io.StringWriter;
public class StackTraceUtils {
public static String stackTraceToString(StackTraceElement[] stackTrace) {
StringWriter sw = new StringWriter();
printStackTrace(stackTrace, new PrintWriter(sw));
return sw.toString();
}
public static void printStackTrace(StackTraceElement[] stackTrace, PrintWriter pw) {
for(StackTraceElement stackTraceEl : stackTrace) {
pw.println(stackTraceEl);
}
}
}
Dies ist nützlich, wenn Sie den aktuellen Thread-Stack-Trace drucken möchten, ohne eine Instanz von zu erstellen. Throwable
Beachten Sie jedoch, dass das Erstellen eines neuen Throwable
und das Abrufen des Stack-Trace von dort tatsächlich schneller und billiger ist als das Aufrufen Thread.getStackTrace
.
private String getCurrentStackTraceString() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
return Arrays.stream(stackTrace).map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
}
Das clevere Sniping in den ersten Kommentaren war sehr amüsant, aber es hängt wirklich davon ab, was Sie versuchen zu tun. Wenn Sie noch nicht die richtige Bibliothek haben, sind 3 Codezeilen (wie in der Antwort von D. Wroblewski) perfekt. OTOH, wenn Sie bereits über die Bibliothek apache.commons verfügen (wie es die meisten großen Projekte tun), ist Amars Antwort kürzer. OK, es kann zehn Minuten dauern, bis Sie die Bibliothek abgerufen und korrekt installiert haben (weniger als eine, wenn Sie wissen, was Sie tun). Aber die Uhr tickt, so dass Sie möglicherweise nicht die Zeit haben, um zu sparen. Jarek Przygódzki hatte eine interessante Einschränkung - "Wenn Sie keine verschachtelten Ausnahmen benötigen".
Aber was , wenn ich Sie den vollständigen Stack - Traces benötigen, verschachtelt und alle? In diesem Fall besteht das Geheimnis darin, getFullStackTrace von apache.common zu verwenden (siehe http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html) # getFullStackTrace% 28java.lang.Throwable% 29 )
Es hat meinen Speck gerettet. Danke, Amar, für den Hinweis!
Code aus Apache Commons Lang 3.4 ( JavaDoc ):
public static String getStackTrace(final Throwable throwable) {
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw, true);
throwable.printStackTrace(pw);
return sw.getBuffer().toString();
}
Der Unterschied zu den anderen Antworten besteht darin, dass es autoFlush
auf der verwendet wird PrintWriter
.
Ohne das geht java.io.*
es so.
String trace = e.toString() + "\n";
for (StackTraceElement e1 : e.getStackTrace()) {
trace += "\t at " + e1.toString() + "\n";
}
Und dann enthält die trace
Variable Ihre Stapelverfolgung. Die Ausgabe enthält auch die ursprüngliche Ursache, die Ausgabe ist identisch mitprintStackTrace()
Beispiel printStackTrace()
ergibt:
java.io.FileNotFoundException: / (Is a directory)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:270)
at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
at Test.main(Test.java:9)
Die trace
Zeichenfolge gilt beim Drucken aufstdout
java.io.FileNotFoundException: / (Is a directory)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:270)
at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
at Test.main(Test.java:9)
Scala-Version
def stackTraceToString(e: Exception): String = {
import java.io.PrintWriter
val sw = new StringWriter()
e.printStackTrace(new PrintWriter(sw))
sw.toString
}
Wenn Sie Java 8 verwenden, versuchen Sie dies
Arrays.stream(e.getStackTrace())
.map(s->s.toString())
.collect(Collectors.joining("\n"));
Den Code für die getStackTrace()
Funktion finden Sie Throwable.java
unter:
public StackTraceElement[] getStackTrace() {
return getOurStackTrace().clone();
}
und für StackTraceElement
Anbieter toString()
wie:
public String toString() {
return getClassName() + "." + methodName +
(isNativeMethod() ? "(Native Method)" :
(fileName != null && lineNumber >= 0 ?
"(" + fileName + ":" + lineNumber + ")" :
(fileName != null ? "("+fileName+")" : "(Unknown Source)")));
}
Also einfach StackTraceElement
mit "\ n" verbinden.
eine Erklärung zu Galas Antwort, die auch die Ursachen für die Ausnahme enthält:
private String extrapolateStackTrace(Exception ex) {
Throwable e = ex;
String trace = e.toString() + "\n";
for (StackTraceElement e1 : e.getStackTrace()) {
trace += "\t at " + e1.toString() + "\n";
}
while (e.getCause() != null) {
e = e.getCause();
trace += "Cause by: " + e.toString() + "\n";
for (StackTraceElement e1 : e.getStackTrace()) {
trace += "\t at " + e1.toString() + "\n";
}
}
return trace;
}
Die Lösung besteht darin, die stackTrace des Arrays in einen String- Datentyp zu konvertieren . Siehe folgendes Beispiel:
import java.util.Arrays;
try{
}catch(Exception ex){
String stack = Arrays.toString(ex.getStackTrace());
System.out.println("stack "+ stack);
}
Mit der Java 8 Stream API können Sie Folgendes tun:
Stream
.of(throwable.getStackTrace())
.map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
Es werden Arrays von Stack-Trace-Elementen verwendet, in Zeichenfolgen konvertiert und zu mehrzeiligen Zeichenfolgen zusammengefügt.
Mein Oneliner zum Konvertieren der Stapelverfolgung in die beiliegende mehrzeilige Zeichenfolge:
Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))
Einfach an den Logger "wie es ist" zu übergeben.
printStackTrace()
hier unterscheidet. Sie verlieren: 1) Ausnahme, die geworfen wurde; 2) Ursachen und ihre
printStackTrace()
Nie ein Teil der Frage war.
Wenn Sie keine externe Bibliothek verwenden möchten und nicht für Android entwickeln , können Sie eine Erweiterungsmethode wie die folgende erstellen :
public static String getStackTraceString(Throwable e) {
return getStackTraceString(e, "");
}
private static String getStackTraceString(Throwable e, String indent) {
StringBuilder sb = new StringBuilder();
sb.append(e.toString());
sb.append("\n");
StackTraceElement[] stack = e.getStackTrace();
if (stack != null) {
for (StackTraceElement stackTraceElement : stack) {
sb.append(indent);
sb.append("\tat ");
sb.append(stackTraceElement.toString());
sb.append("\n");
}
}
Throwable[] suppressedExceptions = e.getSuppressed();
// Print suppressed exceptions indented one level deeper.
if (suppressedExceptions != null) {
for (Throwable throwable : suppressedExceptions) {
sb.append(indent);
sb.append("\tSuppressed: ");
sb.append(getStackTraceString(throwable, indent + "\t"));
}
}
Throwable cause = e.getCause();
if (cause != null) {
sb.append(indent);
sb.append("Caused by: ");
sb.append(getStackTraceString(cause, indent));
}
return sb.toString();
}
Alte Frage, aber ich möchte nur den Sonderfall hinzufügen, in dem Sie nicht den gesamten Stapel drucken möchten , indem Sie einige Teile entfernen, an denen Sie eigentlich nicht interessiert sind, mit Ausnahme bestimmter Klassen oder Pakete.
Anstelle einer PrintWriter
Verwendung a SelectivePrintWriter
:
// This filters out this package and up.
String packageNameToFilter = "org.springframework";
StringWriter sw = new StringWriter();
PrintWriter pw = new SelectivePrintWriter(sw, packageNameToFilter);
e.printStackTrace(pw);
String sStackTrace = sw.toString();
System.out.println(sStackTrace);
Wo die SelectivePrintWriter
Klasse gegeben ist durch:
public class SelectivePrintWriter extends PrintWriter {
private boolean on = true;
private static final String AT = "\tat";
private String internal;
public SelectivePrintWriter(Writer out, String packageOrClassName) {
super(out);
internal = "\tat " + packageOrClassName;
}
public void println(Object obj) {
if (obj instanceof String) {
String txt = (String) obj;
if (!txt.startsWith(AT)) on = true;
else if (txt.startsWith(internal)) on = false;
if (on) super.println(txt);
} else {
super.println(obj);
}
}
}
Bitte beachten Sie, dass diese Klasse leicht angepasst werden kann, um nach Regex contains
oder anderen Kriterien herauszufiltern . Beachten Sie auch, dass dies von den Throwable
Implementierungsdetails abhängt (wahrscheinlich nicht geändert, aber immer noch).
import java.io.PrintWriter;
import java.io.StringWriter;
public class PrintStackTrace {
public static void main(String[] args) {
try {
int division = 0 / 0;
} catch (ArithmeticException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
System.out.println(exceptionAsString);
}
}
}
Wenn Sie das Programm ausführen, ist die Ausgabe ähnlich:
java.lang.ArithmeticException: / by zero
at PrintStackTrace.main(PrintStackTrace.java:9)
Ich frage mich, warum niemand erwähnt hat ExceptionUtils.getStackFrames(exception)
Für mich ist es der bequemste Weg, Stacktrace mit all seinen Ursachen bis zum Ende zu sichern:
String.join("\n", ExceptionUtils.getStackFrames(exception));
Warnung: Dies mag ein bisschen vom Thema abweichen, aber na ja ...;)
Ich weiß nicht, warum der ursprüngliche Postergrund dafür war, dass der Stack-Trace überhaupt als Zeichenfolge verwendet werden sollte. Wenn der Stack-Trace in einem SLF4J / Logback-LOG enden sollte, aber keine Ausnahme ausgelöst wurde oder werden sollte, gehe ich folgendermaßen vor:
public void remove(List<String> ids) {
if(ids == null || ids.isEmpty()) {
LOG.warn(
"An empty list (or null) was passed to {}.remove(List). " +
"Clearly, this call is unneccessary, the caller should " +
"avoid making it. A stacktrace follows.",
getClass().getName(),
new Throwable ("Stacktrace")
);
return;
}
// actual work, remove stuff
}
Ich mag es, weil es keine externe Bibliothek erfordert (außer Ihrem Protokollierungs-Backend, das natürlich sowieso die meiste Zeit vorhanden sein wird).
Nur wenige Optionen
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Verwenden von Google Guava lib
String stackTrace = Throwables.getStackTraceAsString ( myException ) ;
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace (Throwable)