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


当前回答

我不久前写了一些方法,所以我想为什么不花我的两分钱。

/** @param stackTraceElements The elements to convert
 * @return The resulting string */
public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements) {
    return stackTraceElementsToStr(stackTraceElements, "\n");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @return The resulting string */
public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements, String lineSeparator) {
    return stackTraceElementsToStr(stackTraceElements, lineSeparator, "");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting string */
public static final String stackTraceElementsToStr(StackTraceElement[] stackTraceElements, String lineSeparator, String padding) {
    String str = "";
    if(stackTraceElements != null) {
        for(StackTraceElement stackTrace : stackTraceElements) {
            str += padding + (!stackTrace.toString().startsWith("Caused By") ? "\tat " : "") + stackTrace.toString() + lineSeparator;
        }
    }
    return str;
}

/** @param stackTraceElements The elements to convert
 * @return The resulting string */
public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements) {
    return stackTraceCausedByElementsOnlyToStr(stackTraceElements, "\n");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @return The resulting string */
public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements, String lineSeparator) {
    return stackTraceCausedByElementsOnlyToStr(stackTraceElements, lineSeparator, "");
}

/** @param stackTraceElements The elements to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting string */
public static final String stackTraceCausedByElementsOnlyToStr(StackTraceElement[] stackTraceElements, String lineSeparator, String padding) {
    String str = "";
    if(stackTraceElements != null) {
        for(StackTraceElement stackTrace : stackTraceElements) {
            str += (!stackTrace.toString().startsWith("Caused By") ? "" : padding + stackTrace.toString() + lineSeparator);
        }
    }
    return str;
}

/** @param e The {@link Throwable} to convert
 * @return The resulting String */
public static final String throwableToStrNoStackTraces(Throwable e) {
    return throwableToStrNoStackTraces(e, "\n");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @return The resulting String */
public static final String throwableToStrNoStackTraces(Throwable e, String lineSeparator) {
    return throwableToStrNoStackTraces(e, lineSeparator, "");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting String */
public static final String throwableToStrNoStackTraces(Throwable e, String lineSeparator, String padding) {
    if(e == null) {
        return "null";
    }
    String str = e.getClass().getName() + ": ";
    if((e.getMessage() != null) && !e.getMessage().isEmpty()) {
        str += e.getMessage() + lineSeparator;
    } else {
        str += lineSeparator;
    }
    str += padding + stackTraceCausedByElementsOnlyToStr(e.getStackTrace(), lineSeparator, padding);
    for(Throwable suppressed : e.getSuppressed()) {
        str += padding + throwableToStrNoStackTraces(suppressed, lineSeparator, padding + "\t");
    }
    Throwable cause = e.getCause();
    while(cause != null) {
        str += padding + "Caused by:" + lineSeparator + throwableToStrNoStackTraces(e.getCause(), lineSeparator, padding);
        cause = cause.getCause();
    }
    return str;
}

/** @param e The {@link Throwable} to convert
 * @return The resulting String */
public static final String throwableToStr(Throwable e) {
    return throwableToStr(e, "\n");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @return The resulting String */
public static final String throwableToStr(Throwable e, String lineSeparator) {
    return throwableToStr(e, lineSeparator, "");
}

/** @param e The {@link Throwable} to convert
 * @param lineSeparator The line separator to use
 * @param padding The string to be used at the start of each line
 * @return The resulting String */
public static final String throwableToStr(Throwable e, String lineSeparator, String padding) {
    if(e == null) {
        return "null";
    }
    String str = padding + e.getClass().getName() + ": ";
    if((e.getMessage() != null) && !e.getMessage().isEmpty()) {
        str += e.getMessage() + lineSeparator;
    } else {
        str += lineSeparator;
    }
    str += padding + stackTraceElementsToStr(e.getStackTrace(), lineSeparator, padding);
    for(Throwable suppressed : e.getSuppressed()) {
        str += padding + "Suppressed: " + throwableToStr(suppressed, lineSeparator, padding + "\t");
    }
    Throwable cause = e.getCause();
    while(cause != null) {
        str += padding + "Caused by:" + lineSeparator + throwableToStr(e.getCause(), lineSeparator, padding);
        cause = cause.getCause();
    }
    return str;
}

例子:

try(InputStream in = new FileInputStream(file)) {
    ...
} catch(IOException e) {
    String exceptionToString = throwableToStr(e);
    someLoggingUtility.println(exceptionToString);
    ...
}

打印:

java.io.FileNotFoundException: C:\test.txt (The system cannot find the file specified)
    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(Unknown Source)
    at java.io.FileInputStream.<init>(Unknown Source)
    at com.gmail.br45entei.Example.main(Example.java:32)

其他回答

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

是将结果转换为字符串的最简单方法我在程序中使用这个来打印堆栈跟踪

LOGGER.log(Level.SEVERE, "Query Builder Issue Stack Trace : {0} ,Message : {1} objid {2}", new Object[]{Arrays.toString(e.getStackTrace()), e.getMessage(),objId});

如果您使用的是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。

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

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

以下代码允许您使用字符串格式获取整个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.
}