如何将堆栈跟踪转换为字符串?

Throwable.getStackTrace()的结果转换为描述堆栈跟踪的字符串的最简单方法是什么?

714642 次浏览

使用#0将堆栈跟踪发送到适当的写入器。

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 stringSystem.out.println(sStackTrace);

警告:不包括原因(这通常是有用的位!)

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

这应该工作:

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

可以使用以下方法将Exception堆栈跟踪转换为String。此类在Apache Commons-lang是最常见的依赖库,有许多流行的开源中可用

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

打印堆栈跟踪到字符串

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

当您想在不创建Throwable实例的情况下打印当前线程堆栈跟踪时,它很有用-但请注意,创建新的Throwable并从那里获取堆栈跟踪实际上比调用Thread.getStackTrace更快,更便宜。

对我来说,最简单、最简单的方法是:

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

番石榴的#0

如果你有实际的Throwable实例,googleguava提供#1

示例:

String s = Throwables.getStackTraceAsString ( myException ) ;

如果你正在为Android开发,一个更简单的方法是使用:

import android.util.Log;
String stackTrace = Log.getStackTraceString(exception);

格式与getStackTrace相同,例如。

09-24 16:09:07.042: I/System.out(4844): java.lang.NullPointerException09-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)

这是一个可直接复制到代码中的版本:

import java.io.StringWriter;import java.io.PrintWriter;
//Two lines of code to get the exception into a StringWriterStringWriter sw = new StringWriter();new Throwable().printStackTrace(new PrintWriter(sw));
//And to actually print itlogger.info("Current stack trace is:\n" + sw.toString());

或者,在捕获块中

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

以下代码允许您使用String格式获取整个stackTrace,而无需使用log4J甚至java.util.Logger等API:

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.}
public static String getStackTrace(Throwable t) {StringWriter sw = new StringWriter();t.printStackTrace(new PrintWriter(sw));return sw.toString();}

第一组评论中巧妙的狙击非常有趣,但这真的取决于你想做什么。如果您还没有正确的库,那么3行代码(如D. Wroblewski的回答)是完美的。OTOH,如果你已经有了apache.commons库(就像大多数大型项目一样),那么Amar的答案就更短了。好的,你可能需要十分钟的时间来获得库并正确安装它(如果你知道你在做什么,不到一分钟)。但是时间紧迫,所以你可能没有多余的时间。Jarek Przygódzki有一个有趣的警告——“如果你不需要嵌套异常”。

但是如果我需要全栈跟踪,嵌套和所有呢?在这种情况下,秘诀是使用apache.common的getFullStackTrace(参见http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html#getFullStackTrace%28java.lang.Throwable%29

它救了我的培根。谢谢,阿马尔,提示!

如果您不想使用外部库并且您没有开发for android,您可以像这样创建扩展方法

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

代码来自Apache Commons Lang 3.4javadoc):

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

与其他答案的不同之处在于PrintWriter上的它使用autoFlush

如果没有java.io.*,可以这样做。

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

然后trace变量保存您的堆栈跟踪。输出也保存初始原因,输出与printStackTrace()相同

例如,printStackTrace()产生:

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)

当打印到stdout时,trace字符串保持不变

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)

对Gala的回答进行了解释,其中还包括例外的原因:

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

静态编程语言>=1.4

Throwable上使用内置函数#0

静态编程语言<1.4

扩展Throwable类将为您提供String属性error.stackTraceString

val Throwable.stackTraceString: Stringget() {val sw = StringWriter()val pw = PrintWriter(sw)this.printStackTrace(pw)return sw.toString()}
private String getCurrentStackTraceString() {StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();return Arrays.stream(stackTrace).map(StackTraceElement::toString).collect(Collectors.joining("\n"));}

老问题,但我只想添加你不想打印所有的堆栈的特殊情况,通过删除一些你实际上不感兴趣的部分,排除某些类或包。

而不是PrintWriter使用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);

其中SelectivePrintWriter类由以下人员给出:

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

请注意,这个类可以很容易地适应正则表达式、contains或其他条件。还要注意,它取决于Throwable的实现细节(不太可能改变,但仍然)。

警告:这可能有点偏离主题,但哦,好吧…;)

我不知道最初的海报原因是为了首先将堆栈跟踪作为字符串。当堆栈跟踪应该最终出现在SLF4J/Logback日志中时,但没有或应该抛出异常,这就是我所做的:

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}

我喜欢它,因为它不需要外部库(除了您的日志后端,当然大部分时间都会到位)。

Arrays.toString(thrown.getStackTrace())

是将结果转换为String的最简单方法我在我的程序中使用它来打印堆栈跟踪

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

我的oneliner将堆栈跟踪转换为封闭的多行字符串:

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

易于传递给记录器“按原样”。

解决方案是将数组的stackTrace转换为字符串数据类型。请参阅以下示例:

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

如果你使用Java8,试试这个

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

您可以找到Throwable.java提供的getStackTrace()函数的代码:

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

对于StackTraceElement,它提供toString()如下:

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

所以只需将StackTraceElement与“\n”连接起来。

将堆栈跟踪打印为PrintStream,然后将其转换为String

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

选择不多

  1. StringWriter sw=new StringWriter();

    StringWriter sw=new StringWriter();e.printStackTrace(新的PrintWriter(sw));sw.toString();

  2. 使用Google Guava libString stackTrace=Throwables.getStackTraceAsString(myException);

  3. org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(可抛出的)

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

当您运行程序时,输出将类似于:

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

我之前为此写了一些方法,所以我想为什么不投入我的两分钱。

/** @param stackTraceElements The elements to convert* @return The resulting string */public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements) {return stackTraceElementsToStr(stackTraceElements, "\n");}
/** @param stackTraceElements The elements to convert* @param lineSeparator The line separator to use* @return The resulting string */public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements, String lineSeparator) {return stackTraceElementsToStr(stackTraceElements, lineSeparator, "");}
/** @param stackTraceElements The elements to convert* @param lineSeparator The line separator to use* @param padding The string to be used at the start of each line* @return The resulting string */public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements, String lineSeparator, String padding) {String str = "";if(stackTraceElements != null) {for(StackTraceElement stackTrace : stackTraceElements) {str += padding + (!stackTrace.toString().startsWith("Caused By") ? "\tat " : "") + stackTrace.toString() + lineSeparator;}}return str;}
/** @param stackTraceElements The elements to convert* @return The resulting string */public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements) {return stackTraceCausedByElementsOnlyToStr(stackTraceElements, "\n");}
/** @param stackTraceElements The elements to convert* @param lineSeparator The line separator to use* @return The resulting string */public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements, String lineSeparator) {return stackTraceCausedByElementsOnlyToStr(stackTraceElements, lineSeparator, "");}
/** @param stackTraceElements The elements to convert* @param lineSeparator The line separator to use* @param padding The string to be used at the start of each line* @return The resulting string */public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements, String lineSeparator, String padding) {String str = "";if(stackTraceElements != null) {for(StackTraceElement stackTrace : stackTraceElements) {str += (!stackTrace.toString().startsWith("Caused By") ? "" : padding + stackTrace.toString() + lineSeparator);}}return str;}
/** @param e The {@link Throwable} to convert* @return The resulting String */public static final String throwableToStrNoStackTraces(Throwable e) {return throwableToStrNoStackTraces(e, "\n");}
/** @param e The {@link Throwable} to convert* @param lineSeparator The line separator to use* @return The resulting String */public static final String throwableToStrNoStackTraces(Throwable e, String lineSeparator) {return throwableToStrNoStackTraces(e, lineSeparator, "");}
/** @param e The {@link Throwable} to convert* @param lineSeparator The line separator to use* @param padding The string to be used at the start of each line* @return The resulting String */public static final String throwableToStrNoStackTraces(Throwable e, String lineSeparator, String padding) {if(e == null) {return "null";}String str = e.getClass().getName() + ": ";if((e.getMessage() != null) && !e.getMessage().isEmpty()) {str += e.getMessage() + lineSeparator;} else {str += lineSeparator;}str += padding + stackTraceCausedByElementsOnlyToStr(e.getStackTrace(), lineSeparator, padding);for(Throwable suppressed : e.getSuppressed()) {str += padding + throwableToStrNoStackTraces(suppressed, lineSeparator, padding + "\t");}Throwable cause = e.getCause();while(cause != null) {str += padding + "Caused by:" + lineSeparator + throwableToStrNoStackTraces(e.getCause(), lineSeparator, padding);cause = cause.getCause();}return str;}
/** @param e The {@link Throwable} to convert* @return The resulting String */public static final String throwableToStr(Throwable e) {return throwableToStr(e, "\n");}
/** @param e The {@link Throwable} to convert* @param lineSeparator The line separator to use* @return The resulting String */public static final String throwableToStr(Throwable e, String lineSeparator) {return throwableToStr(e, lineSeparator, "");}
/** @param e The {@link Throwable} to convert* @param lineSeparator The line separator to use* @param padding The string to be used at the start of each line* @return The resulting String */public static final String throwableToStr(Throwable e, String lineSeparator, String padding) {if(e == null) {return "null";}String str = padding + e.getClass().getName() + ": ";if((e.getMessage() != null) && !e.getMessage().isEmpty()) {str += e.getMessage() + lineSeparator;} else {str += lineSeparator;}str += padding + stackTraceElementsToStr(e.getStackTrace(), lineSeparator, padding);for(Throwable suppressed : e.getSuppressed()) {str += padding + "Suppressed: " + throwableToStr(suppressed, lineSeparator, padding + "\t");}Throwable cause = e.getCause();while(cause != null) {str += padding + "Caused by:" + lineSeparator + throwableToStr(e.getCause(), lineSeparator, padding);cause = cause.getCause();}return str;}

示例:

try(InputStream in = new FileInputStream(file)) {...} catch(IOException e) {String exceptionToString = throwableToStr(e);someLoggingUtility.println(exceptionToString);...}

打印:

java.io.FileNotFoundException: C:\test.txt (The system cannot find the file specified)at java.io.FileInputStream.open0(Native Method)at java.io.FileInputStream.open(Unknown Source)at java.io.FileInputStream.<init>(Unknown Source)at com.gmail.br45entei.Example.main(Example.java:32)

scala版本

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

使用Java8流式接口,您可以这样做:

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

它将获取堆栈跟踪元素数组,将它们转换为字符串并连接到多行字符串。

我想知道为什么没有人提到ExceptionUtils.getStackFrames(exception)

对我来说,这是将所有原因转储到最后的最方便的方法:

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