中间件接入logback

611 阅读2分钟

因为有需求sentry,钉钉,kafka进行日志追踪,有错误的时候可以直接发送警报,需要与logback进行整合。 先看下Logger的构造函数,其实就是一个多叉树,头结点为root,子节点的名称分别为下一层的包名,其中LoggerContext是一个全局的logger上下文,里面装有所有logger的指针和一些系统配置如xml文件

Logger(String name, Logger parent, LoggerContext loggerContext) {
        //当前这一层的包名,顶层为root
        this.name = name;
        //父节点,顶层为null
        this.parent = parent;
        //logger的执行上下文
        this.loggerContext = loggerContext;
    }

再来说一下AppenderAttachableImpl这个类只会在有Appender的结点进行创建,按照我们把logback.xml配置在resources目录的默认约定,我们重写的Appender只会出现在root结点的logger初始化的时候会把配置文件里的重写的Appender加载到一个对CopyOnWriteArrayList进行再次封装的COWArrayList集合,添加Appender方法简化如下:

public synchronized void addAppender(Appender<ILoggingEvent> newAppender) {
        if (aai == null) {
            aai = new AppenderAttachableImpl<ILoggingEvent>();
        }
        aai.addAppender(newAppender);
    }

当遇到打印日志需求的时候,就会取当前包下的logger调用callAppenders去找到AppenderAttachableImpl如果为null就会一直去父节点找,直到找到root结点为止

public void callAppenders(ILoggingEvent event) {
        int writes = 0;
        for (Logger l = this; l != null; l = l.parent) {
            writes += l.appendLoopOnAppenders(event);  
        }
 }
private int appendLoopOnAppenders(ILoggingEvent event) {
        if (aai != null) {
            return aai.appendLoopOnAppenders(event);
        } else {
            return 0;
        }
    }

再来看看aai.appendLoopOnAppenders(event)这个方法,虽然方法名一样但是不要搞混淆了,上面那个是logger的方法,下面这个是AppenderAttachableImpl的方法

public int appendLoopOnAppenders(E e) {
        int size = 0;
        //获取Appender数组
        final Appender<E>[] appenderArray = appenderList.asTypedArray();
        final int len = appenderArray.length;
        for (int i = 0; i < len; i++) {
            //虽然都是实现了Appender的类,但具体实现不同
            appenderArray[i].doAppend(e);
            size++;
        }
        return size;
    }

doAppend()是抽象类AppenderBase的一个方法经过一系列判断然后最终调用getFilterChainDecision()里面主要是有一堆的过滤器包括自己指定的Filter要是有其他需求也可以写一个类extends Filter自己写过滤逻辑

<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>WARN</level>
</filter>
public FilterReply getFilterChainDecision(E event) {

        final Filter<E>[] filterArrray = filterList.asTypedArray();
        final int len = filterArrray.length;

        for (int i = 0; i < len; i++) {
            //一堆过滤器
            final FilterReply r = filterArrray[i].decide(event);
            if (r == FilterReply.DENY || r == FilterReply.ACCEPT) {
                return r;
            }
        }

        // 不符合要求
        return FilterReply.NEUTRAL;
    }

经过过滤器日志等级判定后最终会调用this.append(),所以我们只需要继承AppenderBase重写append()方法就可以写需要的业务逻辑,不管是钉钉、sentry、还是mq都可以按如下代码:

public class SentryAppender extends AppenderBase<ILoggingEvent> {
    @Override
    protected void append(ILoggingEvent iLoggingEvent) {
         EventBuilder eventBuilder = createEventBuilder(iLoggingEvent);
         Sentry.capture(eventBuilder);
}

filter同理

<appender name="SENTRY" class="io.sentry.logback.SentryAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>WARN</level>
        </filter>
 </appender>