Apa cara termudah untuk mengonversi hasil Throwable.getStackTrace()
menjadi string yang menggambarkan stacktrace?
Apa cara termudah untuk mengonversi hasil Throwable.getStackTrace()
menjadi string yang menggambarkan stacktrace?
Jawaban:
Orang dapat menggunakan metode berikut untuk mengkonversi Exception
jejak stack String
. Kelas ini tersedia di Apache commons-lang yang merupakan pustaka dependen paling umum dengan banyak sumber terbuka yang populer
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)
org.apache.commons.lang3.exception.ExceptionUtils
.
Gunakan Throwable.printStackTrace(PrintWriter pw)
untuk mengirim jejak tumpukan ke penulis yang sesuai.
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
dan PrintWriter
?
Ini seharusnya bekerja:
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
printStackTrace
seharusnya hanya mengembalikan string, meninggalkan keputusan apakah mencetaknya atau tidak kepada pengguna :)
printXXX()
harus mencetak XXX.
Jika Anda mengembangkan untuk Android, cara yang jauh lebih mudah adalah dengan menggunakan ini:
import android.util.Log;
String stackTrace = Log.getStackTraceString(exception);
Formatnya sama dengan getStacktrace, misalnya
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
KelasJika Anda memiliki Throwable
instance aktual , Google Guava menyediakanThrowables.getStackTraceAsString()
.
Contoh:
String s = Throwables.getStackTraceAsString ( myException ) ;
PERINGATAN: Tidak termasuk penyebab (yang biasanya sedikit berguna!)
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")
atau sesuatu yang serupa alih-alih "\n"
untuk membuat DOS lamers senang.
Bagi saya cara terbersih dan termudah adalah:
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
dan PrintWriter
harus close
d .... (atau saya kira hanya PrintWriter
perlu ditutup karena menutupnya harus menutup StringWriter
juga)
Kode berikut memungkinkan Anda untuk mendapatkan seluruh stackTrace dengan String
format, tanpa menggunakan API seperti log4J atau bahkan 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.
}
Berikut ini adalah versi yang dapat disalin secara langsung ke dalam kode:
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());
Atau, di blok penangkap
} catch (Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
logger.info("Current stack trace is:\n" + sw.toString());
}
Throwable
didefinisikan, kan?
Arrays.toString(thrown.getStackTrace())
Apakah cara termudah untuk mengubah hasilnya menjadi String Saya menggunakan ini di program saya untuk mencetak jejak tumpukan
LOGGER.log(Level.SEVERE, "Query Builder Issue Stack Trace : {0} ,Message : {1} objid {2}", new Object[]{Arrays.toString(e.getStackTrace()), e.getMessage(),objId});
Cetak jejak tumpukan ke PrintStream
, lalu ubah menjadi String
:
// ...
catch (Exception e)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(out));
String str = new String(out.toByteArray());
System.out.println(str);
}
Mencetak jejak stack ke string
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);
}
}
}
Ini berguna ketika Anda ingin mencetak jejak tumpukan thread saat ini tanpa membuat instance Throwable
- tetapi perhatikan bahwa membuat Throwable
jejak stack baru dan mendapatkan dari sana sebenarnya lebih cepat dan lebih murah daripada menelepon Thread.getStackTrace
.
private String getCurrentStackTraceString() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
return Arrays.stream(stackTrace).map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
}
Mengecam pada set komentar pertama sangat menyenangkan, tetapi itu benar-benar tergantung pada apa yang Anda coba lakukan. Jika Anda belum memiliki perpustakaan yang benar, maka 3 baris kode (seperti pada jawaban D. Wroblewski) sempurna. OTOH, jika Anda sudah memiliki perpustakaan apache.commons (seperti kebanyakan proyek besar akan), maka jawaban Amar lebih pendek. Oke, mungkin Anda butuh sepuluh menit untuk mendapatkan perpustakaan dan menginstalnya dengan benar (kurang dari satu jika Anda tahu apa yang Anda lakukan). Tetapi jam terus berdetak, jadi Anda mungkin tidak punya waktu luang. Jarek Przygódzki memiliki peringatan menarik - "Jika Anda tidak perlu pengecualian bersarang".
Tapi bagaimana jika saya tidak membutuhkan jejak stack penuh, bersarang dan semua? Dalam hal ini, rahasianya adalah menggunakan getFullStackTrace apache.common (lihat http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html # getFullStackTrace% 28java.lang.Throwable% 29 )
Ini menghemat daging saya. Terima kasih, Amar, untuk petunjuknya!
Kode dari 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();
}
Perbedaannya dengan jawaban lain adalah yang digunakan autoFlush
pada PrintWriter
.
Tanpa java.io.*
itu bisa dilakukan seperti ini.
String trace = e.toString() + "\n";
for (StackTraceElement e1 : e.getStackTrace()) {
trace += "\t at " + e1.toString() + "\n";
}
Dan kemudian trace
variabel tersebut menyimpan jejak stack Anda. Output juga memegang penyebab awal, output identik denganprintStackTrace()
Contoh, printStackTrace()
hasil:
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)
The trace
String memegang, saat dicetakstdout
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)
Versi scala
def stackTraceToString(e: Exception): String = {
import java.io.PrintWriter
val sw = new StringWriter()
e.printStackTrace(new PrintWriter(sw))
sw.toString
}
jika Anda menggunakan Java 8, coba ini
Arrays.stream(e.getStackTrace())
.map(s->s.toString())
.collect(Collectors.joining("\n"));
Anda dapat menemukan kode untuk getStackTrace()
fungsi yang disediakan oleh Throwable.java
:
public StackTraceElement[] getStackTrace() {
return getOurStackTrace().clone();
}
dan untuk StackTraceElement
, penyedia toString()
sebagai:
public String toString() {
return getClassName() + "." + methodName +
(isNativeMethod() ? "(Native Method)" :
(fileName != null && lineNumber >= 0 ?
"(" + fileName + ":" + lineNumber + ")" :
(fileName != null ? "("+fileName+")" : "(Unknown Source)")));
}
Jadi gabung saja StackTraceElement
dengan "\ n".
exapansion pada jawaban Gala yang juga akan mencakup penyebab pengecualian:
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;
}
Solusinya adalah mengubah stackTrace dari array ke tipe data string . Lihat contoh berikut:
import java.util.Arrays;
try{
}catch(Exception ex){
String stack = Arrays.toString(ex.getStackTrace());
System.out.println("stack "+ stack);
}
Dengan Java 8 Stream API Anda dapat melakukan sesuatu seperti ini:
Stream
.of(throwable.getStackTrace())
.map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
Ini akan mengambil array elemen jejak stack, mengubahnya menjadi string dan bergabung menjadi string multiline.
Oneliner saya untuk mengonversi tumpukan jejak ke string multi-garis terlampir:
Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))
Mudah diteruskan ke logger "apa adanya".
printStackTrace()
Di sini Anda akan kehilangan: 1) Pengecualian yang dilemparkan; 2) Penyebab dan stacktrace mereka
printStackTrace()
tidak pernah menjadi bagian dari pertanyaan.
Jika Anda tidak ingin menggunakan perpustakaan eksternal dan Anda tidak mengembangkan untuk Android , Anda dapat membuat metode 'ekstensi' seperti ini:
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();
}
Pertanyaan lama, tapi saya hanya ingin menambahkan case khusus di mana Anda tidak ingin mencetak semua tumpukan , dengan menghapus beberapa bagian yang sebenarnya tidak Anda minati, tidak termasuk kelas atau paket tertentu.
Alih-alih PrintWriter
menggunakan 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);
Di mana SelectivePrintWriter
kelas diberikan oleh:
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);
}
}
}
Harap dicatat bahwa kelas ini dapat dengan mudah disesuaikan untuk disaring oleh Regex, contains
atau kriteria lainnya. Juga perhatikan itu tergantung pada Throwable
detail implementasi (tidak mungkin berubah, tetapi masih).
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);
}
}
}
Saat Anda menjalankan program, hasilnya akan serupa:
java.lang.ArithmeticException: / by zero
at PrintStackTrace.main(PrintStackTrace.java:9)
Saya heran mengapa tidak ada yang menyebutkan ExceptionUtils.getStackFrames(exception)
Bagi saya ini adalah cara paling mudah untuk membuang stacktrace dengan semua penyebabnya sampai akhir:
String.join("\n", ExceptionUtils.getStackFrames(exception));
Peringatan: Ini mungkin sedikit keluar dari topik, tapi oh well ...;)
Saya tidak tahu apa alasan poster asli karena ingin jejak tumpukan sebagai string di tempat pertama. Ketika jejak stack harus berakhir dengan SLF4J / Logback LOG, tapi tidak ada pengecualian atau harus dibuang di sini yang saya lakukan:
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
}
Saya suka karena itu tidak memerlukan perpustakaan eksternal (selain backend logging Anda, yang akan tetap ada di sebagian besar waktu, tentu saja).
Beberapa pilihan
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Menggunakan Google Guava lib
String stackTrace = Throwables.getStackTraceAsString ( myException ) ;
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace (Throwable)