Java / Android: ¿cómo imprimir un seguimiento de pila completa?

124

En Android (Java), ¿cómo imprimo una traza de pila completa? Si mi aplicación se bloquea desde nullPointerException o algo así, imprime un seguimiento (casi) completo de la pila de esta manera:

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

Sin embargo, a veces, para fines de depuración, quiero registrar un seguimiento completo de la pila desde donde estoy en el código. Pensé que podría hacer esto:

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

Pero esto solo imprime el puntero al objeto ... ¿Tengo que recorrer en iteración todos los elementos traza de la pila para imprimirlos? ¿O hay un método simple para imprimirlo todo?

Jake Wilson
fuente
1
Puede usar este método Thread.currentThread (). GetStackTrace () stackoverflow.com/questions/1069066/…
user2024270
1
Posible duplicado de Android: imprima el
rastreo de

Respuestas:

119

Hay anulaciones de todos los métodos de registro con (String tag, String msg, Throwable tr)firmas.

Pasar una excepción como el tercer parámetro debería darle el seguimiento completo de la pila en logcat.

Philipp Reichart
fuente
55
Para su información, los métodos de registro de tres argumentos utilizan el getStackTraceString()método mencionado por @Thomas detrás de escena.
Philipp Reichart
66
He desarrollado Android durante dos años y nunca antes me había dado cuenta. Muchas gracias.
Anh Tuan
Mirando el código fuente, sí tienes razón @PhilippReichart. Aquí está el código para Log.d en AOSP 4.2.2_r1
Ehtesh Choudhury
152

Lo siguiente debería hacer el truco:

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

Tenga ...x moreen cuenta que al final no corta ninguna información del seguimiento de la pila:

(Esto indica) que el resto de la traza de la pila para esta excepción coincide con el número indicado de fotogramas desde la parte inferior de la traza de la pila de la excepción causada por esta excepción (la excepción "adjunta").

... o en otras palabras, reemplace x morecon las últimas xlíneas de la primera excepción.

Michael Berry
fuente
1
¿Dónde está getStackTraceString()desde? ¿No aparece en Eclipse? No es parte de Throwableo Exception....
Jake Wilson
9
"... 6 más" al final no está cortando ninguna información. Le está diciendo que el resto del seguimiento de la pila es el mismo que para la excepción superior. Solo mire las últimas 6 líneas de la primera excepción.
Tomasz
Probablemente necesite importar la biblioteca de registro (usando import android.util.Log;).
Dan
10

Utilice Log.getStackTraceString (Throwable t). Puede obtener rastros de pila más largos al cavar más profundo. Por ejemplo:

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

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

Thomas
fuente
Log.getStackTraceString()no registra el seguimiento de la pila, solo lo devuelve como String. El código anterior no registrará nada y también fallará con un NPE si e.getCause()es así 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
fuente
6

Puedes usar esto:

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
fuente
4

También puede imprimir un seguimiento de la pila en cualquier punto del código de su aplicación utilizando métodos como Thread.dumpStack()

Visite el enlace para más detalles.

ajaykoppisetty
fuente
2

Necesita usar Throwable Object para obtener el stackTrace completo.

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
fuente
0

Rápidamente hice una función recursiva que iterará el throwable y throwable.getCause ().

Esto se debe a que cada "throwable.getCause ()" le devuelve un nuevo mensaje de excepción con algunas líneas repetidas y nuevas. Entonces, el concepto es: si hay una "causa", hay una línea con "n more .." en la línea principal, así que obtengo la última línea antes de la que tiene "n more ..", entonces recibo el mensaje de causa y finalmente subcadena el mensaje de causa obteniendo solo la parte después de la última línea repetida (la última línea que aparece en ambas: la principal arrojable y la causa arrojable).

Luego uso la recursividad cuando recibo el mensaje de causa, por lo que al volver a llamar a la misma función para obtener el mensaje de causa del elemento principal, obtendré un mensaje ya reemplazado. Si la causa que se puede lanzar desde el principal también tiene otra causa, entonces el principal que se puede lanzar tiene 3 niveles (principal -> causa -> causa de causa), en el principal que se arroja se obtiene un "mensaje de causa", un mensaje ya reemplazado (usando el mismo concepto de principal

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

Lo probé solo con 2 niveles (principal -> causa) y no con más: / Si hay algún problema, edite la función y escriba un comentario: D

que tengas una buena codificación y un buen día también: D

Importante:

Este código a veces recibe una excepción si el "st" no contiene "\ n" o similar (encontré algún tipo de excepciones stacktraces tienen este problema). Para resolver esto, debe agregar alguna comprobación antes de la fila de código: "String r1 = ..."

Debe comprobar: "st" contiene "\ n" y que los índices de inicio y fin de "st.subSequence" son válidos.

De todos modos, sugiero poner esto dentro de un try-catch y devolver una cadena vacía en caso de excepción. (Es recursivo, por lo que la cadena vacía devuelta se concatenará con la cadena procesada anterior).

Z3R0
fuente