java异常堆栈 - java获取异常堆栈信息




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

番石榴的Throwables

如果您有实际的Throwable实例, Google Guava会提供Throwables.getStackTraceAsString()

例:

String s = Throwables.getStackTraceAsString ( myException ) ;

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


科特林

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

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

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

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

受@Brian Agnew启发:

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


如果您不想使用外部库,并且您没有为Android开发,则可以创建如下所示的“扩展”方法 :

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

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

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

// ...

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

将堆栈跟踪打印到字符串

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


来自Apache Commons Lang 3.4JavaDoc )的代码:

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

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


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

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

而不是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实现细节(不太可能改变,但仍然)。


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

import java.util.Arrays;

try{

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

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

我不知道最初的海报原因是什么原因是希望首先将堆栈跟踪作为字符串使用。 当堆栈跟踪应该在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
}

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


这应该工作:

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

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

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




tostring