Як я можу отримати поточний слід стека на Java?


1001

Як отримати поточний слід стека на Java, як, наприклад, у .NET, який ви можете зробити Environment.StackTrace?

Я знайшов, Thread.dumpStack()але це не те, що я хочу - я хочу повернути слід стека, а не роздрукувати його.


73
Я завжди використовую "новий Exception (). PrintStackTrace ()" як вираз перегляду, коли я налагоджую в Eclipse. Це зручно, коли ви зупиняєтесь на точці розриву і хочете знати, звідки ви прийшли.
Тім Бют

22
@ TimBüthe: чи Eclipse вже не повідомляє вам стежу стека, коли ви перебуваєте в режимі налагодження? Я думаю так.
Луїджі Масса Галлерано

41
Arrays.toString (Thread.currentThread (). GetStackTrace ()); досить простий.
Аджай

2
@Arkanon Це стосується Java, і показує, як вони це роблять у .net та який еквівалент у Java.
Pokechu22

9
Для гарного друку ви можете використовувати apache StringUtils: StringUtils.join (currentThread (). GetStackTrace (), "\ n");
Арт

Відповіді:


1158

Можна використовувати Thread.currentThread().getStackTrace().

Це повертає масив StackTraceElements, який представляє поточний слід стека програми.


48
Крута один вкладиш , якщо ви вже використовуєте Apache Commons , щоб отримати рядок: String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); stackoverflow.com/a/10620951/11236
ripper234

5
Перший елемент (індекс 0) у масиві - це метод java.lang.Thread.getStackTrace, другий (індекс 1), як правило, перший цікавить.
lilalinux

175
Один вкладиш для перетворення сліду стека в рядок, який працює, коли у вас немає винятку, і ви не використовуєте Apache Arrays.toString (Thread.currentThread (). GetStackTrace ())
Тоні

9
Рішення @Tony краще, тому що воно не потребує перекидання
mvd

3
Як зазначається у багатьох відповідях нижче - new Throwable().getStackTrace()це набагато швидше, тому що йому не потрібно перевіряти this != Thread.currentThread()та обминати потенційні накладні витрати JVM, щоб викликати це через дитячий клас ( Exception extends Throwable)
Влад,

264
Thread.currentThread().getStackTrace();

чудово, якщо вам все одно, що є першим елементом стека.

new Throwable().getStackTrace();

буде мати визначене положення для вашого поточного методу, якщо це має значення.


35
(new Throwable()).getStackTrace()швидше виконувати теж (див. bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302 )
Могутній

2
Чи можете ви пояснити більш докладно, як результати Thread.currentThread (). GetStackTrace () можуть відрізнятися від нових Throwable (). GetStackTrace ()? Я спробував і те, і виявив, що Thread.currentThread (). GetStackTrace () повертає масив am з Thread.getStackTrace в індексі 0, а метод виклику знаходиться в індексі 1. Новий метод Throwable (). GetStackTrace () повертає масив з викликом метод в індексі 0. Схоже, обидва методи мають визначене положення для поточного методу, але позиції різні. Чи є інша різниця, яку ви вказуєте?
Райан

9
@Ryan, немає гарантії, що Thread.currentThread (). GetStackTrace () не обіцяє зберегти цю позицію в різних версіях методу. Тож коли вам трапляється перевірити це було в індексі 1. У деяких версіях JVM (1.5 або 1.6, не пам’ятаю) для Sun, це було індексом 2. Це я маю на увазі під певною позицією - специфікація вимагає це бути там і залишатися там і надалі.
Yishai

5
@MightyE Про помилку тепер повідомляється як закрито, як виправлено в Java 6. Дивлячись на внутрішні, він виглядає так, як зараз, (new Exception()).getStackTrace()коли запитуваний стек стека знаходиться в поточному потоці (що завжди буде такThread.currentThread().getStackTrace();
М. Джастін

3
@MJustin: Про помилку не повідомляється як про виправлення, вона була виправлена ​​ще за шість років до того, як MightyE написав коментар. Насправді це було виправлено ще до того, як був заснований Stackoverflow…
Holger

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…
Holger

40

Ви можете використовувати спільноти Apache для цього:

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

13
Це приємне рішення з однієї лінії. FYI, для всіх, хто використовує org.apache.commons.lang3, повний рядок:org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
зсув файлу

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


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

... ОП НЕ запитав, як отримати Stringсліди стека від Exception. І хоча я великий шанувальник Apache Commons, коли є щось таке просте, як вище, немає логічної причини використовувати зовнішню бібліотеку.


У мене є список потоків, і мені потрібно надрукувати їх сліди стека.
Даніель С. Яїцков

У цьому випадку переконайтеся, що ви використовуєте, Thread.getAllStackTraces()що дає вам Map<Thread, StackTraceElement[]>. Точка доступу захистить всі потоки, коли це потрібно для безпечної точки. Цінг може підвести окремі нитки до безпечної точки, не заважаючи іншим. Отримати стек-трек потрібно безпечну точку. Thread.getAllStackTraces()отримує всі сліди стека і зупиняє всі потоки лише один раз. Звичайно, ви повинні з'ясувати, яке відображення вас насправді цікавить.
Ralf H

14

Я пропоную це

  Thread.dumpStack()

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


1
Гаразд, насправді dumpStack () є статичним методом, і до нього слід звертатися статично. Спасибі, затемнення!
Thomas Adkins

1
Мені подобається ярлик, але вихідний код цього методу такий: new Exception("Stack trace").printStackTrace();таким чином він фактично будує Throwable
Florent

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.
Leif Gruenwoldt

це реєстратор - вбудований реєстратор або той, який ви створили та записуєте у файл.
Дуг Хауф

@Doug Hauf, реєстратор - це посилання на вбудований Java Logger. Переконайтеся, що ви налаштували файл logging.properties. Додайте його на початку свого класу так: приватний статичний остаточний реєстратор реєстратора = Logger.getLogger (Your_Class_Name.class.getName ());
Сальвадор Валенсія

1
java.util.logging.Logger#log(Level, String, Throwable)вже робить це. Це переписування речей, які вже існують у стандартній бібліотеці Java без необхідності і вказують на нових розробників у неправильному напрямку, що далеко від документації. Роблячи це зараз, ви змусили формат Stacktrace певним чином відформатований, оскільки loggingAPI дозволяє вам динамічно змінювати форматування оператора журналу під час його введення. Наскільки мені відомо, log4jтеж має подібну поведінку. Не винаходити колесо, тому що ти втрачаєш речі, як я пояснив.
searchchengine27

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

Чи не ваш найприкладніший приклад дасть вам лише слід стека щодо блоку спробу / лову?
Дан Монего

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...
}

Дякуємо, що згадали, що останній елемент містить найновіший. Контрінтуїтивна і врятувала мене деякий час.
clearlight

Також .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.
Парк JongBum

-3

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

Це допоможе вам надрукувати слід стека без циклу.


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