Qual è il modo più semplice per convertire il risultato Throwable.getStackTrace()
in una stringa che raffigura lo stacktrace?
Qual è il modo più semplice per convertire il risultato Throwable.getStackTrace()
in una stringa che raffigura lo stacktrace?
Risposte:
Si può usare il seguente metodo per convertire una Exception
traccia dello stack in String
. Questa classe è disponibile in Apache commons-lang che è la libreria dipendente più comune con molti open source popolari
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)
org.apache.commons.lang3.exception.ExceptionUtils
.
Utilizzare Throwable.printStackTrace(PrintWriter pw)
per inviare la traccia dello stack a un writer appropriato.
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
e PrintWriter
?
Questo dovrebbe funzionare:
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
printStackTrace
dovrebbe solo restituire una stringa, lasciando la decisione se stamparla o meno all'utente :)
printXXX()
dovrebbe stampare XXX.
Se stai sviluppando per Android, un modo molto più semplice è usare questo:
import android.util.Log;
String stackTrace = Log.getStackTraceString(exception);
Il formato è lo stesso di getStacktrace, ad es
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
classe di GuavaSe hai l' Throwable
istanza effettiva , Google Guava fornisce Throwables.getStackTraceAsString()
.
Esempio:
String s = Throwables.getStackTraceAsString ( myException ) ;
ATTENZIONE: non include la causa (che di solito è il bit utile!)
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")
o qualcosa di simile invece di "\n"
rendere felici i lamer DOS.
Per me il modo più semplice e pulito era:
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
e PrintWriter
dovrebbero essere close
d .... (o immagino che solo i PrintWriter
bisogni debbano essere chiusi poiché chiudendolo dovrebbe chiudere StringWriter
anche quello)
Il codice seguente consente di ottenere l'intero stackTrace con un String
formato, senza utilizzare API come log4J o addirittura 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.
}
Ecco una versione che è copiabile in pasta direttamente nel codice:
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());
Oppure, in un blocco di cattura
} catch (Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
logger.info("Current stack trace is:\n" + sw.toString());
}
Throwable
è definito, giusto?
Arrays.toString(thrown.getStackTrace())
È il modo più semplice per convertire il risultato in String. Lo sto usando nel mio programma per stampare la traccia dello stack
LOGGER.log(Level.SEVERE, "Query Builder Issue Stack Trace : {0} ,Message : {1} objid {2}", new Object[]{Arrays.toString(e.getStackTrace()), e.getMessage(),objId});
Stampa la traccia dello stack in a PrintStream
, quindi convertila 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);
}
Stampa dello stack stack su stringa
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);
}
}
}
È utile quando si desidera stampare la traccia dello stack del thread corrente senza creare l'istanza di Throwable
- ma si noti che la creazione di una nuova Throwable
traccia dello stack da lì è in realtà più veloce ed economica della chiamata Thread.getStackTrace
.
private String getCurrentStackTraceString() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
return Arrays.stream(stackTrace).map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
}
L'intelligente sniping nella prima serie di commenti è stato molto divertente, ma dipende davvero da cosa stai cercando di fare. Se non hai già la libreria corretta, allora 3 righe di codice (come nella risposta di D. Wroblewski) sono perfette. OTOH, se hai già la libreria apache.commons (come faranno i progetti più grandi), la risposta di Amar è più breve. OK, potrebbero essere necessari dieci minuti per ottenere la libreria e installarla correttamente (meno di una se sai cosa stai facendo). Ma il tempo stringe, quindi potresti non avere il tempo di risparmiare. Jarek Przygódzki aveva un avvertimento interessante: "Se non hai bisogno di eccezioni nidificate".
Ma cosa succede se io ne servono le tracce dello stack completi, nidificati e tutti? In tal caso, il segreto è utilizzare getFullStackTrace di apache.common (consultare http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html # getFullStackTrace% 28java.lang.Throwable% 29 )
Mi ha salvato la pancetta. Grazie, Amar, per il suggerimento!
Codice da 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();
}
La differenza con le altre risposte è che utilizza autoFlush
sul PrintWriter
.
Senza di java.io.*
essa si può fare così.
String trace = e.toString() + "\n";
for (StackTraceElement e1 : e.getStackTrace()) {
trace += "\t at " + e1.toString() + "\n";
}
E quindi la trace
variabile contiene la traccia dello stack. L'output contiene anche la causa iniziale, l'output è identico aprintStackTrace()
Esempio, printStackTrace()
rese:
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)
La trace
stringa regge, se stampata sustdout
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)
Versione Scala
def stackTraceToString(e: Exception): String = {
import java.io.PrintWriter
val sw = new StringWriter()
e.printStackTrace(new PrintWriter(sw))
sw.toString
}
se stai usando Java 8, prova questo
Arrays.stream(e.getStackTrace())
.map(s->s.toString())
.collect(Collectors.joining("\n"));
puoi trovare il codice per la getStackTrace()
funzione fornito da Throwable.java
:
public StackTraceElement[] getStackTrace() {
return getOurStackTrace().clone();
}
e per StackTraceElement
, fornisce toString()
come:
public String toString() {
return getClassName() + "." + methodName +
(isNativeMethod() ? "(Native Method)" :
(fileName != null && lineNumber >= 0 ?
"(" + fileName + ":" + lineNumber + ")" :
(fileName != null ? "("+fileName+")" : "(Unknown Source)")));
}
Quindi unisciti StackTraceElement
a "\ n".
una spiegazione sulla risposta di Gala che includerà anche le cause dell'eccezione:
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;
}
La soluzione è convertire stackTrace dell'array in un tipo di dati stringa . Vedi il seguente esempio:
import java.util.Arrays;
try{
}catch(Exception ex){
String stack = Arrays.toString(ex.getStackTrace());
System.out.println("stack "+ stack);
}
Con l' API Java 8 Stream puoi fare qualcosa del genere:
Stream
.of(throwable.getStackTrace())
.map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
Ci vorrà una serie di elementi traccia stack, li convertirà in stringa e si unirà in stringa multilinea.
Il mio oneliner per convertire la traccia dello stack nella stringa multilinea inclusa:
Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))
Facile da passare al logger "così com'è".
printStackTrace()
Qui perderai: 1) Eccezione che è stata lanciata; 2) Cause e loro stacktrace
printStackTrace()
mai è stata una parte della domanda.
Se non si desidera utilizzare una libreria esterna e non si sta sviluppando per Android , è possibile creare un metodo di 'estensione' come questo:
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();
}
Vecchia domanda, ma vorrei solo aggiungere il caso speciale in cui non si desidera stampare tutta la pila , rimuovendo alcune parti che non sono realmente interessate, escludendo determinate classi o pacchetti.
Invece di un PrintWriter
uso 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);
Dove la SelectivePrintWriter
lezione è data da:
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);
}
}
}
Si noti che questa classe può essere facilmente adattata per filtrare da Regex contains
o altri criteri. Si noti inoltre che dipende dai Throwable
dettagli di implementazione (non è probabile che cambi, ma comunque).
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);
}
}
}
Quando esegui il programma, l'output sarà qualcosa di simile:
java.lang.ArithmeticException: / by zero
at PrintStackTrace.main(PrintStackTrace.java:9)
Mi chiedo perché nessuno ne abbia parlato ExceptionUtils.getStackFrames(exception)
Per me è il modo più conveniente per scaricare stacktrace con tutte le sue cause fino alla fine:
String.join("\n", ExceptionUtils.getStackFrames(exception));
Attenzione: questo potrebbe essere un po 'fuori tema, ma vabbè ...;)
In primo luogo, non so quale sia stata la ragione dei poster originali per volere la traccia dello stack come stringa. Quando la traccia dello stack dovrebbe finire in un LOG SLF4J / Logback, ma non è stata o deve essere generata alcuna eccezione, ecco cosa faccio:
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
}
Mi piace perché non richiede una libreria esterna (a parte il back-end di registrazione, che sarà comunque attivo nella maggior parte dei casi, ovviamente).
Poche opzioni
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Utilizzando Google Guava lib
String stackTrace = Throwables.getStackTraceAsString ( myException ) ;
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace (Throwable)