Как преобразовать трассировку стека в строку?


какой самый простой способ преобразовать результат Throwable.getStackTrace() к строке, которая изображает stacktrace?

26 1241

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.
}

вот версия, которая копируется непосредственно в код:

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)

The 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 (документация):

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 строки кода (как в ответе Д. Вроблевского) идеально подходят. Ото, если у вас уже есть "Апач".библиотека 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 ответ на Гала, которая также будет включать в себя причины для исключения:

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

решение трассировка стека для преобразования массива в строку тип данных. Рассмотрим следующий пример:

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 as:

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

обратите внимание, что этот класс может быть легко приспособлены для фильтрации по регулярному выражению, contains или другим критериям. Также обратите внимание, что это зависит по факту Throwable детали реализации (вряд ли изменится, но все же).

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