Android - установить максимальную длину сообщений logcat

По умолчанию кажется, что logcat усекает любое сообщение журнала, которое считается слишком длинным. Это происходит как внутри Eclipse, так и при запуске logcat в командной строке с использованием adb -d logcat и обрезает некоторые важные сообщения для отладки.

Есть ли способ увеличить максимальную длину строки, поддерживаемую logcat, чтобы остановить ее отключение отладки? Официальная документация подразумевает, что ее может не быть, но, возможно, logcat поддерживает некоторые дополнительные опции, не упомянутые там?

Ответ 1

В двоичных журналах (/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) также говорят:

  • Сообщение могло быть усечено драйвером журнала ядра.

Я бы порекомендовал вам инструмент nxlog, который не использует двоичный файл logcat, но из-за ограничений в ядре я сомневаюсь, что он решит вашу проблему, Тем не менее, возможно, стоит попробовать. (отказ от ответственности: я автор.)

Ответ 2

Хорошо, интересно. Я был разочарован, увидев, что ответ был "вы не можете его расширить". Моя первоначальная мысль заключалась в том, чтобы разбить его, чтобы я мог рассмотреть все это, поэтому здесь я разделяю с вами, как я это делаю (не то, чтобы это ничем не показалось, и это не эффективно, но это делает работу в крайнем случае):

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

Отредактировано, чтобы показать последнюю строку!

Ответ 3

Разбить его на несколько частей рекурсивно.

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

Ответ 4

for( String line : logMesg.split("\n") ) {
    Log.d( TAG, line );
}

Ответ 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 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;
    }
}

Ответ 6

Код ниже является уточнением того, что написал Марк Буйкема. Это разрывает строку в новых строках. Полезно для регистрации длинных строк 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);
    }
  }

Ответ 7

нас эта логика поискового вызова

    /*
     * 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));
            }
        }
    }

}

Ответ 8

предоставление моего собственного решения 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". затем рекурсивно называйте себя частью сообщения, которое невозможно зарегистрировать, пока ничего не останется.

Ответ 9

Если ваш журнал очень длинный (например, запись всего дампа вашей базы данных по причинам отладки и т.д.), может случиться, что logcat предотвращает чрезмерное ведение журнала. Чтобы обойти это, вы можете добавить тайм-аут evry 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);
}

Остерегайтесь, используйте его только для целей отладки, так как он может остановить основной поток блоков.

Ответ 10

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

Ответ 11

Я не знаю какой-либо опции для увеличения длины logcat, но мы можем найти разные журналы, такие как основной журнал, журнал событий и т.д. Основной журнал обычно содержит все его длины до 4 Мб. Поэтому вы можете получить что вы потеряли в лог-терминале. Путь:\data\logger.

Ответ 12

Как упомянул @mhsmith, LOGGER_ENTRY_MAX_PAYLOAD - это 4068 в последних версиях Android. Однако если вы используете 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);
}