Apache Log4j 架构之二 日志输出

来源:互联网 发布:docker运行windows程序 编辑:程序博客网 时间:2024/05/25 23:24

Log4j输出日志 | Log4j write log

Log4j输出日志分为六个步骤:全局开关控制、日志等级过滤、封装日志信息、过滤器处理、日志信息格式化、输出至文件。下面分两个环节来介绍这六个步骤是如何实现的:
1、第一环节:预处理。
当调用Log4j的方法(如:debug(String, Throwable)、info(String, Throwable))输出日志时,首先对日志信息进行预处理,其序列图如下;
Apache Log4j 架构之输出日志 | Apache Log4j Architecture Level 2:Write Log - 傲风 - 宝剑锋从磨砺出 梅花香自苦寒来
说明:
  • isDisabled(int level):根据全局日志等级threshold进行判断,如果日志等级低于threshold,不输出日志。
  • isGreaterOrEquals(Priority r):根据当前logger配置的日志等级level进行判断,如果日志等级低于当前logger配置的日志等级,不输出日志。
  • foredLog(String fqcn Priority level, Object message, Throwable t):将日志信息封装成LoggingEvent对象。
  • callAppenders(LoggingEvent event):将LoggingEvent对象分发给所有的Appender。其实现代码如下:
        public void callAppenders(LoggingEvent event) {
            int writes = 0;

            for (Category c = this; c != null; c = c.parent) {
                // Protected against simultaneous call to addAppender,
                // removeAppender,...
                synchronized (c) {
                    if (c.aai != null) {
                        writes += c.aai.appendLoopOnAppenders(event);
                    }
                    if (!c.additive) {
                        break;
                    }
                }
            }

            if (writes == 0) {
                repository.emitNoAppenderWarning(this);
            }
        }
            public int appendLoopOnAppenders(LoggingEvent event) {
            int size = 0;
            Appender appender;

            if (appenderList != null) {
                size = appenderList.size();
                for (int i = 0; i < size; i++) {
                    appender = (AppenderappenderList.elementAt(i);
                    appender.doAppend(event);
                }
            }
            return size;
        }
  

2、第二环节:输出日志。
输出日志前还有两道工序需要处理:Filter处理和日志信息格式化。其执行序列图如下:
Apache Log4j 架构之输出日志 | Apache Log4j Architecture Level 2:Write Log - 傲风 - 宝剑锋从磨砺出 梅花香自苦寒来
 
相应的代码如下:
    public synchronized void doAppend(LoggingEvent event) {
        if (closed) {
            LogLog.error("Attempted to append to closed appender named ["
                    + name + "].");
            return;
        }

        if (!isAsSevereAsThreshold(event.getLevel())) {
            return;
        }

        Filter f = this.headFilter;

        FILTER_LOOP: while (f != null) {
            switch (f.decide(event)) {

            case Filter.DENY:
                return;
            case Filter.ACCEPT:
                break FILTER_LOOP;
            case Filter.NEUTRAL:
                f = f.getNext();
            }
        }

        this.append(event);
    }

    protected void subAppend(LoggingEvent event) {
        this.qw.write(this.layout.format(event));

        if (layout.ignoresThrowable()) {
            String[] s = event.getThrowableStrRep();
            if (s != null) {
                int len = s.length;
                for (int i = 0; i < len; i++) {
                    this.qw.write(s[i]);
                    this.qw.write(Layout.LINE_SEP);
                }
            }
        }

        if (shouldFlush(event)) {
            this.qw.flush();
        }
    }

说明:
  • decide(LoggingEvent event):有三种返回值 DENY、ACCEPT、NEUTRAL,DENY表示丢弃当前日志信息,ACCEPT表示输出当前日志信息,NEUTRAL表示继续下一个Filter。Filter只能在XML配置文件中使用,Properties文件中不支持。
  • format(LoggingEvent event):对日志进行格式化处理。
  • write(String string):将日志信息输出至目的地(文件、数据库或网格)。
0 0