【问题标题】:How to display long messages in logcat如何在logcat中显示长消息
【发布时间】:2011-11-28 04:43:21
【问题描述】:

我正在尝试在 logcat 上显示长消息。如果消息的长度超过 1000 个字符,它就会被破坏。

logcat中长信息全部显示的机制是什么?

【问题讨论】:

  • 我从服务器收到一个长字符串的响应。
  • 即使那样你为什么要打印整个字符串,将其写入文件或数据库并在那里查看 - 如果它用于调试
  • 复制你的 logcat 字符串并粘贴到记事本中,你可以看到完整的 1000 长度的字符串。

标签: android logcat


【解决方案1】:

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

【讨论】:

  • Log cat 只打印一半的响应.. 我怎么能得到整个响应的长度。你说veryLongString.length() 但是当我在log cat中打印json结果时它只打印了一半的响应
  • 但在 iphone 控制台中我得到了整个响应字符串
  • 您可以通过将 length() 写入日志来检查响应的长度。如果此值不是您的预期值,则问题可能与日志记录无关。
  • 不敢相信 Android 让它这么难!
  • 如果veryLongString.length()maxLogSize 的倍数,我认为这段代码最后会记录一个额外的空日志条目。也许将&lt;= 更改为&lt;
【解决方案2】:

作为对 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));
        }
    }

}

【讨论】:

    【解决方案3】:

    试试这段代码在 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
        }
    }
    

    【讨论】:

    • 当一个简单的循环就足够了,为什么要使用递归。
    • 我是递归的粉丝,因为我发现代码的易读性和重用性非常好。但是,如果您的编译器不优化堆栈帧(我不相信 Android 工作室会这样做),这种尾端递归可以快速构建堆栈帧。这意味着,如果您有一个相当长的消息导致大量递归调用,您可以轻松创建 StackOverflowError。
    • @pellucide 展示如何使用“简单循环”
    【解决方案4】:

    这建立在 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个符号,我就这么用。
    【解决方案5】:

    为了不最小化跨日志消息的拆分行,我采用大字符串并分别记录每一行。

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

    【讨论】:

      【解决方案6】:

      这就是 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”标签。

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

      下面的这个类是一个帮助类,你可以使用(如果你有 lambda 支持 throw Jack & Jill 或 retrolambda)来做 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);
          }
      }
      

      【讨论】:

      • 我自己在他们的代码中寻找它,但找不到它。谢谢。
      【解决方案7】:

      这里是 @spatulamania answer 的 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))
      }
      

      【讨论】:

        【解决方案8】:

        我认为 Timber 是解决这个问题的好选择。 Timber 在 logcat 中自动拆分和打印消息块。

        https://github.com/JakeWharton/timber

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

        【讨论】:

          【解决方案9】:

          如果打印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)
                      }
                  }
              }
          

          full code

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

          【讨论】:

            【解决方案10】:

            要获得简单的解决方案,请使用以下附加点中的 使用软包装 选项,第 4 个选项可能会对您有所帮助。

            【讨论】:

              【解决方案11】:

              使用 Kotlin,我们可以使用 stdlib chunked 函数:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2017-08-03
                • 1970-01-01
                • 2016-03-13
                • 1970-01-01
                • 2011-01-01
                • 2013-07-28
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多