将结果转换为Throwable.getStackTrace()
描述堆栈跟踪的字符串的最简单方法是什么?
将结果转换为Throwable.getStackTrace()
描述堆栈跟踪的字符串的最简单方法是什么?
Answers:
可以使用以下方法将Exception
堆栈跟踪转换为String
。此类可在Apache commons-lang中找到,它是最常见的依赖库,具有许多流行的开源代码
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)
org.apache.commons.lang3.exception.ExceptionUtils
。
使用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);
StringWriter
和PrintWriter
吗?
这应该工作:
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
printStackTrace
应该只是返回字符串,而决定是否打印给用户:)
printXXX()
应打印XXX。
如果您是为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)
Log.e("TAG", "My message", new Throwable());
Throwables
课如果您有实际Throwable
实例,则Google Guava将提供Throwables.getStackTraceAsString()
。
例:
String s = Throwables.getStackTraceAsString ( myException ) ;
警告:不包括原因(通常是有用的位!)
public String stackTraceToString(Throwable e) {
StringBuilder sb = new StringBuilder();
for (StackTraceElement element : e.getStackTrace()) {
sb.append(element.toString());
sb.append("\n");
}
return sb.toString();
}
String.format("%n")
或类似的方法代替"\n"
使DOS胶合剂满意。
对我来说,最干净,最简单的方法是:
import java.util.Arrays;
Arrays.toString(e.getStackTrace());
public static String getStackTrace(Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
return sw.toString();
}
StringWriter
and PrintWriter
对象应该是close
d...。(或者我猜只PrintWriter
需要关闭,因为关闭它也应该关闭StringWriter
)
以下代码允许您使用某种String
格式获取整个stackTrace ,而无需使用log4J或什至这样的API java.util.Logger
:
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 (Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
logger.info("Current stack trace is:\n" + sw.toString());
}
Throwable
定义的,对不对?
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});
将堆栈跟踪打印到PrintStream
,然后将其转换为String
:
// ...
catch (Exception e)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(out));
String str = new String(out.toByteArray());
System.out.println(str);
}
将堆栈跟踪打印到字符串
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
。
private String getCurrentStackTraceString() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
return Arrays.stream(stackTrace).map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
}
第一组评论中的巧妙剪裁非常有趣,但这实际上取决于您要执行的操作。如果您还没有正确的库,那么三行代码(如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)
它保存了我的培根。谢谢,阿马尔,提示!
来自Apache Commons Lang 3.4(JavaDoc)的代码:
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();
}
与其他答案的区别在于它 autoFlush
在上使用PrintWriter
。
没有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)
如果您使用的是Java 8,请尝试以下操作
Arrays.stream(e.getStackTrace())
.map(s->s.toString())
.collect(Collectors.joining("\n"));
您可以找到as getStackTrace()
提供的功能代码Throwable.java
:
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)")));
}
因此,只需将StackTraceElement
“ \ n” 加入。
盛大地回答了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;
}
使用Java 8 Stream API,您可以执行以下操作:
Stream
.of(throwable.getStackTrace())
.map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
它将使用堆栈跟踪元素数组,将它们转换为字符串,然后加入多行字符串。
如果您不想使用外部库并且不打算为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();
}
这是个老问题,但是我想添加一种特殊情况,即您不想打印所有堆栈,只需删除一些您实际上不感兴趣的部分,就可以排除某些类或程序包。
代替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
实现细节(不太可能更改,但仍会更改)。
import java.io.PrintWriter;
import java.io.StringWriter;
public class PrintStackTrace {
public static void main(String[] args) {
try {
int division = 0 / 0;
} catch (ArithmeticException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
System.out.println(exceptionAsString);
}
}
}
当您运行该程序时,输出将类似于以下内容:
java.lang.ArithmeticException: / by zero
at PrintStackTrace.main(PrintStackTrace.java:9)
我不知道为什么没人提到 ExceptionUtils.getStackFrames(exception)
对我来说,这是将stacktrace及其所有原因转储到最后的最方便的方法:
String.join("\n", ExceptionUtils.getStackFrames(exception));
警告:这可能有点题外话了,但是好吧...;)
我不知道最初的张贴者为什么要首先将堆栈跟踪作为字符串。当堆栈跟踪应该以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();
使用Google Guava库
String stackTrace = Throwables.getStackTraceAsString ( myException ) ;
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)