2012-01-17 22 views
71

默认情况下,logcat将会截断它认为“太长”的任何日志消息。这发生在Eclipse内部以及在命令行上使用adb -d logcat运行logcat时,并且会截断一些重要的调试消息。Android - 设置logcat消息的最大长度

是否有任何方法来增加logcat支持的最大字符串长度以使其停止截断调试信息? official documentation意味着可能没有,但也许logcat支持一些没有在那里提到的其他选项?

+0

类似:http://stackoverflow.com/questions/6321555/what-is-the-size-limit-for-logcat – 2016-02-01 15:36:39

+0

类似:如何显示在logcat的长消息(https://开头stackoverflow.com/questions/7606077/how-to-display-long-messages-in-logcat) – chancyWu 2017-08-15 06:32:14

回答

29

logcat中有一个固定大小的缓冲区用于二进制日志(/dev/log/events),该限制是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

(通过logcat的使用)的liblog人士还称:

  • 的消息可能已经通过内核日志司机截断。

我会建议你nxlog工具,它不使用二进制logcat中,但由于在内核中的局限性,所以我怀疑它会解决你的问题。不过,这可能值得一试。 (免责声明:我是作者。)

+5

我在哪里可以找到这个?它在“logcat”代码中吗?那么,我需要编译自己的修改后的logcat吗? – d4Rk 2015-07-02 15:38:01

+1

什么是二进制/非二进制日志? – fobbymaster 2016-11-09 18:17:45

+0

由于添加了元数据字段,在更新版本的Android中,LOGGER_ENTRY_MAX_PAYLOAD已从4076减少到4068(请参见[这里](https://android.googlesource.com/platform/system/core.git/+/主/ liblog /包含/数/ log_read.h))。 – mhsmith 2018-02-14 16:10:35

0

我不知道增加logcat的长度的任何选项,但我们可以找到不同的日志,如主日志,事件日志等。主日志通常包含它的长度上升到4Mb的所有东西。所以,你可能能够得到你在日志终端丢失的东西。路径是:\ data \ logger。

79

好吧,有趣。我很失望地看到答案是“你无法真正扩展它”。我最初的想法是分解它,以便我可以查看整个事情,所以在这里我与你分享我如何做到这一点(不是说它是什么幻想也不是有效的,但它可以在紧要关头完成工作):

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

编辑显示最后一个字符串!

+0

谢谢!我也打算长时间存储数据 – 2012-06-29 21:47:52

+0

没问题!希望它能帮到你 – Travis 2012-07-03 17:50:04

+0

我很确定这里有一个错误。我不得不使用“我 Dan 2013-02-12 19:25:08

1

上特拉维斯的解决方案,提供我自己拿,那字节Log.println()收益数量来写,以避免硬编码“4000”的事实

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

占据优势。然后,递归地调用自己的消息部分,直到没有任何东西可以记录为止。

+0

不幸的是,println返回写入的字节数,字符!=字节。 – gnuf 2013-05-29 18:39:42

+1

好吧,它的工作原理。我假设因为我只记录ascii文本。 – 2013-05-29 20:21:17

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

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

这里是我使用的代码 - 它在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; 
    } 
} 
+0

完美的作品! – 2014-10-20 14:07:51

+0

不客气:) – enl8enmentnow 2014-10-30 22:11:05

28

打破它在几件递归。

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 22:54:34

+1

@Aggressor为什么你需要在生产中记录4000多条长信息? – TWiStErRob 2016-09-10 09:24:45

+0

@TWiStErRob需要串化的非常大的对象。例如。一个有数千个位置的阵列。 – Aggressor 2016-09-10 15:49:24

1

如果您的日志很长(如登录数据库的转储全部用于调试的原因等),可能会发生的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); 
} 

当心,只能用于调试目的,因为它可能会阻止块主线程。

0

下面的代码是由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); 
    } 
    }