提问



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

最佳参考


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


org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable) [60]

其它参考1


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


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

其它参考2


这应该工作:


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

其它参考3


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


其它参考4


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


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

其它参考5


番石榴Throwables



如果您有实际Throwable实例,Google Guava提供Throwables.getStackTraceAsString()[62] [63] [64]


例:


String s = Throwables.getStackTraceAsString ( myException ) ;

其它参考6


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


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

其它参考7


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

其它参考8


灵感来自@Brian Agnew:


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

其它参考9


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


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 (Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    logger.info("Current stack trace is:\n" + sw.toString());
}

其它参考10


将堆栈跟踪打印到字符串


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更快更便宜]]。

其它参考11


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

其它参考12


private String getCurrentStackTraceString() {
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
    return Arrays.stream(stackTrace).map(StackTraceElement::toString)
            .collect(Collectors.joining("\n"));
}

其它参考13


将stacktrace打印到PrintStream,然后将其转换为String


// ...

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

    System.out.println(str);
}

其它参考14


科特林



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


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

其它参考15


没有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字符串成立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)

其它参考16


代码来自 Apache Commons Lang 3.4 (JavaDoc):[65]


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


与其他答案的区别在于[[strong>它在PrintWriter上使用 autoFlush

其它参考17


第一组评论中的聪明狙击是非常有趣的,但这实际上取决于你想要做什么。
如果你还没有正确的库,那么3行代码(如在D. Wroblewski的回答中)是完美的。
OTOH,如果你已经有了apache.commons库(就像大多数大型项目一样),那么Amar的答案就更短了。
好的,你可能需要十分钟才能获得库并正确安装(如果你知道你在做什么的话,不到一个)。但是时钟正在滴答作响,所以你可能没有时间。
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)[66]


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

其它参考18


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

其它参考19


如果你不想使用外部库并且你没有为Android开发,你可以创建一个像这样的扩展方法:[67]


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

其它参考20


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


而不是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);
        }
    }
}


请注意,此类可以很容易地通过Regex,contains或其他标准进行过滤。另请注意,它取决于Throwable实现细节(不太可能改变,但仍然)。

其它参考21


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


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


很容易按原样传递给记录器。

其它参考22


如果您使用的是Java 8,请尝试此操作


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


所以只需使用\\ n加入StackTraceElement即可

其它参考23


警告:这可能有点偏离主题,但是很好......;)


我不知道原始的海报理由是什么原因,首先想要将堆栈跟踪作为字符串。当堆栈跟踪最终应该在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
}


我喜欢它,因为它不需要外部库(除了你的日志记录后端,当然,大多数时候它都将在适当的位置使用)。

其它参考24


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


import java.util.Arrays;

try{

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

其它参考25


使用exp.printStackTrace()显示异常堆栈。


try {
   int zero = 1 - 1;
   int a = 1/zero;
} catch (Exception e) {
    e.printStackTrace();
}