How can I convert a stack trace to a string?
将
使用
1 2 3 4 5 6 7 8 9 10 | 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); |
可以使用以下方法将
这应该有效:
1 2 3 | StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); String exceptionAsString = sw.toString(); |
如果您正在为Android开发,一个更简单的方法是使用它:
1 2 3 |
格式与GetStackTrace相同,例如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 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)
番石榴的
如果你有实际的
例子:
1 |
警告:不包括原因(通常是有用的位!)
1 2 3 4 5 6 7 8 9 |
对我来说,最干净和最简单的方法是:
1 2 |
1 2 3 4 5 | public static String getStackTrace(Throwable t) { StringWriter sw = new StringWriter(); t.printStackTrace(new PrintWriter(sw)); return sw.toString(); } |
以下代码允许您使用
1 2 3 4 5 6 7 8 9 10 |
下面是一个可直接复制到代码中的版本:
1 2 3 4 5 6 7 8 9 10 | 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: " + sw.toString()); |
或者,在接球区
1 2 3 4 5 6 | } catch (Throwable t) { StringWriter sw = new StringWriter(); t.printStackTrace(new PrintWriter(sw)); logger.info("Current stack trace is: " + sw.toString()); } |
将堆栈跟踪打印到字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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); } } } |
如果您想打印当前线程堆栈跟踪而不创建
将stacktrace打印到打印流,然后将其转换为字符串
1 2 3 4 5 6 7 8 9 10 | // ... catch (Exception e) { ByteArrayOutputStream out = new ByteArrayOutputStream(); e.printStackTrace(new PrintStream(out)); String str = new String(out.toByteArray()); System.out.println(str); } |
1 2 3 4 5 6 |
1 |
是将结果转换为字符串的最简单方法我在程序中使用这个来打印堆栈跟踪
1 |
来自ApacheCommonsLang3.4(JavaDoc)的代码:
1 2 3 4 5 6 | 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(); } |
与其他答案不同的是,它在
第一组评论中巧妙的剪接非常有趣,但这真的取决于你想做什么。如果您还没有正确的库,那么3行代码(如D.Wroblewski的答案)是完美的。Otoh,如果您已经有了apache.commons库(大多数大型项目都有),那么Amar的答案就更短了。好的,您可能需要10分钟才能找到库并正确安装它(如果您知道自己在做什么,则不到一分钟)。但是时钟在滴答滴答地响,所以你可能没有时间休息。JarekPrzyg_dzki有一个有趣的警告——"如果不需要嵌套异常的话"。
但是如果我确实需要完整的堆栈跟踪,嵌套的和全部的呢?在这种情况下,秘密是使用apache.common的getfullstacktrace(请参见http://common s.apache.org/proper/common s lang/javadocs/api-2.6/org/apache/common s/lang/exception/exceptionutils.html getfullstacktrace%28java.lang.throwable%29)
它救了我的培根。谢谢,阿马尔,给我提示!
科特林
扩展throwable类将为您提供字符串属性
1 2 3 4 5 6 7 | val Throwable.stackTraceString: String get() { val sw = StringWriter() val pw = PrintWriter(sw) this.printStackTrace(pw) return sw.toString() } |
如果没有
1 2 3 4 5 6 7 | String trace = e.toString() +" "; for (StackTraceElement e1 : e.getStackTrace()) { trace +="\t at" + e1.toString() +" "; } |
然后,
例如,
1 2 3 4 5 6 | 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) |
当打印到
1 2 3 4 5 6 | 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) |
如果您正在使用Java 8,请尝试
1 2 3 4 |
您可以找到throwable.java提供的getstacktrace()函数的代码,如下所示:
1 2 3 | public StackTraceElement[] getStackTrace() { return getOurStackTrace().clone(); } |
对于stacktraceelement,它提供程序将字符串设置为:
1 2 3 4 5 6 7 | public String toString() { return getClassName() +"." + methodName + (isNativeMethod() ?"(Native Method)" : (fileName != null && lineNumber >= 0 ? "(" + fileName +":" + lineNumber +")" : (fileName != null ? "("+fileName+")" :"(Unknown Source)"))); } |
所以只需将stacktraceelement与
对Gala的回答的一个严格审查,也将包括例外的原因:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | private String extrapolateStackTrace(Exception ex) { Throwable e = ex; String trace = e.toString() +" "; for (StackTraceElement e1 : e.getStackTrace()) { trace +="\t at" + e1.toString() +" "; } while (e.getCause() != null) { e = e.getCause(); trace +="Cause by:" + e.toString() +" "; for (StackTraceElement e1 : e.getStackTrace()) { trace +="\t at" + e1.toString() +" "; } } return trace; } |
我的OneLiner将堆栈跟踪转换为封闭的多行字符串:
1 2 | Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining(" ","[","]")) |
很容易"照原样"传递给记录器。
解决方案是将数组的stacktrace转换为字符串数据类型。请参见以下示例:
1 2 3 4 5 6 7 8 |
如果您不想使用外部库,而不是为Android开发,您可以创建一个"扩展"方法,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 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(" "); StackTraceElement[] stack = e.getStackTrace(); if (stack != null) { for (StackTraceElement stackTraceElement : stack) { sb.append(indent); sb.append("\tat"); sb.append(stackTraceElement.toString()); sb.append(" "); } } 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(); } |
旧问题,但我想添加一个特殊情况,您不想打印所有堆栈,通过删除一些您实际上不感兴趣的部分,不包括某些类或包。
用
1 2 3 4 5 6 7 8 | // 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); |
其中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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); } } } |
请注意,这一类可以很容易地通过regex、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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); } } } |
运行程序时,输出将类似:
1 2 |
斯卡拉版本
1 2 3 4 5 6 | def stackTraceToString(e: Exception): String = { import java.io.PrintWriter val sw = new StringWriter() e.printStackTrace(new PrintWriter(sw)) sw.toString } |
警告:这可能有点离题,但哦,好吧…;)
我不知道最初的海报为什么要把堆栈跟踪作为字符串放在首位。当堆栈跟踪应该在slf4j/logback日志中结束时,但没有异常发生或应该被抛出,我要做的是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 } |
我喜欢它,因为它不需要外部库(除了您的日志记录后端,当然,大多数情况下,它都会在适当的位置)。
几乎没有选择
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
使用google guava lib
org.apache.commons.lang.exception.exceptionutils.getstacktrace(可丢弃)
不久前我为这个写了一些方法,所以我想为什么不把我的两分钱扔到这个上面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | /** @param stackTraceElements The elements to convert * @return The resulting string */ public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements) { return stackTraceElementsToStr(stackTraceElements," "); } /** @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," "); } /** @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," "); } /** @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," "); } /** @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; } |
例子:
1 2 3 4 5 6 7 | try(InputStream in = new FileInputStream(file)) { ... } catch(IOException e) { String exceptionToString = throwableToStr(e); someLoggingUtility.println(exceptionToString); ... } |
印刷品:
1 2 3 4 5 | 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) |