Come posso convertire una traccia di stack in una stringa?

Qual è il modo più semplice per convertire il risultato di Throwable.getStackTrace() in una stringa che descrive lo stacktrace?

È ansible utilizzare il seguente metodo per convertire una traccia di stack Exception in String . Questa class è disponibile in Apache commons-lang, che è la libreria dipendente più comune con molte popolari fonti aperte

org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)

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); 

Questo dovrebbe funzionare:

 StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); String exceptionAsString = sw.toString(); 

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) 

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(); } 

Classe di Throwables di Guava

Se Throwable dell’istanza Throwable effettiva, Google Guava fornisce Throwables.getStackTraceAsString() .

Esempio:

 String s = Throwables.getStackTraceAsString ( myException ) ; 

Per me il modo più semplice e pulito era:

 import java.util.Arrays; Arrays.toString(e.getStackTrace()); 

Ispirato da @ Brian Agnew:

 public static String getStackTrace(Throwable t) { StringWriter sw = new StringWriter(); t.printStackTrace(new PrintWriter(sw)); return sw.toString(); } 

Il seguente codice consente di ottenere l’intero stackTrace con un formato String , senza utilizzare API come log4J o 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 può essere copiata 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()); 

O, 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()); } 

Stampa traccia da traccia a 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 l’attuale traccia dello stack di thread senza creare l’istanza di Throwable , ma si noti che la creazione di nuove Throwable e l’ottenimento della traccia di stack da lì è in realtà più veloce ed economica rispetto a chiamare Thread.getStackTrace .

 Arrays.toString(thrown.getStackTrace()) 

È il modo più semplice per convertire il risultato in String. Sto usando questo 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}); 
 private String getCurrentStackTraceString() { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); return Arrays.stream(stackTrace).map(StackTraceElement::toString) .collect(Collectors.joining("\n")); } 

Stampare lo stacktrace su PrintStream, quindi convertirlo in una stringa

 // ... catch (Exception e) { ByteArrayOutputStream out = new ByteArrayOutputStream(); e.printStackTrace(new PrintStream(out)); String str = new String(out.toByteArray()); System.out.println(str); } 

Kotlin

L’estensione della class Throwable ti darà la proprietà String error.stackTraceString :

 val Throwable.stackTraceString: String get() { val sw = StringWriter() val pw = PrintWriter(sw) this.printStackTrace(pw) return sw.toString() } 

Senza java.io.* può essere fatto in questo modo.

 String trace = e.toString() + "\n"; for (StackTraceElement e1 : e.getStackTrace()) { trace += "\t at " + e1.toString() + "\n"; } 

E quindi la variabile trace mantiene la traccia dello stack. Anche l’output contiene la causa iniziale, l’output è identico a printStackTrace()

Esempio, printStackTrace() produce:

 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.(FileOutputStream.java:213) at java.io.FileOutputStream.(FileOutputStream.java:101) at Test.main(Test.java:9) 

La stringa di trace contiene, se stampata su stdout

 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.(FileOutputStream.java:213) at java.io.FileOutputStream.(FileOutputStream.java:101) at Test.main(Test.java:9) 

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 su PrintWriter .

L’intelligente sniping nel primo gruppo di commenti è stato molto divertente, ma dipende molto da cosa stai cercando di fare. Se non hai già la libreria corretta, allora 3 linee di codice (come nella risposta di D. Wroblewski) sono perfette. OTOH, se hai già la libreria apache.commons (come la maggior parte dei progetti di grandi dimensioni), la risposta di Amar sarà 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 ha avuto un avvertimento interessante: “Se non hai bisogno di eccezioni annidate”.

Ma cosa succede se ho bisogno delle tracce dello stack completo, annidato e tutto? In questo caso, il segreto è usare getFullStackTrace di apache.common (vedi http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html # getFullStackTrace% 28java.lang.Throwable% 29 )

Ha salvato il mio bacon. Grazie, Amar, per il suggerimento!

un’espansione 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; } 

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 funzione getStackTrace () fornita da Throwable.java come:

 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 allo StackTraceElement con “\ n”

Se non si desidera utilizzare una libreria esterna e non si sta sviluppando per Android , è ansible 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 tutto lo stack , rimuovendo alcune parti a cui non si è realmente interessati, escludendo determinate classi o pacchetti.

Invece di un PrintWriter usa 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 class SelectivePrintWriter è 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 prega di notare che questa class può essere facilmente adattata per filtrare da Regex, contains o altri criteri. Si noti inoltre che dipende dai dettagli di implementazione Throwable (non è probabile che cambi, ma comunque).

Il mio oneliner per convertire la traccia dello stack nella stringa multilinea racchiusa:

 Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]")) 

Facile da passare al logger “così com’è”.

La soluzione è convertire lo stackTrace di array nel tipo di dati stringa . Guarda il seguente esempio:

 import java.util.Arrays; try{ }catch(Exception ex){ String stack = Arrays.toString(ex.getStackTrace()); System.out.println("stack "+ stack); } 

Attenzione: questo potrebbe essere un po ‘fuori tema, ma vabbè …;)

Non so quale fosse il motivo originale dei poster per volere che lo stack tracciasse come stringa in primo luogo. Quando la traccia dello stack dovrebbe finire in un LOG SLF4J / Logback, ma nessuna eccezione è stata o dovrebbe essere gettata ecco cosa faccio:

 public void remove(List 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 (oltre al back-end di registrazione, che sarà comunque disponibile per la maggior parte del tempo, ovviamente).

Utilizzare exp.printStackTrace() per visualizzare lo stack della propria eccezione.

 try { int zero = 1 - 1; int a = 1/zero; } catch (Exception e) { e.printStackTrace(); }