Получить текущую трассировку стека в Java

817

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

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

  • 69
    Я всегда использую «new Exception (). PrintStackTrace ()» в качестве выражения наблюдения, когда я отлаживаю в Eclipse. Это удобно, когда вы останавливаетесь в точке останова и хотите знать, откуда вы пришли.
  • 22
    @ TimBüthe: разве Eclipse не сообщает вам трассировку стека, когда вы находитесь в режиме отладки? Я думаю так.
Показать ещё 5 комментариев
Теги:
stack-trace

22 ответа

961
Лучший ответ

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

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

  • 42
    String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); строка, если вы уже используете Apache Commons для получения строки: String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); stackoverflow.com/a/10620951/11236
  • 4
    Первый элемент (индекс 0) в массиве - это метод java.lang.Thread.getStackTrace, второй (индекс 1) обычно представляет первый интерес.
Показать ещё 7 комментариев
223
Thread.currentThread().getStackTrace();

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

new Throwable().getStackTrace();

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

  • 32
    (new Throwable()).getStackTrace() выполняется быстрее (см. bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302 )
  • 2
    Можете ли вы объяснить более подробно, как результаты Thread.currentThread (). GetStackTrace () могут отличаться от новых Throwable (). GetStackTrace ()? Я попробовал оба и обнаружил, что Thread.currentThread (). GetStackTrace () возвращает массив с Thread.getStackTrace в индексе 0, а вызывающий метод - в индексе 1. Новый метод Throwable (). GetStackTrace () возвращает массив с вызывающим Метод с индексом 0. Кажется, что оба метода имеют определенную позицию для текущего метода, но позиции разные. Есть ли другая разница, на которую вы указываете?
Показать ещё 5 комментариев
169
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
    System.out.println(ste);
}
  • 17
    В Java есть метод printStackTrace, определенный для Throwable, который вы можете сделать: new Exception().printStackTrace(System.out) который я помню, цикл for, вероятно, имеет меньше накладных расходов, но вы все равно должны использовать его только в качестве средства отладки. ,
  • 1
    Мне этот for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } } всего, потому что у вас есть возможность убрать шум, обернув оператор println, например, for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
52
Thread.currentThread().getStackTrace();

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

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

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
  • 1
    new Throwable().getStackTrace() доступен с JDK1.4…
36

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

String fullStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
  • 13
    Это хорошее решение в одну строку. К вашему сведению, для всех, кто использует org.apache.commons.lang3 , полная строка: org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
  • 2
    Просто чтобы повторить комментарий fileoffset при переходе на org.apache.commons.lang3 , который я изначально упустил из виду - импорт использует lang3 вместо lang и заменяет getFullStackTrace на getStackTrace .
Показать ещё 1 комментарий
20

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

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

Чтобы получить трассировку стека всех потоков, вы можете использовать утилиту 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 но я думаю, что большинство людей могли бы решить это.
  • 0
    Спасибо Джорджу - исправил мой пример кода.
16

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

new Exception().printStackTrace();   
new Error().printStackTrace();
  • 0
    отличное решение. Теперь мне не нужно перебирать все кадры стека
12

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

8

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

Arrays.toString(Thread.currentThread().getStackTrace());

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

  • 0
    У меня есть список потоков, и мне нужно распечатать их следы стека.
  • 0
    В этом случае убедитесь, что вы используете Thread.getAllStackTraces() который дает вам Map<Thread, StackTraceElement[]> . Hotspot будет защищать все потоки всякий раз, когда это необходимо. Zing может привести отдельные темы в безопасную точку, не мешая другим. Получение трассировки стека требует безопасной точки. Thread.getAllStackTraces() получает все трассировки стека и останавливает все потоки только один раз. Конечно, вы должны выяснить, какое отображение вам действительно интересно.
8

Строка с guava:

Throwables.getStackTraceAsString(new Throwable())
7

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

  Thread.dumpStack()

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

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

У меня есть метод утилиты, который возвращает строку с помощью 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();
}

И просто логит вроде...

... 
catch (FileNotFoundException e) {
    logger.config(getStackTrace(e));
}
  • 0
    Это похоже на один авто, сгенерированный Netbeans.
  • 0
    Является ли logger встроенным логгером или тем, который вы создали и записали в файл.
Показать ещё 4 комментария
6

В 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 );
}
6
try {
}
catch(Exception e) {
    StackTraceElement[] traceElements = e.getStackTrace();
    //...
}

или

Thread.currentThread().getStackTrace()
  • 0
    Разве ваш лучший пример не даст вам только трассировку стека относительно блока try / catch?
  • 0
    действительно, это будет
Показать ещё 1 комментарий
4
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();

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

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

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

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

Возможно, вы могли бы попробовать следующее:

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

Строка 'errorDetail' содержит stacktrace.

2

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

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
0

Получение stacktrace:

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

Печать stacktrace (JAVA 9+):

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

Печать stacktrage (JAVA 7):

StringBuilder sb = new StringBuilder();

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

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

Thread.currentThread().dumpStack();

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

  • 3
    Поскольку Thread.dumpStack () является статическим, вы должны просто вызвать его напрямую.
  • 2
    ОП указала, что они хотят в коде ссылку на трассировку стека, а не распечатывать ее.
Показать ещё 1 комментарий
-2

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

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

  • 0
    Ваш ответ такой же, как мой, опубликованный 3 месяцами ранее.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню