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

avatar
ripper234
19 июля 2009 в 11:31
657883
31
1597

Как проще всего преобразовать результат Throwable.getStackTrace() в строку, изображающую трассировку стека?

Источник
Stijn de Witt
31 января 2012 в 18:45
7

Поскольку ответ jqno фактически использует метод Throwable.getStackTrace (), который вы указали в своем вопросе, тогда как Брайан не использует. Вместо этого он использует Throwable.printStackTrace ().

Russell Silva
15 августа 2013 в 21:32
10

Практически каждый проект Java должен включать Apache commons-lang. Он включает в себя множество удобных методов, реализующих чрезвычайно распространенные потребности разработки.

Andrew Spencer
22 октября 2013 в 08:12
20

@StijndeWitt Эти три строки кода почти наверняка нуждаются в выделении из того места, где вы их назвали. Поскольку вы не знаете, куда их поместить, они войдут в ваш набор служебных инструментов вместе со всеми другими полезными фрагментами. Бинго! вы только что заново изобрели гуаву / общедоступный язык / что угодно ... только не так хорошо. Вместо этого импортируйте разумную библиотеку утилит и не изобретайте велосипед. Верный признак новичка - думать, что вы можете сделать работу лучше, чем писатели библиотеки.

Andrew Spencer
22 октября 2013 в 08:16
2

NB Принцип единого уровня абстракции является причиной, по которой подобные вещи следует исключить. Повышает удобочитаемость и тестируемость, обнаруживает многоразовые элементы. См .: slideshare.net/guestebde/10-ways-to-improve-your-code-neal-ford

user2323036
10 марта 2014 в 10:52
9

1. У Guava есть - Throwables.getStackTraceAsString (e) 2. Apache Commons Lang - ExceptionUtils.getFullStackTrace 3. Напишите наши собственные методы

jm0
2 марта 2016 в 16:30
10

@AndrewSpencer Я не понимаю, почему вы, ребята, так стараетесь раскритиковать StijndeWitt за то, что вы хотите добиться этого с помощью небольшого фрагмента. На самом деле нет особой опасности в написании крошечного служебного метода (я не вижу в этом выражения «СОВЕРШЕННО ГОРДЕНСТВО, о, неееет !! он думает, что он лучше, чем Apache !!»). Существует множество проектов, особенно на языках JVM, отличных от Java, которые действительно не хотят включать Guava или Commons Lang только для регистрации трассировки стека. Я пишу библиотеки Scala и Clojure и, конечно же, не буду превращать Apache Commons Lang в транзитивную зависимость только для одного метода.

Andrew Spencer
7 апреля 2016 в 13:56
0

@ jm0 Не треп, просто несогласие с оговорками. Это было слишком ехидно, я готов был драться, увидев несколько плохих самодельных утилит. Согласен, есть причины не добавлять зависимость, просто чаще вижу обратную ошибку.

Andrew
13 октября 2017 в 16:05
0

@Gewure Теперь мы намного более развиты и продвинулись в наших знаниях и понимании кода. Больше нет нужды в таких мелких вопросах. Пусть простые люди гниют в своих недостатках.

MarcG
16 октября 2017 в 22:09
0

Я пришел сюда, потому что при написании функций Amazon Lambda на Java вы, возможно, захотите избежать импорта библиотек, поскольку они отнимают время запуска контейнера. Так что иногда все же необходимо изобретать велосипед. Или, может быть, я смогу решить эту проблему с помощью ProGuard ...

Gewure
5 декабря 2017 в 15:06
0

@ Андрей, я не знаю, интерпретирую ли я твой сарказм? правильно, но я думаю, что вы тоже меня неправильно истолковали: я хотел сказать, что у SO есть проблема. Действительно, он стал элитарным. Он полностью не может открыть соединение для входа новичков. Например. они не хотели неанглоязычного SO. Что недемократично и элитарно. Есть люди, которые могут программировать / хотят, но не говорят по-английски.

Andrew
6 декабря 2017 в 04:55
1

@Gewure Это помогло бы, если бы вы не удалили свой комментарий ... Хотя это был явно сарказм. ТАК. всегда был полон элитарных и недалеких снобов. Я не думаю, что это не совсем вина С.О., а просто общий недостаток человечества, который здесь очень заметно проявляется. Что касается говорения по-английски: есть некоторая чувствительность с обеих сторон; Однако я могу говорить только о самом аргументе.

jpangamarca
26 декабря 2017 в 14:53
3

Используйте commons-lang. Джош Блох говорит: «Знайте и используйте библиотеки. [...] не изобретайте велосипед. Если вам нужно сделать что-то, что кажется достаточно распространенным, возможно, в библиотеках уже есть класс. он делает то, что вы хотите. Если есть, используйте его; если не знаете, проверьте. [...] Код библиотеки, вероятно, будет лучше, чем код, который вы бы написали самостоятельно, и, вероятно, со временем улучшится. Это не отражает ваших способностей как программиста. Экономия на масштабе требует, чтобы коду библиотеки уделялось гораздо больше внимания, чем большинство разработчиков могло бы позволить себе уделить той же функциональности. "

Ответы (31)

avatar
amar
21 января 2010 в 14:39
1086

Для преобразования трассировки стека Exception в String можно использовать следующий метод. Этот класс доступен в Apache commons-lang, который является наиболее распространенной зависимой библиотекой со многими популярными открытыми исходными кодами

org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)

Brian Agnew
31 января 2012 в 10:10
88

@Stijn - честно говоря (я написал текущий ответ с наибольшим количеством голосов ниже), стоит посмотреть на commons-lang для гораздо большей функциональности

WhyNotHugo
21 мая 2012 в 14:54
55

@StijndeWitt Commons Lang довольно распространен. Он уже присутствует в большинстве моих проектов / проектов на работе.

Nathanial
10 апреля 2013 в 00:53
17

@Hugo, спасибо, собирался использовать StringWriter, чтобы избежать добавления новой библиотеки - оказывается, это уже зависимость трех моих зависимостей. Итак, что касается остального, проверьте, есть ли он у вас уже.

Brian Agnew
28 августа 2013 в 16:31
34

@MartinAsenov - по вашей логике вы бы никогда не использовали такую ​​библиотеку, не так ли? Вы бы не использовали его, если уже не используете?

schmmd
13 ноября 2013 в 23:18
17

К вашему сведению, пакет изменился, и теперь класс находится по адресу org.apache.commons.lang3.exception.ExceptionUtils.

avatar
Andrey Sarul
13 апреля 2020 в 12:19
2

Интересно, почему никто не упомянул ExceptionUtils.getStackFrames(exception)

Для меня это наиболее удобный способ выгрузить stacktrace со всеми его причинами до конца:

String.join("\n", ExceptionUtils.getStackFrames(exception));
Stealth Rabbi
11 августа 2020 в 12:37
2

а что такое ExceptionUtils?

Andrey Sarul
13 августа 2020 в 23:17
0

Это класс утилиты commons lang

avatar
ivanjermakov
29 сентября 2019 в 08:56
7

С Java 8 Stream API вы можете сделать что-то вроде этого:

Stream
    .of(throwable.getStackTrace())
    .map(StackTraceElement::toString)
    .collect(Collectors.joining("\n"));

Он будет принимать массив элементов трассировки стека, преобразовывать их в строку и объединять в многострочную строку.

judovana
7 ноября 2019 в 13:54
4

Это решение удаляет сообщение и игнорирует все родительские трассировки.

avatar
samthebest
5 марта 2019 в 15:43
5

Версия Scala

def stackTraceToString(e: Exception): String = {
  import java.io.PrintWriter
  val sw = new StringWriter()
  e.printStackTrace(new PrintWriter(sw))
  sw.toString
}
avatar
Brian_Entei
13 января 2019 в 04:38
2

Я написал несколько методов для этого некоторое время назад, поэтому я подумал, почему бы не бросить на это свои два цента.

/** @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)
avatar
Prakhar Nigam
17 ноября 2018 в 10:45
3
 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)
avatar
Eric
30 октября 2018 в 17:46
2

Несколько вариантов

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

  2. Использование библиотеки Google Guava String stackTrace = Throwables.getStackTraceAsString ( myException ) ;

  3. org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)

avatar
Baked Inhalf
23 апреля 2018 в 12:06
20

Распечатайте трассировку стека в PrintStream, затем преобразуйте ее в String:

// ...

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

    System.out.println(str);
}
avatar
Pengcheng Zhang
10 апреля 2018 в 07:58
9

, если вы используете 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».

avatar
Jorge Santos
30 марта 2018 в 18:39
4

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

import java.util.Arrays;

try{

}catch(Exception ex){
    String stack = Arrays.toString(ex.getStackTrace());
    System.out.println("stack "+ stack);
}
avatar
Andrey Lebedenko
17 марта 2018 в 10:32
3

Моя единственная строка для преобразования трассировки стека в закрытую многострочную строку:

Stream.of(e.getStackTrace()).map((a) -> a.toString()).collect(Collectors.joining("\n", "[", "]"))

Легко передать в регистратор "как есть".

valijon
11 декабря 2018 в 10:51
0

Вы получите что-то, что отличается от printStackTrace(). Здесь вы потеряете: 1) Сгенерированное исключение; 2) Причины и их трассировка

Andrey Lebedenko
11 декабря 2018 в 14:29
0

Разница вполне ожидаема, поскольку преобразование printStackTrace() никогда не было частью вопроса.

avatar
Ramanan Durairaj
26 декабря 2017 в 13:37
19
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});
avatar
Alexander Wessel
6 декабря 2017 в 19:39
2

Предупреждение: это может быть немного не по теме, ну да ладно ...;)

Я не знаю, каковы исходные плакаты , причина в том, что трассировка стека должна быть в первую очередь строковой. Когда трассировка стека должна заканчиваться в 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
}

Мне это нравится, потому что для него не требуется внешняя библиотека (кроме вашего бэкэнда журналирования, который, конечно, будет работать большую часть времени).

avatar
MarcG
16 октября 2017 в 21:59
2

Старый вопрос, но я просто хотел бы добавить особый случай, когда вы не хотите печатать весь стек , удалив некоторые части, которые вам на самом деле не интересны, за исключением определенных классов или пакетов.

Вместо 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 (вряд ли изменится, но все же).

avatar
eddyrokr
14 сентября 2017 в 09:44
11
private String getCurrentStackTraceString() {
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
    return Arrays.stream(stackTrace).map(StackTraceElement::toString)
            .collect(Collectors.joining("\n"));
}
avatar
vonox7
10 марта 2017 в 11:24
14

Котлин> = 1,4

Используйте встроенную функцию stackTraceToString() на Throwable.

Котлин <1,4

Расширение класса Throwable даст вам свойство String error.stackTraceString:

val Throwable.stackTraceString: String
  get() {
    val sw = StringWriter()
    val pw = PrintWriter(sw)
    this.printStackTrace(pw)
    return sw.toString()
  }
Aguragorn
25 марта 2021 в 03:26
0

Начиная с Kotlin 1.4 теперь есть встроенный API для этого kotlinlang.org/api/latest/jvm/stdlib/kotlin/…

avatar
ido flax
15 июля 2016 в 10:11
5

расширение ответа Галы, которое также будет включать причины исключения:

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;
}
avatar
Gala
7 июня 2016 в 20:30
8

Без 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)
avatar
IvanRF
7 июля 2015 в 16:59
10

Код из 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.

avatar
Kapé
13 сентября 2014 в 11:59
3

Если вы не хотите использовать внешнюю библиотеку и не разрабатываете для 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();
}
avatar
Tihamer
15 апреля 2014 в 15:07
9

Умный снайпер в первом наборе комментариев был очень забавным, но это действительно зависит от того, что вы пытаетесь сделать. Если у вас еще нет нужной библиотеки, тогда 3 строки кода (как в ответе Д. Вроблевски) идеально подходят. OTOH, если у вас уже есть библиотека apache.commons (как и в большинстве крупных проектов), то ответ Amar будет короче. Хорошо, вам может потребоваться десять минут, чтобы получить библиотеку и правильно ее установить (меньше одной, если вы знаете, что делаете). Но время идет, так что времени у вас может не быть. У Ярека Пшигодски было интересное предостережение - «Если вам не нужны вложенные исключения».

Но что, если мне нужны полные трассировки стека, вложенные и все такое? В этом случае секрет заключается в использовании getFullStackTrace apache.common (см. http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/exception/ ExceptionUtils.html # getFullStackTrace% 28java.lang.Throwable% 29)

Это спасло мой бекон. Спасибо, Амар, за подсказку!

avatar
Akira Yamamoto
3 октября 2013 в 19:15
29
public static String getStackTrace(Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    return sw.toString();
}
Eric
16 августа 2016 в 02:38
1

Привет, я просто хотел бы отметить, что в разделе комментариев к цитируемому ответу указывается, что объекты StringWriter и PrintWriter должны быть close d .... (или я думаю, только PrintWriter необходимо закрыть, так как закрытие должно закрывать и StringWriter)

avatar
dumonderic
24 октября 2012 в 16:57
26

Следующий код позволяет получить весь 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.
}
avatar
rouble
12 июня 2012 в 16:15
20

Вот версия, которую можно скопировать непосредственно в код:

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());
}
avatar
Vicky Kapadia
30 апреля 2012 в 07:29
247

Если вы разрабатываете для 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)
avatar
stumbav
15 февраля 2012 в 10:20
142

Гуавы Throwables класс

Если у вас есть фактический экземпляр Throwable, Google Guava предоставляет Throwables.getStackTraceAsString().

.

Пример:

String s = Throwables.getStackTraceAsString ( myException ) ;
avatar
Vladas Diržys
15 декабря 2011 в 14:37
103

Для меня самым чистым и простым способом был:

import java.util.Arrays;
Arrays.toString(e.getStackTrace());
fury
9 января 2012 в 04:03
41

Код чистый, а вывод - нет. В конце вы должны выполнить .replaceAll (",", "\ n"). Однако вы теряете отступ, предлагаемый printStackTrace.

webjockey
24 января 2017 в 21:23
5

Это полезно, когда вы записываете трассировку в одну строку.

avatar
Jarek Przygódzki
11 мая 2011 в 18:40
12

Печать трассировки стека до строки

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.

avatar
D. Wroblewski
19 июля 2009 в 11:41
483

Это должно работать:

StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
dmitry
14 июля 2015 в 11:14
74

Лаконичность в контексте java всегда горькая. Этот printStackTrace должен просто возвращать строку, оставляя решение о том, печатать ее или нет, пользователю :)

Mateus Viccari
13 октября 2016 в 18:32
44

Печать printStackTrace в консоли приемлема, но по крайней мере getStackTrace, возвращающий ее как String, должен быть доступен по умолчанию.

ArtOfWarfare
14 ноября 2016 в 23:02
6

Какая часть этого лаконичного? Вам нужно создать 2 объекта, которые существуют только для того, чтобы поместить трассировку стека в строку.

user207421
11 августа 2017 в 05:56
9

@dmitry Метод с именем printXXX() должен печатать XXX.

Andrew
13 октября 2017 в 16:08
2

@Greg На самом деле это был даже не сарказм, просто нужно было просто прочитать то, что он сказал.

Smit-Tay
14 июля 2021 в 10:11
0

Печать исключения без трассировки стека в большинстве случаев (почти) бесполезна. По умолчанию Throwable.toString () должен возвращать понятное человеку объяснение, за которым следует трассировка стека. Если мне нужно только сообщение, я попрошу его, как и стек. Опять же, разработчики Java в основном школьники, которые, кажется, никогда не занимаются разработкой, кроме самой Java. Если бы они это сделали, они бы разработали свои вещи так, чтобы их было намного проще использовать.

Hulk
22 июля 2021 в 07:25
0

@ Smit-Tay ну, в профессиональной среде мне почти никогда не приходилось напрямую печатать исключение где-либо - обычно оно передается в библиотеку журналов, и конфигурация журналов заботится обо всех деталях того, какой уровень детализации исключение заканчивается в том, в каком файле журнала и как он там форматируется.

avatar
jqno
19 июля 2009 в 11:38
114

ПРЕДУПРЕЖДЕНИЕ: не включает причину (обычно это полезный бит!)

public String stackTraceToString(Throwable e) {
    StringBuilder sb = new StringBuilder();
    for (StackTraceElement element : e.getStackTrace()) {
        sb.append(element.toString());
        sb.append("\n");
    }
    return sb.toString();
}
avatar
Brian Agnew
19 июля 2009 в 11:36
2289

Используйте 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);
Laila Agaev
29 ноября 2013 в 20:20
8

Это обрезает трассировку стека так же, как printStackTrace (). Все исключения в стеке видны, но для каждого исключения стек может быть обрезан. Любой, кому требуется вся трассировка, должен это учитывать.

ticktock
4 марта 2014 в 22:30
7

Это, как оказалось, в значительной степени именно то, что делает метод Apache ExceptionUtils.getStackTrace (). Фактически, почти в буквальном смысле.

Muhammad Gelbana
2 августа 2015 в 21:07
6

@BrianAgnew, разве вы не должны закрыть StringWriter и PrintWriter?

Brian Agnew
3 августа 2015 в 08:42
5

@MuhammadGelbana - да. Сказанное выше показано для удобства. Я подозреваю, что если вы этого не сделаете, это не вызовет проблем, но я бы поддержал это на основании хорошей практики.

Muhammad Gelbana
3 августа 2015 в 09:31
15

@BrianAgnew, спасибо за ответ. Мне стало любопытно, и вот что я нашел: coderhelper.com/questions/14542535/…

Hello234
1 августа 2021 в 23:38
0

Это должен быть выбранный ответ. нет внешних библиотек, просто, быстро и отлично работает.