Java / Android - Comment imprimer une trace de pile complète?

125

Sous Android (Java), comment imprimer une trace de pile complète? Si mon application se bloque à partir de nullPointerException ou de quelque chose, elle imprime une trace de pile (presque) complète comme ceci:

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

Cependant, parfois, à des fins de débogage, je souhaite enregistrer une trace de pile complète d'où je suis dans le code. J'ai pensé que je pouvais simplement faire ceci:

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

Mais cela imprime juste le pointeur vers l'objet ... Dois-je parcourir tous les éléments traces de la pile pour les imprimer? Ou existe-t-il une méthode simple pour tout imprimer?

Jake Wilson
la source
1
Vous pouvez utiliser cette méthode Thread.currentThread (). GetStackTrace () stackoverflow.com/questions/1069066/…
user2024270
1
Copie
TT

Réponses:

119

Il y a des remplacements de toutes les méthodes de journal avec des (String tag, String msg, Throwable tr)signatures.

Passer une exception comme troisième paramètre devrait vous donner le stacktrace complet dans logcat.

Philipp Reichart
la source
5
Pour info, les méthodes de journalisation à trois arguments utilisent la getStackTraceString()méthode mentionnée par @Thomas dans les coulisses.
Philipp Reichart
6
J'ai développé Android pendant deux ans et je n'ai jamais remarqué cela auparavant. Merci beaucoup.
Anh Tuan
En regardant le code source, vous avez raison @PhilippReichart. Voici le code pour Log.d sur AOSP 4.2.2_r1
Ehtesh Choudhury
152

Ce qui suit devrait faire l'affaire:

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

Notez qu'à ...x morela fin ne coupe aucune information de la trace de la pile:

(Cela indique) que le reste de la trace de pile pour cette exception correspond au nombre de trames indiqué à partir du bas de la trace de pile de l'exception qui a été provoquée par cette exception (l'exception «englobante»).

... ou en d'autres termes, remplacer x morepar les dernières xlignes de la première exception.

Michael Berry
la source
1
D'où vient getStackTraceString()? N'apparaît pas dans Eclipse? Cela ne fait pas partie de Throwableou Exception....
Jake Wilson
9
"... 6 de plus" à la fin ne coupe aucune information. Il vous dit que le reste de la trace de pile est le même que pour l'exception supérieure. Regardez simplement les 6 dernières lignes de la première exception.
Tomasz
Vous devrez probablement importer la bibliothèque de journalisation (en utilisant import android.util.Log;).
Dan
10

Utilisez Log.getStackTraceString (Throwable t). Vous pouvez obtenir des traces de pile plus longues en creusant plus profondément. Par exemple:

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

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

Thomas
la source
Log.getStackTraceString()ne consigne pas la trace de la pile, il la renvoie simplement sous forme de chaîne. Le code ci-dessus ne consignera rien et échouera également avec un NPE si e.getCause()c'est le cas 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
la source
6

Vous pouvez utiliser ceci:

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
la source
4

Vous pouvez également imprimer une trace de pile à tout moment dans le code de votre application à l'aide de méthodes telles que Thread.dumpStack()

Veuillez parcourir le lien pour plus de détails

ajaykoppisetty
la source
2

Vous devez utiliser Throwable Object pour obtenir le stackTrace complet.

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

Réf: https://stackoverflow.com/a/18546861

Houssin Boulla
la source
0

J'ai rapidement fait une fonction récursive qui itérera le throwable et throwable.getCause ().

C'est parce que chaque "throwable.getCause ()" vous renvoie un nouveau message d'exception avec quelques lignes répétées et de nouvelles lignes. Donc, le concept est: s'il y a une "cause", il y a une ligne avec "n plus .." sur le jetable principal donc j'obtiens la dernière ligne avant celle avec "n plus .." alors j'obtiens le message de cause et enfin, je sous-chaîne le message de cause ne récupérant que la partie après la dernière ligne répétée (la dernière ligne qui apparaît sur les deux: le jetable principal et le jetable de cause).

Ensuite, j'utilise la récursivité lorsque j'obtiens le message de cause, donc en réappelant la même fonction pour obtenir le message de cause du jetable principal, j'obtiendrai un message déjà remplacé. Si la cause jetable du jetable principal a également une autre cause, donc le jetable principal a 3 niveaux (main -> cause -> cause-of-cause), sur le jetable principal, j'obtiendrai un message de cause, un message déjà remplacé (en utilisant le même concept de la principale

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

Je l'ai essayé uniquement avec 2 niveaux (principal -> cause) et pas avec plus: / S'il y a quelque chose qui ne va pas, veuillez modifier la fonction et écrire un commentaire: D

bonne programmation et bonne journée aussi: D

Important:

Ce code obtient parfois une exception si le "st" ne contient pas "\ n" ou similaire (j'ai trouvé que certaines sortes d'exceptions stacktraces ont ce problème). Pour résoudre ce problème, vous devez ajouter une vérification avant la ligne de code: "String r1 = ..."

Vous devez vérifier: "st" contient "\ n" et que les index de début et de fin de "st.subSequence" sont tous les deux valides.

Quoi qu'il en soit, je suggère de mettre cela dans un try-catch et de retourner une chaîne vide en cas d'exception. (Il est récursif donc la chaîne vide renvoyée sera concaténée à la chaîne traitée précédente).

Z3R0
la source