Как я могу получить текущую трассировку стека в Java?

1002

Как получить текущую трассировку стека в Java, например, как в .NET вы можете сделать Environment.StackTrace?

Я нашел, Thread.dumpStack()но это не то, что я хочу - я хочу вернуть трассировку стека, а не распечатать его.

ripper234
источник
73
Я всегда использую «new Exception (). PrintStackTrace ()» в качестве выражения наблюдения, когда я отлаживаю в Eclipse. Это удобно, когда вы останавливаетесь в точке останова и хотите знать, откуда вы пришли.
Тим Бюте
22
@ TimBüthe: разве Eclipse не сообщает вам трассировку стека, когда вы находитесь в режиме отладки? Я думаю так.
Луиджи Масса Галлерано
41
Arrays.toString (Thread.currentThread () getStackTrace ().); достаточно просто.
Ajay
2
@Arkanon Это относится к Java, и показывает, как они будут делать это в .net и каков эквивалент в Java.
Pokechu22
9
Чтобы хорошо его распечатать, вы можете использовать apache StringUtils: StringUtils.join (currentThread (). GetStackTrace (), "\ n");
Art

Ответы:

1160

Вы можете использовать Thread.currentThread().getStackTrace().

Это возвращает массив StackTraceElements, которые представляют текущую трассировку стека программы.

jjnguy
источник
48
String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e);
Крутая однострочная
5
Первый элемент (индекс 0) в массиве - это метод java.lang.Thread.getStackTrace, второй (индекс 1) обычно представляет первый интерес.
lilalinux
175
Одна строка для преобразования трассировки стека в строку, которая работает, когда у вас нет исключения и вы не используете Apache Arrays.toString (Thread.currentThread (). GetStackTrace ())
Tony
9
Решение @Tony лучше, потому что оно не требует
броска
3
Как указывалось во многих ответах ниже - new Throwable().getStackTrace()гораздо быстрее, потому что не нужно проверять this != Thread.currentThread()и обходить потенциальные издержки JVM при вызове через child-class ( Exception extends Throwable)
Влад
265
Thread.currentThread().getStackTrace();

хорошо, если вам все равно, какой первый элемент стека.

new Throwable().getStackTrace();

будет иметь определенную позицию для вашего текущего метода, если это имеет значение.

Ишай
источник
35
(new Throwable()).getStackTrace()выполняется быстрее (см. bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302 )
MightyE
2
Можете ли вы объяснить более подробно, как результаты Thread.currentThread (). GetStackTrace () могут отличаться от новых Throwable (). GetStackTrace ()? Я попробовал оба и обнаружил, что Thread.currentThread (). GetStackTrace () возвращает массив с Thread.getStackTrace в индексе 0, а вызывающий метод - в индексе 1. Новый метод Throwable (). GetStackTrace () возвращает массив с вызывающим Метод с индексом 0. Кажется, что оба метода имеют определенную позицию для текущего метода, но позиции разные. Есть ли другая разница, на которую вы указываете?
Райан
9
@Ryan, нет никакой гарантии, что Thread.currentThread (). GetStackTrace () не обещает поддерживать эту позицию в разных версиях метода. Поэтому, когда вы проверяете, что он был по индексу 1. На некоторых версиях JVM (1.5 или 1.6, не помню) для Sun это был индекс 2. Это то, что я имею в виду под определенной позицией - спецификация требует это быть там и оставаться там в будущем.
Ишай
5
@MightyE Эта ошибка теперь сообщается как закрытые , как зафиксировано в Java 6. Глядя на внутренностях, это выглядит , как он теперь делает , (new Exception()).getStackTrace()когда запрашиваемая трассировки стека на текущем потоке (который всегда будет иметь место в случаеThread.currentThread().getStackTrace();
М. Джастин
3
@MJustin: ошибка не «сейчас» сообщается как исправленная, она была исправлена ​​даже за шесть лет до того, как MightyE написал комментарий. На самом деле, это было исправлено еще до того, как был основан Stackoverflow…
Хольгер
181
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
    System.out.println(ste);
}
Лейф Грюнвольдт
источник
20
У java есть метод printStackTrace, определенный для Throwable, вы можете сделать: new Exception().printStackTrace(System.out)что я помню, цикл for, вероятно, имеет меньше накладных расходов, но вы все равно должны использовать это только как средство отладки ...
Jaap
2
Мне это нравится больше всего, потому что у вас есть шанс избавиться от шума, обернув свое выражение println, например,for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
nby
61
Thread.currentThread().getStackTrace();

доступен с JDK1.5.

Для более старой версии вы можете перенаправить exception.printStackTrace()на StringWriter():

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
RealHowTo
источник
3
new Throwable().getStackTrace()доступен с JDK1.4…
Хольгер
40

Вы можете использовать Apache для этого:

String fullStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
stikkos
источник
13
Это хорошее решение в одну строку. К вашему сведению, для всех, кто использует org.apache.commons.lang3, полная строка:org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
fileoffset
2
Просто чтобы повторить комментарий fileoffset при переходе на org.apache.commons.lang3, который я изначально пропустил - импорт использует lang3вместо lang, а заменяет getFullStackTraceна getStackTrace.
ggkmath
Это очень полезно! При отладке с использованием IDE (например, IntelliJ IDEA), здорово использовать ExceptionUtils.getStackTrace(new Throwable())выражение для получения трассировки стека.
Сергей Брунов
24

На Android гораздо проще использовать это:

import android.util.Log;
String stackTrace = Log.getStackTraceString(exception); 
Вики Кападия
источник
4
Где определяется getStackTraceString? Это из сторонней библиотеки логов?
skiphoppy
6
android.util.Log.getStackTraceString developer.android.com/reference/android/util/Log.html
Ондрей Квасновский
22

Чтобы получить трассировку стека всех потоков, вы можете использовать утилиту jstack, JConsole или отправить сигнал kill -quit (в операционной системе Posix).

Однако, если вы хотите сделать это программно, вы можете попробовать использовать ThreadMXBean:

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

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

Как уже упоминалось, если вам нужна только трассировка стека текущего потока, это намного проще - просто используйте Thread.currentThread().getStackTrace();

Адамский
источник
2
Фрагмент кода в этом ответе приближается к программному генерированию вида дампа, который вы видите при отправке JVM сигнала QUIT (в Unix-подобных системах) или <ctrl> <break> в Windows. В отличие от других ответов, вы видите мониторы и синхронизаторы, а также только трассировки стека (например, если вы выполняете итерацию по массиву StackTraceElement и делаете System.err.println(elems[i])для каждого). Вторая строка во фрагменте отсутствует bean.раньше, dumpAllThreadsно я думаю, что большинство людей могли бы решить это.
Джордж Хокинс
22

Другое решение (всего 35 31 символов):

new Exception().printStackTrace();   
new Error().printStackTrace();
Кукис
источник
1
отличное решение. Теперь мне не нужно перебирать все кадры стека
Vineel Kovvuri
17

Глупый я, это Thread.currentThread().getStackTrace();

ripper234
источник
17

Тони, в качестве комментария к принятому ответу, дал лучший ответ, который на самом деле отвечает на вопрос ОП :

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

... OP НЕ спрашивал, как получить Stringтрассировку стека от Exception. И хотя я большой поклонник Apache Commons, когда есть что-то простое, как указано выше, нет логической причины использовать стороннюю библиотеку.

Майк Грызун
источник
У меня есть список потоков, и мне нужно распечатать их следы стека.
Даниэль С. Яицков
В этом случае убедитесь, что вы используете, Thread.getAllStackTraces()который дает вам Map<Thread, StackTraceElement[]>. Hotspot будет защищать все потоки всякий раз, когда это необходимо. Zing может привести отдельные темы в безопасную точку, не мешая другим. Получение трассировки стека требует безопасной точки. Thread.getAllStackTraces()получает все трассировки стека и останавливает все потоки только один раз. Конечно, вы должны выяснить, какое отображение вам на самом деле интересно.
Ральф Х
14

Я предполагаю, что

  Thread.dumpStack()

это более простой способ, и его преимущество заключается в том, что на самом деле не создается исключение и не может быть выброшено, когда проблемы могут вообще не быть, и это значительно более важно.

Томас Адкинс
источник
1
Ладно, на самом деле dumpStack () является статическим методом, и к нему следует обращаться статическим способом. Спасибо, затмение!
Томас Адкинс
1
Мне нравится ярлык, но исходный код для этого метода: new Exception("Stack trace").printStackTrace();так что он на самом деле строит Throwable
Флоран
13

Получение трассировки стека:

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

Печать трассировки стека (JAVA 8+):

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

Печатание укладки (JAVA 7):

StringBuilder sb = new StringBuilder();

for (StackTraceElement st : ste) {
    sb.append(st.toString() + System.lineSeparator());
}
System.out.println(sb);
Витольд Качурба
источник
12

В Java 9 появился новый способ:

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 );
}
Кристиан Улленбум
источник
Интересно. :-)
djangofan
10

У меня есть служебный метод, который возвращает строку с трассировкой стека:

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

И просто логит как ...

... 
catch (FileNotFoundException e) {
    logger.config(getStackTrace(e));
}
Сальвадор Валенсия
источник
Это похоже на один авто, сгенерированный Netbeans.
Лейф Грюнвольдт
Является ли регистратор встроенным регистратором или созданным вами и записанным в файл.
Даг Хауф
@Doug Hauf, logger - это ссылка на встроенный Java Logger. Убедитесь, что вы настроили файл logging.properties. Добавьте его в начало вашего класса следующим образом: private static final Logger logger = Logger.getLogger (Your_Class_Name.class.getName ());
Сальвадор Валенсия
1
java.util.logging.Logger#log(Level, String, Throwable)уже делает это. Это переписывает вещи, которые уже существуют в стандартной библиотеке Java без необходимости, и указывает новым разработчикам в неправильном направлении, что далеко от документации. Сделав это сейчас, вы заставили Stacktrace форматироваться определенным образом, где loggingAPI позволяет динамически изменять форматирование оператора log по мере его указания. Насколько мне известно, log4jтакже имеет аналогичное поведение. Не изобретайте велосипед, потому что вы теряете вещи, как я объяснил.
searchengine27
1
Он существовал и в 2012 году. Дата не имеет значения в вашем случае, к сожалению. См. [Ссылка] (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)), [ссылка] (docs.oracle.com/javase/1.5.0/docs/api/java/util/logging/Logger.html#log (java.util.logging.LogRecord)) и т. Д. несколько функций , которые проходят Throwableпрочь к Handlerс помощью к Formatterс в 2012 году , который был Java7, больше , чем я перечислил здесь И эти функции датируются гораздо дольше , чем Java7 было вокруг,. , следовательно , J2SE 5,0 JavaDocs)
searchengine27
10

Для струнной гуавы:

Throwables.getStackTraceAsString(new Throwable())
Zitrax
источник
8
try {
}
catch(Exception e) {
    StackTraceElement[] traceElements = e.getStackTrace();
    //...
}

или

Thread.currentThread().getStackTrace()
butterchicken
источник
Разве ваш лучший пример не даст вам только трассировку стека относительно блока try / catch?
Дэн Монего
1
в чем разница между двумя
twlkyao
5

Может быть, вы могли бы попробовать это:

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

Строка errorDetail содержит трассировку стека.

user1782556
источник
5
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();

Последний элемент массива представляет нижнюю часть стека, что является наименее недавним вызовом метода в последовательности.

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

переберите StackTraceElement и получите желаемый результат.

for (StackTraceElement ste : stackTraceElements ) 
{
    //do your stuff here...
}
Джавад Зеб
источник
Спасибо за упоминание, что последний элемент содержит самый последний. Против интуитивно понятно и сэкономило мне время.
ясный свет
также .toString () будет красиво выводить все эти данные в строку
Влад
4

Я использовал ответы сверху и добавил форматирование

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

Вы можете использовать утилиту jstack, если хотите проверить текущий стек вызовов вашего процесса.

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

Это старый пост, но вот мое решение:

Thread.currentThread().dumpStack();

Больше информации и методов здесь: http://javarevisited.blogspot.fr/2013/04/how-to-get-current-stack-trace-in-java-thread.html

Manov
источник
3
Поскольку Thread.dumpStack () является статическим, вы должны просто вызвать его напрямую.
Дэвид Авендасора
2
ОП указал, что они хотят в коде ссылку на трассировку стека, а не распечатывать ее.
Тейлор Р
1
как упомянул @DavidAvendasora, вы должны вызывать Thread.dumpStack()напрямую, потому что это статический метод.
M-WaJeEh
Да, java.lang.Thread.dumpStack () работает на Java 11.
Park JongBum
-3

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

Это поможет вам распечатать трассировку стека без цикла.

Bhuvanwaitz
источник
1
Ваш ответ такой же, как мой, опубликованный 3 месяцами ранее.
Майк Грызун