Comment obtenir la trace de pile actuelle en Java?

1002

Comment puis-je obtenir la trace de pile actuelle en Java, comme la façon dont .NET vous pouvez le faire Environment.StackTrace?

J'ai trouvé Thread.dumpStack()mais ce n'est pas ce que je veux - je veux récupérer la trace de la pile, pas l'imprimer.

ripper234
la source
73
J'utilise toujours "new Exception (). PrintStackTrace ()" comme expression de surveillance lorsque je débogue dans Eclipse. C'est pratique lorsque vous suspendez à un point d'arrêt et que vous voulez savoir d'où vous venez.
Tim Büthe
22
@ TimBüthe: Eclipse ne vous dit-il pas déjà la trace de pile lorsque vous êtes en mode débogage? Je le pense.
Luigi Massa Gallerano
41
Arrays.toString (Thread.currentThread (). GetStackTrace ()); assez simple.
Ajay
2
@Arkanon Il fait référence à java et montre comment ils le feraient en .net et quel est l'équivalent en java.
Pokechu22
9
Pour bien l'imprimer, vous pouvez utiliser apache StringUtils: StringUtils.join (currentThread (). GetStackTrace (), "\ n");
Art

Réponses:

1159

Vous pouvez utiliser Thread.currentThread().getStackTrace().

Cela renvoie un tableau de StackTraceElements qui représentent la trace de pile actuelle d'un programme.

jjnguy
la source
48
Un one-liner cool si vous utilisez déjà apache commons pour obtenir une chaîne: String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); stackoverflow.com/a/10620951/11236
ripper234
5
Le premier élément (index 0) du tableau est la méthode java.lang.Thread.getStackTrace, le second (index 1) est généralement le premier d'intérêt.
lilalinux
175
Un liner pour convertir la trace de pile en une chaîne qui fonctionne lorsque vous n'avez pas d'exception et que vous n'utilisez pas Apache Arrays.toString (Thread.currentThread (). GetStackTrace ())
Tony
9
La solution de @Tony est meilleure car elle ne nécessite pas de jetable
mvd
3
Comme indiqué dans de nombreuses réponses ci-dessous - le new Throwable().getStackTrace()est beaucoup plus rapide, car il n'a pas besoin de vérifier this != Thread.currentThread()et de contourner les frais généraux JVM potentiels de l'appel via la classe enfant ( Exception extends Throwable)
Vlad
265
Thread.currentThread().getStackTrace();

est bien si vous ne vous souciez pas du premier élément de la pile.

new Throwable().getStackTrace();

aura une position définie pour votre méthode actuelle, si cela importe.

Yishai
la source
35
(new Throwable()).getStackTrace()s'exécute également plus rapidement (voir bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302 )
MightyE
2
Pouvez-vous expliquer plus en détail en quoi les résultats de Thread.currentThread (). GetStackTrace () peuvent être différents de la nouvelle Throwable (). GetStackTrace ()? J'ai essayé les deux et j'ai trouvé que Thread.currentThread (). GetStackTrace () renvoie un tableau avec Thread.getStackTrace dans l'index 0 et la méthode d'appel est à l'index 1. La nouvelle méthode Throwable (). GetStackTrace () renvoie un tableau avec l'appel à l'index 0. Il semble que les deux méthodes aient une position définie pour la méthode actuelle mais les positions sont différentes. Y a-t-il une autre différence que vous signalez?
Ryan
9
@Ryan, rien ne garantit que Thread.currentThread (). GetStackTrace () ne promet pas de conserver cette position sur différentes versions de la méthode. Donc, lorsque vous vérifiez qu'il était à l'index 1. Sur une version de la JVM (1.5 ou 1.6, je ne me souviens pas) pour Sun, c'était l'index 2. C'est ce que je veux dire par une position définie - la spécification appelle qu'il soit là, et y reste à l'avenir.
Yishai
5
@MightyE Le bogue est désormais signalé comme fermé et corrigé dans Java 6. En regardant les éléments internes, il semble qu'il le fasse maintenant (new Exception()).getStackTrace()lorsque la trace de pile demandée se trouve sur le thread actuel (ce qui sera toujours le cas pourThread.currentThread().getStackTrace();
M. Justin
3
@MJustin: le bug n'est pas "maintenant" signalé comme corrigé, il a été corrigé même six ans avant que MightyE n'écrive le commentaire. En fait, il a été corrigé avant même la fondation de Stackoverflow…
Holger
181
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
    System.out.println(ste);
}
Leif Gruenwoldt
la source
20
java a une méthode printStackTrace définie sur Throwable, vous pouvez le faire: new Exception().printStackTrace(System.out)ce dont je me souviens, la boucle for a probablement moins de surcharge, mais vous ne devriez de toute façon l'utiliser que comme débogage ...
Jaap
2
J'aime mieux celui-ci parce que vous avez la possibilité de supprimer le bruit, en enveloppant votre déclaration println, par exemplefor (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
nby
61
Thread.currentThread().getStackTrace();

est disponible depuis JDK1.5.

Pour une ancienne version, vous pouvez rediriger exception.printStackTrace()vers StringWriter():

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
RealHowTo
la source
3
new Throwable().getStackTrace()est disponible depuis JDK1.4…
Holger
40

Vous pouvez utiliser les communs d'Apache pour cela:

String fullStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
stikkos
la source
13
Il s'agit d'une belle solution en ligne. Pour info, pour toute personne utilisant org.apache.commons.lang3, la ligne complète est:org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
fileoffset
2
Juste pour réitérer le commentaire de fileoffset lors du passage à org.apache.commons.lang3, ce que j'ai initialement ignoré - l'importation utilise à la lang3place de langet remplace getFullStackTracepar getStackTrace.
ggkmath du
C'est très utile! Lors du débogage à l'aide d'un IDE (par exemple, IntelliJ IDEA), il est bon d'utiliser l' ExceptionUtils.getStackTrace(new Throwable())expression pour obtenir la trace de la pile.
Sergey Brunov
24

Sur Android, un moyen beaucoup plus simple consiste à utiliser ceci:

import android.util.Log;
String stackTrace = Log.getStackTraceString(exception); 
Vicky Kapadia
la source
4
Où est définie getStackTraceString? S'agit-il d'une bibliothèque de journalisation tierce?
skiphoppy
6
android.util.Log.getStackTraceString developer.android.com/reference/android/util/Log.html
Ondrej Kvasnovsky
22

Pour obtenir la trace de pile de tous les threads, vous pouvez utiliser l'utilitaire jstack, JConsole ou envoyer un signal kill -quit (sur un système d'exploitation Posix).

Cependant, si vous souhaitez le faire par programme, vous pouvez essayer d'utiliser ThreadMXBean:

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

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

Comme mentionné, si vous ne voulez que la trace de pile du thread actuel, c'est beaucoup plus facile - Utilisez simplement Thread.currentThread().getStackTrace();

Adamski
la source
2
L'extrait de code de cette réponse se rapproche le plus de la génération par programmation du type de vidage que vous voyez lors de l'envoi à la JVM du signal QUIT (sur les systèmes de type Unix) ou de <ctrl> <break> sous Windows. Contrairement aux autres réponses, vous pouvez voir les moniteurs et les synchroniseurs ainsi que les traces de pile (par exemple, si vous parcourez le tableau StackTraceElement et le faites System.err.println(elems[i])sur chacun). La deuxième ligne de l'extrait est manquante bean.avant le, dumpAllThreadsmais je suppose que la plupart des gens pourraient résoudre ce problème.
George Hawkins
22

Autre solution (seulement 35 31 caractères):

new Exception().printStackTrace();   
new Error().printStackTrace();
kukis
la source
1
solution géniale. Maintenant, je n'ai plus à parcourir tous les cadres de pile
Vineel Kovvuri
17

Bête moi c'est Thread.currentThread().getStackTrace();

ripper234
la source
17

Tony, en tant que commentaire de la réponse acceptée, a donné ce qui semble être la meilleure réponse qui répond en fait à la question du PO :

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

... l'OP n'a PAS demandé comment obtenir un Stringde la trace de pile d'un Exception. Et même si je suis un grand fan d'Apache Commons, quand il y a quelque chose d'aussi simple que ci-dessus, il n'y a aucune raison logique d'utiliser une bibliothèque externe.

Mike rongeur
la source
J'ai une liste de threads et j'ai besoin d'imprimer leurs traces de pile.
Daneel S. Yaitskov
Dans ce cas, assurez-vous d'utiliser Thread.getAllStackTraces()ce qui vous donne un Map<Thread, StackTraceElement[]>. Le point d'accès sécurise tous les threads chaque fois qu'il en a besoin. Zing peut amener des threads individuels à un point de sauvegarde sans déranger l'autre. L'obtention d'une trace de pile nécessite un point de sécurité. Thread.getAllStackTraces()obtient toutes les traces de pile et arrête tous les threads une seule fois. Bien sûr, vous devez savoir quelle cartographie vous intéresse réellement.
Ralf H
14

je suggère que

  Thread.dumpStack()

est un moyen plus facile et présente l'avantage de ne pas réellement construire d'exception ou de lancer lorsqu'il n'y a peut-être pas de problème du tout, et est beaucoup plus pertinent.

Thomas Adkins
la source
1
D'accord, en fait, le dumpStack () est une méthode statique, et devrait être accessible de manière statique. Merci, éclipse!
Thomas Adkins
1
J'adore le raccourci, mais le code source de cette méthode est: new Exception("Stack trace").printStackTrace();il s'agit donc de construire un Throwable
Florent
13

Obtenir stacktrace:

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

Impression de stacktrace (JAVA 8+):

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

Impression de stacktrage (JAVA 7):

StringBuilder sb = new StringBuilder();

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

Dans Java 9, il existe une nouvelle façon:

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
la source
Intéressant. :-)
djangofan
10

J'ai une méthode utilitaire qui renvoie une chaîne avec le 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();
}

Et juste logit comme ...

... 
catch (FileNotFoundException e) {
    logger.config(getStackTrace(e));
}
Salvador Valence
la source
Cela ressemble à une auto générée par Netbeans.
Leif Gruenwoldt
L'enregistreur est-il un enregistreur intégré ou que vous avez créé et écrit dans un fichier.
Doug Hauf
@Doug Hauf, logger est une référence au logger Java intégré. Assurez-vous de configurer le fichier logging.properties. Ajoutez-le au début de votre classe comme ceci: private static final Logger logger = Logger.getLogger (Your_Class_Name.class.getName ());
Salvador Valence
1
java.util.logging.Logger#log(Level, String, Throwable)fait déjà cela. Cela réécrit inutilement des choses qui existent déjà dans la bibliothèque standard Java et pointe les nouveaux développeurs dans la mauvaise direction, ce qui est loin de la documentation. En procédant ainsi, vous avez forcé le formatage de Stacktrace d'une certaine manière, alors que l' loggingAPI vous permet de varier dynamiquement le formatage de l'instruction de journal lorsque vous le spécifiez. À ma connaissance, a log4jégalement un comportement similaire. Ne réinventez pas la roue parce que vous finissez par perdre des choses comme je l'ai expliqué.
searchengine27
1
Il existait aussi en 2012. La date ne fait pas de différence dans votre cas, malheureusement. Voir [lien] (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)), etc. (là sont plusieurs fonctions qui passent le Throwablelarge aux Handlers grâce aux Formatters en 2012 qui était java7, plus que je ne l' ai dans cette liste et ces fonctions remontent beaucoup plus longtemps que java7 a été autour;. d' où J2SE 5.0 javadocs)
searchengine27
10

Pour enchaîner avec de la goyave:

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

ou

Thread.currentThread().getStackTrace()
poulet au beurre
la source
Votre premier exemple ne vous donnera-t-il pas uniquement la trace de la pile par rapport au bloc try / catch?
Dan Monego
1
quelles sont les différences entre les deux
twlkyao
5

Vous pourriez peut-être essayer ceci:

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

La chaîne «errorDetail» contient la trace de pile.

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

Le dernier élément du tableau représente le bas de la pile, qui est l'appel de méthode le moins récent de la séquence.

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

parcourez StackTraceElement et obtenez le résultat souhaité.

for (StackTraceElement ste : stackTraceElements ) 
{
    //do your stuff here...
}
Jawad Zeb
la source
Merci d'avoir mentionné que le dernier élément contient le plus récent. Contre-intuitif et m'a fait gagner du temps.
clearlight
également .toString () affichera correctement toutes ces données dans une chaîne
Vlad
4

J'ai utilisé les réponses ci-dessus et ajouté un formatage

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

la source
2

Vous pouvez utiliser l'utilitaire jstack si vous souhaitez vérifier la pile d'appels actuelle de votre processus.

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
la source
1

Ceci est un ancien poste, mais voici ma solution:

Thread.currentThread().dumpStack();

Plus d'informations et plus de méthodes là-bas: http://javarevisited.blogspot.fr/2013/04/how-to-get-current-stack-trace-in-java-thread.html

Manov
la source
3
Étant donné que Thread.dumpStack () est statique, vous devez simplement l'appeler directement.
David Avendasora
2
L'OP a indiqué qu'il voulait une référence dans le code à la trace de la pile, et non pour l'imprimer.
Taylor R
1
comme @DavidAvendasora l'a mentionné, vous devez appeler Thread.dumpStack()directement en raison de sa méthode statique.
M-WaJeEh
Oui, java.lang.Thread.dumpStack () fonctionne sur Java 11.
Park JongBum
-3

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

Cela vous aidera à imprimer la trace de la pile sans boucle.

Bhuvanwaitz
la source
1
Votre réponse est la même que la mienne publiée 3 mois plus tôt.
mike rodent