Как преобразовать трассировку стека в строку?
каков самый простой способ преобразовать результат Throwable.getStackTrace()
к строке, которая изображает stacktrace?
26 ответов
можно использовать следующий метод, чтобы преобразовать Exception
стек String
. Этот класс доступен в Apache commons-lang, который является наиболее распространенной зависимой библиотекой со многими популярными открытыми источниками
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)
использовать 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 sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.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.access0(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)
предупреждение: не включает причину (которая обычно является полезным битом!)
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()
.
пример:
String s = Throwables.getStackTraceAsString ( myException ) ;
для меня самым чистым и простым способом было:
import java.util.Arrays;
Arrays.toString(e.getStackTrace());
вдохновленный @Brian Agnew:
public static String getStackTrace(Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
return sw.toString();
}
следующий код позволяет получить весь stackTrace с String
формат, без использования API, таких как log4J или даже 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.
}
вот версия, что это копия-pastable прямо на код:
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());
}
печать трассировки стека в строку
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
.
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});
распечатайте stacktrace в PrintStream, затем преобразуйте его в строку
// ...
catch (Exception e)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(out));
String str = new String(out.toByteArray());
System.out.println(str);
}
private String getCurrentStackTraceString() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
return Arrays.stream(stackTrace).map(StackTraceElement::toString)
.collect(Collectors.joining("\n"));
}
Котлин
расширение класса Throwable даст вам свойство String error.stackTraceString
:
val Throwable.stackTraceString: String
get() {
val sw = StringWriter()
val pw = PrintWriter(sw)
this.printStackTrace(pw)
return 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)
код 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
.
умный снайпер в первом наборе комментариев был очень забавным, но это действительно зависит от того, что вы пытаетесь сделать. Если у вас еще нет правильной библиотеки, то 3 строки кода (как в ответе Д. Вроблевского) идеальны. OTOH, если у вас уже есть apache.библиотека commons (Как и большинство крупных проектов), тогда ответ Амара короче. Хорошо, вам может потребоваться десять минут, чтобы получить библиотеку и установить ее правильно (меньше одного, если вы знаете, что делаете). Но часы тикает, так что у тебя может не быть свободного времени. У Ярека Пшигодзки было интересное предостережение- "Если вам не нужны вложенные исключения".
но что, если я do нужны полные трассировки стека, вложенные и все? В этом случае секрет заключается в использовании apache.common's getFullStackTrace (см. http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ExceptionUtils.html#getFullStackTrace%28java.lang.Throwable%29)
Это спас мою шкуру. Спасибо, Амар, за подсказку!
exapansion на ответ 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;
}
решение чтобы преобразовать stackTrace массива в string тип данных. Рассмотрим следующий пример:
import java.util.Arrays;
try{
}catch(Exception ex){
String stack = Arrays.toString(ex.getStackTrace());
System.out.println("stack "+ stack);
}
Если вы используете java 8, Попробуйте это
Arrays.stream(e.getStackTrace())
.map(s->s.toString())
.collect(Collectors.joining("\n"));
вы можете найти код для функции 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"
Если вы не хотите использовать внешнюю библиотеку, и вы не развивающихся для 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);
}
}
}
обратите внимание, что этот класс может быть легко адаптирован для фильтрации с помощью Regex,contains
или другим критериям. Также обратите внимание, что это зависит на Throwable
детали реализации (вряд ли изменится, но все же).
My oneliner для преобразования трассировки стека в заключенную многострочную строку:
Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))
легкий для того чтобы пройти к лесопогрузчику "как есть".
предупреждение: это может быть немного не по теме, Но да ладно... ;)
Я не знаю, что оригинальные плакаты причина был для того, чтобы хотеть трассировку стека в качестве строки в первую очередь. Когда трассировка стека должна закончиться в журнале SLF4J/Logback, но никаких исключений не было или не должно быть брошено вот что я делаю:
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
}
мне это нравится, потому что он не требует внешней библиотеки (кроме вашего бэкэнда ведения журнала, который будет на месте большую часть времени в любом случае, курс.)
использовать exp.printStackTrace()
для отображения стека исключений.
try {
int zero = 1 - 1;
int a = 1/zero;
} catch (Exception e) {
e.printStackTrace();
}