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

1708

如何最简单地将Throwable.getStackTrace()的结果转换为描述堆栈跟踪的字符串?


8
因为jqno的回答实际上使用了你在问题中指定的Throwable.getStackTrace()方法,而Brian没有使用它。他改用了Throwable.printStackTrace()方法。 - Stijn de Witt
10
几乎每个 Java 项目都应该包含 Apache commons-lang。它包含了许多实现极为常见的开发需求的方便方法。 - Russell Silva
20
这三行代码几乎肯定需要从您调用它们的位置中分离出来。由于您不知道将它们放在哪里,因此它们将与所有其他有用的片段一起放在您的实用工具箱中。瞧!你刚刚重新发明了guava / commons-lang /等等……只是没有那么好。相反,导入一个明智的实用程序库,并节省重新发明轮子。真正的新手标志是认为您可以比库编写者做得更好。 - Andrew Spencer
9
  1. Guava库提供了Throwables.getStackTraceAsString(e)方法。
  2. Apache Commons Lang库提供了ExceptionUtils.getFullStackTrace方法。
  3. 我们可以编写自己的自定义方法。
- user2323036
16
我不明白为什么你们要这样努力地抨击StijndeWitt想通过一些小片段来实现这个目标。编写一个小型实用程序并没有什么危险性(我不认为他是“绝对自大,哦不!他认为自己比Apache优秀!”)。有很多项目,特别是在非Java JVM语言中,真的不想包含Guava或Commons Lang只为了记录堆栈跟踪。我编写Scala和Clojure库,肯定不会为了一个方法而将Apache Commons Lang作为传递性依赖项。 - jm0
显示剩余7条评论
32个回答

2366

使用 Throwable.printStackTrace(PrintWriter pw) 将堆栈跟踪发送到适当的 writer。

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

9
这确实会修剪堆栈跟踪,就像printStackTrace()一样。堆栈中的所有异常都是可见的,但对于每个异常,堆栈可能会被修剪。需要完整跟踪的人应该考虑这一点。 - Laila Agaev
9
事实证明,这正是 Apache 的 ExceptionUtils.getStackTrace() 方法所做的事情。实际上,几乎完全一致。 - ticktock
7
@BrianAgnew,你不应该关闭StringWriterPrintWriter吗? - Muhammad Gelbana
6
@MuhammadGelbana - 是的。上面的内容是为了方便起见而显示的。我怀疑如果你不这样做,不会引起问题,但出于良好实践的考虑,我建议这样做。 - Brian Agnew
17
@BrianAgnew,谢谢回复。这激起了我的好奇心,以下是我发现的内容:https://dev59.com/K2Uq5IYBdhLWcg3wYvd6 - Muhammad Gelbana
显示剩余2条评论

1138

89
@Stijn - 公平来说(我在下面写了当前得票最高的答案),值得看一看commons-lang,因为它提供了更多功能。 - Brian Agnew
55
Commons Lang 相当常见。它已经存在于我在工作中的大多数项目中。 - WhyNotHugo
17
@Hugo谢谢,我本来想使用StringWriter来避免添加新的库——结果它已经是我另外三个依赖项的一个依赖。所以对于其他人,请检查您是否已经有它了。 - Nathanial
35
按照你的逻辑,你永远不会使用这样的库,是吗?除非你已经在使用它,否则你不会使用它吗? - Brian Agnew
19
请注意,该程序包已更改,类现在位于:org.apache.commons.lang3.exception.ExceptionUtils - schmmd
这种方法对我来说非常有用,只需将整个错误(消息+原因+堆栈跟踪)记录到数据库中以供进一步调试:ExceptionUtils.getFullStackTrace(e) - takanuva15

503

这应该可以工作:

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

85
在Java上下文中,“简洁”这个词总是很有趣。printStackTrace方法应该只返回字符串,让用户决定是否打印它,这样会更好 :) - dmitry
52
在控制台中打印printStackTrace是可以接受的,但默认情况下至少应该提供一个将其作为字符串返回的getStackTrace方法。 - Mateus Viccari
7
哪部分是简洁的?你需要构建两个对象,其存在的唯一目的是将堆栈跟踪转换为字符串。 - ArtOfWarfare
9
一个名为printXXX()的方法应该打印XXX。 - user207421
2
@Greg 实际上那甚至不是讽刺,只需要对他所说的内容进行简单的阅读就可以了。 - Andrew
显示剩余3条评论

267

如果你正在为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)

如果cause链中的任何throwable是UnknownHostException,则返回一个空字符串。请参见https://developer.android.com/reference/android/util/Log。 - Pavel Chuchuva

154

120

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

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

108

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

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

43
代码很干净,但输出不清晰。你需要在最后加上 .replaceAll(", ", "\n")。然而这会丢失 printStackTrace 建议的缩进。 - fury
6
在单行记录跟踪时,这将非常有用。 - webjockey

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

1
嗨,我只想指出所引用的答案的评论部分指出StringWriterPrintWriter对象应该被关闭...(或者只需关闭PrintWriter,因为关闭它应该也会关闭StringWriter)。 - Eric

27
以下代码可以让您以字符串格式获取整个堆栈跟踪,而无需使用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.
}

24

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

// ...

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

    System.out.println(str);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接