Java / Android-전체 스택 추적을 인쇄하는 방법은 무엇입니까?


125

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 2014

답변:


119

모두의 무시있다 로그 방법(String tag, String msg, Throwable tr)서명.

세 번째 매개 변수 로 예외를 전달하면 logcat에서 전체 스택 추적을 제공해야합니다.


5
참고로 3 인수 로그 메서드는 getStackTraceString()뒤에서 @Thomas가 언급 한 메서드를 사용합니다 .
Philipp Reichart

6
저는 2 년 동안 Android를 개발해 왔지만이 사실을 알아 차리지 못했습니다. 대단히 감사합니다.
Anh Tuan 2011

소스 코드를 보면 @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에 표시되지 않습니까? 의 일부가 아니 Throwable거나 Exception....
Jake Wilson

9
끝에있는 "... 6 more"는 정보를 자르지 않습니다. 스택 추적의 나머지 부분은 최상위 예외와 동일하다는 것을 알려줍니다. 첫 번째 예외에서 마지막 6 줄을보십시오.
Tomasz

아마도 로깅 라이브러리를 가져와야 할 것입니다 (사용 import android.util.Log;).
Dan

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()스택 추적을 기록하지 않고 문자열로 반환합니다. 위의 코드는 아무것도 기록하지 않으며 경우도 NPE와 함께 실패 할 것 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

이것을 사용할 수 있습니다 :

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 ()"가 일부 행이 반복되고 새 행이있는 새 예외 메시지를 리턴하기 때문입니다. 그래서 개념은 : 만약 "원인"이 있다면 주 throwable에 "n more .."가있는 줄이 있으므로 "n more .."가있는 줄 앞에 마지막 줄이 표시되면 원인 메시지를 받고 마지막으로 나는 마지막 반복 된 줄 (둘 다에 나타나는 마지막 줄 : 주 throwable 및 원인 throwable) 다음 부분 만 가져 오는 원인 메시지를 하위 문자열로 지정합니다.

그런 다음 원인 메시지를받을 때 재귀를 사용하므로 동일한 함수를 다시 호출하여 기본 throwable에서 원인 메시지를 가져 오면 이미 대체 된 메시지가 표시됩니다. 주 throwable에서 throwable 원인이 다른 원인도 있으므로 주 throwable에 3 단계 (main-> cause-> cause-of-cause)가있는 경우 주 throwable에서 "cause message"가 이미 교체 된 메시지를 받게됩니다. (주요의 동일한 개념 사용

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.