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




13 Answers

使用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);
java stack-trace tostring

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




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






以下代码允许您以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.
}



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

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

或者,在一个catch块

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



没有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)

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

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)



科特林

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

val Throwable.stackTraceString: String
  get() {
    val sw = StringWriter()
    val pw = PrintWriter(sw)
    this.printStackTrace(pw)
    return sw.toString()
  }



第一组评论中的聪明狙击非常有趣,但这取决于你想要做什么。 如果你还没有正确的库,那么3行代码(如D. Wroblewski的答案)是完美的。 OTOH,如果你已经有了apache.commons库(就像大多数大项目一样),那么Amar的答案就更短了。 好吧,可能需要10分钟才能获得库并正确安装(如果您知道自己在做什么,可以少于1分钟)。 但时钟在滴答滴答,所以你可能没有时间空闲。 JarekPrzygó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

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




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



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

而不是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 LOG中结束时,但是这里没有或者应该抛出异常:

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
}

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




解决方案是将数组的stackTrace转换为字符串数据类型。 看下面的例子:

import java.util.Arrays;

try{

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



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

// ...

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



Related