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


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


1215
2017-07-19 11:31


起源


因为jqno的答案实际上使用了你在问题中指定的Throwable.getStackTrace()方法,而Brian没有。他使用Throwable.printStackTrace()代替。 - Stijn de Witt
几乎每个Java项目都应该包含Apache commons-lang。它包括许多实现极为共同的开发需求的便捷方法。 - Russell Silva
@StijndeWitt这三行代码几乎肯定需要从你调用它们的地方中分解出来。由于您不知道将它们放在何处,因此它们将使用所有其他有用的片段进入实用工具箱。答对了!你刚刚重新发明番石榴/公共厕所/其他......只是不太好。相反,导入一个合理的实用程序库,并保存重新发明轮子。 新手的真实迹象是认为你可以比图书馆作家做得更好。 - Andrew Spencer
1. Guava有 - Throwables.getStackTraceAsString(e)2。Apache Commons Lang - ExceptionUtils.getFullStackTrace 3.编写我们自己的自定义方法 - user2323036
@AndrewSpencer我不明白为什么你们这么努力地打击StijndeWitt想要通过一些小片段来实现这个目标。写一个小实用方法真的没什么危险(我不认为它是“SHERER ARROGANCE哦nooooo !!他认为他比Apache好!”)。有很多项目,特别是在非Java JVM语言中,实际上不希望包含Guava或Commons Lang来记录堆栈跟踪。我编写了Scala和Clojure库,当然不会仅仅针对一种方法使Apache Commons Lang成为传递依赖。 - jm0


答案:


可以使用以下方法转换 Exception 堆栈跟踪到 String。这个课程可用 Apache commons-lang是最常见的依赖库,有许多流行的开源

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


847
2018-01-21 14:39



一行需要外部库... - Stijn de Witt
@Stijn - 公平(我在下面写了当前最高的投票答案)值得看看commons-lang以获得更多功能 - Brian Agnew
@StijndeWitt Commons Lang非常普遍。它已经出现在我工作的大部分项目/项目中。 - WhyNotHugo
@Hugo谢谢,打算使用StringWriter来避免添加一个新库 - 结果证明它已经是我的3个依赖项的依赖项。所以对其他人来说,检查一下你是否已经拥有它。 - Nathanial
@MartinAsenov - 按照你的逻辑你永远不会使用这样的库,对吗?除非你已经在使用它,否则你不会使用它? - Brian Agnew


使用 Throwable.printStackTrace(PrintWriter pw) 将堆栈跟踪发送给适当的编写器。

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

1937
2017-07-19 11:36



如果您不喜欢将外部库包含在这样小而简单的内容中,请使用此答案。 - Stijn de Witt
这会修改堆栈跟踪,与printStackTrace()相同。堆栈中的所有异常都是可见的,但是对于每个异常,可以修剪堆栈。任何需要整个跟踪的人都应该考虑这一点 - Laila Agaev
事实证明,这正是apache的ExceptionUtils.getStackTrace()方法所做的。实际上几乎到了这封信。 - ticktock
@BrianAgnew,你不应该关闭 StringWriter 和 PrintWriter ? - Muhammad Gelbana
@BrianAgnew,谢谢你的回复。它让我好奇,这就是我发现的: stackoverflow.com/questions/14542535/... - Muhammad Gelbana


这应该工作:

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

395
2017-07-19 11:41



简洁的java上下文总是很有趣。那 printStackTrace 应该只返回字符串,决定是否打印到用户:) - dmitry
可以接受在控制台中打印printStackTrace,但至少应该将一个getStackTrace作为String返回 - Mateus Viccari
这部分内容简洁明了?除了将堆栈跟踪放入字符串之外,您必须构造2个除了目的之外的对象。 - ArtOfWarfare
@ArtOfWarfare他显然是在讽刺。 - Greg
@dmitry一个叫做的方法 printXXX() 应该打印XXX。 - user207421


如果您正在为Android开发,更简单的方法是使用它:

import android.util.Log;

String stackTrace = Log.getStackTraceString(exception); 

格式与getStacktrace相同,例如

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)

182
2018-04-30 07:29



谢谢。在这种情况下,日期和标记不会像printStackTrace()中那样写入每一行。 - CoolMind
实际上其核心中的Log.getStackTraceString使用上面提到的(D. Wroblewski的)StringWriter和Printwriter。 - MikeL
在Android日志中打印它的最简单方法是: Log.e("TAG", "My message", new Throwable()); - Erick M. Sprengel


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

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

106
2017-07-19 11:38



如果你想修剪迹线,我可以使用这种方法的扩展,例如:传递一个maxLines参数,只将很多行添加到跟踪中 - Rich Seller
缺少e.getStackTrace之后的括号。 public static String stackTraceToString(Exception e){StringBuilder sb = new StringBuilder(); for(StackTraceElement element:e.getStackTrace()){sb.append(element.toString()); sb.append(“<br />”); } return sb.toString(); } - rlc
不确定,但我认为这不会打印根本原因异常的堆栈跟踪。 - apoorv020
无论你做什么,都不要修剪痕迹。很多次,我在GlassFish日志中查看了堆栈跟踪,其中有用的部分被修剪掉了。 - cayhorstmann
使用 String.format("%n") 或类似的东西而不是 "\n" 让DOS更快乐。 - ceving


番石榴的 Throwables 类

如果你有实际的 Throwable 例如, 谷歌番石榴 提供 Throwables.getStackTraceAsString()

例:

String s = Throwables.getStackTraceAsString ( myException ) ;

96
2018-02-15 10:20





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

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

80
2017-12-15 14:37



代码很干净,但输出不是。你最后必须做一个.replaceAll(“,”,“\ n”)。但是你丢失了printStackTrace建议的缩进。 - fury
当您在一行中记录跟踪时,这非常有用 - webjockey