Java / Android-完全なスタックトレースを出力する方法


124

Android(Java)で完全なスタックトレースを出力するにはどうすればよいですか?アプリケーションがnullPointerExceptionまたは何かからクラッシュした場合、次のように(ほぼ)完全なスタックトレースが出力されます。

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

ただし、デバッグの目的で、コードのどこにいるかからの完全なスタックトレースをログに記録したい場合があります。私はこれを行うことができると思った:

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

しかし、これはオブジェクトへのポインタを出力するだけです...それらを出力するためにすべてのスタックトレース要素を反復処理する必要がありますか?それともすべてを印刷する簡単な方法はありますか?


1
。あなたはこの方法にThread.currentThread()getStackTraceメソッド()を使用することができますstackoverflow.com/questions/1069066/...
user2024270

回答:


119

署名付きのすべてのログメソッドのオーバーライドがあります(String tag, String msg, Throwable tr)

3番目のパラメーターとして例外を渡すと、logcatの完全なスタックトレースが得られます。


5
参考までに、3つの引数を持つログメソッドは、getStackTraceString()@ Thomasが舞台裏で述べたメソッドを使用しています。
Philipp Reichart、2011年

6
私は2年間Androidを開発してきましたが、これに気づいたことはありません。どうもありがとうございました。
Anh Tuan

ソースコードを見て、うん、あなたは正しい@PhilippReichart。AOSP 4.2.2_r1のLog.dのコードは次のとおりです
Ehtesh Choudhury

152

次の方法でうまくいくはずです。

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

...x more最後に、スタックトレースから情報を切り取らないことに注意してください

(これは、この例外のスタックトレースの残りの部分が、この例外によって引き起こされた例外(「囲んでいる」例外)のスタックトレースの最下部から指定されたフレーム数と一致することを示します)。

...または言い換えると、最初の例外のx more最後のx行で置き換えます。


1
どこgetStackTraceString()から来たの?Eclipseに表示されませんか?それはの一部ではないのですThrowableException....
ジェイク・ウィルソン

9
最後の "... 6 more"は情報を切り取っていません。スタックトレースの残りの部分は、最初の例外の場合と同じであることがわかります。最初の例外から最後の6行を見てください。
Tomasz

おそらく、(を使用してimport android.util.Log;)ロギングライブラリをインポートする必要があります。
ダン

10

Log.getStackTraceString(Throwable t)を使用します。より深く掘ることで、より長いスタックトレースを取得できます。例えば:

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

http://developer.android.com/reference/android/util/Log.html#getStackTraceString%28java.lang.Throwable%29から取得


Log.getStackTraceString()スタックトレースをログに記録せず、文字列として返すだけです。上記のコードは何もログに記録せず、である場合e.getCause()はNPEでも失敗し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

あなたはこれを使うかもしれません:

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


2

完全なstackTraceを取得するには、Throwable Objectを使用する必要があります。

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

参照:https : //stackoverflow.com/a/18546861


0

throwableとthrowable.getCause()を反復する再帰関数をすばやく実行しました。

これは、すべての "throwable.getCause()"が、いくつかの行が繰り返された新しい例外メッセージと新しい行を返すためです。したがって、コンセプトは、「原因」がある場合、メインのスロー可能オブジェクトに「n more ..」の行があるため、「n more ..」のある行の前の最後の行を取得し、原因メッセージを取得して、最後に、原因メッセージをサブストリング化して、最後に繰り返された行(メインのスロー可能オブジェクトと原因スロー可能オブジェクトの両方に表示される最後の行)の後の部分のみを取得します。

その後、原因メッセージを取得するときに再帰を使用します。そのため、同じ関数を再度呼び出して、メインのスロー可能オブジェクトから原因メッセージを取得すると、既に置き換えられたメッセージが表示されます。メインスローアブルからスロー可能な原因にも別の原因がある場合、メインスローアブルに3つのレベル(メイン->原因->原因の原因)がある場合、メインスローアブルで「原因メッセージ」が既に置き換えられているメッセージが表示されます。 (メインの同じ概念を使用して

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

私は2レベル(メイン->原因)ではなくそれ以上でそれを試しました:/何か問題がある場合は関数を編集してコメントを書いてください:D

素敵なコーディングと素敵な一日も:D

重要:

「st」に「\ n」などが含まれていない場合、このコードで例外が発生することがあります(スタックトレースにある種の例外にこの問題があることがわかりました)。これを解決するには、コード行の前にチェックを追加する必要があります: "String r1 = ..."

「st」に「\ n」が含まれており、「st.subSequence」の開始インデックスと終了インデックスがどちらも有効であることを確認する必要があります。

とにかく、これをtry-catchの中に入れて、例外が発生した場合は空の文字列を返すことをお勧めします。(再帰的であるため、返された空の文字列は、前に処理された文字列に連結されます)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.