Java / Android - Bagaimana cara mencetak jejak tumpukan penuh?

124

Di Android (Jawa) bagaimana cara mencetak jejak tumpukan penuh? Jika aplikasi saya macet dari nullPointerException atau sesuatu, itu akan mencetak jejak stack penuh (hampir) seperti:

java.io.IOException: Attempted read from closed stream.
com.android.music.sync.common.SoftSyncException: java.io.IOException: Attempted read from closed stream.
    at com.android.music.sync.google.MusicSyncAdapter.getChangesFromServerAsDom(MusicSyncAdapter.java:545)
    at com.android.music.sync.google.MusicSyncAdapter.fetchDataFromServer(MusicSyncAdapter.java:488)
    at com.android.music.sync.common.AbstractSyncAdapter.download(AbstractSyncAdapter.java:417)
    at com.android.music.sync.common.AbstractSyncAdapter.innerPerformSync(AbstractSyncAdapter.java:313)
    at com.android.music.sync.common.AbstractSyncAdapter.onPerformLoggedSync(AbstractSyncAdapter.java:243)
    at com.google.android.common.LoggingThreadedSyncAdapter.onPerformSync(LoggingThreadedSyncAdapter.java:33)
    at android.content.AbstractThreadedSyncAdapter$SyncThread.run(AbstractThreadedSyncAdapter.java:164)
Caused by: java.io.IOException: Attempted read from closed stream.
    at org.apache.http.impl.io.ChunkedInputStream.read(ChunkedInputStream.java:148)
    at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:159)
    at java.util.zip.GZIPInputStream.readFully(GZIPInputStream.java:212)
    at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:81)
    at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:64)
    at android.net.http.AndroidHttpClient.getUngzippedContent(AndroidHttpClient.java:218)
    at com.android.music.sync.api.MusicApiClientImpl.createAndExecuteMethod(MusicApiClientImpl.java:312)
    at com.android.music.sync.api.MusicApiClientImpl.getItems(MusicApiClientImpl.java:588)
    at com.android.music.sync.api.MusicApiClientImpl.getTracks(MusicApiClientImpl.java:638)
    at com.android.music.sync.google.MusicSyncAdapter.getChangesFromServerAsDom(MusicSyncAdapter.java:512)
    ... 6 more

Namun terkadang, untuk keperluan debugging, saya ingin mencatat jejak stack penuh dari tempat saya berada dalam kode. Saya pikir saya bisa melakukan ini:

StackTraceElement trace = new Exception().getStackTrace();
Log.d("myapp", trace.toString());

Tapi ini hanya mencetak pointer ke objek ... Apakah saya harus mengulangi semua elemen stack stack untuk mencetaknya? Atau adakah metode sederhana untuk mencetak semuanya?

Jake Wilson
sumber
1
Anda dapat menggunakan metode ini Thread.currentThread (). GetStackTrace () stackoverflow.com/questions/1069066/…
user2024270
1
Kemungkinan duplikat Android - cetak
jejak balik

Jawaban:

119

Ada penggantian semua metode log dengan (String tag, String msg, Throwable tr)tanda tangan.

Melewati pengecualian sebagai parameter ketiga harus memberi Anda stacktrace penuh di logcat.

Philipp Reichart
sumber
5
FYI metode log tiga argumen menggunakan getStackTraceString()metode yang disebutkan oleh @Thomas di belakang layar.
Philipp Reichart
6
Saya telah mengembangkan Android selama dua tahun dan tidak pernah memperhatikan ini sebelumnya. Terima kasih banyak.
Anh Tuan
Melihat kode sumber, ya Anda benar @PhilippReichart. Berikut kode untuk Log.d pada AOSP 4.2.2_r1
Ehtesh Choudhury
152

Yang berikut harus melakukan trik:

Log.d("myapp", Log.getStackTraceString(new Exception()));

Perhatikan bahwa ...x morepada akhirnya tidak memotong informasi apa pun dari jejak tumpukan:

(Ini menunjukkan) bahwa sisa jejak tumpukan untuk pengecualian ini cocok dengan jumlah bingkai yang ditunjukkan dari bagian bawah jejak tumpukan pengecualian yang disebabkan oleh pengecualian ini (pengecualian "melampirkan").

... atau dengan kata lain, ganti x moredengan xbaris terakhir dari pengecualian pertama.

Michael Berry
sumber
1
Dari mana getStackTraceString()? Tidak muncul di Eclipse? Itu bukan bagian dari Throwableatau Exception....
Jake Wilson
9
"... 6 lebih" pada akhirnya tidak memotong informasi apa pun. Ia memberi tahu Anda, bahwa sisa jejak tumpukan adalah sama seperti itu untuk pengecualian teratas. Lihat saja 6 baris terakhir dari pengecualian pertama.
Tomasz
Anda mungkin perlu mengimpor perpustakaan logging (menggunakan import android.util.Log;).
Dan
10

Gunakan Log.getStackTraceString (Throwable t). Anda bisa mendapatkan jejak tumpukan yang lebih lama dengan menggali lebih dalam. Sebagai contoh:

try {
    ...
} catch(Exception e) {
    Log.d("Some tag", Log.getStackTraceString(e.getCause().getCause()));
}

Diperoleh dari http://developer.android.com/reference/android/util/Log.html#getStackTraceString%28java.lang.Throwable%29

Thomas
sumber
Log.getStackTraceString()tidak mencatat jejak stack, ia hanya mengembalikannya sebagai String. Kode di atas tidak akan mencatat apa pun dan juga akan gagal dengan NPE jika e.getCause()ada null.
Philipp Reichart
9
private static String buildStackTraceString(final StackTraceElement[] elements) {
    StringBuilder sb = new StringBuilder();
    if (elements != null && elements.length > 0) {
        for (StackTraceElement element : elements) {
            sb.append(element.toString());
        }
    }
    return sb.toString();
}


// call this at your check point
Log.d(TAG, buildStackTraceString(Thread.currentThread().getStackTrace()));
faywong
sumber
6

Anda dapat menggunakan ini:

public static String toString(StackTraceElement[] stackTraceElements) {
    if (stackTraceElements == null)
        return "";
    StringBuilder stringBuilder = new StringBuilder();
    for (StackTraceElement element : stackTraceElements)
        stringBuilder.append(element.toString()).append("\n");
    return stringBuilder.toString();
}
Mohsen Afshin
sumber
4

Anda juga dapat mencetak jejak tumpukan di setiap titik dalam kode aplikasi Anda menggunakan metode seperti Thread.dumpStack()

Silakan buka tautan untuk detail lebih lanjut

ajaykoppisetty
sumber
2

Anda perlu menggunakan Throwable Object untuk mendapatkan stackTrace lengkap.

try{
 // code here
}catch(Exception e){
    String exception = getStackTrace(e);
}

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

Ref: https://stackoverflow.com/a/18546861

Houssin Boulla
sumber
0

Saya cepat lakukan sekarang fungsi rekursif yang akan mengulangi throwable dan throwable.getCause ().

Itu karena setiap "throwable.getCause ()" mengembalikan kepada Anda pesan pengecualian baru dengan beberapa baris berulang dan baris baru. Jadi konsepnya adalah: jika ada "penyebab" ada garis dengan "n lebih .." pada main throwable jadi saya mendapatkan baris terakhir sebelum yang dengan "n lebih .." maka saya mendapatkan pesan penyebab dan akhirnya saya substring pesan sebab hanya mendapatkan bagian setelah baris berulang terakhir (baris terakhir yang muncul di keduanya: main throwable dan penyebab throwable).

Kemudian saya menggunakan rekursi ketika saya mendapatkan pesan penyebab, jadi memanggil kembali fungsi yang sama untuk mendapatkan pesan penyebab dari throwable utama saya akan mendapatkan pesan yang sudah diganti. Jika penyebab lemparan dari lemparan utama juga memiliki penyebab lain, maka lemparan utama memiliki 3 level (utama -> penyebab -> penyebab-penyebab), pada lemparan utama saya akan mendapatkan "pesan" pesan yang sudah diganti (menggunakan konsep utama yang sama

public static <T extends Throwable> String printStackTraceString(T ex) {     // Recursive
    Throwable tr = ex;
    if (tr != null) {
        String st = Log.getStackTraceString(tr);
        if (tr.getCause() != null) {
            // Recursion...
            String cs = printStackTraceString(tr.getCause());

            String r1 = st.subSequence(0x0, st.lastIndexOf("\n", st.lastIndexOf("\n") - "\n".length())).toString();
            String replace = r1.substring(r1.lastIndexOf("\n"));
            if (cs.contains(replace)) {
                return r1.concat(cs.subSequence(cs.indexOf(replace) + replace.length(), cs.length()).toString());
            }
        }
        return st;
    }
    return "";
}

Saya mencobanya hanya dengan 2 level (utama -> penyebab) dan tidak dengan lebih banyak: / Jika ada yang salah silakan edit fungsinya dan tulis komentar: D

Selamat menikmati coding dan hari yang menyenangkan: D

Penting:

Kode ini terkadang mendapatkan pengecualian jika "st" tidak mengandung "\ n" atau serupa (saya menemukan beberapa jenis pengecualian stacktraces memiliki masalah ini). Untuk mengatasi ini, Anda perlu menambahkan beberapa cek sebelum baris kode: "String r1 = ..."

Anda perlu memeriksa: "st" berisi "\ n" dan bahwa indeks awal & akhir "st.subSequence" keduanya valid.

Pokoknya saya sarankan untuk meletakkan ini di dalam try-catch dan mengembalikan string kosong jika terkecuali. (Ini rekursif sehingga string kosong yang dikembalikan akan digabungkan ke string yang diproses sebelumnya).

Z3R0
sumber