Wie kann ich den aktuellen Stack-Trace in Java abrufen?

1001

Wie erhalte ich den aktuellen Stack-Trace in Java, wie in .NET Environment.StackTrace?

Ich habe gefunden, Thread.dumpStack()aber es ist nicht das, was ich will - ich möchte den Stack-Trace zurückbekommen, nicht ausdrucken.

ripper234
quelle
73
Ich verwende immer "new Exception (). PrintStackTrace ()" als Überwachungsausdruck, wenn ich in Eclipse debugge. Dies ist praktisch, wenn Sie an einem Haltepunkt anhalten und wissen möchten, woher Sie kommen.
Tim Büthe
22
@ TimBüthe: Sagt Eclipse Ihnen nicht bereits den Stack Trace, wenn Sie sich im Debug-Modus befinden? Ich glaube schon.
Luigi Massa Gallerano
41
Arrays.toString (Thread.currentThread (). GetStackTrace ()); einfach genug.
Ajay
2
@Arkanon Es bezieht sich auf Java und zeigt, wie sie es in .net machen würden und was das Äquivalent in Java ist.
Pokechu22
9
Um es schön zu drucken, können Sie Apache StringUtils verwenden: StringUtils.join (currentThread (). GetStackTrace (), "\ n");
Art

Antworten:

1159

Sie können verwenden Thread.currentThread().getStackTrace().

Das gibt ein Array von StackTraceElements zurück, das den aktuellen Stack-Trace eines Programms darstellt.

jjnguy
quelle
48
Ein cooler String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); Einzeiler,
ripper234
5
Das erste Element (Index 0) im Array ist die Methode java.lang.Thread.getStackTrace, das zweite (Index 1) ist normalerweise das erste von Interesse.
Lilalinux
175
Ein Einzeiler zum Konvertieren der Stapelverfolgung in eine Zeichenfolge, die funktioniert, wenn Sie keine Ausnahme haben und Apache Arrays.toString (Thread.currentThread (). GetStackTrace ()) nicht verwenden
Tony
9
@ Tonys Lösung ist besser, weil es kein
Wurfgeschirr
3
Wie in vielen Antworten unten gezeigt - das new Throwable().getStackTrace()ist viel schneller, weil es this != Thread.currentThread()potenzielle JVM-Overheads beim Aufrufen über child-class ( Exception extends Throwable) nicht überprüfen und umgehen muss
Vlad
264
Thread.currentThread().getStackTrace();

ist in Ordnung, wenn es Ihnen egal ist, was das erste Element des Stapels ist.

new Throwable().getStackTrace();

wird eine definierte Position für Ihre aktuelle Methode haben, wenn das wichtig ist.

Yishai
quelle
35
(new Throwable()).getStackTrace()ist auch schneller auszuführen (siehe bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302 )
MightyE
2
Können Sie genauer erklären, wie sich die Ergebnisse von Thread.currentThread (). GetStackTrace () von denen von new Throwable (). GetStackTrace () unterscheiden können? Ich habe beide ausprobiert und festgestellt, dass Thread.currentThread (). GetStackTrace () ein Array mit Thread.getStackTrace in Index 0 zurückgibt und die aufrufende Methode auf Index 1 steht. Die neue Methode Throwable (). GetStackTrace () gibt ein Array mit dem Aufruf zurück Methode bei Index 0. Es scheint, dass beide Methoden eine definierte Position für die aktuelle Methode haben, aber die Positionen sind unterschiedlich. Gibt es einen weiteren Unterschied, auf den Sie hinweisen?
Ryan
9
@ Ryan, es gibt keine Garantie dafür, dass Thread.currentThread (). GetStackTrace () nicht verspricht, diese Position über verschiedene Versionen der Methode hinweg beizubehalten. Wenn Sie also überprüfen, ob es sich um Index 1 handelt. Bei einer Version der JVM (1.5 oder 1.6, nicht erinnern) für Sun war es Index 2. Das meine ich mit einer definierten Position - die Spezifikation fordert es, dort zu sein und dort in der Zukunft zu bleiben.
Yishai
5
@MightyE Der Fehler wird jetzt als geschlossen gemeldet, wie in Java 6 behoben. Wenn man sich die Interna ansieht, sieht es so aus, als ob sich (new Exception()).getStackTrace()der angeforderte Stack-Trace im aktuellen Thread befindet (was fürThread.currentThread().getStackTrace();
M. Justin
3
@MJustin: Der Fehler wird nicht "jetzt" als behoben gemeldet, er wurde sogar sechs Jahre vor dem Schreiben des Kommentars durch MightyE behoben. Tatsächlich wurde es bereits vor der Gründung von Stackoverflow behoben…
Holger,
181
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
    System.out.println(ste);
}
Leif Gruenwoldt
quelle
20
Java hat eine printStackTrace-Methode, die auf Throwable definiert ist. Sie können Folgendes tun: new Exception().printStackTrace(System.out)Ich kann mich erinnern, dass die for-Schleife wahrscheinlich weniger Overhead hat, aber Sie sollten diese sowieso nur als Debugging-Sache verwenden ...
Jaap
2
Ich mag dieses am besten, weil Sie die Möglichkeit haben, Lärm zu beseitigen, indem Sie Ihre Print-Erklärung einpacken, z. B.for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
24.
61
Thread.currentThread().getStackTrace();

ist seit JDK1.5 verfügbar.

Bei einer älteren Version können Sie exception.printStackTrace()zu einem umleiten StringWriter():

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
RealHowTo
quelle
3
new Throwable().getStackTrace()ist seit JDK1.4 verfügbar…
Holger
40

Sie können Apaches Commons dafür verwenden:

String fullStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
Stikkos
quelle
13
Dies ist eine schöne einzeilige Lösung. Zu org.apache.commons.lang3org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
Ihrer Information
2
Nur um den Kommentar von fileoffset beim Wechseln zu wiederholen org.apache.commons.lang3, den ich anfangs übersehen habe - der Import verwendet lang3anstelle von langund ersetzt getFullStackTracedurch getStackTrace.
ggkmath
Das ist sehr nützlich! Beim Debuggen mit einer IDE (z. B. IntelliJ IDEA) empfiehlt es sich, den ExceptionUtils.getStackTrace(new Throwable())Ausdruck zum Abrufen des Stack-Trace zu verwenden.
Sergey Brunov
24

Unter Android ist es weitaus einfacher, Folgendes zu verwenden:

import android.util.Log;
String stackTrace = Log.getStackTraceString(exception); 
Vicky Kapadia
quelle
4
Wo ist getStackTraceString definiert? Ist dies aus einer Protokollierungsbibliothek eines Drittanbieters?
Skiphoppy
6
android.util.Log.getStackTraceString developer.android.com/reference/android/util/Log.html
Ondrej Kvasnovsky
22

Um die Stapelverfolgung aller Threads abzurufen, können Sie entweder das Dienstprogramm jstack, JConsole, verwenden oder ein Kill-Quit-Signal senden (auf einem Posix-Betriebssystem).

Wenn Sie dies jedoch programmgesteuert ausführen möchten, können Sie ThreadMXBean verwenden:

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

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

Wie bereits erwähnt, ist es viel einfacher, wenn Sie nur den Stack-Trace des aktuellen Threads verwenden möchten Thread.currentThread().getStackTrace().

Adamski
quelle
2
Das Code-Snippet in dieser Antwort kommt der programmgesteuerten Generierung der Art von Speicherauszug am nächsten, die beim Senden des QUIT-Signals (unter Unix-ähnlichen Systemen) oder <ctrl> <break> unter Windows an die JVM angezeigt wird. Im Gegensatz zu den anderen Antworten sehen Sie Monitore und Synchronisierer sowie nur die Stack-Traces (z. B. wenn Sie über das StackTraceElement-Array iterieren und dies System.err.println(elems[i])jeweils tun ). Die zweite Zeile im Snippet fehlt bean.vor dem, dumpAllThreadsaber ich denke, die meisten Leute könnten das klären.
George Hawkins
22

Eine andere Lösung (nur 35 31 Zeichen):

new Exception().printStackTrace();   
new Error().printStackTrace();
Kukis
quelle
1
tolle Lösung. Jetzt muss ich nicht alle
Stapelrahmen durchlaufen
17

Dumm von mir, das ist es Thread.currentThread().getStackTrace();

ripper234
quelle
17

Tony hat als Kommentar zu der akzeptierten Antwort die scheinbar beste Antwort gegeben, die die Frage des OP tatsächlich beantwortet :

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

... das OP hat NICHT gefragt, wie man eine Stringvom Stack-Trace von einem bekommt Exception. Und obwohl ich ein großer Fan von Apache Commons bin, gibt es keinen logischen Grund, eine externe Bibliothek zu verwenden, wenn es etwas so Einfaches wie das oben Genannte gibt.

Mike Nagetier
quelle
Ich habe eine Liste von Threads und muss deren Stapelspuren drucken.
Daneel S. Yaitskov
Stellen Sie in diesem Fall sicher, dass Sie verwenden Thread.getAllStackTraces(), was Ihnen eine gibt Map<Thread, StackTraceElement[]>. Hotspot speichert alle Threads sicher, wann immer sie einen sicheren Punkt benötigen. Zing kann einzelne Threads zu einem sicheren Punkt bringen, ohne den anderen zu stören. Um eine Stapelverfolgung zu erhalten, ist ein Sicherheitspunkt erforderlich. Thread.getAllStackTraces()Ruft alle Stack-Traces ab und stoppt alle Threads nur einmal. Natürlich müssen Sie herausfinden, an welchem ​​Mapping Sie tatsächlich interessiert sind.
Ralf H
14

Ich schlage vor, dass

  Thread.dumpStack()

ist ein einfacher Weg und hat den Vorteil, dass keine Ausnahme erstellt oder ausgelöst werden kann, wenn möglicherweise überhaupt kein Problem vorliegt, und ist wesentlich wichtiger.

Thomas Adkins
quelle
1
Okay, eigentlich ist dumpStack () eine statische Methode und sollte statisch aufgerufen werden. Danke, Sonnenfinsternis!
Thomas Adkins
1
Ich liebe die Verknüpfung, aber der Quellcode für diese Methode lautet: new Exception("Stack trace").printStackTrace();Es wird also tatsächlich ein Throwable
Florent
13

Stacktrace erhalten:

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

Stacktrace drucken (JAVA 8+):

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

Stacktrage drucken (JAVA 7):

StringBuilder sb = new StringBuilder();

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

In Java 9 gibt es einen neuen Weg:

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
quelle
Interessant. :-)
Djangofan
10

Ich habe eine Dienstprogrammmethode, die einen String mit dem Stacktrace zurückgibt:

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

Und loggen Sie einfach wie ...

... 
catch (FileNotFoundException e) {
    logger.config(getStackTrace(e));
}
Salvador Valencia
quelle
Dies sieht aus wie eine von Netbeans automatisch generierte.
Leif Gruenwoldt
Ist Logger ein eingebauter Logger oder einer, den Sie erstellt und in eine Datei geschrieben haben.
Doug Hauf
@ Doug Hauf, Logger ist eine Referenz auf den eingebauten Java Logger. Stellen Sie sicher, dass Sie die Datei logging.properties konfigurieren. Fügen Sie es am Anfang Ihrer Klasse folgendermaßen hinzu: private static final Logger logger = Logger.getLogger (Your_Class_Name.class.getName ());
Salvador Valencia
1
java.util.logging.Logger#log(Level, String, Throwable)macht das schon. Dies schreibt Dinge, die bereits in der Java-Standardbibliothek vorhanden sind, unnötig um und weist neue Entwickler in die falsche Richtung, die von der Dokumentation abweicht. Auf diese Weise haben Sie jetzt die Formatierung des Stacktrace auf eine bestimmte Weise erzwungen, wobei Sie mit der loggingAPI die Formatierung der Protokollanweisung dynamisch variieren können, während Sie sie angeben. Meines Wissens hat log4jauch ähnliches Verhalten. Erfinden Sie das Rad nicht neu, weil Sie am Ende Dinge verlieren, wie ich sie erklärt habe.
Searchengine27
1
Es gab es auch 2012. Das Datum macht in Ihrem Fall leider keinen Unterschied. Siehe [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)) usw. (dort) Es gibt mehrere Funktionen, die Throwabledas Handlers an das s bis zum Formatters im Jahr 2012 weitergeben, das Java7 war, mehr als ich hier aufgelistet habe. Und diese Funktionen reichen viel länger zurück als Java7; daher J2SE 5.0 javadocs)
searchengine27
10

So schnüren Sie mit Guave:

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

oder

Thread.currentThread().getStackTrace()
Butterhuhn
quelle
Gibt Ihnen Ihr Top-Beispiel nicht nur die Stapelverfolgung relativ zum Try / Catch-Block?
Dan Monego
1
Was ist der Unterschied zwischen den beiden
Twlkyao
5

Vielleicht könnten Sie das versuchen:

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

Die Zeichenfolge 'errorDetail' enthält die Stapelverfolgung.

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

Das letzte Element des Arrays stellt den unteren Rand des Stapels dar. Dies ist der am wenigsten aktuelle Methodenaufruf in der Sequenz.

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

Durchlaufen Sie StackTraceElement und erhalten Sie das gewünschte Ergebnis.

for (StackTraceElement ste : stackTraceElements ) 
{
    //do your stuff here...
}
Jawad Zeb
quelle
Vielen Dank für die Erwähnung, dass das letzte Element das neueste enthält. Kontraintuitiv und hat mir Zeit gespart.
klares Licht
auch .toString () gibt all diese Daten schön in einen String aus
Vlad
4

Ich habe Antworten von oben verwendet und Formatierungen hinzugefügt

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

quelle
2

Sie können das Dienstprogramm jstack verwenden, wenn Sie den aktuellen Aufrufstapel Ihres Prozesses überprüfen möchten.

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
quelle
1

Dies ist ein alter Beitrag, aber hier ist meine Lösung:

Thread.currentThread().dumpStack();

Weitere Informationen und Methoden finden Sie dort: http://javarevisited.blogspot.fr/2013/04/how-to-get-current-stack-trace-in-java-thread.html

Manov
quelle
3
Da Thread.dumpStack () statisch ist, sollten Sie es einfach direkt aufrufen.
David Avendasora
2
Das OP gab an, dass ein Verweis im Code auf die Stapelverfolgung gewünscht wird, um ihn nicht auszudrucken.
Taylor R
1
Wie @DavidAvendasora erwähnte, sollten Sie Thread.dumpStack()wegen seiner statischen Methode direkt aufrufen .
M-WaJeEh
Ja, java.lang.Thread.dumpStack () funktioniert unter Java 11.
Park JongBum
-3

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

Auf diese Weise können Sie die Stapelverfolgung ohne Schleife drucken.

Bhuvanwaitz
quelle
1
Ihre Antwort ist dieselbe wie meine, die 3 Monate zuvor veröffentlicht wurde.
Mike Nagetier