美文网首页
Logger框架解析

Logger框架解析

作者: Poseidon_Wang | 来源:发表于2016-11-14 12:33 被阅读111次

Logger简介

用了蛮久的Logger框架,突然想自己做一个,所以从Github上down了一份源码,研究了一下,本身原理比较简单,主要是定制个人有个人需求,技术点就那么几个。
网上使用较高的就是orhanobut的Logger框架,题外话,用了蛮多他的插件的,属于国外的大神。

引用自Logger,效果图

主要原理

StackTraceElement
关于这个StackTraceElement的原生api解释,网上有很多,我就简单说一下。
本身我们知道方法栈的概念就是当每个方法嵌套调用的时候,方法会以指针形式存到我们的方法栈,符合先进后出的原理,也就是最内层的方法是最后入栈的,出栈也就意为着程序执行这个方法。
我们核心代码是

StackTraceElement[] elements=Thread.currentThread().getStackTrace();

调用这个方法就能获取到当前方法所在方法栈信息,我们再来看看StackTraceElement这个类

StackTraceElement

主要关注这几个方法,后面我们需要用到这几个api打印一些关键信息,以及定位。
另外需要注意的是上述的数组,因为会先走底层方法

at dalvik.system.VMStack.getThreadStackTrace(Native Method)
at java.lang.Thread.getStackTrace(Thread.java:579)

所以第三条信息才是我们定义的方法(自定义方法),接下来就是被嵌套的函数,依次类推。

源码分析

因为Logger框架有许多定制的地方,我们需要来看看各个实现,先不上升到设计模式,单纯功能性分析。
按照我的习惯,我喜欢先从功能入手来看源码,于是我首先查看了Logger类,一般辅助类与主类属于从属关系,我决定以下面的顺序进行解读(缩略版的话其实可以省略这些)

Logger的类
  1. Helper类,这个类看到他的使用后就知道他是个辅助类,类似util做一些处理
  • isEmpty(CharSequence):boolean 判断字符串是否为空或者长度为0
  • equals(CharSequence,CharSequence);boolean 逐字比较字符串是否相等
  • getStackTraceString(Throwable):String 打印错误信息
  1. Setting因为嵌套在Printer里面所以首先选择解析这个
Settings

如图这些都是Settings的属性,其实Settings就跟他的名字一样用来控制Log的打印,这里的methodCount,methodOffset目前意义不详,我们到时候回过头来分析

  • showThreadInfo 就是是否需要打印线程信息
  • logAdapter 就是对系统提供的Log框架的分享
  • logLevel 枚举有两个常量FULL,NONE就是是否需要打印log的开关了

3.AndroidLogAdapter是LogAdapter的实现,无非是系统log的实现
4.接下来看Logger类,除了init方法需要注意,也就是我们阅读程序的入口了,其他只是对外提供方法调用而已,在init里面我们看到了整个框架的核心LoggerPrinter

5.LoggerPrinter是Printer的实现,此类实现了所有打印的定制,格式问题我们就不展开了,具体看下几个核心业务的实现就可以动手写我们自己的了

仔细一看所有设计到log(e,w,i,d...)的最后都调用到log方法,那么就简单了我们之需要看这个函数就行了

logTopBorder(priority, tag);
logHeaderContent(priority, tag, methodCount);
//get bytes of message with system's default charset (which is UTF-8 for Android)
byte[] bytes = message.getBytes();
int length = bytes.length;
if (length <= CHUNK_SIZE) {
  if (methodCount > 0) {
    logDivider(priority, tag);
  }
  logContent(priority, tag, message);
  logBottomBorder(priority, tag);
  return;
}
if (methodCount > 0) {
  logDivider(priority, tag);
}
for (int i = 0; i < length; i += CHUNK_SIZE) {
  int count = Math.min(length - i, CHUNK_SIZE);
  //create a new String with system's default charset (which is UTF-8 for Android)
  logContent(priority, tag, new String(bytes, i, count));
}
logBottomBorder(priority, tag);

省略了前面的各种判断,这里首先打印了头,就是那个花哨的东西,然后判断log内容是否超出限制
然后我们再进到logHeaderContent,logContent函数
这两个函数分别打印线程信息,与消息体,这里我们只需要关注线程信息就可以了

private void logHeaderContent(int logType, String tag, int methodCount) {
  StackTraceElement[] trace = Thread.currentThread().getStackTrace();
  if (settings.isShowThreadInfo()) {
    logChunk(logType, tag, HORIZONTAL_DOUBLE_LINE + " Thread: " + Thread.currentThread().getName()); 
   logDivider(logType, tag);
  } 
 String level = "";
  int stackOffset = getStackOffset(trace) + settings.getMethodOffset();
  //corresponding method count with the current stack may exceeds the stack trace. Trims the count  
if (methodCount + stackOffset > trace.length) {
    methodCount = trace.length - stackOffset - 1;
  } 
 for (int i = methodCount; i > 0; i--) {
    int stackIndex = i + stackOffset; 
   if (stackIndex >= trace.length) {
      continue;
    }
    StringBuilder builder = new StringBuilder(); 
   builder.append("║ ")
        .append(level)
        .append(getSimpleClassName(trace[stackIndex].getClassName()))
        .append(".")
        .append(trace[stackIndex].getMethodName())
        .append(" ")
        .append(" (")
        .append(trace[stackIndex].getFileName())
        .append(":")
        .append(trace[stackIndex].getLineNumber())
        .append(")");
    level += "   ";
    logChunk(logType, tag, builder.toString());
  }
}

根据前面的原理桌布来看就很容易理解了,我们首先获取队栈信息,然后打印线程信息,接着打印具体方法,这时候我们就知道Settings里面的offset的用处了,他就是用来帮助我们定位到自己的方法的,所以尽量不要去懂Settings里面的默认值,这个methodCount的含义就是总的嵌套方法数,写了这么多,其实要是不是初学者看下原理,基本自己能实现了
最后附上自己的github地址已上传Maven

相关文章

网友评论

      本文标题:Logger框架解析

      本文链接:https://www.haomeiwen.com/subject/ilbmuttx.html