Android-logcat 메시지의 최대 길이 설정


101

기본적으로 logcat은 "너무 긴"것으로 간주되는 모든 로그 메시지를 자릅니다. 이것은 Eclipse 내부에서와를 사용하여 명령 줄에서 logcat을 실행할 때 발생하며 adb -d logcat중요한 디버깅 메시지가 잘립니다.

디버그 정보 자르기를 중지하도록 logcat에서 지원하는 최대 문자열 길이를 늘리는 방법이 있습니까? 공식 문서가 존재하지 않을 수 있음을 의미한다,하지만 어쩌면 지원 로그 캣 몇 가지 추가 옵션이 언급되지?





1
@JoshCorreia 나는 그것이 전체 버퍼 크기를 나타 내기 때문에 좋은 복제라고 생각하지 않으며 이것은 로그 메시지 당입니다.
Ryan M

1
@RyanM 아 아, 다른 질문을 오해했습니다. 감사합니다. 복제 표시를 제거했습니다.
Josh Correia

답변:


45

바이너리 로그 ( /dev/log/events)에 대한 logcat에는 고정 크기 버퍼가 있으며이 제한은 1024 바이트입니다. 바이너리가 아닌 로그의 경우에도 제한이 있습니다.

#define LOGGER_ENTRY_MAX_LEN        (4*1024)
#define LOGGER_ENTRY_MAX_PAYLOAD (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))

따라서 바이너리 및 비 바이너리 로그의 실제 메시지 크기는 ~ 4076 바이트입니다. 커널 로거 인터페이스는이 LOGGER_ENTRY_MAX_PAYLOAD제한을 부과합니다 .

liblog 소스 (logcat에서 사용)는 다음과 같이 말합니다.

  • 커널 로그 드라이버에 의해 메시지가 잘 렸을 수 있습니다.

logcat 바이너리를 사용하지 않는 nxlog 도구를 권장 하지만 커널의 제한으로 인해 문제가 해결 될 것 같지 않습니다. 그럼에도 불구하고 시도해 볼 가치가 있습니다. (면책 조항 : 저자입니다.)


6
어디에서 찾을 수 있습니까? "logcat"코드에 있습니까? 그렇다면 수정 된 logcat을 직접 컴파일해야합니까?
d4Rk

2
바이너리 / 비 바이너리 로그 란 무엇입니까?
fobbymaster

2
추가되는 메타 데이터 필드로 인해 LOGGER_ENTRY_MAX_PAYLOAD최신 버전의 Android에서 4076에서 4068로 축소되었습니다 ( 여기 참조 ).
mhsmith

87

좋아요, 흥미 롭군요. 대답이 "정말로 확장 할 수 없다"는 것을보고 실망했습니다. 나의 초기 생각은 모든 것을 볼 수 있도록 그것을 깨뜨리는 것이 었습니다. 그래서 여기에서 제가 어떻게하는지 여러분과 공유합니다.

if (sb.length() > 4000) {
    Log.v(TAG, "sb.length = " + sb.length());
    int chunkCount = sb.length() / 4000;     // integer division
    for (int i = 0; i <= chunkCount; i++) {
        int max = 4000 * (i + 1);
        if (max >= sb.length()) {
            Log.v(TAG, "chunk " + i + " of " + chunkCount + ":" + sb.substring(4000 * i));
        } else {
            Log.v(TAG, "chunk " + i + " of " + chunkCount + ":" + sb.substring(4000 * i, max));
        }
    }
} else {
    Log.v(TAG, sb.toString());
}

마지막 문자열을 표시하도록 편집되었습니다!


문제 없어요! 도움이 되었기를 바랍니다
Travis

나는 여기에 하나의 오류가 있다고 확신합니다. 마지막 청크를 얻기 위해 "i <chunkCount + 1"을 사용해야했습니다
Dan

2
마지막 문자열을 잃었습니다. int chunkCount = sb.length() / 4000;사용 int chunkCount = sb.length() / 4000; if (chunkCount * 4000 < sb.length()) chunkCount++;
Timur Gilfanov 2013

2
더하다 else { Log.v(TAG, sb); } 메시지가 <= 4000 개 긴 문자 인 경우에도 로그를 인쇄
보얀 Radivojevic 폭격기

4
이 대답은 ASCII가 아닌 문자에 대해서는 잘못되었습니다. logcat은 UTF8을 지원하며 제한은 문자가 아닌 4k 바이트 입니다.
miguel

58

반복적으로 여러 조각으로 나눕니다.

public static void largeLog(String tag, String content) {
   if (content.length() > 4000) {
       Log.d(tag, content.substring(0, 4000));
       largeLog(tag, content.substring(4000));
   } else {
       Log.d(tag, content);
   }
}

3
이것은 지금까지 가장 깨끗한 솔루션이며 실제로 프로덕션 코드에서 재귀를 실제로 사용한 것은 처음입니다.
Aggressor 2016-07-25

2
@Aggressor 프로덕션에서 4000 개 이상의 긴 메시지를 기록해야하는 이유는 무엇입니까?
TWiStErRob

1
내 사용 사례는 큰 json 물건을 출력하는 것입니다. 파일은 단순히 고통입니다.
Marcel Falliere 17.07.07

1
매우 유용합니다. 줄 끝에서 문자열을 끊는 답변을 게시했습니다.
dazed

1
굉장 간단하고 깨끗하고 시원하고 아름답습니다. 박수
Muhammad Ashfaq


5

내가 사용하는 코드는 다음과 같습니다. 4000 제한에서 줄을 자르고 줄 중간이 아닌 새 줄에서 줄을 끊습니다. 로그 파일을 더 쉽게 읽을 수 있습니다.

용법:

Logger.debugEntire("....");

이행:

package ...;

import android.util.Log;

import java.util.Arrays;

public class Logger {

    private static final String LOG_TAG = "MyRockingApp";

    /** @see <a href="http://stackoverflow.com/a/8899735" /> */
    private static final int ENTRY_MAX_LEN = 4000;

    /**
     * @param args If the last argument is an exception than it prints out the stack trace, and there should be no {}
     *             or %s placeholder for it.
     */
    public static void d(String message, Object... args) {
        log(Log.DEBUG, false, message, args);
    }

    /**
     * Display the entire message, showing multiple lines if there are over 4000 characters rather than truncating it.
     */
    public static void debugEntire(String message, Object... args) {
        log(Log.DEBUG, true, message, args);
    }

    public static void i(String message, Object... args) {
        log(Log.INFO, false, message, args);
    }

    public static void w(String message, Object... args) {
        log(Log.WARN, false, message, args);
    }

    public static void e(String message, Object... args) {
        log(Log.ERROR, false, message, args);
    }

    private static void log(int priority, boolean ignoreLimit, String message, Object... args) {
        String print;
        if (args != null && args.length > 0 && args[args.length-1] instanceof Throwable) {
            Object[] truncated = Arrays.copyOf(args, args.length -1);
            Throwable ex = (Throwable) args[args.length-1];
            print = formatMessage(message, truncated) + '\n' + android.util.Log.getStackTraceString(ex);
        } else {
            print = formatMessage(message, args);
        }
        if (ignoreLimit) {
            while (!print.isEmpty()) {
                int lastNewLine = print.lastIndexOf('\n', ENTRY_MAX_LEN);
                int nextEnd = lastNewLine != -1 ? lastNewLine : Math.min(ENTRY_MAX_LEN, print.length());
                String next = print.substring(0, nextEnd /*exclusive*/);
                android.util.Log.println(priority, LOG_TAG, next);
                if (lastNewLine != -1) {
                    // Don't print out the \n twice.
                    print = print.substring(nextEnd+1);
                } else {
                    print = print.substring(nextEnd);
                }
            }
        } else {
            android.util.Log.println(priority, LOG_TAG, print);
        }
    }

    private static String formatMessage(String message, Object... args) {
        String formatted;
        try {
            /*
             * {} is used by SLF4J so keep it compatible with that as it's easy to forget to use %s when you are
             * switching back and forth between server and client code.
             */
            formatted = String.format(message.replaceAll("\\{\\}", "%s"), args);
        } catch (Exception ex) {
            formatted = message + Arrays.toString(args);
        }
        return formatted;
    }
}

4

아래 코드는 Mark Buikema가 게시 한 내용을 수정 한 것입니다. 새 줄에서 문자열을 끊습니다. 긴 JSON 문자열을 로깅하는 데 유용합니다.

  public static void dLong(String theMsg)
  {
    final int MAX_INDEX = 4000;
    final int MIN_INDEX = 3000;

    // String to be logged is longer than the max...
    if (theMsg.length() > MAX_INDEX)
    {
      String theSubstring = theMsg.substring(0, MAX_INDEX);
      int    theIndex = MAX_INDEX;

      // Try to find a substring break at a line end.
      theIndex = theSubstring.lastIndexOf('\n');
      if (theIndex >= MIN_INDEX)
      {
        theSubstring = theSubstring.substring(0, theIndex);
      }
      else
      {
        theIndex = MAX_INDEX;
      }

      // Log the substring.
      Log.d(APP_LOG_TAG, theSubstring);

      // Recursively log the remainder.
      dLong(theMsg.substring(theIndex));
    }

    // String to be logged is shorter than the max...
    else
    {
      Log.d(APP_LOG_TAG, theMsg);
    }
  }

3
int i = 3000;
while (sb.length() > i) {
    Log.e(TAG, "Substring: "+ sb.substring(0, i));
    sb = sb.substring(i);
}
Log.e(TAG, "Substring: "+ sb);

2

이 페이징 로직

    /*
     * StringBuffer sb - long text which want to show in multiple lines 
     * int lenth - lenth of line need
     */

public static void showInPage(StringBuffer sb, int lenth) {
    System.out.println("sb.length = " + sb.length());
    if (sb.length() > lenth) {

        int chunkCount = sb.length() / lenth; // integer division
        if ((chunkCount % lenth) > 1)
            chunkCount++;
        for (int i = 0; i < chunkCount; i++) {
            int max = lenth * (i + 1);
            if (max >= sb.length()) {
                System.out.println("");
                System.out.println("chunk " + i + " of " + chunkCount + ":"
                        + sb.substring(lenth * i));
            } else {
                System.out.println("");
                System.out.println("chunk " + i + " of " + chunkCount + ":"
                        + sb.substring(lenth * i, max));
            }
        }
    }

}

1

Travis의 솔루션에 대한 저만의 의견을 제공하고

void d(String msg) {
  println(Log.DEBUG, msg);
}

private void println(int priority, String msg) {
    int l = msg.length();
    int c = Log.println(priority, TAG, msg);
    if (c < l) {
        return c + println(priority, TAG, msg.substring(c+1));
    } else {
        return c;
    }
}

Log.println()"4000"하드 코딩을 피하기 위해 쓰여진 바이트 수 를 반환 한다는 사실을 이용하십시오 . 그런 다음 아무것도 남지 않을 때까지 기록 할 수없는 메시지 부분에서 자신을 재귀 적으로 호출합니다.


불행히도 println은 쓰여진 바이트 수와 문자! = 바이트를 반환합니다.
gnuf

1
음, 작동합니다. 나는 ASCII 텍스트 만 로깅하기 때문에 가정합니다.
Jeffrey Blattman 2013 년

1

로그가 매우 긴 경우 (예 : 디버깅 이유로 데이터베이스의 전체 덤프 로깅 등) logcat이 과도한 로깅을 방지 할 수 있습니다. 이 문제를 해결하기 위해 x 밀리 초에 시간 초과를 추가 할 수 있습니다.

/**
 * Used for very long messages, splits it into equal chunks and logs each individual to
 * work around the logcat max message length. Will log with {@link Log#d(String, String)}.
 *
 * @param tag     used in for logcat
 * @param message long message to log
 */
public static void longLogDebug(final String tag, @NonNull String message) {
    int i = 0;

    final int maxLogLength = 1000;
    while (message.length() > maxLogLength) {
        Log.d(tag, message.substring(0, maxLogLength));
        message = message.substring(maxLogLength);
        i++;

        if (i % 100 == 0) {
            StrictMode.noteSlowCall("wait to flush logcat");
            SystemClock.sleep(32);
        }
    }
    Log.d(tag, message);
}

주 스레드 차단을 중지 할 수 있으므로 디버깅 목적으로 만 사용하십시오.


1

@mhsmith가 언급했듯이 LOGGER_ENTRY_MAX_PAYLOAD최신 Android 버전에서는 4068입니다. 그러나 다른 답변에서 제공되는 코드 조각에서 최대 메시지 길이로 4068을 사용하면 메시지가 잘립니다. Android가 메시지의 시작과 끝에 더 많은 문자를 추가하기 때문입니다. 다른 답변은 4000 제한을 해결 방법으로 사용합니다. 그러나이 코드로 전체 제한을 실제로 사용할 수 있습니다 (코드는 스택 추적에서 태그를 생성하여 로그를 호출 한 클래스 이름과 줄 번호를 표시하므로 자유롭게 수정할 수 있습니다).

private static final int MAX_MESSAGE_LENGTH = 4068;

private enum LogType {
    debug,
    info,
    warning,
    error
}

private static void logMessage(LogType logType, @Nullable String message, @Nullable String tag) {
    logMessage(logType, message, tag, Thread.currentThread().getStackTrace()[4]);
}

private static void logMessage(LogType logType, @Nullable String message, @Nullable String customTag, StackTraceElement stackTraceElement) {
    // don't use expensive String.format
    String tag = "DASHBOARDS(" + stackTraceElement.getFileName() + "." + (!TextUtils.isEmpty(customTag) ? customTag : stackTraceElement.getMethodName()) + ":" + stackTraceElement.getLineNumber() + ")";
    int maxMessageLength = MAX_MESSAGE_LENGTH - (tag.length()) - 4; // minus four because android adds a letter showing the log type before the tag, e. g. "D/" for debug, and a colon and space are added behind it, i. e. ": "
    if (message == null || message.length() <= maxMessageLength) {
        logMessageInternal(logType, message, tag);
    } else {
        maxMessageLength -= 8; // we will add counter to the beginning of the message, e. g. "(12/15) "
        int totalChunks = (int) Math.ceil((float) message.length() / maxMessageLength);
        for (int i = 1; i <= totalChunks; i++) {
            int start = (i - 1) * maxMessageLength;
            logMessageInternal(logType, "(" + i + "/" + totalChunks + ") " + message.substring(start, Math.min(start + maxMessageLength, message.length())), tag);
        }
    }
}

private static void logMessageInternal(LogType logType, String message, String tag) {
    if (message == null) {
        message = "message is null";
    }
    switch (logType) {
        case debug:
            Log.d(tag, message);
            break;
        case info:
            Log.i(tag, message);
            break;
        case warning:
            Log.w(tag, message);
            break;
        case error:
            Log.e(tag, message);
    }
}

public static void d(String debug, String tag) {
    logMessage(LogType.debug, debug, tag);
}

0

logcat의 길이를 늘릴 수있는 옵션이 없지만, 메인 로그, 이벤트 로그 등과 같은 다른 로그를 찾을 수 있습니다. 메인 로그에는 일반적으로 길이가 4Mb에 이르는 모든 것이 포함되어 있습니다. 따라서 잃어버린 것을 얻을 수 있습니다. 로그 터미널에서. 경로는 \ data \ logger입니다.


0

제공된 다른 솔루션이 도움이되었지만 로그가 @ b0ti에서 언급 한 LOGGER_ENTRY_MAX_LEN보다 두 배 이상 긴 경우를 다루지 않았기 때문에 만족하지 못했습니다. 또한 LOGGER_ENTRY_MAX_LEN이 동적으로 가져 오지 않기 때문에 내 다음 솔루션조차 완벽하지 않습니다. 누군가 이것을하는 방법을 알고 있다면 댓글에서 그것에 대해 듣고 싶습니다! 어쨌든 이것은 지금 내 코드에서 사용하는 솔루션입니다.

final int loggerEntryMaxLength = 4000;
int logLength = loggerEntryMaxLength - 2 - TAG.length();
int i = 0;
while (output.length() / logLength > i) {
    int startIndex = i++ * logLength;
    int endIndex = i * logLength;
    Log.d(TAG, output.substring(startIndex, endIndex));
}
int startIndex = i * logLength;
Log.d(
        TAG,
        output.substring(
                startIndex,
                startIndex + (output.length() % logLength)
        )
);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.