Java / Android - Wie drucke ich einen vollständigen Stack-Trace aus?

124

Wie drucke ich in Android (Java) einen vollständigen Stack-Trace aus? Wenn meine Anwendung aufgrund einer nullPointerException oder ähnlichem abstürzt, wird eine (fast) vollständige Stapelverfolgung wie folgt gedruckt:

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

Manchmal möchte ich jedoch zu Debugging-Zwecken einen vollständigen Stack-Trace protokollieren, von dem aus ich mich im Code befinde. Ich dachte, ich könnte das einfach machen:

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

Dies druckt jedoch nur den Zeiger auf das Objekt aus ... Muss ich alle Stapelverfolgungselemente durchlaufen, um sie auszudrucken? Oder gibt es eine einfache Methode, um alles auszudrucken?

Jake Wilson
quelle
1
Sie können diese Methode verwenden Thread.currentThread (). GetStackTrace () stackoverflow.com/questions/1069066/…
user2024270

Antworten:

119

Es gibt Überschreibungen aller Protokollmethoden mit (String tag, String msg, Throwable tr)Signaturen.

Wenn Sie eine Ausnahme als dritten Parameter übergeben, erhalten Sie die vollständige Stapelverfolgung in logcat.

Philipp Reichart
quelle
5
Zu getStackTraceString()Ihrer Information: Die Protokollmethoden mit drei Argumenten verwenden die von @Thomas hinter den Kulissen erwähnte Methode.
Philipp Reichart
6
Ich habe Android zwei Jahre lang entwickelt und das noch nie bemerkt. Vielen Dank.
Anh Tuan
Wenn Sie sich den Quellcode ansehen, haben Sie Recht @PhilippReichart. Hier ist der Code für Log.d auf AOSP 4.2.2_r1
Ehtesh Choudhury
152

Folgendes sollte den Trick tun:

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

Beachten Sie, dass ...x moream Ende keine Informationen aus dem Stack-Trace abgeschnitten werden:

(Dies zeigt an), dass der Rest der Stapelverfolgung für diese Ausnahme mit der angegebenen Anzahl von Frames vom unteren Rand der Stapelverfolgung der Ausnahme übereinstimmt, die durch diese Ausnahme verursacht wurde (die "einschließende" Ausnahme).

... oder mit anderen Worten, durch x moredie letzten xZeilen der ersten Ausnahme ersetzen .

Michael Berry
quelle
1
Woher kommt das getStackTraceString()? Wird in Eclipse nicht angezeigt? Es ist nicht Teil von Throwableoder Exception...
Jake Wilson
9
"... 6 weitere" am Ende schneidet keine Informationen ab. Es sagt Ihnen, dass der Rest des Stack-Trace derselbe ist wie für die oberste Ausnahme. Schauen Sie sich einfach die letzten 6 Zeilen der ersten Ausnahme an.
Tomasz
Sie müssten wahrscheinlich die Protokollierungsbibliothek importieren (mit import android.util.Log;).
Dan
10

Verwenden Sie Log.getStackTraceString (Throwable t). Sie können längere Stapelspuren erhalten, indem Sie tiefer graben. Beispielsweise:

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

Abgerufen von http://developer.android.com/reference/android/util/Log.html#getStackTraceString%28java.lang.Throwable%29

Thomas
quelle
Log.getStackTraceString()protokolliert den Stack-Trace nicht, sondern gibt ihn nur als String zurück. Der obige Code protokolliert nichts und schlägt auch mit einer NPE fehl, wenn dies der Fall e.getCause()ist null.
Philipp Reichart
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
quelle
6

Sie können dies verwenden:

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();
}
Mohsen Afshin
quelle
4

Sie können einen Stack-Trace auch an einer beliebigen Stelle in Ihrem App-Code mit Methoden wie drucken Thread.dumpStack()

Bitte gehen Sie über den Link für weitere Details

ajaykoppisetty
quelle
2

Sie müssen Throwable Object verwenden, um die vollständige stackTrace zu erhalten.

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

Ref: https://stackoverflow.com/a/18546861

Houssin Boulla
quelle
0

Ich habe jetzt schnell eine rekursive Funktion ausgeführt, die das throwable und das throwable.getCause () iteriert.

Das liegt daran, dass jede "throwable.getCause ()" eine neue Ausnahmemeldung mit einigen wiederholten Zeilen und neuen Zeilen an Sie zurückgibt. Das Konzept lautet also: Wenn es eine "Ursache" gibt, gibt es eine Zeile mit "n mehr .." auf dem Hauptwurf, so dass ich die letzte Zeile vor der mit "n mehr .." erhalte, dann erhalte ich die Ursachenmeldung und Schließlich unterstriche ich die Ursachenmeldung, indem ich nur den Teil nach der letzten wiederholten Zeile erhalte (die letzte Zeile, die auf beiden erscheint: die Hauptauswurf- und die Auslösungsausgabe).

Dann verwende ich die Rekursion, wenn ich die Ursachenmeldung erhalte. Wenn ich also dieselbe Funktion erneut aufrufe, um die Ursachenmeldung vom Hauptwurf zu erhalten, erhalte ich eine bereits ersetzte Nachricht. Wenn die Ursache, die vom Hauptwurf ausgelöst werden kann, auch eine andere Ursache hat, so dass der Hauptwurf 3 Ebenen hat (Haupt -> Ursache -> Ursache der Ursache), wird auf dem Hauptwurf, den ich bekomme, "Ursache Nachricht" eine bereits ersetzte Nachricht (unter Verwendung des gleichen Konzepts der Haupt

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

Ich habe es nur mit 2 Levels versucht (Haupt -> Ursache) und nicht mit mehr: / Wenn etwas nicht stimmt, bearbeiten Sie bitte die Funktion und schreiben Sie einen Kommentar: D.

habe eine schöne Codierung und auch einen schönen Tag: D.

Wichtig:

Dieser Code erhält manchmal eine Ausnahme, wenn "st" kein "\ n" oder ähnliches enthält (ich habe festgestellt, dass einige Arten von Stacktraces dieses Problem haben). Um dies zu lösen, müssen Sie vor der Codezeile eine Prüfung hinzufügen: "String r1 = ..."

Sie müssen überprüfen, ob "st" "\ n" enthält und ob die Start- und Endindizes von "stSequence" beide gültig sind.

Wie auch immer, ich schlage vor, dies in einen Try-Catch zu setzen und im Ausnahmefall eine leere Zeichenfolge zurückzugeben. (Es ist rekursiv, sodass die zurückgegebene leere Zeichenfolge mit der zuvor verarbeiteten Zeichenfolge verkettet wird.)

Z3R0
quelle