Qual é a maneira mais fácil de converter o resultado Throwable.getStackTrace()
em uma sequência que representa o rastreamento de pilha?
Qual é a maneira mais fácil de converter o resultado Throwable.getStackTrace()
em uma sequência que representa o rastreamento de pilha?
Respostas:
Pode-se usar o seguinte método para converter um Exception
rastreamento 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)
org.apache.commons.lang3.exception.ExceptionUtils
.
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);
StringWriter
e PrintWriter
?
Isso deve funcionar:
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
printStackTrace
deve apenas retornar a string, deixando a decisão de imprimí-la ou não para o usuário :) #
printXXX()
deve imprimir XXX.
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)
Log.e("TAG", "My message", new Throwable());
Throwables
Classe da goiabaSe você possui a Throwable
instância real , o Google Guava fornece Throwables.getStackTraceAsString()
.
Exemplo:
String s = Throwables.getStackTraceAsString ( myException ) ;
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();
}
String.format("%n")
ou algo semelhante em vez de "\n"
fazer os lamers do DOS felizes.
Para mim, a maneira mais limpa e fácil era:
import java.util.Arrays;
Arrays.toString(e.getStackTrace());
public static String getStackTrace(Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
return sw.toString();
}
StringWriter
e PrintWriter
devem ser close
d .... (ou acho que apenas as PrintWriter
necessidades precisam ser fechadas, pois o fechamento deve fechar StringWriter
também)
O código a seguir permite obter o stackTrace inteiro com um String
formato, 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.
}
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());
}
Throwable
é definido, certo?
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});
Imprima o rastreamento de pilha em a PrintStream
e 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);
}
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 Throwable
e obter rastreamento de empilhamento a partir daí é realmente mais rápido e mais barato do que chamar Thread.getStackTrace
.
private String getCurrentStackTraceString() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
return Arrays.stream(stackTrace).map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
}
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!
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
.
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 trace
variá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 trace
String 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)
Versão Scala
def stackTraceToString(e: Exception): String = {
import java.io.PrintWriter
val sw = new StringWriter()
e.printStackTrace(new PrintWriter(sw))
sw.toString
}
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".
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;
}
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);
}
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.
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á".
printStackTrace()
daqui. Você perderá: 1) Exceção que foi lançada; 2) Causas e seu rastreamento de pilha
printStackTrace()
nunca fazia parte da questão.
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();
}
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 PrintWriter
usar 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 SelectivePrintWriter
classe é 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 contains
ou outros critérios. Observe também que depende dos Throwable
detalhes da implementação (provavelmente não será alterado, mas ainda).
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)
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));
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).
Poucas opções
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
Usando o Google Guava lib
String stackTrace = Throwables.getStackTraceAsString ( myException ) ;
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace (Throwable)