默认情况下,似乎logcat会截断它认为“太长”的任何日志消息。这在Eclipse内部和使用adb -d logcat
在命令行上运行logcat时都会发生,并且会截断一些重要的调试消息。
有没有办法增加logcat支持的最大字符串长度,以使其停止截断调试信息? official documentation意味着可能没有,但是logcat可能支持那里没有提到的一些其他选项?
答案 0 :(得分:84)
好的,有趣的。我很失望地看到答案是“你无法真正扩展它”。我最初的想法是打破它,所以我可以查看整个事情,所以我在这里与大家分享我是如何做到的(不是它有什么特别的,也不是接近效率,但它可以在紧要关头完成工作):
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());
}
编辑显示最后一个字符串!
答案 1 :(得分:47)
递归地将它分成几部分。
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);
}
}
答案 2 :(得分:36)
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
限制。
liblog源(由logcat使用)也说:
- 内核日志驱动程序可能已截断该消息。
我建议您使用不使用logcat二进制文件的nxlog工具,但由于内核的限制,我怀疑它会解决您的问题。不过,它可能值得一试。 (免责声明:我是作者。)
答案 3 :(得分:10)
for( String line : logMesg.split("\n") ) {
Log.d( TAG, line );
}
答案 4 :(得分: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;
}
}
答案 5 :(得分:3)
下面的代码是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);
}
}
答案 6 :(得分: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));
}
}
}
}
答案 7 :(得分: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”的事实。然后,递归地调用自己的消息部分,直到没有任何东西,无法记录。
答案 8 :(得分: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);
}
请注意,只能将其用于调试目的,因为它可能会停止阻塞主线程。
答案 9 :(得分:1)
int i = 3000;
while (sb.length() > i) {
Log.e(TAG, "Substring: "+ sb.substring(0, i));
sb = sb.substring(i);
}
Log.e(TAG, "Substring: "+ sb);
答案 10 :(得分:0)
我不知道增加logcat长度的任何选项,但我们可以找到不同的日志,如主日志,事件日志等。主日志通常包含其长度达到4Mb的所有内容..所以你可能得到你在日志终端丢失了什么。路径是:\ data \ logger。
答案 11 :(得分:0)
正如@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);
}
答案 12 :(得分: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)
)
);