Java / Android - как распечатать полную трассировку стека?

125

В Android (Java) как распечатать полную трассировку стека? Если мое приложение вылетает из-за nullPointerException или чего-то еще, оно распечатывает (почти) полную трассировку стека следующим образом:

java.io.IOException: Attempted read from closed stream.
com.android.music.sync.common.SoftSyncException: java.io.IOException: Attempted read from closed stream.
    at com.android.music.sync.google.MusicSyncAdapter.getChangesFromServerAsDom(MusicSyncAdapter.java:545)
    at com.android.music.sync.google.MusicSyncAdapter.fetchDataFromServer(MusicSyncAdapter.java:488)
    at com.android.music.sync.common.AbstractSyncAdapter.download(AbstractSyncAdapter.java:417)
    at com.android.music.sync.common.AbstractSyncAdapter.innerPerformSync(AbstractSyncAdapter.java:313)
    at com.android.music.sync.common.AbstractSyncAdapter.onPerformLoggedSync(AbstractSyncAdapter.java:243)
    at com.google.android.common.LoggingThreadedSyncAdapter.onPerformSync(LoggingThreadedSyncAdapter.java:33)
    at android.content.AbstractThreadedSyncAdapter$SyncThread.run(AbstractThreadedSyncAdapter.java:164)
Caused by: java.io.IOException: Attempted read from closed stream.
    at org.apache.http.impl.io.ChunkedInputStream.read(ChunkedInputStream.java:148)
    at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:159)
    at java.util.zip.GZIPInputStream.readFully(GZIPInputStream.java:212)
    at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:81)
    at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:64)
    at android.net.http.AndroidHttpClient.getUngzippedContent(AndroidHttpClient.java:218)
    at com.android.music.sync.api.MusicApiClientImpl.createAndExecuteMethod(MusicApiClientImpl.java:312)
    at com.android.music.sync.api.MusicApiClientImpl.getItems(MusicApiClientImpl.java:588)
    at com.android.music.sync.api.MusicApiClientImpl.getTracks(MusicApiClientImpl.java:638)
    at com.android.music.sync.google.MusicSyncAdapter.getChangesFromServerAsDom(MusicSyncAdapter.java:512)
    ... 6 more

Однако иногда в целях отладки я хочу регистрировать полную трассировку стека с того места, где я нахожусь в коде. Я подумал, что могу просто сделать это:

StackTraceElement trace = new Exception().getStackTrace();
Log.d("myapp", trace.toString());

Но при этом просто выводится указатель на объект ... Нужно ли мне перебирать все элементы трассировки стека, чтобы распечатать их? Или есть простой способ все это распечатать?

Джейк Уилсон
источник
1
Вы можете использовать этот метод Thread.currentThread (). GetStackTrace () stackoverflow.com/questions/1069066/…
user2024270

Ответы:

119

Есть переопределения всех методов журнала с (String tag, String msg, Throwable tr)подписями.

Передача исключения в качестве третьего параметра должна дать вам полную трассировку стека в logcat.

Филипп Рейхарт
источник
5
К вашему сведению, методы журнала с тремя аргументами используют getStackTraceString()метод, упомянутый @Thomas за кулисами.
Филипп Рейхарт,
6
Я занимаюсь разработкой Android два года и никогда раньше этого не замечал. Большое спасибо.
Anh Tuan
Глядя на исходный код, да, вы правы, @PhilippReichart. Вот код для Log.d на AOSP 4.2.2_r1
Эхтеш Чоудхури
152

Следующее должно помочь:

Log.d("myapp", Log.getStackTraceString(new Exception()));

Обратите внимание, что ...x moreв конце не обрезается никакой информации из трассировки стека:

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

... или, другими словами, заменить x moreна последние xстроки из первого исключения.

Майкл Берри
источник
1
Откуда getStackTraceString()? Не отображается в Eclipse? Это не часть Throwableили Exception....
Джейк Уилсон
9
"... еще 6" в конце не отсекает никакой информации. Он сообщает вам, что остальная часть трассировки стека такая же, как и для верхнего исключения. Просто посмотрите на последние 6 строк из первого исключения.
Tomasz
Возможно, вам потребуется импортировать библиотеку журналов (используя import android.util.Log; ).
Дэн
10

Используйте Log.getStackTraceString (Throwable t). Вы можете получить более длинные следы стека, копнув глубже. Например:

try {
    ...
} catch(Exception e) {
    Log.d("Some tag", Log.getStackTraceString(e.getCause().getCause()));
}

Получено с http://developer.android.com/reference/android/util/Log.html#getStackTraceString%28java.lang.Throwable%29

Томас
источник
Log.getStackTraceString()не регистрирует трассировку стека, а просто возвращает ее как String. Приведенный выше код ничего не регистрирует, а также не сработает с NPE, если e.getCause()есть null.
Филипп Рейхарт
9
private static String buildStackTraceString(final StackTraceElement[] elements) {
    StringBuilder sb = new StringBuilder();
    if (elements != null && elements.length > 0) {
        for (StackTraceElement element : elements) {
            sb.append(element.toString());
        }
    }
    return sb.toString();
}


// call this at your check point
Log.d(TAG, buildStackTraceString(Thread.currentThread().getStackTrace()));
faywong
источник
6

Вы можете использовать это:

public static String toString(StackTraceElement[] stackTraceElements) {
    if (stackTraceElements == null)
        return "";
    StringBuilder stringBuilder = new StringBuilder();
    for (StackTraceElement element : stackTraceElements)
        stringBuilder.append(element.toString()).append("\n");
    return stringBuilder.toString();
}
Мохсен Афшин
источник
4

Вы также можете распечатать трассировку стека в любой точке кода приложения, используя такие методы, как Thread.dumpStack()

Пожалуйста, пройдите по ссылке, чтобы узнать больше

ajaykoppisetty
источник
2

Вам нужно использовать Throwable Object, чтобы получить полный stackTrace.

try{
 // code here
}catch(Exception e){
    String exception = getStackTrace(e);
}

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

Ссылка: https://stackoverflow.com/a/18546861

Хуссен Булла
источник
0

Я быстро сделал рекурсивную функцию, которая будет повторять throwable и throwable.getCause ().

Это потому, что каждый "throwable.getCause ()" возвращает вам новое сообщение об исключении с повторением некоторых строк и новыми строками. Итак, концепция такова: если есть "причина", в главном файле throwable есть строка с "n more ..", поэтому я получаю последнюю строку перед строкой с "n more ..", тогда я получаю сообщение о причине и наконец, я делаю подстроку сообщения о причине, получая только часть после последней повторяющейся строки (последняя строка, которая появляется на обоих: основной объект throwable и объект throwable причины).

Затем я использую рекурсию, когда получаю сообщение о причине, поэтому повторно вызывая ту же функцию, чтобы получить сообщение о причине из основного объекта throw, я получаю уже замененное сообщение. Если причина, вызываемая из основного объекта throwable, имеет также другую причину, поэтому основной объект throwable имеет 3 уровня (main -> cause -> cause-of-cause), на основном throwable я получу "сообщение причины" уже замененное сообщение. (используя ту же концепцию основного

public static <T extends Throwable> String printStackTraceString(T ex) {     // Recursive
    Throwable tr = ex;
    if (tr != null) {
        String st = Log.getStackTraceString(tr);
        if (tr.getCause() != null) {
            // Recursion...
            String cs = printStackTraceString(tr.getCause());

            String r1 = st.subSequence(0x0, st.lastIndexOf("\n", st.lastIndexOf("\n") - "\n".length())).toString();
            String replace = r1.substring(r1.lastIndexOf("\n"));
            if (cs.contains(replace)) {
                return r1.concat(cs.subSequence(cs.indexOf(replace) + replace.length(), cs.length()).toString());
            }
        }
        return st;
    }
    return "";
}

Я пробовал только 2 уровня (основной -> причина) и не более: / Если что-то не так, отредактируйте функцию и напишите комментарий: D

Удачного кодирования и хорошего дня: D

Важный:

В этом коде иногда возникает исключение, если "st" не содержит "\ n" и т.п. (я обнаружил, что некоторые исключения имеют эту проблему в трассировках стека). Чтобы решить эту проблему, вам нужно добавить некоторую проверку перед строкой кода: "String r1 = ..."

Вам необходимо проверить: «st» содержит «\ n» и что оба начального и конечного индексов «st.subSequence» действительны.

В любом случае я предлагаю поместить это в try-catch и вернуть пустую строку в случае исключения. (Это рекурсивно, поэтому возвращенная пустая строка будет объединена с предыдущей обработанной строкой).

Z3R0
источник