Como posso obter o rastreamento de pilha atual em Java?

1002

Como obtenho o rastreamento de pilha atual em Java, como no .NET você pode fazer Environment.StackTrace?

Encontrei, Thread.dumpStack()mas não é o que eu quero - quero recuperar o rastreio da pilha, não imprimi-lo.

ripper234
fonte
73
Eu sempre uso "new Exception (). PrintStackTrace ()" como uma expressão de observação quando estou depurando no Eclipse. Isso é útil quando você suspende em um ponto de interrupção e deseja saber de onde você veio.
217 Tim Timeley
22
@ TimBüthe: o Eclipse já não está dizendo o Rastreamento de Pilha quando você está no modo de depuração? Acho que sim.
Luigi Massa Gallerano 9/08/13
41
Arrays.toString (Thread.currentThread (). GetStackTrace ()); simples o suficiente.
quer
2
@Arkanon Refere-se a java, e está mostrando como eles o fariam em .net e qual é o equivalente em java.
Pokechu22
9
Para imprimir bem, você pode usar o apache StringUtils: StringUtils.join (currentThread (). GetStackTrace (), "\ n");
Art

Respostas:

1159

Você pode usar Thread.currentThread().getStackTrace().

Isso retorna uma matriz de StackTraceElements que representa o rastreamento de pilha atual de um programa.

jjnguy
fonte
48
Um fresco de uma linha se você já está usando Apache commons para obter uma string: String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e); stackoverflow.com/a/10620951/11236
ripper234
5
O primeiro elemento (índice 0) na matriz é o método java.lang.Thread.getStackTrace, o segundo (índice 1) geralmente é o primeiro de interesse.
lilalinux
175
Um um forro para converter o rastreamento de pilha para uma cadeia que funciona quando você não tem uma exceção e você não está usando Apache Arrays.toString (Thread.currentThread () getStackTrace ().)
Tony
9
A solução da @Tony é melhor porque não requer um lançamento
mvd
3
Como apontado em muitas respostas abaixo - o new Throwable().getStackTrace()é muito mais rápido, porque ele não precisa verificar this != Thread.currentThread()e ignora potenciais despesas gerais JVM de chamá-lo através de classe criança ( Exception extends Throwable)
Vlad
265
Thread.currentThread().getStackTrace();

é bom se você não se importa qual é o primeiro elemento da pilha.

new Throwable().getStackTrace();

terá uma posição definida para o seu método atual, se isso interessar.

Yishai
fonte
35
(new Throwable()).getStackTrace()também está executando mais rapidamente (consulte bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302 )
MightyE
2
Você pode explicar com mais detalhes como os resultados de Thread.currentThread (). GetStackTrace () podem ser diferentes de new Throwable (). GetStackTrace ()? Tentei os dois e descobri que Thread.currentThread (). GetStackTrace () retorna uma matriz com Thread.getStackTrace no índice 0 e o método de chamada está no índice 1. O novo método Throwable (). GetStackTrace () retorna uma matriz com a chamada método no índice 0. Parece que os dois métodos têm uma posição definida para o método atual, mas as posições são diferentes. Há outra diferença que você está apontando?
21713 Ryan
9
@ Ryan, não há garantia de que Thread.currentThread (). GetStackTrace () não prometa manter essa posição em diferentes versões do método. Então, quando você verificou que estava no índice 1. Em algumas versões da JVM (1.5 ou 1.6, não se lembra) da Sun, era o índice 2. Isso é o que quero dizer com uma posição definida - a especificação exige estar lá e permanecer lá no futuro.
Yishai
5
@MightyE O bug agora é relatado como fechado como corrigido no Java 6. Observando as partes internas, parece que agora ocorre (new Exception()).getStackTrace()quando o rastreamento de pilha solicitado está no encadeamento atual (o que sempre será o caso paraThread.currentThread().getStackTrace();
M. Justin
3
@MJustin: o bug não é "agora" relatado como corrigido, foi corrigido mesmo seis anos antes de o MightyE escrever o comentário. De fato, ele foi corrigido antes mesmo de o Stackoverflow ser fundado ...
Holger
181
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
    System.out.println(ste);
}
Leif Gruenwoldt
fonte
20
java tem um método printStackTrace definido em Throwable, você pode fazer: new Exception().printStackTrace(System.out)que me lembro, o loop for, provavelmente tem menos sobrecarga, mas você só deve usar isso como uma coisa depuração de qualquer maneira ...
Jaap
2
I como este melhor porque você tem a chance de retirar ruído, envolvendo sua declaração println, por exemplofor (StackTraceElement ste : Thread.currentThread().getStackTrace()) { if(ste.toString().contains("mypackages")){ System.out.println(ste); } }
npor
61
Thread.currentThread().getStackTrace();

está disponível desde o JDK1.5.

Para uma versão mais antiga, você pode redirecionar exception.printStackTrace()para StringWriter():

StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
RealHowTo
fonte
3
new Throwable().getStackTrace()está disponível desde JDK1.4…
Holger
40

Você pode usar os recursos comuns do Apache para isso:

String fullStackTrace = org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
stikkos
fonte
13
Esta é uma ótima solução de uma linha. Para sua informação, para quem está usando org.apache.commons.lang3, a linha completa é:org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(e);
fileoffset 26/07
2
Apenas para reiterar o comentário do fileoffset ao mudar para org.apache.commons.lang3, o qual eu inicialmente ignorei - a importação usa em lang3vez de lange substitui getFullStackTracepor getStackTrace.
ggkmath
Isso é muito útil! Ao depurar usando um IDE (por exemplo, IntelliJ IDEA), é ótimo usar a ExceptionUtils.getStackTrace(new Throwable())expressão para obter o rastreamento de pilha.
Sergey Brunov 21/02/19
24

No android, uma maneira muito mais fácil é usar isso:

import android.util.Log;
String stackTrace = Log.getStackTraceString(exception); 
Vicky Kapadia
fonte
4
Onde o getStackTraceString está definido? Isso é de uma biblioteca de log de terceiros?
Skiphoppy
6
android.util.Log.getStackTraceString developer.android.com/reference/android/util/Log.html
Ondrej Kvasnovsky
22

Para obter o rastreio da pilha de todos os encadeamentos, você pode usar o utilitário jstack, JConsole, ou enviar um sinal de kill-quit (em um sistema operacional Posix).

No entanto, se você quiser fazer isso programaticamente, tente usar o ThreadMXBean:

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

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

Como mencionado, se você deseja apenas o rastreamento de pilha do encadeamento atual, é muito mais fácil - basta usar Thread.currentThread().getStackTrace();

Adamski
fonte
2
O trecho de código nesta resposta é o mais próximo de gerar programaticamente o tipo de despejo que você vê ao enviar à JVM o sinal QUIT (em sistemas como Unix) ou <ctrl> <break> no Windows. Ao contrário das outras respostas, você vê monitores e sincronizadores, bem como apenas os rastreamentos de pilha (por exemplo, se você iterar sobre a matriz StackTraceElement e executar System.err.println(elems[i])em cada um). A segunda linha do trecho está faltando bean.antes do, dumpAllThreadsmas acho que a maioria das pessoas poderia resolver isso.
George Hawkins
22

Outra solução (apenas 35 31 caracteres):

new Exception().printStackTrace();   
new Error().printStackTrace();
kukis
fonte
1
solução incrível. Agora eu não tenho que percorrer todos os quadros de pilha
Vineel Kovvuri
17

Bobo eu, é Thread.currentThread().getStackTrace();

ripper234
fonte
17

Tony, como comentário à resposta aceita, deu a que parece ser a melhor resposta que realmente responde à pergunta do OP :

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

... o OP NÃO perguntou como obter um Stringdo rastreamento de pilha de um Exception. E embora eu seja um grande fã do Apache Commons, quando há algo tão simples quanto o descrito acima, não há razão lógica para usar uma biblioteca externa.

microfone roedor
fonte
Eu tenho uma lista de threads e preciso imprimir seus rastreamentos de pilha.
Daneel S. Yaitskov
Nesse caso, certifique-se de usar o Thread.getAllStackTraces()que lhe dá a Map<Thread, StackTraceElement[]>. O ponto de acesso apontará com segurança todos os threads sempre que precisar apontar com segurança um. O Zing pode levar segmentos individuais a um ponto seguro sem incomodar o outro. Obter um rastreamento de pilha requer um ponto seguro. Thread.getAllStackTraces()obtém todos os rastreamentos de pilha e para todos os threads apenas uma vez. Obviamente, você deve descobrir em qual mapeamento você realmente está interessado.
Ralf H
14

Eu sugiro que

  Thread.dumpStack()

é uma maneira mais fácil e tem a vantagem de não criar uma exceção ou uma ação de lançar quando não pode haver nenhum problema e é consideravelmente mais direto ao ponto.

Thomas Adkins
fonte
1
Ok, na verdade, o dumpStack () é um método estático e deve ser acessado de maneira estática. Obrigado, eclipse!
Thomas Adkins
1
Eu amo o atalho, mas o código fonte para este método é: new Exception("Stack trace").printStackTrace();por isso é realmente construir um Throwable
Florent
13

Obtendo o stacktrace:

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

Rastreio de pilha de impressão (JAVA 8+):

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

Stacktrage de impressão (JAVA 7):

StringBuilder sb = new StringBuilder();

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

No Java 9, há uma nova maneira:

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
fonte
Interessante. :-)
djangofan 20/02
10

Eu tenho um método utilitário que retorna uma seqüência de caracteres com o 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();
}

E apenas logit como ...

... 
catch (FileNotFoundException e) {
    logger.config(getStackTrace(e));
}
Salvador Valencia
fonte
Parece um auto gerado pelo Netbeans.
Leif Gruenwoldt 12/09
é um criador de logs incorporado ou que você criou e grava em um arquivo.
Doug Hauf 15/02
@Doug Hauf, logger é uma referência ao Java Logger embutido. Certifique-se de configurar o arquivo logging.properties. Adicione-o no início da sua classe desta maneira: private static final Logger logger = Logger.getLogger (Your_Class_Name.class.getName ());
Salvador Valencia
1
java.util.logging.Logger#log(Level, String, Throwable)já faz isso. Isso está reescrevendo coisas que já existem na biblioteca padrão Java desnecessariamente e está apontando novos desenvolvedores na direção errada, o que está longe da documentação. Ao fazer isso agora, você forçou o Stacktrace a ser formatado de uma certa maneira, onde a loggingAPI permite variar a formatação da instrução de log dinamicamente conforme você a especifica. Que eu saiba, log4jtambém tem um comportamento semelhante. Não reinvente a roda porque você acaba perdendo coisas como eu expliquei.
usar o seguinte
1
Também existia em 2012. Infelizmente, a data não faz diferença no seu caso. Consulte [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)), etc. (existem existem várias funções que passam Throwablede Handlers para Formatters em 2012, que era Java7, mais do que eu listei aqui.E essas funções datam de muito mais tempo que o Java7 existe; daí o J2SE 5.0 javadocs)
searchengine27
10

Para string com goiaba:

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

ou

Thread.currentThread().getStackTrace()
manteiga
fonte
Seu exemplo principal não fornecerá apenas o rastreamento da pilha em relação ao bloco try / catch?
Dan Dan
1
Qual é a diferença entre os dois
twlkyao
5

Talvez você possa tentar o seguinte:

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

A sequência 'errorDetail' contém o rastreamento de pilha.

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

O último elemento da matriz representa a parte inferior da pilha, que é a invocação de método menos recente na sequência.

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

percorrer StackTraceElement e obter o resultado desejado.

for (StackTraceElement ste : stackTraceElements ) 
{
    //do your stuff here...
}
Jawad Zeb
fonte
Obrigado por mencionar o último elemento que contém o mais recente. Contra-intuitivo e me salvou algum tempo.
Clearlight 16/08/2015
Também .ToString saída vontade () todos os dados muito bem em uma corda
Vlad
4

Usei as respostas acima e adicionei formatação

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

fonte
2

Você pode usar o utilitário jstack se quiser verificar a pilha de chamadas atual do seu processo.

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

Este é um post antigo, mas aqui está a minha solução:

Thread.currentThread().dumpStack();

Mais informações e mais métodos lá: http://javarevisited.blogspot.fr/2013/04/how-to-get-current-stack-trace-in-java-thread.html

Manov
fonte
3
Como Thread.dumpStack () é estático, você deve chamá-lo diretamente.
9306 David Avendasora #
2
O OP indicou que deseja uma referência no código para o rastreamento da pilha, para não imprimi-lo.
Taylor R
1
como o @DavidAvendasora mencionou, você deve ligar Thread.dumpStack()diretamente porque é um método estático.
M-Wajeeh
Sim, java.lang.Thread.dumpStack () funciona no Java 11.
Park JongBum
-3

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

Isso ajudará você a imprimir o rastreamento de pilha sem loop.

Bhuvanwaitz
fonte
1
Sua resposta é a mesma que a minha postada 3 meses antes.
mike roedor