如何在logcat中显示长消息

113

我正在尝试在Logcat上显示长消息。如果消息的长度超过1000个字符,它会被断开。

有什么机制可以在Logcat中显示长消息的所有字符吗?


7
我收到服务器的回复,是一个很长的字符串。 - Vasu
1
即使如此,您为什么想要打印整个字符串,将其写入文件或数据库并在那里查看 - 如果是为了调试。 - Rahul Choudhary
将您的logcat字符串复制并粘贴到记事本中,您可以看到完整的1000个字符长度。 - ilango j
https://dev59.com/52ox5IYBdhLWcg3w6oj0 - Ciro Santilli OurBigBook.com
12个回答

170

如果logcat将长度限制在1000个字符以内,那么您可以使用String.subString()将要记录的字符串分割成若干块进行记录。例如:

int maxLogSize = 1000;
for(int i = 0; i <= veryLongString.length() / maxLogSize; i++) {
    int start = i * maxLogSize;
    int end = (i+1) * maxLogSize;
    end = end > veryLongString.length() ? veryLongString.length() : end;
    Log.v(TAG, veryLongString.substring(start, end));
}

1
日志打印只有响应的一半..我该如何获取整个响应的长度。你说过很长的字符串.length(),但当我在日志cat中打印json结果时,这里只打印了响应的一半。 - Vasu
这种方法需要特别小心!在Android M中,你可能会遇到OutOfMemoryError错误,导致应用程序崩溃。 - Toochka
4
Android 真让人难以置信,做得这么复杂! - Alston
1
如果 veryLongString.length()maxLogSize 的倍数,我认为这段代码将在结尾记录一个额外的空日志条目。也许将 <= 改为 < - LarsH
@spatulamania 做得好,它对我有用,继续编程吧 ;) - Bipin Bharti
显示剩余5条评论

34
作为对 spatulamania 答案的跟进,我写了一个包装类来为您处理这个问题。您只需要更改导入,并且它将记录所有内容。

作为对 spatulamania 答案的跟进,我写了一个包装类来为您处理这个问题。您只需要更改导入,并且它将记录所有内容

public class Log {

    public static void d(String TAG, String message) {
        int maxLogSize = 2000;
        for(int i = 0; i <= message.length() / maxLogSize; i++) {
            int start = i * maxLogSize;
            int end = (i+1) * maxLogSize;
            end = end > message.length() ? message.length() : end;
            android.util.Log.d(TAG, message.substring(start, end));
        }
    }

}

27

这是在 spatulamania 的回答基础上进行的补充,更为简洁,并且不会在末尾添加空日志信息:

final int chunkSize = 2048;
for (int i = 0; i < s.length(); i += chunkSize) {
    Log.d(TAG, s.substring(i, Math.min(s.length(), i + chunkSize)));
}

谢谢。不建议使用超过3000个符号,我也这样做。 - CoolMind

13

尝试使用以下代码在 logcat 中显示长消息。

public void logLargeString(String str) {
    if(str.length() > 3000) {
        Log.i(TAG, str.substring(0, 3000));
        logLargeString(str.substring(3000));
    } else {
        Log.i(TAG, str); // continuation
    }
}

9
在只需要使用简单的循环时,为什么要使用递归。 - pellucide
3
我喜欢递归,因为我觉得它能增强代码的可读性和重用性。然而,如果编译器无法对尾递归进行优化(我不认为Android Studio的编译器会这样做),那么尾递归可能会快速地积累堆栈帧。这意味着,如果你有一个长度相当长的消息,导致了众多递归调用,就很容易出现StackOverflowError。 - Luke
1
@pellucide展示如何使用“简单循环”来完成它。 - Fernando Torres

11

这就是OkHttp和HttpLoggingInterceptor的实现方式:

public void log(String message) {
  // Split by line, then ensure each line can fit into Log's maximum length.
  for (int i = 0, length = message.length(); i < length; i++) {
    int newline = message.indexOf('\n', i);
    newline = newline != -1 ? newline : length;
    do {
      int end = Math.min(newline, i + MAX_LOG_LENGTH);
      Log.d("OkHttp", message.substring(i, end));
      i = end;
    } while (i < newline);
  }
}

MAX_LOG_LENGTH 是 4000。

这里使用 Log.d(调试)和硬编码的“OkHttp”标记。

它会在换行或达到最大长度时拆分日志。

下面的类是一个帮助类,您可以使用它(如果通过Jack&Jill或retrolambda支持lambda)来完成与 OkHttp 相同的任何日志记录:

/**
 * Help printing logs splitting text on new line and creating multiple logs for too long texts
 */

public class LogHelper {

    private static final int MAX_LOG_LENGTH = 4000;

    public static void v(@NonNull String tag, @Nullable String message) {
        log(message, line -> Log.v(tag, line));
    }

    public static void d(@NonNull String tag, @Nullable String message) {
        log(message, line -> Log.d(tag, line));
    }

    public static void i(@NonNull String tag, @Nullable String message) {
        log(message, line -> Log.i(tag, line));
    }

    public static void w(@NonNull String tag, @Nullable String message) {
        log(message, line -> Log.w(tag, line));
    }

    public static void e(@NonNull String tag, @Nullable String message) {
        log(message, line -> Log.e(tag, line));
    }

    public static void v(@NonNull String tag, @Nullable String message, @Nullable Throwable throwable) {
        log(message, throwable, line -> Log.v(tag, line));
    }

    public static void d(@NonNull String tag, @Nullable String message, @Nullable Throwable throwable) {
        log(message, throwable, line -> Log.d(tag, line));
    }

    public static void i(@NonNull String tag, @Nullable String message, @Nullable Throwable throwable) {
        log(message, throwable, line -> Log.i(tag, line));
    }

    public static void w(@NonNull String tag, @Nullable String message, @Nullable Throwable throwable) {
        log(message, throwable, line -> Log.w(tag, line));
    }

    public static void e(@NonNull String tag, @Nullable String message, @Nullable Throwable throwable) {
        log(message, throwable, line -> Log.e(tag, line));
    }

    private static void log(@Nullable String message, @NonNull LogCB callback) {
        if (message == null) {
            callback.log("null");
            return;
        }
        // Split by line, then ensure each line can fit into Log's maximum length.
        for (int i = 0, length = message.length(); i < length; i++) {
            int newline = message.indexOf('\n', i);
            newline = newline != -1 ? newline : length;
            do {
                int end = Math.min(newline, i + MAX_LOG_LENGTH);
                callback.log(message.substring(i, end));
                i = end;
            } while (i < newline);
        }
    }

    private static void log(@Nullable String message, @Nullable Throwable throwable, @NonNull LogCB callback) {
        if (throwable == null) {
            log(message, callback);
            return;
        }
        if (message != null) {
            log(message + "\n" + Log.getStackTraceString(throwable), callback);
        } else {
            log(Log.getStackTraceString(throwable), callback);
        }
    }

    private interface LogCB {
        void log(@NonNull String message);
    }
}

我自己在他们的代码中寻找,但没有找到。谢谢。 - Bugs Happen

5

使用 Kotlin 我们可以利用 stdlib 中的 chunked 函数:

fun logUnlimited(tag: String, string: String) {
    val maxLogSize = 1000
    string.chunked(maxLogSize).forEach { Log.v(tag, it) }
}

3
为了避免将换行符分割到日志消息中,我将长字符串拆分为每行单独记录日志。
void logMultilineString(String data) {
    for (String line : data.split("\n")) {
        logLargeString(line);
    }
}

void logLargeString(String data) {
    final int CHUNK_SIZE = 4076;  // Typical max logcat payload.
    int offset = 0;
    while (offset + CHUNK_SIZE <= data.length()) {
        Log.d(TAG, data.substring(offset, offset += CHUNK_SIZE));
    }
    if (offset < data.length()) {
        Log.d(TAG, data.substring(offset));
    }
}

2
我认为Timber是解决这个问题的好选择。Timber会自动将消息分割并打印到logcat中。

https://github.com/JakeWharton/timber

您可以在timber.log.Timber.DebugTree静态类中看到日志方法的实现。

1

这是一个针对@spatulamania的答案的Kotlin版本(特别适用于懒惰/聪明的人):

val maxLogSize = 1000
val stringLength = yourString.length
for (i in 0..stringLength / maxLogSize) {
    val start = i * maxLogSize
    var end = (i + 1) * maxLogSize
    end = if (end > yourString.length) yourString.length else end
    Log.v("YOURTAG", yourString.substring(start, end))
}

0

如果要打印JSON字符串,可以使用以下代码

    @JvmStatic
    fun j(level: Int, tag: String? = null, msg: String) {
        if (debug) {
            if (TextUtils.isEmpty(msg)) {
                p(level, tag, msg)
            } else {
                val message: String
                message = try {
                    when {
                        msg.startsWith("{") -> {
                            val jsonObject = JSONObject(msg)
                            jsonObject.toString(4)
                        }
                        msg.startsWith("[") -> {
                            val jsonArray = JSONArray(msg)
                            jsonArray.toString(4)
                        }
                        else -> msg
                    }
                } catch (e: JSONException) {
                    e.printStackTrace()
                    msg
                }
                p(level, tag, "╔═══════════════════════════════════════════════════════════════════════════════════════", false)
                val lines = message.split(LINE_SEPARATOR.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                for (line in lines) {
                    p(level, tag, "║ $line", false)
                }
                p(level, tag, "╚═══════════════════════════════════════════════════════════════════════════════════════", false)
            }
        }
    }

完整代码

CXLogUtil.j("json-tag","{}")

preview result


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接