Geçerli yığın izlemesini Java'da nasıl edinebilirim?


1001

.NET'te nasıl yapabileceğiniz gibi , geçerli yığın izlemesini Java'da nasıl edinebilirim Environment.StackTrace?

Buldum Thread.dumpStack()ama istediğim bu değil - Yığın izini geri almak istiyorum, yazdırmamak istiyorum.


73
Her zaman Eclipse hata ayıklama zaman bir saat ifadesi olarak "yeni Exception (). PrintStackTrace ()" kullanın. Bir kesme noktasında askıya aldığınızda ve nereden geldiğinizi bilmek istediğinizde kullanışlıdır.
Tim Büthe

22
@ TimBüthe: Eclipse, hata ayıklama modundayken Yığın İzini söylemiyor mu? Sanırım.
Luigi Massa Gallerano

41
Arrays.toString (Thread.currentThread () getStackTrace ().); yeterince basit.
Ajay

2
@Arkanon Java'yı ifade eder ve bunu .net içinde nasıl yapacaklarını ve java'da eşdeğerinin ne olduğunu gösterir.
Pokechu22

9
Güzelce yazdırmak için apache StringUtils: StringUtils.join (currentThread (). GetStackTrace (), "\ n");
Sanat

Yanıtlar:


1159

Kullanabilirsiniz Thread.currentThread().getStackTrace().

Bu StackTraceElement, bir programın geçerli yığın izlemesini temsil eden s dizisini döndürür .


48
Bir dizgi almak için zaten apache ortaklarını kullanıyorsanız havalı bir astar: String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); stackoverflow.com/a/10620951/11236
ripper234

5
Dizideki ilk öğe (dizin 0) java.lang.Thread.getStackTrace yöntemidir, ikincisi (dizin 1) genellikle ilk ilgi alanıdır.
lilalinux

175
Bir tek astar Apache Arrays.toString eserler Bir istisna yokken ve kullandığınız kalmadığı bir dizeye yığın izlemesini dönüştürmek için (Thread.currentThread () () getStackTrace.)
Tony

9
@Tony 'ın çözüm bir throwable gerektirmediğinden iyidir
MVD

3
Aşağıdaki birçok cevaba işaret ettiği gibi - new Throwable().getStackTrace()çok daha hızlıdır, çünkü this != Thread.currentThread()çocuk sınıfı ( Exception extends Throwable) aracılığıyla çağrılma potansiyel JVM genel giderlerini kontrol etmek ve atlamak zorunda değildir
Vlad

264
Thread.currentThread().getStackTrace();

yığının ilk öğesinin ne olduğunu umursamıyorsanız iyi olur.

new Throwable().getStackTrace();

geçerli olması durumunda geçerli yönteminiz için tanımlanmış bir konuma sahip olacaktır.


35
(new Throwable()).getStackTrace()daha hızlı yürütülüyor (bkz. bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302 )
MightyE

2
Thread.currentThread (). GetStackTrace () sonuçlarının new Throwable (). GetStackTrace () sonuçlarının nasıl farklı olabileceğini daha ayrıntılı olarak açıklayabilir misiniz? Her ikisini de denedim ve Thread.currentThread (). GetStackTrace () dizin 0'da Thread.getStackTrace ile am dizisini döndürdüğünü ve çağıran yöntem dizin 1'de olduğunu buldu. Yeni Throwable (). GetStackTrace () yöntemi çağrı ile bir dizi döndürür Her iki yöntemin de geçerli yöntem için tanımlı bir konumu var gibi görünüyor, ancak konumlar farklı. İşaret ettiğiniz başka bir fark var mı?
Ryan

9
@Ryan, Thread.currentThread (). GetStackTrace () yönteminin, yöntemin farklı sürümleri üzerinde bu konumu koruma sözü vermediğine dair bir garanti yoktur. Yani, Dizin 1'de olduğunu kontrol ettiğinizde, JVM'nin (1.5 veya 1.6, hatırlamayın) bazı versiyonunda, Dizin 2 idi. Tanımlanmış bir pozisyonla kastettiğim budur - spec çağırır orada olmak ve gelecekte orada kalmak.
Yishai

5
@MightyE Hata artık Java 6'da olduğu gibi kapalı olarak bildirildi. İç kısımlara bakıldığında (new Exception()).getStackTrace(), istenen yığın izinin geçerli iş parçacığında olduğu zaman olduğu gibi görünüyor (her zaman böyle olacakThread.currentThread().getStackTrace();
M. Justin

3
@ Justin: hata "şimdi" sabit olarak bildirilmedi, MightyE yorumu yazmadan altı yıl önce düzeltildi. Aslında, Stackoverflow kurulmadan önce bile düzeltildi ...
Holger

181
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
    System.out.println(ste);
}

20
Java, Throwable'da tanımlanmış bir printStackTrace yöntemine sahiptir, şunları yapabilirsiniz: new Exception().printStackTrace(System.out)hatırlayabildiğim için, for döngüsünün muhtemelen daha az yükü vardır, ancak bunu yine de sadece hata ayıklama şey olarak kullanmalısınız ...
Jaap

2
Bunu en sevdiğim için, örneğin println ifadenizi sararak gürültüyü ayırma şansı elde edersiniz, örneğinfor (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
nby

61
Thread.currentThread().getStackTrace();

JDK 1.5'ten beri kullanılabilir.

Eski bir sürüm için, sen yönlendirebilirsiniz exception.printStackTrace()a StringWriter():

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();

3
new Throwable().getStackTrace()JDK 1.4'ten beri kullanılabilir…
Holger

40

Bunun için Apache'nin müştereklerini kullanabilirsiniz:

String fullStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);

13
Bu güzel bir tek çözüm. FYI, kullanan herkes org.apache.commons.lang3için tam çizgi:org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
fileoffset

2
Sadece Yinelediler fileoffset yorumuna göre taşırken org.apache.commons.lang3ithalat kullanımları - Başlangıçta gözden kaçan, hangi lang3yerine langve cümledeki getFullStackTraceile getStackTrace.
ggkmath

Bu çok faydalı! Bir IDE (örneğin, IntelliJ IDEA) kullanarak hata ayıklarken ExceptionUtils.getStackTrace(new Throwable()), yığın izlemesi elde etmek için ifadeyi kullanmak harika olur .
Sergey Brunov


22

Tüm iş parçacıklarının yığın izlemesini almak için jstack yardımcı programı JConsole'yi kullanabilir veya bir kill-quit sinyali gönderebilirsiniz (Posix işletim sisteminde).

Ancak, bunu programlı olarak yapmak istiyorsanız ThreadMXBean'ı kullanmayı deneyebilirsiniz:

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

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

Belirtildiği gibi, sadece geçerli iş parçacığının yığın izini istiyorsanız çok daha kolay - Sadece kullanın Thread.currentThread().getStackTrace();


2
Bu yanıttaki kod snippet'i, JVM'ye QUIT sinyalini (Unix benzeri sistemlerde) veya <ctrl> <break> gönderirken programlı olarak gördüğünüz dökümü türüne en yakın şekilde oluşturur. Diğer yanıtlardan farklı olarak, monitörleri ve senkronizörleri ve yalnızca yığın izlerini görürsünüz (örneğin, StackTraceElement dizisi üzerinde yineleyip System.err.println(elems[i])her birini yaparsanız ). Snippet'teki ikinci satır daha bean.önce eksik dumpAllThreadsama sanırım çoğu insan bunu halledebilir.
George Hawkins

22

Başka bir çözüm (sadece 35 31 karakter):

new Exception().printStackTrace();   
new Error().printStackTrace();

1
harika bir çözüm. Şimdi tüm yığın kareleri arasında
dolaşmak zorunda değilim


17

Tony, kabul edilen cevaba bir yorum olarak , OP'nin sorusuna gerçekten cevap veren en iyi cevap olarak görünen şeyi verdi :

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

... OP vermedi DEĞİL bir nasıl sormak Stringbir yığın iziyle dan Exception. Ve Apache Commons'ın büyük bir hayranı olmama rağmen, yukarıdaki kadar basit bir şey olduğunda, bir dış kütüphaneyi kullanmak için mantıklı bir neden yoktur.


Konu listesi var ve onların yığın izleri yazdırmak gerekiyor.
Daneel S.Yaitskov

Bu durumda, Thread.getAllStackTraces()size a Map<Thread, StackTraceElement[]>. Hotspot, herhangi bir konuya ihtiyaç duyduğunda tüm evreleri işaretler. Zing, bireysel iplikleri diğerini rahatsız etmeden bir güvenli noktaya getirebilir. Yığın izleme almak için bir güvenlik noktası gerekir. Thread.getAllStackTraces()tüm yığın izlerini alır ve tüm iş parçacıklarını yalnızca bir kez durdurur. Tabii ki, hangi haritalamayla gerçekten ilgilendiğinizi öğrenmelisiniz.
Ralf H

14

Şunu öneririm

  Thread.dumpStack()

daha kolay bir yoldur ve hiç bir sorun olmadığında gerçekte bir istisna veya atılabilir yapılamama avantajına sahiptir ve bu konuya göre daha fazladır.


1
Tamam, aslında, dumpStack () statik bir yöntemdir ve statik bir şekilde erişilmelidir. Teşekkürler, tutulma!
Thomas Adkins

1
Kısayolu seviyorum, ancak bu yöntemin kaynak kodu: new Exception("Stack trace").printStackTrace();bu yüzden aslında bir Atılabilir inşa ediyor
Florent

13

Yığın izleme alma:

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

Yazdırma yığını izi (JAVA 8+):

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

Yazdırma yığını (JAVA 7):

StringBuilder sb = new StringBuilder();

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

12

Java 9'da yeni bir yol var:

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

İlginç. :-)
djangofan

10

Stacktrace ile bir dize döndüren bir yardımcı program yöntemi var:

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

Ve sadece logit ...

... 
catch (FileNotFoundException e) {
    logger.config(getStackTrace(e));
}

Bu Netbeans tarafından üretilen bir otomatik gibi görünüyor.
Leif Gruenwoldt

günlükçü yerleşik bir günlükçü veya oluşturduğunuz ve bir dosyaya yazdığınız günlüktür.
Doug Hauf

@ Haug, logger yerleşik Java Logger için bir referanstır. Logging.properties dosyasını yapılandırdığınızdan emin olun. Sınıfınızın başına şu şekilde ekleyin: private static final Logger logger = Logger.getLogger (Your_Class_Name.class.getName ());
Salvador Valencia

1
java.util.logging.Logger#log(Level, String, Throwable)zaten bunu yapıyor. Bu, Java standart kitaplığında zaten var olan şeyleri gereksiz yere yeniden yazmak ve yeni geliştiricileri, dokümantasyondan uzak olan yanlış yönde gösteriyor. Bunu yaparak, Stacktrace'ı belirli bir şekilde biçimlendirmeye zorladınız, burada loggingAPI günlük deyiminin formatını belirttiğiniz gibi dinamik olarak değiştirmenize izin verir. Bildiğim kadarıyla log4jda benzer davranışlar var. Tekerleği yeniden icat etme çünkü açıkladığım gibi şeyleri kaybediyorsun.
searchengine27

1
2012'de de vardı. Maalesef tarih sizin durumunuzda bir fark yaratmıyor. Bkz. [Link] (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)), [bağlantı] (docs.oracle.com/javase/1.5.0/docs/api/java/util/logging/Logger.html#log (java.util.logging.LogRecord)) vb. geçmesi birkaç fonksiyonları Throwableiçin kapalı Handlerkadar s Formatterdaha burada listeledik daha Java7 oldu 2012 yılında s Ve bu işlevler çok daha uzun Java7 civarında olmuştur daha eskiye;. dolayısıyla J2SE 5.0 javadocs)
searchengine27

10

Guava ile dizgi yapmak için:

Throwables.getStackTraceAsString(new Throwable())

8
try {
}
catch(Exception e) {
    StackTraceElement[] traceElements = e.getStackTrace();
    //...
}

veya

Thread.currentThread().getStackTrace()

En iyi örneğiniz size sadece try / catch bloğuna göre yığın izlemesi vermeyecek mi?
Dan Monego

1
ikisi arasındaki farklar nedir
twlkyao

5

Belki bunu deneyebilirsiniz:

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

'ErrorDetail' dizesi yığın izini içerir.


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

Dizinin son öğesi, dizideki en yeni yöntem çağırma olan yığının altını temsil eder.

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

StackTraceElement arasında geçiş yapın ve istediğiniz sonucu alın.

for (StackTraceElement ste : stackTraceElements ) 
{
    //do your stuff here...
}

Son öğeden bahsettiğiniz için teşekkürler en son öğeyi içerir. Karşı sezgisel ve biraz zaman kazandım.
clearlight

Ayrıca .toString () tüm bu verileri güzel bir şekilde bir dizgiye gönderir
Vlad

4

Yukarıdaki cevapları kullandım ve biçimlendirme ekledim

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

2

İşleminizin geçerli çağrı yığınını kontrol etmek istiyorsanız jstack yardımcı programını kullanabilirsiniz.

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

1

Bu eski bir gönderi, ama işte benim çözümüm:

Thread.currentThread().dumpStack();

Daha fazla bilgi ve daha fazla yöntem var: http://javarevisited.blogspot.fr/2013/04/how-to-get-current-stack-trace-in-java-thread.html


3
Thread.dumpStack () statik olduğundan, doğrudan çağırmalısınız.
David Avendasora

2
OP, yazdırmak için değil, yığın izlemesine kodda bir referans istediklerini belirtti.
Taylor R

1
@DavidAvendasora belirttiği gibi Thread.dumpStack()statik yöntemi nedeniyle doğrudan aramalısınız .
M-WaJeEh

Evet, java.lang.Thread.dumpStack () Java 11 üzerinde çalışır.
Park JongBum

-3

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

Bu, yığın izlemesini döngü olmadan yazdırmanıza yardımcı olacaktır.


1
Cevabınız, 3 ay önce yayınlanan benimkiyle aynı.
mike kemirgen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.