Bagaimana saya bisa mendapatkan jejak tumpukan saat ini di Jawa?

1002

Bagaimana cara mendapatkan jejak tumpukan saat ini di Jawa, seperti bagaimana di .NET yang dapat Anda lakukan Environment.StackTrace?

saya menemukan Thread.dumpStack() tetapi bukan itu yang saya inginkan - Saya ingin mendapatkan jejak tumpukan kembali, bukan mencetaknya.

ripper234
sumber
73
Saya selalu menggunakan "Pengecualian baru (). PrintStackTrace ()" sebagai ekspresi arloji ketika saya sedang debug di Eclipse. Itu berguna ketika Anda menunda di breakpoint dan ingin tahu dari mana Anda berasal.
Tim Büthe
22
@ TimBüthe: bukankah Eclipse sudah memberi tahu Anda Stack Trace saat Anda dalam mode debug? Aku pikir begitu.
Luigi Massa Gallerano
41
Arrays.toString (Thread.currentThread (). GetStackTrace ()); cukup sederhana.
Ajay
2
@ Arkanon Ini merujuk ke java, dan menunjukkan bagaimana mereka melakukannya di .net dan apa yang setara di java.
Pokechu22
9
Untuk mencetaknya dengan baik, Anda dapat menggunakan apache StringUtils: StringUtils.join (currentThread (). GetStackTrace (), "\ n");
Seni

Jawaban:

1159

Kamu bisa menggunakan Thread.currentThread().getStackTrace() .

Itu mengembalikan array StackTraceElements yang mewakili jejak stack saat ini dari suatu program.

jjnguy
sumber
48
Satu liner keren jika Anda sudah menggunakan apache commons untuk mendapatkan string: String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); stackoverflow.com/a/10620951/11236
ripper234
5
Elemen pertama (indeks 0) dalam array adalah metode java.lang.Thread.getStackTrace, yang kedua (indeks 1) biasanya adalah yang pertama menarik.
lilalinux
175
Satu liner untuk mengonversi jejak stack ke string yang berfungsi saat Anda tidak memiliki pengecualian dan Anda tidak menggunakan Apache Arrays.toString (Thread.currentThread (). GetStackTrace ())
Tony
9
Solusi @Tony lebih baik karena tidak memerlukan throwable
mvd
3
Seperti yang ditunjukkan dalam banyak jawaban di bawah ini - new Throwable().getStackTrace()ini jauh lebih cepat, karena tidak perlu memeriksa this != Thread.currentThread()dan memotong overhead JVM potensial untuk memanggilnya melalui kelas anak-anak ( Exception extends Throwable)
Vlad
265
Thread.currentThread().getStackTrace();

tidak masalah jika Anda tidak peduli apa elemen pertama dari tumpukan itu.

new Throwable().getStackTrace();

akan memiliki posisi yang ditentukan untuk metode Anda saat ini, jika itu penting.

Yishai
sumber
35
(new Throwable()).getStackTrace()lebih cepat mengeksekusi juga (lihat bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302 )
MightyE
2
Bisakah Anda menjelaskan lebih detail bagaimana hasil Thread.currentThread (). GetStackTrace () mungkin berbeda dari Throwable baru (). GetStackTrace ()? Saya mencoba keduanya dan menemukan bahwa Thread.currentThread (). GetStackTrace () mengembalikan array saya dengan Thread.getStackTrace dalam indeks 0 dan metode panggilan pada indeks 1. Metode Throwable (). GetStackTrace () yang baru mengembalikan array dengan pemanggilan metode pada indeks 0. Sepertinya kedua metode memiliki posisi yang ditentukan untuk metode saat ini tetapi posisi berbeda. Apakah ada perbedaan lain yang Anda tunjukkan?
Ryan
9
@Ryan, tidak ada jaminan bahwa Thread.currentThread (). GetStackTrace () tidak berjanji untuk mempertahankan posisi itu dari versi metode yang berbeda. Jadi ketika Anda memeriksa di indeks 1. Pada beberapa versi JVM (1,5 atau 1,6, tidak ingat) untuk Sun, itu indeks 2. Itulah yang saya maksud dengan posisi yang ditentukan - panggilan spesifikasi untuk itu ada di sana, dan tinggal di sana di masa depan.
Yishai
5
@MightyE Bug ini sekarang dilaporkan telah ditutup sebagai diperbaiki di Java 6. Melihat internal, sepertinya sekarang tidak (new Exception()).getStackTrace()ketika jejak stack yang diminta ada di utas saat ini (yang akan selalu menjadi kasus untukThread.currentThread().getStackTrace();
M. Justin
3
@MJustin: bug tidak "sekarang" dilaporkan telah diperbaiki, itu telah diperbaiki bahkan enam tahun sebelum MightyE menulis komentar. Bahkan, itu telah diperbaiki bahkan sebelum Stackoverflow didirikan ...
Holger
181
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
    System.out.println(ste);
}
Leif Gruenwoldt
sumber
20
java memiliki metode printStackTrace yang didefinisikan pada Throwable, yang dapat Anda lakukan: new Exception().printStackTrace(System.out)yang dapat saya ingat, for for loop mungkin memiliki overhead yang lebih sedikit, tetapi Anda seharusnya hanya menggunakan ini sebagai hal debugging ...
Jaap
2
Saya suka yang terbaik ini karena Anda mendapatkan kesempatan untuk menghilangkan kebisingan, dengan membungkus pernyataan println Anda, misalnyafor (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
nby
61
Thread.currentThread().getStackTrace();

tersedia sejak JDK1.5.

Untuk versi yang lebih lama, Anda dapat mengarahkan ulang exception.printStackTrace()ke StringWriter():

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
RealHowTo
sumber
3
new Throwable().getStackTrace()tersedia sejak JDK1.4…
Holger
40

Anda dapat menggunakan commons Apache untuk itu:

String fullStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
stikkos
sumber
13
Ini adalah solusi satu baris yang bagus. FYI, untuk siapa saja yang menggunakan org.apache.commons.lang3, baris lengkapnya adalah:org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
fileoffset
2
Hanya untuk mengulangi komentar fileoffset ketika pindah ke org.apache.commons.lang3, yang awalnya saya abaikan - impor menggunakan lang3alih-alih lang, dan diganti getFullStackTracedengan getStackTrace.
ggkmath
Itu sangat berguna! Saat debugging menggunakan IDE (misalnya, IntelliJ IDEA), sangat bagus untuk menggunakan ExceptionUtils.getStackTrace(new Throwable())ekspresi untuk mendapatkan jejak stack.
Sergey Brunov
24

Di android cara yang jauh lebih mudah adalah dengan menggunakan ini:

import android.util.Log;
String stackTrace = Log.getStackTraceString(exception); 
Vicky Kapadia
sumber
4
Di mana didefinisikan getStackTraceString? Apakah ini dari perpustakaan logging pihak ketiga?
skiphoppy
6
android.util.Log.getStackTraceString developer.android.com/reference/android/util/Log.html
Ondrej Kvasnovsky
22

Untuk mendapatkan jejak stack dari semua thread Anda bisa menggunakan utilitas jstack, JConsole atau mengirim sinyal kill -quit (pada sistem operasi Posix).

Namun, jika Anda ingin melakukan ini secara terprogram Anda bisa mencoba menggunakan ThreadMXBean:

ThreadMXBean bean = ManagementFactory.getThreadMXBean();
ThreadInfo[] infos = bean.dumpAllThreads(true, true);

for (ThreadInfo info : infos) {
  StackTraceElement[] elems = info.getStackTrace();
  // Print out elements, etc.
}

Seperti yang disebutkan, jika Anda hanya ingin jejak tumpukan utas saat ini jauh lebih mudah - Cukup gunakan Thread.currentThread().getStackTrace();

Adamski
sumber
2
Cuplikan kode dalam jawaban ini paling dekat dengan program menghasilkan jenis dump yang Anda lihat mengirim JVM sinyal QUIT (pada sistem seperti Unix) atau <ctrl> <break> pada Windows. Tidak seperti jawaban lain yang Anda dapat melihat monitor dan sinkronisasi serta hanya jejak tumpukan (misalnya jika Anda mengulangi array StackTraceElement dan lakukan System.err.println(elems[i])pada masing-masing). Baris kedua dalam cuplikan tidak ada bean.sebelum dumpAllThreadstetapi saya kira kebanyakan orang bisa menyelesaikannya.
George Hawkins
22

Solusi lain (hanya 35 31 karakter):

new Exception().printStackTrace();   
new Error().printStackTrace();
kukis
sumber
1
solusi yang luar biasa. Sekarang saya tidak perlu mengulang semua frame stack
Vineel Kovvuri
17

Bodoh aku, ini Thread.currentThread().getStackTrace();

ripper234
sumber
17

Tony, sebagai komentar atas jawaban yang diterima, telah memberikan apa yang tampaknya merupakan jawaban terbaik yang sebenarnya menjawab pertanyaan OP :

Arrays.toString(Thread.currentThread().getStackTrace()).replace( ',', '\n' );

... OP TIDAK bertanya bagaimana cara mendapatkan Stringdari jejak stack dari Exception. Dan meskipun saya penggemar berat Apache Commons, ketika ada sesuatu yang sederhana seperti di atas tidak ada alasan logis untuk menggunakan perpustakaan luar.

mike rodent
sumber
Saya memiliki daftar utas dan saya perlu mencetak jejak tumpukan mereka.
Daneel S. Yaitskov
Jika demikian, pastikan Anda menggunakan Thread.getAllStackTraces()yang memberi Anda Map<Thread, StackTraceElement[]>. Hotspot akan melindungi semua utas kapan pun ia membutuhkannya. Zing dapat membawa masing-masing utas ke titik aman tanpa mengganggu yang lain. Mendapatkan stacktrace membutuhkan titik aman. Thread.getAllStackTraces()mendapatkan semua jejak tumpukan dan menghentikan semua utas hanya sekali. Tentu saja, Anda harus mencari tahu pemetaan mana yang benar-benar Anda minati.
Ralf H
14

Saya menyarankan itu

  Thread.dumpStack()

adalah cara yang lebih mudah dan memiliki keuntungan karena tidak benar-benar membangun pengecualian atau yang bisa dibuang ketika mungkin tidak ada masalah sama sekali, dan jauh lebih penting.

Thomas Adkins
sumber
1
Oke, sebenarnya, dumpStack () adalah metode statis, dan harus diakses dengan cara statis. Terima kasih, gerhana!
Thomas Adkins
1
Saya suka jalan pintas, tetapi kode sumber untuk metode ini adalah: new Exception("Stack trace").printStackTrace();jadi itu sebenarnya membangun Throwable
Florent
13

Mendapatkan stacktrace:

StackTraceElement[] ste = Thread.currentThread().getStackTrace();

Mencetak stacktrace (JAVA 8+):

Arrays.asList(ste).forEach(System.out::println);

Mencetak stacktrage (JAVA 7):

StringBuilder sb = new StringBuilder();

for (StackTraceElement st : ste) {
    sb.append(st.toString() + System.lineSeparator());
}
System.out.println(sb);
Witold Kaczurba
sumber
12

Di Jawa 9 ada cara baru:

public static void showTrace() {

  List<StackFrame> frames =
    StackWalker.getInstance( Option.RETAIN_CLASS_REFERENCE )
               .walk( stream  -> stream.collect( Collectors.toList() ) );

  for ( StackFrame stackFrame : frames )
    System.out.println( stackFrame );
}
Christian Ullenboom
sumber
Menarik. :-)
djangofan
10

Saya memiliki metode utilitas yang mengembalikan string dengan stacktrace:

static String getStackTrace(Throwable t) {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw, true);
    t.printStackTrace(pw);
    pw.flush();
    sw.flush();
    return sw.toString();
}

Dan cukup logit seperti ...

... 
catch (FileNotFoundException e) {
    logger.config(getStackTrace(e));
}
Salvador Valencia
sumber
Ini seperti auto yang dihasilkan oleh Netbeans.
Leif Gruenwoldt
adalah logger bawaan atau yang Anda buat dan tulis ke file.
Doug Hauf
@Doug Hauf, logger adalah referensi ke Java Logger bawaan. Pastikan Anda mengonfigurasi file logging.properties. Tambahkan di awal kelas Anda seperti ini: private static final Logger logger = Logger.getLogger (Your_Class_Name.class.getName ());
Salvador Valencia
1
java.util.logging.Logger#log(Level, String, Throwable)sudah melakukan ini. Ini menulis ulang hal-hal yang sudah ada di perpustakaan standar Java yang tidak perlu dan menunjuk pengembang baru ke arah yang salah, yang jauh dari dokumentasi. Dengan melakukan ini sekarang, Anda telah memaksa Stacktrace diformat dengan cara tertentu, sedangkan loggingAPI memungkinkan Anda untuk memvariasikan pemformatan pernyataan log secara dinamis saat Anda menentukannya. Setahu saya, log4jjuga punya perilaku serupa juga. Jangan menemukan kembali roda karena Anda akhirnya kehilangan hal-hal seperti yang saya jelaskan.
searchengine27
1
Itu ada di 2012 juga. Tanggal tidak membuat perbedaan dalam kasus Anda, sayangnya. Lihat [tautan] (docs.oracle.com/javase/1.5.0/docs/api/java/util/logging/Logger.html#log (java.util.logging.Level, java.lang.String, java.lang .Throwable)), [tautan] (docs.oracle.com/javase/1.5.0/docs/api/java/util/logging/Logger.html#log (java.util.logging.LogRecord)), dll (di sana beberapa fungsi yang lulus Throwableoff ke Handlers melalui ke Formatters pada 2012 yang Java7, lebih dari saya sudah tercantum di sini Dan fungsi-fungsi ini tanggal kembali jauh lebih lama dari Java7 telah sekitar;. maka J2SE 5.0 javadocs)
searchengine27
10

Untuk merangkai dengan jambu biji:

Throwables.getStackTraceAsString(new Throwable())
Zitrax
sumber
8
try {
}
catch(Exception e) {
    StackTraceElement[] traceElements = e.getStackTrace();
    //...
}

atau

Thread.currentThread().getStackTrace()
ayam mentega
sumber
Bukankah contoh teratas Anda hanya memberi Anda jejak stack relatif terhadap blok try / catch?
Dan Monego
1
apa perbedaan antara keduanya
twlkyao
5

Mungkin Anda bisa mencoba ini:

catch(Exception e)
{
    StringWriter writer = new StringWriter();
    PrintWriter pw = new PrintWriter(writer);
    e.printStackTrace(pw);
    String errorDetail = writer.toString();
}

String 'errorDetail' berisi stacktrace.

pengguna1782556
sumber
5
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();

Elemen terakhir dari array mewakili bagian bawah tumpukan, yang merupakan doa metode terbaru dalam urutan.

A StackTraceElement has getClassName(), getFileName(), getLineNumber() and getMethodName().

loop melalui StackTraceElement dan dapatkan hasil yang Anda inginkan.

for (StackTraceElement ste : stackTraceElements ) 
{
    //do your stuff here...
}
Jawad Zeb
sumber
Terima kasih telah menyebutkan elemen terakhir berisi yang terbaru. Kontra-intuitif dan menghemat waktu saya.
clearlight
juga .toString () akan menampilkan semua data dengan baik ke dalam string
Vlad
4

Saya menggunakan jawaban dari atas dan menambahkan pemformatan

public final class DebugUtil {

    private static final String SEPARATOR = "\n";

    private DebugUtil() {
    }

    public static String formatStackTrace(StackTraceElement[] stackTrace) {
        StringBuilder buffer = new StringBuilder();
        for (StackTraceElement element : stackTrace) {
            buffer.append(element).append(SEPARATOR);
        }
        return buffer.toString();
    }

    public static String formatCurrentStacktrace() {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        return formatStackTrace(stackTrace);
    }
}

sumber
2

Anda dapat menggunakan utilitas jstack jika Anda ingin memeriksa tumpukan panggilan saat ini dari proses Anda.

Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message
Sampath
sumber
1

Ini adalah pos lama, tapi ini solusinya:

Thread.currentThread().dumpStack();

Info lebih lanjut dan lebih banyak metode di sana: http://javarevisited.blogspot.fr/2013/04/how-to-get-current-stack-trace-in-java-thread.html

Manov
sumber
3
Karena Thread.dumpStack () bersifat statis, Anda harus memanggilnya langsung.
David Avendasora
2
OP mengindikasikan bahwa mereka ingin referensi dalam kode ke jejak stack, bukan untuk mencetaknya.
Taylor R
1
seperti @DavidAvendasora sebutkan Anda harus memanggil Thread.dumpStack()langsung karena metode statisnya.
M-WaJeEh
Ya, java.lang.Thread.dumpStack () berfungsi di Java 11.
Park JongBum
-3

System.out.println(Arrays.toString(Thread.currentThread().getStackTrace()));

Ini akan membantu Anda untuk mencetak jejak tumpukan tanpa loop.

Bhuvanwaitz
sumber
1
Jawaban Anda sama dengan jawaban saya yang diposting 3 bulan sebelumnya.
mike rodent