Java / Android - Como imprimir um rastreamento de pilha completa?


124

No Android (Java), como imprimo um rastreamento de pilha completa? Se meu aplicativo travar com nullPointerException ou algo assim, ele imprimirá um (quase) rastreamento de pilha completa da seguinte maneira:

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

No entanto, às vezes, para fins de depuração, quero registrar um rastreamento de pilha completo de onde estou no código. Imaginei que poderia fazer isso:

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

Mas isso apenas imprime o ponteiro para o objeto ... Preciso percorrer todos os elementos de rastreamento da pilha para imprimi-los? Ou existe um método simples para imprimir tudo?


1
Você pode usar esse método Thread.currentThread (). GetStackTrace () stackoverflow.com/questions/1069066/…
user2024270

Respostas:


119

Há substituições de todos os métodos de log por (String tag, String msg, Throwable tr)assinaturas.

Passar uma exceção como terceiro parâmetro deve fornecer o rastreamento de pilha completo no logcat.


5
Para sua informação, os métodos de log de três argumentos usam o getStackTraceString()método mencionado por @Thomas nos bastidores.
Philipp Reichart

6
Eu desenvolvi o Android por dois anos e nunca notei isso antes. Muito obrigado.
Anh Tuan #

Olhando para o código fonte, sim, você está certo @PhilippReichart. Aqui está o código para Log.d em AOSP 4.2.2_r1
Ehtesh Choudhury

152

O seguinte deve fazer o truque:

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

Observe que, ...x moreno final , não remove nenhuma informação do rastreamento de pilha:

(Isso indica) que o restante do rastreamento de pilha para esta exceção corresponde ao número indicado de quadros da parte inferior do rastreamento de pilha da exceção que foi causada por essa exceção (a exceção "anexa").

... ou em outras palavras, substitua x morepelas últimas xlinhas da primeira exceção.


1
De onde é getStackTraceString()? Não aparece no Eclipse? Não é parte de Throwableou Exception....
Jake Wilson

9
"... mais 6" no final não está cortando nenhuma informação. Está dizendo a você que o restante do rastreamento de pilha é o mesmo da exceção principal. Basta olhar para as últimas 6 linhas da primeira exceção.
Tomasz

Você provavelmente precisaria importar a biblioteca de log (usando import android.util.Log;).
Dan

10

Use Log.getStackTraceString (Throwable t). Você pode obter rastreamentos de pilha mais longos cavando mais fundo. Por exemplo:

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


Log.getStackTraceString()não registra o rastreamento de pilha, apenas o retorna como String. O código acima não registrará nada e também falhará com um NPE, se e.getCause()houver null.
precisa

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

Você pode usar isto:

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

Você também pode imprimir um rastreamento de pilha em qualquer ponto do código do aplicativo usando métodos como Thread.dumpStack()

Por favor, acesse o link para mais detalhes


2

Você precisa usar o Throwable Object para obter o 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


0

Eu rapidamente fiz agora uma função recursiva que iterará o throwable e throwable.getCause ().

Isso ocorre porque todo "throwable.getCause ()" retorna para você uma nova mensagem de exceção com algumas linhas repetidas e novas. Portanto, o conceito é: se existe uma "causa", há uma linha com "n mais .." na tela principal de lançamento, para que eu obtenha a última linha antes da linha com "n mais ..", então recebo a mensagem de causa e finalmente, eu substring a mensagem de causa, obtendo apenas a parte após a última linha repetida (a última linha que aparece em ambos: o lançamento principal e o lançamento da causa).

Então eu uso a recursão quando recebo a mensagem de causa, e, ao chamar novamente a mesma função para obter a mensagem de causa do principal lançável, receberei uma mensagem já substituída. Se a causa jogável da lança principal também tiver outra causa, a bola principal terá 3 níveis (principal -> causa -> causa-causa), na bola principal que eu receberei a mensagem "causa" já será substituída (usando o mesmo conceito do 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 "";
}

Eu tentei apenas com 2 níveis (principal -> causa) e não com mais: / Se houver algo errado, edite a função e escreva um comentário: D

tenha uma boa codificação e um bom dia também: D

Importante:

Às vezes, esse código recebe uma exceção se o "st" não contém "\ n" ou semelhante (eu encontrei algum tipo de exceção no stacktraces com esse problema). Para resolver isso, é necessário adicionar uma verificação antes da linha de código: "String r1 = ..."

Você precisa verificar: "st" contém "\ n" e se os índices de início e fim de "st.subSequence" são válidos.

De qualquer forma, sugiro colocar isso dentro de um try-catch e retornar uma string vazia em caso de exceção. (É recursiva, a sequência vazia retornada será concatenada com a sequência processada anterior).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.