一个优秀的软件系统一定会实时保存系统运行过程中产生的异常或非异常性数据,用于记录系统运行过程产生的各种行为,作为日后发现问题、跟踪问题并解决问题的一个很重要的依据。一般以输出文件的形式保存,同时也可以选择性的在控台打印。日志处理,可谓是任何软件开发过程中必不可少的一个环节。
在Android应用开发阶段,我们常常会使用系统提供的日志打印功能选择性地在Logcat控制台上打印一些数据信息,便于更加直观地调试跟踪应用运行的一个状态,常见如客户端与服务器通讯过程中涉及到的URL链接、request请求参数和response响应结果等。
常规使用
Android的日志工具Log(import android.util.Log;
)一共为我们提供了5个方法(优先级依次升高)来供我们打印日志,当然他们有不同的重载,按需使用。
- Log.v()
对应的级别为verbose,是Android日志级别最低的一种。用于打印开发调试中的一些详细信息,最为琐碎、意义最小的日志,包含诸如方法名,变量值之类的信息,仅在开发中使用,不可在发布产品中输出。 - Log.d()
对应级别为debug,比verbose高一级。开发中经常选择输出此种级别的日志,用于打印一些调试信息,这些信息对日常开发调试程序和分析问题应该是最有帮助的,可以在发布产品中关闭,有时在beta版应用中出现。 - Log.i()
对应级别是info,比debug高一级,用于打印一些比较重要的数据,这些数据是自己要看到的,多用于分析用户行为、流程走向,该等级日志显示运行状态信息,可在产品出现问题时提供帮助,从该级别开始的日志通常包含完整意义的英语语句和调试信息,是最常见的日志级别。 - Log.w()
对应为warn,比infor高一级。用于打印警告信息,运行出现异常即将发生错误或表明已发生非致命性错误,可能潜在风险、异常或错误的时候需要打印警示性文字,例如将try-catch语句块中的异常打印堆栈轨迹之后可输出此种级别日志,最好修复好这些问题。 - Log.e()
对应为error级别,是最高级别信息。用于打印程序中的而错误信息,比如提示程序进入catch语句中,一般用于打印程序出现了严重问题,比如应用crash时输出的日志,必须尽快修复。
Tips:Log和println的区别
Java程序员一般喜欢/习惯了用System.out.println();因为输入“sout”即可。
在Android Studio中开发时候,Logcat窗口可以添加过滤器,也可以选择当前App、自定义规则、全部日志等,可以筛选关键字,定位自己关心的内容(tag、keyword),支持正则表达式。
相关的封装代码
如果打印时候懒得写TAG标签,可以自己封装Log工具类实现,如下:
/**
* 得到tag(所在类.方法(L:行))
*
* @return
*/
private static String generateTag() {
StackTraceElement trace = Thread.currentThread().getStackTrace()[4];
String callerClazzName = trace.getClassName();
callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1);
String tag = "%s.%s(L:%d)";
tag = String.format(tag, callerClazzName, trace.getMethodName(), Integer.valueOf(trace.getLineNumber()));
//给tag设置前缀
tag = TextUtils.isEmpty(tagPrefix) ? tag : tagPrefix + ":" + tag;
return tag;
}
如果打印的message过长,比如接口响应结果过大,将会导致Logcat控台数据显示不全。自打使用Log以来经常遇到这个问题,之前也是没太在意,毕竟message太长的情况也是少见,偶尔遇到这种情况就通过Debug工具跟踪调试,复制对应response信息到bejson等其他辅助工具上格式化浏览,多少还是有点不方便。如果也懒得断点或者不方便断点时候,这个方法可以分行打印结束,然后自己把几行日志拼接一下就是完整的数据。
后来经过查询才得知,Android系统的单条日志打印长度是有限的,在底层Logger驱动程序的一个类Logger.h头文件中有如下两行代码:
#define LOGGER_ENTRY_MAX_LEN (4*1024)
#define LOGGER_ENTRY_MAX_PAYLOAD\(LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
可以看出,系统显示单条Log信息的长度是固定的,为4*1024个字节!Logcat使用的liblog资源包也提到,使用Log打印的message有可能被log内核驱动缩短:
The message may have been truncated by the kernel log driver.
了解了其中的长度限制,就好办了。我们可以对Message做个长度判断,采取分段打印的办法输出日志信息,送佛送到西,再送一段我常用的封装代码,我们需要手动突破这个限制:
/**
* 信息太长,分段打印
*
* @param tag tag
* @param msg msg
*/
private static void prePrintLog(String tag, String msg, int type) {
// 因为String的length是字符数量不是字节数量所以为了防止中文字符过多,
// 把4*1024的MAX字节打印长度改为2001字符数
int max_str_length = 2001 - tag.length();
// 大于4000时
while (msg.length() > max_str_length) {
printLog(tag, msg.substring(0, max_str_length), type);
msg = msg.substring(max_str_length);
}
// 剩余部分
printLog(tag, msg, type);
}
另外一种写法,参考:
private static void prePrintLog(String msg) {
if(msg.length() > 4000) {
for(int i = 0; i < msg.length(); i += 4000){
if(i + 4000 < msg.length()){
Log.i("rescounter"+i, msg.substring