美文网首页
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