Come posso ottenere la traccia dello stack corrente in Java?


1002

Come posso ottenere la traccia dello stack corrente in Java, come in .NET Environment.StackTrace.

Ho trovato Thread.dumpStack()ma non è quello che voglio: voglio recuperare la traccia dello stack, non stamparla.


73
Uso sempre "new Exception (). PrintStackTrace ()" come espressione di controllo quando eseguo il debug in Eclipse. È utile quando ti fermi ad un breakpoint e vuoi sapere da dove vieni.
Tim Büthe

22
@ TimBüthe: Eclipse non ti dice già Stack Trace quando sei in modalità debug? Credo di si.
Luigi Massa Gallerano,

41
Arrays.toString (Thread.currentThread () getStackTrace ().); abbastanza semplice.
Ajay,

2
@Arkanon Si riferisce a java e mostra come lo farebbero in .net e qual è l'equivalente in java.
Pokechu22,

9
Per stamparlo bene puoi usare apache StringUtils: StringUtils.join (currentThread (). GetStackTrace (), "\ n");
Art

Risposte:


1159

È possibile utilizzare Thread.currentThread().getStackTrace().

Ciò restituisce una matrice di StackTraceElements che rappresentano la traccia dello stack corrente di un programma.


48
Un fresco one-liner, se si sta già utilizzando Apache Commons per ottenere una stringa: String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); stackoverflow.com/a/10620951/11236
ripper234

5
Il primo elemento (indice 0) nella matrice è il metodo java.lang.Thread.getStackTrace, il secondo (indice 1) di solito è il primo di interesse.
lilalinux,

175
Un solo liner per convertire la traccia dello stack in una stringa che funziona quando non si ha un'eccezione e non si utilizza Apache Arrays.toString (Thread.currentThread (). GetStackTrace ())
Tony

9
La soluzione di @Tony è migliore perché non richiede un lancio
mvd

3
Come indicato in molte risposte di seguito - new Throwable().getStackTrace()è molto più veloce, perché non ha bisogno di controllare this != Thread.currentThread()e aggira i potenziali costi generali JVM di chiamarlo tramite classe figlio ( Exception extends Throwable)
Vlad

265
Thread.currentThread().getStackTrace();

va bene se non ti interessa quale sia il primo elemento dello stack.

new Throwable().getStackTrace();

avrà una posizione definita per il tuo metodo attuale, se questo è importante.


35
(new Throwable()).getStackTrace()è anche più veloce (vedi bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302 )
MightyE

2
Puoi spiegare in modo più dettagliato come i risultati di Thread.currentThread (). GetStackTrace () potrebbero essere diversi dal nuovo Throwable (). GetStackTrace ()? Ho provato entrambi e ho scoperto che Thread.currentThread (). GetStackTrace () restituisce un array am con Thread.getStackTrace nell'indice 0 e il metodo di chiamata è nell'indice 1. Il nuovo metodo Throwable (). GetStackTrace () restituisce un array con la chiamata metodo all'indice 0. Sembra che entrambi i metodi abbiano una posizione definita per il metodo corrente ma le posizioni sono diverse. C'è un'altra differenza che stai sottolineando?
Ryan,

9
@Ryan, non vi è alcuna garanzia che Thread.currentThread (). GetStackTrace () non prometta di mantenere quella posizione su diverse versioni del metodo. Quindi, quando ti capita di verificare che fosse nell'indice 1. Su alcune versioni di JVM (1.5 o 1.6, non ricordare) per Sun, era l'indice 2. Questo è ciò che intendo per una posizione definita - le specifiche richiedono essere lì e stare lì in futuro.
Yishai,

5
@MightyE Il bug è ora segnalato come chiuso come risolto in Java 6. Guardando gli interni, sembra che lo faccia ora (new Exception()).getStackTrace()quando la traccia dello stack richiesta è sul thread corrente (che sarà sempre il caso diThread.currentThread().getStackTrace();
M. Justin

3
@MJustin: il bug non è "ora" segnalato come riparato, è stato corretto anche sei anni prima che MightyE scrivesse il commento. In effetti, è stato risolto anche prima che Stackoverflow fosse fondato ...
Holger,

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

20
java ha un metodo printStackTrace definito su Throwable, puoi farlo: new Exception().printStackTrace(System.out)cosa che posso ricordare, il ciclo for probabilmente ha meno overhead, ma dovresti comunque usarlo solo come cosa di debugging ...
Jaap

2
Mi piace di più, perché hai la possibilità di eliminare il rumore, avvolgendo la tua dichiarazione for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
stampata

61
Thread.currentThread().getStackTrace();

è disponibile da JDK1.5.

Per una versione precedente, puoi reindirizzare exception.printStackTrace()a StringWriter():

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

3
new Throwable().getStackTrace()è disponibile dal JDK 1,4 ...
Holger,

40

Puoi usare i beni comuni di Apache per questo:

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

13
Questa è una bella soluzione a una riga. Cordiali saluti, per chiunque utilizzi org.apache.commons.lang3, la linea completa è:org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
fileoffset

2
Solo per ribadire il commento di fileoffset quando ci si sposta org.apache.commons.lang3, che inizialmente ho trascurato: l'importazione utilizza lang3invece di lange sostituisce getFullStackTracecon getStackTrace.
ggkmath,

Questo è molto utile! Quando si esegue il debug utilizzando un IDE (ad esempio IntelliJ IDEA), è consigliabile utilizzare l' ExceptionUtils.getStackTrace(new Throwable())espressione per ottenere la traccia dello stack.
Sergey Brunov,


22

Per ottenere la traccia dello stack di tutti i thread è possibile utilizzare l'utilità jstack, JConsole o inviare un segnale kill -quit (su un sistema operativo Posix).

Tuttavia, se si desidera farlo a livello di codice, è possibile provare a utilizzare ThreadMXBean:

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

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

Come accennato, se vuoi solo la traccia dello stack del thread corrente è molto più semplice - Usa solo Thread.currentThread().getStackTrace();


2
Lo snippet di codice in questa risposta si avvicina di più alla generazione programmatica del tipo di dump che vedi quando si invia alla JVM il segnale QUIT (su sistemi come Unix) o <ctrl> <break> su Windows. A differenza delle altre risposte, puoi vedere monitor e sincronizzatori, nonché solo le tracce dello stack (ad es. Se esegui l'iterazione sull'array StackTraceElement e fai System.err.println(elems[i])su ciascuno). La seconda riga dello snippet è mancante bean.prima dumpAllThreadsma credo che la maggior parte delle persone possa risolverlo.
George Hawkins,

22

Un'altra soluzione (solo 35 31 caratteri):

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

1
soluzione fantastica. Ora non devo scorrere tutti i frame dello stack
Vineel Kovvuri il

17

Silly me, lo è Thread.currentThread().getStackTrace();


17

Tony, come commento alla risposta accettata, ha dato quella che sembra essere la migliore risposta che risponde effettivamente alla domanda del PO :

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

... l'OP NON ha chiesto come ottenere uno Stringdalla traccia dello stack da un Exception. E sebbene io sia un grande fan di Apache Commons, quando c'è qualcosa di così semplice come sopra non c'è alcun motivo logico per usare una libreria esterna.


Ho un elenco di thread e devo stampare le loro tracce dello stack.
Daneel S. Yaitskov,

In tal caso, assicurati di utilizzare ciò Thread.getAllStackTraces()che ti dà un Map<Thread, StackTraceElement[]>. L'hotspot salva i punti ogni volta che deve salvarne uno. Zing può portare singoli thread in un punto di sicurezza senza disturbare l'altro. Ottenere uno stacktrace richiede un safepoint. Thread.getAllStackTraces()ottiene tutte le tracce dello stack e arresta tutti i thread una sola volta. Certo, devi scoprire a quale mappatura sei effettivamente interessato.
Ralf H,

14

Lo consiglio

  Thread.dumpStack()

è un modo più semplice e ha il vantaggio di non creare effettivamente un'eccezione o gettabile quando potrebbe non esserci alcun problema ed è notevolmente più pertinente.


1
Va bene, in realtà, dumpStack () è un metodo statico e dovrebbe essere accessibile in modo statico. Grazie, eclissi!
Thomas Adkins,

1
Adoro il collegamento, ma il codice sorgente di questo metodo è: new Exception("Stack trace").printStackTrace();quindi in realtà sta costruendo un Throwable
Florent

13

Ottenere stacktrace:

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

Stack di stampa (JAVA 8+):

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

Stacktrage di stampa (JAVA 7):

StringBuilder sb = new StringBuilder();

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

12

In Java 9 c'è un nuovo modo:

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

Interessante. :-)
djangofan,

10

Ho un metodo di utilità che restituisce una stringa con 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();
}

E basta accedere come ...

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

Sembra uno generato automaticamente da Netbeans.
Leif Gruenwoldt,

è un logger incorporato o uno che è stato creato e scritto in un file.
Doug Hauf,

@Doug Hauf, logger è un riferimento al Logger Java integrato. Assicurarsi di configurare il file logging.properties. Aggiungilo all'inizio della tua classe in questo modo: private static final Logger logger = Logger.getLogger (Your_Class_Name.class.getName ());
Salvador Valencia,

1
java.util.logging.Logger#log(Level, String, Throwable)lo fa già. Questo sta riscrivendo cose che già esistono nella libreria standard Java inutilmente e sta indirizzando i nuovi sviluppatori nella direzione sbagliata, che è lontano dalla documentazione. In questo modo ora hai costretto Stacktrace a essere formattato in un certo modo, dove l' loggingAPI ti consente di variare dinamicamente la formattazione dell'istruzione di registro mentre la specifichi. Per quanto ne sappia, log4jha anche un comportamento simile. Non reinventare la ruota perché finisci per perdere cose come ho spiegato.
searchengine27,

1
Esisteva anche nel 2012. Purtroppo la data non fa differenza nel tuo caso. Vedi [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)), ecc. (Lì sono diverse funzioni che passano Throwabledalla Handlers alla Formatters nel 2012 che era Java7, più di quanto ho elencato qui. E queste funzioni risalgono molto più a lungo di quanto Java7 sia stato in circolazione; quindi J2SE 5.0 javadocs)
searchengine27

10

Per stringere con guava:

Throwables.getStackTraceAsString(new Throwable())

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

o

Thread.currentThread().getStackTrace()

Il tuo esempio principale non ti darà solo la traccia dello stack relativa al blocco try / catch?
Dan Monego,

1
quali sono le differenze tra i due
twlkyao,

5

Forse potresti provare questo:

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

La stringa 'errorDetail' contiene lo stacktrace.


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

L'ultimo elemento dell'array rappresenta il fondo dello stack, che è l'invocazione del metodo meno recente nella sequenza.

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

scorrere in StackTraceElement e ottenere il risultato desiderato.

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

Grazie per aver menzionato l'ultimo elemento contiene il più recente. Controintuitivo e mi ha fatto risparmiare un po 'di tempo.
chiarimento

anche .toString () genererà tutti quei dati in una stringa
Vlad

4

Ho usato le risposte dall'alto e ho aggiunto la formattazione

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

È possibile utilizzare l'utilità jstack se si desidera controllare lo stack di chiamate corrente del processo.

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

Questo è un vecchio post, ma ecco la mia soluzione:

Thread.currentThread().dumpStack();

Maggiori informazioni e più metodi lì: http://javarevisited.blogspot.fr/2013/04/how-to-get-current-stack-trace-in-java-thread.html


3
Poiché Thread.dumpStack () è statico, dovresti semplicemente chiamarlo direttamente.
David Avendasora,

2
L'OP ha indicato che desiderano un riferimento nel codice alla traccia dello stack, non per stamparlo.
Taylor R,

1
come ha detto @DavidAvendasora, dovresti chiamare Thread.dumpStack()direttamente perché è un metodo statico.
M-WaJeEh,

Sì, java.lang.Thread.dumpStack () funziona su Java 11.
Park JongBum

-3

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

Questo ti aiuterà a stampare la traccia dello stack senza loop.


1
La tua risposta è la stessa della mia pubblicata 3 mesi prima.
mike rodent,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.