Como converter um rastreamento de pilha em uma string?


1502

Qual é a maneira mais fácil de converter o resultado Throwable.getStackTrace()em uma sequência que representa o rastreamento de pilha?


6
Como a resposta do jqno realmente usa o método Throwable.getStackTrace () que você especificou na sua pergunta, enquanto Brian não. Ele usa Throwable.printStackTrace ().
— Stijn de Witt

10
Quase todos os projetos Java devem incluir o Apache commons-lang. Inclui muitos métodos de conveniência que implementam necessidades de desenvolvimento extremamente comuns.
— Russell Silva

20
@StijndeWitt Essas três linhas de código quase certamente precisam ser fatoradas fora do lugar que você as chamou. Como você não sabe onde colocá-los, eles entrarão na sua caixa de ferramentas utilitárias com todos os outros trechos úteis. Bingo! você acabou de reinventar a goiaba / commons-lang / tanto faz ... só que não tão bem. Importe uma biblioteca de utilitários sensata e salve a reinvenção da roda. O verdadeiro sinal de um novato é pensar que você pode fazer um trabalho melhor do que os escritores da biblioteca.
— Andrew Spencer

6
1. A goiaba possui - Throwables.getStackTraceAsString (e) 2. Apache Commons Lang - ExceptionUtils.getFullStackTrace 3. Escreva nossos próprios métodos personalizados
— user2323036

8
@AndrewSpencer Não entendo por que vocês tentam atacar o StijndeWitt por querer conseguir isso com um pequeno trecho. Realmente não há muito perigo em escrever um método minúsculo de utilidade (não o vejo como "ARROGÂNCIA MAIS ESSA oh nãooooo !! ele pensa que é melhor que o Apache !!"). Existem muitos projetos, especialmente em linguagens JVM não Java, que realmente não desejam incluir o Guava ou o Commons Lang apenas para registrar um rastreamento de pilha. Escrevo as bibliotecas Scala & Clojure e certamente não fará do Apache Commons Lang uma dependência transitiva apenas por um método.
— Jm0 2/16

Respostas:


1039

Pode-se usar o seguinte método para converter um Exceptionrastreamento de pilha em String. Esta classe está disponível no Apache commons-lang, que é a biblioteca dependente mais comum com muitos fontes abertas populares

org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)


88
@Stijn - para ser justo (eu escrevi a maior resposta atual votou abaixo) vale a pena olhar para commons-lang para muito mais funcionalidade
— Brian Agnew

54
@StijndeWitt Commons Lang é bastante comum. Já está presente na maioria dos meus projetos / projetos em andamento.
— precisa saber é o seguinte

16
@ Hugo, obrigado, ia usar o StringWriter para evitar adicionar uma nova biblioteca - acontece que já é uma dependência de três das minhas dependências. De resto, verifique se já o possui.
— Nathanial

33
@ MartinAsenov - seguindo sua lógica, você nunca usaria uma biblioteca assim, usaria? Você não o usaria a menos que já o esteja usando?
— Brian Agnew

16
FYI, o pacote foi alterado ea classe está agora em: org.apache.commons.lang3.exception.ExceptionUtils.
— schmmd

2201

Use Throwable.printStackTrace(PrintWriter pw)para enviar o rastreamento de pilha para um gravador apropriado.

import java.io.StringWriter;
import java.io.PrintWriter;

// ...

StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String sStackTrace = sw.toString(); // stack trace as a string
System.out.println(sStackTrace);

505
Se você não gosta de incluir uma biblioteca externa para algo tão pequeno e simples como esse, use esta resposta.
— Stijn de Witt

8
Isso apara o rastreamento da pilha, da mesma forma que printStackTrace (). Todas as exceções na pilha são visíveis, mas para cada exceção a pilha pode ser cortada. Qualquer pessoa que exija o rastreamento inteiro deve considerar isso.
— Laila Agaev #

5
Acontece que isso é exatamente o que o método ExceptionUtils.getStackTrace () do apache faz. Quase ao pé da letra, na verdade.
— ticktock

6
@BrianAgnew, você não deveria fechar o StringWritere PrintWriter?
— Muhammad Gelbana

13
@BrianAgnew, obrigado pela resposta. Isso me fez curioso e aqui está o que eu encontrei: stackoverflow.com/questions/14542535/...
— Muhammad Gelbana

459

Isso deve funcionar:

StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();

69
Conciso no contexto java é sempre colunar. Isso printStackTracedeve apenas retornar a string, deixando a decisão de imprimí-la ou não para o usuário :) #
— 395

35
impressão printStackTrace no console é aceitável, mas pelo menos um getStackTrace devolvê-lo como uma String deve estar disponível por padrão
— Mateus Viccari

5
Que parte disso é concisa? Você precisa construir 2 objetos que existem apenas para colocar o rastreamento de pilha em uma sequência.
— ArtOfWarfare 14/11/16

7
@dmitry Um método chamado printXXX()deve imprimir XXX.
— Marquês de Lorne

2
@ Greg Na verdade, isso não foi nem sarcasmo, apenas exigiu uma leitura clara do que ele disse.
— Andrew

224

Se você está desenvolvendo para Android, uma maneira muito mais fácil é usar isso:

import android.util.Log;

String stackTrace = Log.getStackTraceString(exception); 

O formato é o mesmo que getStacktrace, por exemplo

09-24 16:09:07.042: I/System.out(4844): java.lang.NullPointerException
09-24 16:09:07.042: I/System.out(4844):   at com.temp.ttscancel.MainActivity.onCreate(MainActivity.java:43)
09-24 16:09:07.042: I/System.out(4844):   at android.app.Activity.performCreate(Activity.java:5248)
09-24 16:09:07.043: I/System.out(4844):   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2162)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread.access$800(ActivityThread.java:139)
09-24 16:09:07.043: I/System.out(4844):   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
09-24 16:09:07.043: I/System.out(4844):   at android.os.Handler.dispatchMessage(Handler.java:102)
09-24 16:09:07.043: I/System.out(4844):   at android.os.Looper.loop(Looper.java:136)
09-24 16:09:07.044: I/System.out(4844):   at android.app.ActivityThread.main(ActivityThread.java:5097)
09-24 16:09:07.044: I/System.out(4844):   at java.lang.reflect.Method.invokeNative(Native Method)
09-24 16:09:07.044: I/System.out(4844):   at java.lang.reflect.Method.invoke(Method.java:515)
09-24 16:09:07.044: I/System.out(4844):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
09-24 16:09:07.044: I/System.out(4844):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)

2
Obrigado. Nesse caso, uma data e uma tag não são gravadas em todas as linhas, como em printStackTrace ().
— CoolMind 01/06

1
Na verdade, o Log.getStackTraceString em seu núcleo usa o StringWriter e o Printwriter mencionados acima (de D. Wroblewski).
— MikeL

2
A maneira mais fácil de apenas imprimi-lo no log Android é: Log.e("TAG", "My message", new Throwable());
— Erick M. Sprengel


113

AVISO: Não inclui a causa (que geralmente é a parte útil!)

public String stackTraceToString(Throwable e) {
    StringBuilder sb = new StringBuilder();
    for (StackTraceElement element : e.getStackTrace()) {
        sb.append(element.toString());
        sb.append("\n");
    }
    return sb.toString();
}

1
Eu iria com uma extensão dessa abordagem se você deseja cortar o traço, por exemplo, passar um maxLines parâmetro e apenas acrescentar que muitas linhas ao traço
— Rich Seller

Os parênteses após e.getStackTrace estão ausentes. public static String stackTraceToString (Exceção e) {StringBuilder sb = new StringBuilder (); para (elemento StackTraceElement: e.getStackTrace ()) {sb.append (element.toString ()); sb.append ("<br />"); } retornar sb.toString (); }
— rlc 20/10/11

2
Não tenho certeza, mas acho que isso não imprimirá o rastreamento de pilha da exceção de causa raiz.
— Apoorv020

7
Faça o que fizer, não apare o rastro. Aconteceu comigo muitas e muitas vezes que observei um rastreamento de pilha nos logs do GlassFish que tinha as partes úteis cortadas.
— Cayhorstmann # 12/12

Use String.format("%n")ou algo semelhante em vez de "\n"fazer os lamers do DOS felizes.
— ceving

89

Para mim, a maneira mais limpa e fácil era:

import java.util.Arrays;
Arrays.toString(e.getStackTrace());

37
O código está limpo, mas a saída não está. Você precisa fazer um .replaceAll (",", "\ n") no final. No entanto, você perde o recuo proposto pelo printStackTrace.
— Fury

4
Isto é útil quando você log trace em uma única linha
— webjockey

28
public static String getStackTrace(Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    return sw.toString();
}

1
Olá, gostaria apenas de salientar que a seção de comentários da resposta citada indica que os objetos StringWritere PrintWriterdevem ser closed .... (ou acho que apenas as PrintWriternecessidades precisam ser fechadas, pois o fechamento deve fechar StringWritertambém)
— Eric Eric

8
Por inspirado você quer dizer copiado? Você só colocá-lo em um método ... Lendo as respostas aqui é como assistir a "Groundhog Day"
— Murmel

26

O código a seguir permite obter o stackTrace inteiro com um Stringformato, sem usar APIs como log4J ou mesmo java.util.Logger:

catch (Exception e) {
    StackTraceElement[] stack = e.getStackTrace();
    String exception = "";
    for (StackTraceElement s : stack) {
        exception = exception + s.toString() + "\n\t\t";
    }
    System.out.println(exception);
    // then you can send the exception string to a external file.
}

1
sim, mas é um pouco volumoso, você não acha? em qualquer estrutura de log projeto de tamanho razoável é uma obrigação então porque se preocupar
— mzzzzb

Este não está dando a mensagem de erro no começo. pode ser adicionado embora
— kommradHomer 13/11

Você pode querer usar um StringBuffer em vez de uma concatenação simples.
— precisa saber é o seguinte

Isso é útil quando você não tem permissão para registrar a mensagem por motivos de privacidade.
— 19m em A1m

Esteja ciente no entanto que esta solução não irá registrar as causas internas
— A1m

19

Aqui está uma versão que pode ser copiada diretamente no código:

import java.io.StringWriter; 
import java.io.PrintWriter;

//Two lines of code to get the exception into a StringWriter
StringWriter sw = new StringWriter();
new Throwable().printStackTrace(new PrintWriter(sw));

//And to actually print it
logger.info("Current stack trace is:\n" + sw.toString());

Ou, em um bloco de captura

} catch (Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    logger.info("Current stack trace is:\n" + sw.toString());
}

isso continuará além do escopo da função atual, ie. onde o Throwableé definido, certo?
— N611x007

16
Arrays.toString(thrown.getStackTrace())

É a maneira mais fácil de converter o resultado em String? Estou usando isso no meu programa para imprimir o rastreamento de pilha

LOGGER.log(Level.SEVERE, "Query Builder Issue Stack Trace : {0} ,Message : {1} objid {2}", new Object[]{Arrays.toString(e.getStackTrace()), e.getMessage(),objId});

Trabalhou para mim, nada parece ser aparado! Mais simples que outras respostas também sem qualquer biblioteca externa, ótima resposta!
— Shaung Cheng

16

Imprima o rastreamento de pilha em a PrintStreame converta-o em String:

// ...

catch (Exception e)
{
    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    e.printStackTrace(new PrintStream(out));
    String str = new String(out.toByteArray());

    System.out.println(str);
}

1
esta é a resposta mais direta
— DaSqy Stc

11

Rastreio da pilha de impressão em sequência

import java.io.PrintWriter;
import java.io.StringWriter;

public class StackTraceUtils {
    public static String stackTraceToString(StackTraceElement[] stackTrace) {
        StringWriter sw = new StringWriter();
        printStackTrace(stackTrace, new PrintWriter(sw));
        return sw.toString();
    }
    public static void printStackTrace(StackTraceElement[] stackTrace, PrintWriter pw) {
        for(StackTraceElement stackTraceEl : stackTrace) {
            pw.println(stackTraceEl);
        }
    }
}

É útil quando você deseja imprimir o rastreamento atual da pilha de encadeamentos sem criar uma instância de Throwable- mas observe que criar novos Throwablee obter rastreamento de empilhamento a partir daí é realmente mais rápido e mais barato do que chamar Thread.getStackTrace.


11

Kotlin

Estender a classe Throwable fornecerá a propriedade String error.stackTraceString:

val Throwable.stackTraceString: String
  get() {
    val sw = StringWriter()
    val pw = PrintWriter(sw)
    this.printStackTrace(pw)
    return sw.toString()
  }

10
private String getCurrentStackTraceString() {
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
    return Arrays.stream(stackTrace).map(StackTraceElement::toString)
            .collect(Collectors.joining("\n"));
}

1
Obrigado eddyrkokr! Funciona perfeito para todas as minhas classes. Acabei de adicioná-lo na classe TestNG base e ele coleta os stacktraces um por um em todos os meus testes!
— Krzysztof Walczewski

9

O sniping inteligente no primeiro conjunto de comentários foi muito divertido, mas realmente depende do que você está tentando fazer. Se você ainda não possui a biblioteca correta, três linhas de código (como na resposta de D. Wroblewski) são perfeitas. OTOH, se você já possui a biblioteca apache.commons (como a maioria dos grandes projetos), a resposta de Amar é mais curta. OK, você pode levar dez minutos para obter a biblioteca e instalá-la corretamente (menos de um, se você souber o que está fazendo). Mas o tempo está passando, então você pode não ter tempo de sobra. Jarek Przygódzki tinha uma ressalva interessante - "Se você não precisa de exceções aninhadas".

Mas e se eu não precisar dos rastreamentos de pilha completos, aninhados e tudo? Nesse caso, o segredo é usar o getFullStackTrace do apache.common (consulte http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html # getFullStackTrace% 28java.lang.Throwable% 29 )

Isso salvou meu bacon. Obrigado, Amar, pela dica!


9

Código do Apache Commons Lang 3.4 ( JavaDoc ):

public static String getStackTrace(final Throwable throwable) {
    final StringWriter sw = new StringWriter();
    final PrintWriter pw = new PrintWriter(sw, true);
    throwable.printStackTrace(pw);
    return sw.getBuffer().toString();
}

A diferença com as outras respostas é que ela usa autoFlush no PrintWriter.


8

Sem java.io.*isso pode ser feito assim.

String trace = e.toString() + "\n";                     

for (StackTraceElement e1 : e.getStackTrace()) {
    trace += "\t at " + e1.toString() + "\n";
}   

E então a tracevariável mantém seu rastreamento de pilha. A saída também mantém a causa inicial, a saída é idêntica àprintStackTrace()

Exemplo, printStackTrace()produz:

java.io.FileNotFoundException: / (Is a directory)
    at java.io.FileOutputStream.open0(Native Method)
    at java.io.FileOutputStream.open(FileOutputStream.java:270)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
    at Test.main(Test.java:9)

A traceString mantém, quando impressa emstdout

java.io.FileNotFoundException: / (Is a directory)
     at java.io.FileOutputStream.open0(Native Method)
     at java.io.FileOutputStream.open(FileOutputStream.java:270)
     at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
     at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
     at Test.main(Test.java:9)

5

Versão Scala

def stackTraceToString(e: Exception): String = {
  import java.io.PrintWriter
  val sw = new StringWriter()
  e.printStackTrace(new PrintWriter(sw))
  sw.toString
}

5

se você estiver usando o Java 8, tente isso

Arrays.stream(e.getStackTrace())
                .map(s->s.toString())
                .collect(Collectors.joining("\n"));

você pode encontrar o código para a getStackTrace()função fornecida por Throwable.java:

public StackTraceElement[] getStackTrace() {
    return getOurStackTrace().clone();
}

e StackTraceElement, para isso, fornece toString()como:

public String toString() {
    return getClassName() + "." + methodName +
        (isNativeMethod() ? "(Native Method)" :
         (fileName != null && lineNumber >= 0 ?
          "(" + fileName + ":" + lineNumber + ")" :
          (fileName != null ?  "("+fileName+")" : "(Unknown Source)")));
}

Então, junte-se ao StackTraceElement"\ n".


Esta solução não respeita o recuo da guia de rastreamento de pilha, caso contrário, funciona muito bem!
— Krizajb 28/0918

4

uma exapansão na resposta de Gala que também incluirá as causas da exceção:

private String extrapolateStackTrace(Exception ex) {
    Throwable e = ex;
    String trace = e.toString() + "\n";
    for (StackTraceElement e1 : e.getStackTrace()) {
        trace += "\t at " + e1.toString() + "\n";
    }
    while (e.getCause() != null) {
        e = e.getCause();
        trace += "Cause by: " + e.toString() + "\n";
        for (StackTraceElement e1 : e.getStackTrace()) {
            trace += "\t at " + e1.toString() + "\n";
        }
    }
    return trace;
}

4

A solução é converter o stackTrace da matriz em tipo de dados string . Veja o seguinte exemplo:

import java.util.Arrays;

try{

}catch(Exception ex){
    String stack = Arrays.toString(ex.getStackTrace());
    System.out.println("stack "+ stack);
}

4

Com a Java 8 Stream API, você pode fazer algo assim:

Stream
    .of(throwable.getStackTrace())
    .map(StackTraceElement::toString)
    .collect(Collectors.joining("\n"));

Ele pegará uma matriz de elementos de rastreio de pilha, os converterá em sequência e ingressará em sequência multilinha.


2
Esta solução é a remoção de mensagem e está ignorando todos os vestígios dos pais
— judovana

3

Meu oneliner para converter o rastreamento de pilha na sequência de várias linhas incluída:

Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))

Fácil de passar para o logger "como está".


Você obtém algo que difere printStackTrace()daqui. Você perderá: 1) Exceção que foi lançada; 2) Causas e seu rastreamento de pilha
— valijon

A diferença é bastante esperada, uma vez que a conversão do printStackTrace()nunca fazia parte da questão.
— Andrey Lebedenko

2

Se você não quiser usar uma biblioteca externa e não estiver desenvolvendo para o Android , poderá criar um método de 'extensão' como este:

public static String getStackTraceString(Throwable e) {
    return getStackTraceString(e, "");
}

private static String getStackTraceString(Throwable e, String indent) {
    StringBuilder sb = new StringBuilder();
    sb.append(e.toString());
    sb.append("\n");

    StackTraceElement[] stack = e.getStackTrace();
    if (stack != null) {
        for (StackTraceElement stackTraceElement : stack) {
            sb.append(indent);
            sb.append("\tat ");
            sb.append(stackTraceElement.toString());
            sb.append("\n");
        }
    }

    Throwable[] suppressedExceptions = e.getSuppressed();
    // Print suppressed exceptions indented one level deeper.
    if (suppressedExceptions != null) {
        for (Throwable throwable : suppressedExceptions) {
            sb.append(indent);
            sb.append("\tSuppressed: ");
            sb.append(getStackTraceString(throwable, indent + "\t"));
        }
    }

    Throwable cause = e.getCause();
    if (cause != null) {
        sb.append(indent);
        sb.append("Caused by: ");
        sb.append(getStackTraceString(cause, indent));
    }

    return sb.toString();
}

2

Pergunta antiga, mas gostaria de adicionar um caso especial em que você não deseja imprimir toda a pilha , removendo algumas partes nas quais não está realmente interessado, excluindo determinadas classes ou pacotes.

Em vez de PrintWriterusar um SelectivePrintWriter:

// This filters out this package and up.
String packageNameToFilter = "org.springframework";

StringWriter sw = new StringWriter();
PrintWriter pw = new SelectivePrintWriter(sw, packageNameToFilter);
e.printStackTrace(pw);
String sStackTrace = sw.toString(); 
System.out.println(sStackTrace);

Onde a SelectivePrintWriterclasse é dada por:

public class SelectivePrintWriter extends PrintWriter {
    private boolean on = true;
    private static final String AT = "\tat";
    private String internal;

    public SelectivePrintWriter(Writer out, String packageOrClassName) {
        super(out);
        internal = "\tat " + packageOrClassName;
    }

    public void println(Object obj) {
        if (obj instanceof String) {
            String txt = (String) obj;
            if (!txt.startsWith(AT)) on = true;
            else if (txt.startsWith(internal)) on = false;
            if (on) super.println(txt);
        } else {
            super.println(obj);
        }
    }
}

Observe que esta classe pode ser facilmente adaptada para filtrar por Regex containsou outros critérios. Observe também que depende dos Throwabledetalhes da implementação (provavelmente não será alterado, mas ainda).


1
Sim, isso funciona bem e é realmente uma ideia bastante útil.
— precisa saber é o seguinte

2
 import java.io.PrintWriter;
import java.io.StringWriter;

public class PrintStackTrace {

    public static void main(String[] args) {

        try {
            int division = 0 / 0;
        } catch (ArithmeticException e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            String exceptionAsString = sw.toString();
            System.out.println(exceptionAsString);
        }
    }
}

Quando você executa o programa, a saída será algo semelhante:

java.lang.ArithmeticException: / by zero
at PrintStackTrace.main(PrintStackTrace.java:9)

1

Eu me pergunto por que ninguém mencionou ExceptionUtils.getStackFrames(exception)

Para mim, é a maneira mais conveniente de despejar o rastreamento de pilha com todas as suas causas até o fim:

String.join("\n", ExceptionUtils.getStackFrames(exception));

0

Aviso: Este tópico pode ser um pouco estranho, mas tudo bem ...;)

Não sei qual era o motivo original dos pôsteres para querer que o rastreamento da pilha fosse string em primeiro lugar. Quando o rastreamento da pilha deve terminar em um SLF4J / Logback LOG, mas nenhuma exceção foi ou deve ser lançada, eis o que eu faço:

public void remove(List<String> ids) {
    if(ids == null || ids.isEmpty()) {
        LOG.warn(
            "An empty list (or null) was passed to {}.remove(List). " +
            "Clearly, this call is unneccessary, the caller should " + 
            "avoid making it. A stacktrace follows.", 
            getClass().getName(),
            new Throwable ("Stacktrace")
        );

        return;
    }

    // actual work, remove stuff
}

Gosto porque não requer uma biblioteca externa (exceto o seu back-end de log, que estará disponível na maioria das vezes, é claro).


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.