Java / Android - Come stampare una traccia dello stack completo?


124

In Android (Java) come stampare una traccia dello stack completo? Se la mia applicazione si arresta in modo anomalo da nullPointerException o qualcosa del genere, stampa una traccia dello stack (quasi) completa in questo modo:

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

Tuttavia a volte, per scopi di debug, voglio registrare una traccia dello stack completo da dove mi trovo nel codice. Ho pensato di poter fare solo questo:

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

Ma questo stampa semplicemente il puntatore all'oggetto ... Devo scorrere tutti gli elementi di traccia dello stack per stamparli? Oppure esiste un metodo semplice per stampare tutto?


1
È possibile utilizzare questo metodo Thread.currentThread () getStackTrace (). Stackoverflow.com/questions/1069066/...
user2024270

Risposte:


119

Esistono sostituzioni di tutti i metodi di registro con (String tag, String msg, Throwable tr)firme.

Il passaggio di un'eccezione come terzo parametro dovrebbe fornire lo stacktrace completo in logcat.


5
Cordiali saluti i metodi di registro a tre argomenti utilizzano il getStackTraceString()metodo menzionato da @Thomas dietro le quinte.
Philipp Reichart,

6
Ho sviluppato Android per due anni e non l'avevo mai notato prima. Grazie mille.
Anh Tuan,

Guardando il codice sorgente, sì hai ragione @PhilippReichart. Ecco il codice per Log.d su AOSP 4.2.2_r1
Ehtesh Choudhury

152

Quanto segue dovrebbe fare il trucco:

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

Si noti che ...x morealla fine non taglia alcuna informazione dalla traccia dello stack:

(Ciò indica) che il resto della traccia dello stack per questa eccezione corrisponde al numero indicato di frame dalla parte inferiore della traccia dello stack dell'eccezione causata da questa eccezione (l'eccezione "racchiusa").

... o in altre parole, sostituisci x morecon le ultime xrighe della prima eccezione.


1
Dove è getStackTraceString()da? Non compare in Eclipse? Non fa parte di Throwableo Exception...
Jake Wilson,

9
"... 6 more" alla fine non interrompe alcuna informazione. Ti sta dicendo che il resto della traccia dello stack è lo stesso che era per l'eccezione principale. Guarda le ultime 6 righe della prima eccezione.
Tomasz,

Probabilmente dovrai importare la libreria di registrazione (usando import android.util.Log;).
Dan,

10

Utilizzare Log.getStackTraceString (Throwable t). Puoi ottenere tracce di stack più lunghe scavando più a fondo. Per esempio:

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

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


Log.getStackTraceString()non registra la traccia dello stack ma la restituisce semplicemente come stringa. Il codice sopra riportato non registra nulla e fallisce anche con un NPE se lo e.getCause()è 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()));

6

Puoi usare questo:

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

Puoi anche stampare una traccia dello stack in qualsiasi punto del codice dell'app usando metodi come Thread.dumpStack()

Si prega di passare attraverso il link per maggiori dettagli


2

È necessario utilizzare Throwable Object per ottenere l'intero 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();
}

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


0

Ho subito fatto una funzione ricorsiva che ripeterà il lancio e il lancio.getCause ().

Questo perché ogni "throwable.getCause ()" restituisce un nuovo messaggio di eccezione con alcune righe ripetute e nuove righe. Quindi il concetto è: se c'è una "causa" c'è una linea con "n più .." sul lancio principale quindi ottengo l'ultima riga prima di quella con "n più .." quindi ricevo il messaggio di causa e infine, sottostringo il messaggio di causa ottenendo solo la parte dopo l'ultima riga ripetuta (l'ultima riga che appare su entrambi: il lancio principale e il lancio della causa).

Quindi utilizzo la ricorsione quando ricevo il messaggio di causa, quindi richiamando la stessa funzione per ottenere il messaggio di causa dal lancio principale riceverò un messaggio già sostituito. Se la causa gettabile dal lancio principale ha anche un'altra causa, quindi il lancio principale ha 3 livelli (principale -> causa -> causa-causa), sul lancio principale avrò "messaggio di causa" un messaggio già sostituito (usando lo stesso concetto di 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 "";
}

L'ho provato solo con 2 livelli (principale -> causa) e non con altro: / Se c'è qualcosa di sbagliato, modifica la funzione e scrivi un commento: D

buona programmazione e buona giornata: D

Importante:

Questo codice a volte ottiene un'eccezione se la "st" non contiene "\ n" o simili (ho riscontrato che un qualche tipo di eccezioni stacktraces presenta questo problema). Per risolvere questo problema è necessario aggiungere un controllo prima della riga di codice: "String r1 = ..."

È necessario verificare: "st" contiene "\ n" e che gli indici di inizio e fine di "st.subSequence" sono entrambi validi.

In ogni caso, suggerisco di inserirlo in un try-catch e di restituire una stringa vuota in caso di eccezione. (È ricorsivo, quindi la stringa vuota restituita verrà concatenata alla stringa elaborata precedente).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.