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


1002

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

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


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, которые представляют текущую трассировку стека программы.


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

3
new Throwable().getStackTrace()доступен с JDK1.4…
Хольгер

40

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

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

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())выражение для получения трассировки стека.
Сергей Брунов


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

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

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


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

или

Thread.currentThread().getStackTrace()

Разве ваш лучший пример не даст вам только трассировку стека относительно блока 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 содержит трассировку стека.


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


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

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


1
Ваш ответ такой же, как мой, опубликованный 3 месяцами ранее.
Майк Грызун
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.