Jak mogę uzyskać bieżący ślad stosu w Javie?


1001

Jak uzyskać bieżące śledzenie stosu w Javie, na przykład jak w .NET możesz to zrobić Environment.StackTrace?

Znalazłem, Thread.dumpStack()ale nie tego chcę - chcę odzyskać ślad stosu, a nie go wydrukować.


73
Zawsze używam „new Exception (). PrintStackTrace ()” jako wyrażenia obserwacyjnego podczas debugowania w Eclipse. Jest to przydatne, gdy zawieszasz się w punkcie przerwania i chcesz wiedzieć, skąd pochodzisz.
— Tim Büthe

22
@ TimBüthe: czy Eclipse nie mówi ci już śladu stosu, gdy jesteś w trybie debugowania? Chyba tak.
— Luigi Massa Gallerano

41
Arrays.toString (Thread.currentThread (). GetStackTrace ()); wystarczająco proste.
— Ajay,

2
@Arkanon Odnosi się do java i pokazuje, jak zrobiliby to w .net i jaki jest odpowiednik w java.
— Pokechu22,

9
Aby ładnie go wydrukować, możesz użyć apache StringUtils: StringUtils.join (currentThread (). GetStackTrace (), "\ n");
— Art.

Odpowiedzi:


1158

Możesz użyć Thread.currentThread().getStackTrace().

Zwraca tablicę StackTraceElements reprezentującą bieżący ślad stosu programu.


48
Fajny one-liner, jeśli już używasz wspólnego apache, aby uzyskać ciąg: String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); stackoverflow.com/a/10620951/11236
— ripper234

5
Pierwszy element (indeks 0) w tablicy to metoda java.lang.Thread.getStackTrace, drugi (indeks 1) zwykle jest pierwszym zainteresowanym.
— lilalinux

175
Jeden linijka do konwersji śledzenia stosu na ciąg znaków, który działa, gdy nie masz wyjątku i nie używasz Apache Arrays.toString (Thread.currentThread (). GetStackTrace ())
— Tony

9
Rozwiązanie @Tony jest lepsze, ponieważ nie wymaga rzucania
— mvd

3
Jak wskazano w wielu odpowiedziach poniżej - new Throwable().getStackTrace()jest znacznie szybszy, ponieważ nie musi sprawdzać this != Thread.currentThread()i omija potencjalnych obciążeń JVM związanych z wywoływaniem go przez child-class ( Exception extends Throwable)
— Vlad

264
Thread.currentThread().getStackTrace();

jest w porządku, jeśli nie obchodzi cię, jaki jest pierwszy element stosu.

new Throwable().getStackTrace();

będzie miał zdefiniowaną pozycję dla twojej obecnej metody, jeśli to ma znaczenie.


35
(new Throwable()).getStackTrace()jest także szybszy w wykonywaniu (patrz bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302 )
— MightyE

2
Czy możesz wyjaśnić bardziej szczegółowo, w jaki sposób wyniki Thread.currentThread (). GetStackTrace () mogą się różnić od nowych Throwable (). GetStackTrace ()? Próbowałem obu i okazało się, że Thread.currentThread (). GetStackTrace () zwraca tablicę z Thread.getStackTrace w indeksie 0, a metoda wywołująca ma indeks 1. Nowa metoda Throwable (). Metoda getStackTrace () zwraca tablicę z wywołaniem metoda o indeksie 0. Wygląda na to, że obie metody mają określoną pozycję dla bieżącej metody, ale pozycje są różne. Czy wskazujesz inną różnicę?
— Ryan

9
@Ryan, nie ma gwarancji, że Thread.currentThread (). GetStackTrace () nie obiecuje utrzymania tej pozycji w stosunku do różnych wersji metody. Więc kiedy zdarzyło ci się sprawdzić, czy był to indeks 1. W niektórych wersjach JVM (1.5 lub 1.6, nie pamiętaj) dla Sun, był to indeks 2. To właśnie rozumiem przez zdefiniowaną pozycję - specyfikacja wymaga być tam i pozostać tam w przyszłości.
— Yishai

5
@MightyE Błąd jest teraz zgłaszany jako zamknięty jako naprawiony w Javie 6. Patrząc na elementy wewnętrzne, wygląda to tak, jak teraz, (new Exception()).getStackTrace()gdy żądany ślad stosu znajduje się w bieżącym wątku (co zawsze będzie miało miejsceThread.currentThread().getStackTrace();
— M. Justin

3
@MJustin: błąd nie jest „teraz” zgłaszany jako naprawiony, został naprawiony nawet sześć lat przed napisaniem komentarza przez MightyE. W rzeczywistości zostało to naprawione jeszcze przed założeniem
— Stackoverflow

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

20
java ma metodę printStackTrace zdefiniowaną w Throwable, możesz zrobić: new Exception().printStackTrace(System.out)co pamiętam, pętla for prawdopodobnie ma mniejszy narzut, ale i tak powinieneś używać jej tylko jako funkcji debugowania ...
— Jaap,

2
Najbardziej podoba mi się ten, ponieważ masz szansę na wyeliminowanie hałasu, owijając swoje oświadczenie println, np.for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
— nb

61
Thread.currentThread().getStackTrace();

jest dostępna od wersji JDK1.5.

W przypadku starszej wersji możesz przekierować exception.printStackTrace()do StringWriter():

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

3
new Throwable().getStackTrace()jest dostępna od JDK1.4…
— Holger

40

Możesz użyć do tego wspólnego Apache:

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

13
To miłe rozwiązanie jednoliniowe. Do Twojej wiadomości, dla każdego używającego org.apache.commons.lang3, pełna linia to:org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
— fileoffset

2
Wystarczy powtórzyć komentarz fileoffset podczas przeprowadzki org.apache.commons.lang3, który początkowo przeoczyłem - import używa lang3zamiast langi zastępuje getFullStackTracego getStackTrace.
— ggkmath

To bardzo przydatne! Podczas debugowania za pomocą IDE (na przykład IntelliJ IDEA) dobrze jest użyć ExceptionUtils.getStackTrace(new Throwable())wyrażenia, aby uzyskać ślad stosu.
— Siergiej Brunow


22

Aby uzyskać ślad stosu wszystkich wątków, możesz albo użyć narzędzia jstack, JConsole, albo wysłać sygnał zabicia-wyjścia (w systemie operacyjnym Posix).

Jeśli jednak chcesz to zrobić programowo, możesz spróbować użyć ThreadMXBean:

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

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

Jak wspomniano, jeśli chcesz tylko śledzenia stosu bieżącego wątku, jest to o wiele łatwiejsze - wystarczy użyć Thread.currentThread().getStackTrace();


2
Fragment kodu w tej odpowiedzi jest najbliższy programowemu generowaniu zrzutu, jaki widzisz po wysłaniu do JVM sygnału QUIT (w systemach uniksowych) lub <ctrl> <break> w systemie Windows. W przeciwieństwie do innych odpowiedzi, możesz zobaczyć monitory i synchronizatory, a także tylko ślady stosu (np. Jeśli iterujesz po tablicy StackTraceElement i robisz System.err.println(elems[i])na każdym z nich). Druga linia fragmentu kodu jest krótka bean.przed, dumpAllThreadsale myślę, że większość ludzi może to rozwiązać.
— George Hawkins

22

Inne rozwiązanie (tylko 35 31 znaków):

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

1
niesamowite rozwiązanie. Teraz nie muszę zapętlać wszystkich ramek stosu
— Vineel Kovvuri,


17

Tony, jako komentarz do zaakceptowanej odpowiedzi, udzielił najlepszej odpowiedzi, która faktycznie odpowiada na pytanie PO :

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

... OP NIE zapytał, jak uzyskać Stringślad stosu z pliku Exception. I chociaż jestem wielkim fanem Apache Commons, kiedy jest coś tak prostego jak powyższe, nie ma logicznego powodu, aby korzystać z zewnętrznej biblioteki.


Mam listę wątków i muszę wydrukować ślady stosu.
— Daneel S. Yaitskov

W takim przypadku upewnij się, że używasz, Thread.getAllStackTraces()co daje ci Map<Thread, StackTraceElement[]>. Hotspot zabezpiecza wszystkie wątki, ilekroć będzie to potrzebne. Zing może przenosić pojedyncze wątki do bezpiecznego punktu, nie przeszkadzając innym. Zdobycie stacktrace wymaga bezpiecznego punktu. Thread.getAllStackTraces()pobiera wszystkie ślady stosu i zatrzymuje wszystkie wątki tylko raz. Oczywiście musisz dowiedzieć się, które mapowanie Cię interesuje.
— Ralf H

14

sugeruję to

  Thread.dumpStack()

jest prostszym sposobem i ma tę zaletę, że nie tworzy wyjątku ani nie można go rzucać, gdy może nie być żadnego problemu, i jest znacznie bardziej istotny.


1
Dobra, faktycznie, dumpStack () jest metodą statyczną i powinno być dostępne w sposób statyczny. Dzięki, zaćmienie!
— Thomas Adkins

1
Uwielbiam ten skrót, ale kod źródłowy tej metody brzmi: new Exception("Stack trace").printStackTrace();tak naprawdę buduje Throwable
— Florent

13

Pobieranie stacktrace:

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

Drukowanie stacktrace (JAVA 8+):

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

Drukowanie stacktrage (JAVA 7):

StringBuilder sb = new StringBuilder();

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

12

W Javie 9 istnieje nowy sposób:

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

Ciekawy. :-)
— djangofan

10

Mam metodę narzędzia, która zwraca ciąg znaków z 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();
}

I po prostu loguj jak ...

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

Wygląda to na jeden automatycznie wygenerowany przez Netbeans.
— Leif Gruenwoldt,

to logger to wbudowany program rejestrujący lub program utworzony i zapisany w pliku.
— Doug Hauf

@Doug Hauf, logger to odniesienie do wbudowanego programu Java Logger. Upewnij się, że skonfigurowałeś plik logging.properties. Dodaj go na początku zajęć w następujący sposób: prywatny statyczny końcowy Logger logger = Logger.getLogger (Your_Class_Name.class.getName ());
— Salvador Valencia,

1
java.util.logging.Logger#log(Level, String, Throwable)już to robi. Jest to niepotrzebne przepisywanie rzeczy, które już istnieją w standardowej bibliotece Java, i wskazuje nowym programistom w złym kierunku, który jest z dala od dokumentacji. Robiąc to teraz, wymusiłeś sformatowanie Stacktrace w określony sposób, gdzie jako loggingAPI pozwala na dynamiczne zmienianie formatowania instrukcji dziennika podczas jej określania. O ile mi wiadomo, log4jma również podobne zachowanie. Nie wymyślaj na nowo koła, bo w końcu tracisz rzeczy, które wyjaśniłem.
— searchengine27,

1
Istniał również w 2012 roku. Niestety data nie ma znaczenia w twoim przypadku. Zobacz [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)), [link] (docs.oracle.com/javase/1.5.0/docs/api/java/util/logging/Logger.html#log (java.util.logging.LogRecord)) itp. (Tam kilka funkcji, które przechodzą Throwableod do Handlers przez do FormatterS w 2012 roku, który był Java7, bardziej niż ja tutaj wymienione A funkcje te sięgają znacznie dłużej niż Java7 została wokół;. Stąd J2SE 5.0 Javadocs)
— searchengine27

10

Aby sznurować za pomocą guawy:

Throwables.getStackTraceAsString(new Throwable())

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

lub

Thread.currentThread().getStackTrace()

Czy twój najlepszy przykład nie da ci tylko śladu stosu w stosunku do bloku try / catch?
— Dan Monego,

1
jakie są różnice między nimi
— twlkyao

5

Może mógłbyś spróbować:

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

Ciąg „errorDetail” zawiera ślad stosu.


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

Ostatni element tablicy reprezentuje spód stosu, który jest najnowszym wywołaniem metody w sekwencji.

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

wykonaj pętlę przez StackTraceElement i uzyskaj pożądany wynik.

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

Dziękujemy za wspomnienie, że ostatni element zawiera najnowszy. Przeciw intuicyjny i zaoszczędził mi trochę czasu.
— jasne

również .toString () ładnie wypisze wszystkie te dane w łańcuch
— Vlad

4

Użyłem odpowiedzi z góry i dodałem formatowanie

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

Możesz użyć narzędzia jstack, jeśli chcesz sprawdzić bieżący stos wywołań swojego procesu.

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

To jest stary post, ale oto moje rozwiązanie:

Thread.currentThread().dumpStack();

Więcej informacji i więcej metod: http://javarevisited.blogspot.fr/2013/04/how-to-get-current-stack-trace-in-java-thread.html


3
Ponieważ Thread.dumpStack () jest statyczny, powinieneś po prostu wywołać go bezpośrednio.
— David Avendasora

2
OP wskazał, że chce odwołania w kodzie do śladu stosu, a nie do wydrukowania.
— Taylor R

1
jak wspomniano @DavidAvendasora, powinieneś wywoływać Thread.dumpStack()bezpośrednio, ponieważ jest to metoda statyczna.
— M-WaJeEh

Tak, java.lang.Thread.dumpStack () działa na Javie 11.
— Park JongBum

-3

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

Pomoże to wydrukować ślad stosu bez pętli.


1
Twoja odpowiedź jest taka sama jak moja wysłana 3 miesiące wcześniej.
— Mike Rodent
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.