log4j源码分析

log4j源码分析

log4j仓库的地址https://github.com/apache/log4j.git

1.0 准备代码

测试配置文件:log4j.properties
log4j.debug=true
log4j.rootLogger = debug,stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %m%n
log4j.logger.test = debug,stdout
测试类
public class LoggerTest {
Logger log = Logger.getLogger(getClass());
@Test
public void testDebug(){
System.out.println(“init”);
log.debug(“debug”);
}
}

1.1 核心类

类图
这里写图片描述
Level:日志级别;
Appender:日志输出;
Layout:日志格式;
AppenderAttachable:允许附加多个不同的日志输出对象
Category: Logger的父类,提供了日子记录的方法,debug等
Logger:日志记录类,提供记录日志记录对象的方法;
LoggingEvent:日志记录过程中产生的信息的抽象.

1.2 初始化

 时序图
这里写图片描述

LogManager:管理对象,负责log4j的初始化与实例的获取
DefaultRepositorySelector:实例仓库的选择器,提供了获取实例仓库的方法
LoggerRepository:Logger实例的仓库,提供了获取Logger的方法
LoggerFactory:Logger的工厂提供了创建Logger 的方法
工具类:
OptionHandler提供了所有选项设置之后的激活接口
Configurator提供了解析配置文件并填充LoggerRepository的方法
OptionConverter作为工具类,提供了解析配置文件,创建Configurator对象和实例化对象的方法(通过反射)

1.2.1 LogManager的静态代码完成对Log4j的初始化

public class LogManager {
    static {
        //初始化RootLogger并指定的日志级别DEBUG,初始化Log仓库
        Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
        //设置repositorySelector对象 
        repositorySelector = new DefaultRepositorySelector(h);
        String override = OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
                null);

        if (override == null || "false".equalsIgnoreCase(override)) {
            String configurationOptionStr = OptionConverter.getSystemProperty(
                    DEFAULT_CONFIGURATION_KEY,
                    null);
            String configuratorClassName = OptionConverter.getSystemProperty(
                    CONFIGURATOR_CLASS_KEY,
                    null);
            URL url = null;
            // 优先查找 "log4j.xml" 然后查找"log4j.properties"
            if (configurationOptionStr == null) {
                url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
                if (url == null) {
                    // 然后查找"log4j.properties"
                    url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
                }
            } else {
                try {
                    url = new URL(configurationOptionStr);
                } catch (MalformedURLException ex) {
                    url = Loader.getResource(configurationOptionStr);
                }
            }

            if (url != null) {
                LogLog.debug("Using URL [" + url + "] for automatic log4j configuration.");
                try {
                    // 加载配置文件,创建Configurator对象,配置LoggerRepository对象
                    OptionConverter.selectAndConfigure(url, configuratorClassName,
                            LogManager.getLoggerRepository());
                } catch (NoClassDefFoundError e) {
                    LogLog.warn("Error during default initialization", e);
                }
            } else {
                LogLog.debug("Could not find resource: [" + configurationOptionStr + "].");
            }
        } else {
            LogLog.debug("Default initialization of overridden by " +
                    DEFAULT_INIT_OVERRIDE_KEY + "property.");
        }
    }
}

1.2.2 OptionConverter默认创建了PropertyConfigurator

public class OptionConverter {
    static
    public void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) {
        Configurator configurator = null;
        String filename = url.getFile();

        if (clazz == null && filename != null && filename.endsWith(".xml")) {
            clazz = "org.apache.log4j.xml.DOMConfigurator";
        }

        if (clazz != null) {
            LogLog.debug("Preferred configurator class: " + clazz);
            configurator = (Configurator) instantiateByClassName(clazz,
                    Configurator.class,
                    null);
            if (configurator == null) {
                LogLog.error("Could not instantiate configurator [" + clazz + "].");
                return;
            }
        } else {
            //创建PropertyConfigurator对象
            configurator = new PropertyConfigurator();
        }
        //加载资源文件,配置Hierarchy(LoggerRepository)对象
        configurator.doConfigure(url, hierarchy);
    }
}

1.2.3通过PropertyConfigurator完成了对配置文件的解析

public class PropertyConfigurator implements Configurator {
    public void doConfigure(java.net.URL configURL, LoggerRepository hierarchy) {
        Properties props = new Properties();
        LogLog.debug("Reading configuration from URL " + configURL);
        InputStream istream = null;
        URLConnection uConn = null;
        try {
            uConn = configURL.openConnection();
            uConn.setUseCaches(false);
            istream = uConn.getInputStream();
            //加载Properties
            props.load(istream);
        } catch (Exception e) {
            if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
                Thread.currentThread().interrupt();
            }
            LogLog.error("Could not read configuration file from URL [" + configURL
                    + "].", e);
            LogLog.error("Ignoring configuration file [" + configURL + "].");
            return;
        } finally {
            if (istream != null) {
                try {
                    istream.close();
                } catch (InterruptedIOException ignore) {
                    Thread.currentThread().interrupt();
                } catch (IOException ignore) {
                } catch (RuntimeException ignore) {
                }
            }
        }
        //继续完成对Hierarchy的解析
        doConfigure(props, hierarchy);
    }

    public void doConfigure(Properties properties, LoggerRepository hierarchy) {
        repository = hierarchy;
        String value = properties.getProperty(LogLog.DEBUG_KEY);
        if (value == null) {
            value = properties.getProperty("log4j.configDebug");
            if (value != null)
                LogLog.warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead.");
        }

        if (value != null) {
            LogLog.setInternalDebugging(OptionConverter.toBoolean(value, true));
        }


        String reset = properties.getProperty(RESET_KEY);
        if (reset != null && OptionConverter.toBoolean(reset, false)) {
            hierarchy.resetConfiguration();
        }

        String thresholdStr = OptionConverter.findAndSubst(THRESHOLD_PREFIX,
                properties);
        if (thresholdStr != null) {
            hierarchy.setThreshold(OptionConverter.toLevel(thresholdStr,
                    (Level) Level.ALL));
            LogLog.debug("Hierarchy threshold set to [" + hierarchy.getThreshold() + "].");
        }
        //设置RootLogger
        configureRootCategory(properties, hierarchy);
        configureLoggerFactory(properties);
        //设置其他Logger对象
        parseCatsAndRenderers(properties, hierarchy);

        LogLog.debug("Finished configuring.");
        registry.clear();
    }

    void configureRootCategory(Properties props, LoggerRepository hierarchy) {
        String effectiveFrefix = ROOT_LOGGER_PREFIX;
        String value = OptionConverter.findAndSubst(ROOT_LOGGER_PREFIX, props);

        if (value == null) {
            value = OptionConverter.findAndSubst(ROOT_CATEGORY_PREFIX, props);
            effectiveFrefix = ROOT_CATEGORY_PREFIX;
        }

        if (value == null)
            LogLog.debug("Could not find root logger information. Is this OK?");
        else {
            //获取RootLogger
            Logger root = hierarchy.getRootLogger();
            synchronized (root) {
                parseCategory(props, root, effectiveFrefix, INTERNAL_ROOT_NAME, value);
            }
        }
    }

    void parseCategory(Properties props, Logger logger, String optionKey,
                       String loggerName, String value) {

        LogLog.debug("Parsing for [" + loggerName + "] with value=[" + value + "].");
        StringTokenizer st = new StringTokenizer(value, ",");

        if (!(value.startsWith(",") || value.equals(""))) {


            if (!st.hasMoreTokens())
                return;

            String levelStr = st.nextToken();
            LogLog.debug("Level token is [" + levelStr + "].");

            if (INHERITED.equalsIgnoreCase(levelStr) ||
                    NULL.equalsIgnoreCase(levelStr)) {
                if (loggerName.equals(INTERNAL_ROOT_NAME)) {
                    LogLog.warn("The root logger cannot be set to null.");
                } else {
                    logger.setLevel(null);
                }
            } else {
                //设置日志等级
                logger.setLevel(OptionConverter.toLevel(levelStr, (Level) Level.DEBUG));
            }
            LogLog.debug("Category " + loggerName + " set to " + logger.getLevel());
        }
        //移除所有Appender 
        logger.removeAllAppenders();

        Appender appender;
        String appenderName;
        while (st.hasMoreTokens()) {
            appenderName = st.nextToken().trim();
            if (appenderName == null || appenderName.equals(","))
                continue;
            LogLog.debug("Parsing appender named \"" + appenderName + "\".");
            //解析Appender 
            appender = parseAppender(props, appenderName);
            if (appender != null) {
                //将Appender添加到Logger
                logger.addAppender(appender);
            }
        }
    }

    Appender parseAppender(Properties props, String appenderName) {
        Appender appender = registryGet(appenderName);
        if ((appender != null)) {
            LogLog.debug("Appender \"" + appenderName + "\" was already parsed.");
            return appender;
        }

        String prefix = APPENDER_PREFIX + appenderName;
        String layoutPrefix = prefix + ".layout";
        //初始化Appender
        appender = (Appender) OptionConverter.instantiateByKey(props, prefix,
                org.apache.log4j.Appender.class,
                null);
        if (appender == null) {
            LogLog.error(
                    "Could not instantiate appender named \"" + appenderName + "\".");
            return null;
        }
        //设置Appender的Name 
        appender.setName(appenderName);

        if (appender instanceof OptionHandler) {
            if (appender.requiresLayout()) {
                //初始化Layout
                Layout layout = (Layout) OptionConverter.instantiateByKey(props,
                        layoutPrefix,
                        Layout.class,
                        null);
                if (layout != null) {
                    //设置Appender的Layout
                    appender.setLayout(layout);
                    LogLog.debug("Parsing layout options for \"" + appenderName + "\".");
                    PropertySetter.setProperties(layout, props, layoutPrefix + ".");
                    LogLog.debug("End of parsing for \"" + appenderName + "\".");
                }
            }
            final String errorHandlerPrefix = prefix + ".errorhandler";
            String errorHandlerClass = OptionConverter.findAndSubst(errorHandlerPrefix, props);
            if (errorHandlerClass != null) {
                ErrorHandler eh = (ErrorHandler) OptionConverter.instantiateByKey(props,
                        errorHandlerPrefix,
                        ErrorHandler.class,
                        null);
                if (eh != null) {
                    appender.setErrorHandler(eh);
                    LogLog.debug("Parsing errorhandler options for \"" + appenderName + "\".");
                    parseErrorHandler(eh, errorHandlerPrefix, props, repository);
                    final Properties edited = new Properties();
                    final String[] keys = new String[]{
                            errorHandlerPrefix + "." + ROOT_REF,
                            errorHandlerPrefix + "." + LOGGER_REF,
                            errorHandlerPrefix + "." + APPENDER_REF_TAG
                    };
                    for (Iterator iter = props.entrySet().iterator(); iter.hasNext(); ) {
                        Map.Entry entry = (Map.Entry) iter.next();
                        int i = 0;
                        for (; i < keys.length; i++) {
                            if (keys[i].equals(entry.getKey())) break;
                        }
                        if (i == keys.length) {
                            edited.put(entry.getKey(), entry.getValue());
                        }
                    }
                    PropertySetter.setProperties(eh, edited, errorHandlerPrefix + ".");
                    LogLog.debug("End of errorhandler parsing for \"" + appenderName + "\".");
                }

            }
            //configureOptionHandler((OptionHandler) appender, prefix + ".", props);
            PropertySetter.setProperties(appender, props, prefix + ".");
            LogLog.debug("Parsed \"" + appenderName + "\" options.");
        }
        parseAppenderFilters(props, appenderName, appender);
        registryPut(appender);
        return appender;
    }
}

1.3 运行

这里写图片描述

1.3.1 Logger类提提供了获取Logger对象的方法

public class Logger extends Category {
static
public Logger getLogger(Class clazz) {
      //对应的Logger对象通过LogManager的静态方法获取
return LogManager.getLogger(clazz.getName());
}
} 

1.3.2 LogManager的默认RepositorySelector由DefaultRepositorySelector实现,提供了获取LoggerRepository的方法

public class LogManager {
public
static Logger getLogger(final String name) {
return getLoggerRepository().getLogger(name);
}

static
public LoggerRepository getLoggerRepository() {
if (repositorySelector == null) {
repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
guard = null;
Exception ex = new IllegalStateException("Class invariant violation");
String msg =
"log4j called after unloading, see http://logging.apache.org/log4j/1.2/faq.html#unload.";
if (isLikelySafeScenario(ex)) {
LogLog.debug(msg, ex);
} else {
LogLog.error(msg, ex);
}
}
//DefaultRepositorySelector作为RepositorySelector的默认实现:实现了LoggerRepository的方法 
return repositorySelector.getLoggerRepository();
}
}

1.3.4 DefaultRepositorySelector的getLoggerRepository方法返回了默认的LoggerRepository对象,

public class DefaultRepositorySelector implements RepositorySelector {
  public
  LoggerRepository getLoggerRepository() {
    //LoggerRepository的默认实现:Hierarchy,通过上面LoggerManager的静态初始化方法设置
    return repository;
  } 
}

1.3.5 Hierarchy持有一个DefaultCategoryFactory对象,并从内部查找Logger对象

public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRendererSupport {
 public
 Logger getLogger(String name, LoggerFactory factory) {
   CategoryKey key = new CategoryKey(name);
   Logger logger;

   synchronized(ht) {
    //根据key获取对应的Logger对象
     Object o = ht.get(key);
     if(o == null) {
//获取不到的时候通过LoggerFactory对象创建
logger = factory.makeNewLoggerInstance(name);
logger.setHierarchy(this);
//缓存这个logger对象
ht.put(key, logger);
updateParents(logger);
return logger;
     } else if(o instanceof Logger) {
return (Logger) o;
     } else if (o instanceof ProvisionNode) {
logger = factory.makeNewLoggerInstance(name);
logger.setHierarchy(this);
ht.put(key, logger);
updateChildren((ProvisionNode) o, logger);
updateParents(logger);
return logger;
     }
     else {
return null;  
     }
   } 
 }
}

1.3.5 找不到时由DefaultCategoryFactory负责创建.

class DefaultCategoryFactory implements LoggerFactory {
DefaultCategoryFactory() {
}

public Logger makeNewLoggerInstance(String name) {
    //直接创建Logger对象
return new Logger(name);
}
}

1.3.6 debug方法在Logger的父类Category中实现

public class Category implements AppenderAttachable {
    public void debug(Object message) {
        if (repository.isDisabled(Level.DEBUG_INT))
            return;
    //检查当前的日志级别是否大于配置文件的日志级别
        if (Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel())) {
      //记录日志
            forcedLog(FQCN, Level.DEBUG, message, null);
        }
    }

    public Level getEffectiveLevel() {
    //循环,获取日志级别,获取不到就检查父类的日志级别
        for (Category c = this; c != null; c = c.parent) {
            if (c.level != null)
                return c.level;
        }
        return null; 
    }

    protected void forcedLog(String fqcn, Priority level, Object message, Throwable t) {
    //创建日志对象,并调用callAppenders方法
        callAppenders(new LoggingEvent(fqcn, this, level, message, t));
    }
   //
    public LoggingEvent(String fqnOfCategoryClass, Category logger,
                        Priority level, Object message, Throwable throwable) {
        this.fqnOfCategoryClass = fqnOfCategoryClass;
        this.logger = logger;
        this.categoryName = logger.getName();
        this.level = level;
        this.message = message;
        if (throwable != null) {
            this.throwableInfo = new ThrowableInformation(throwable, logger);
        }
        timeStamp = System.currentTimeMillis();
    }

    public void callAppenders(LoggingEvent event) {
        int writes = 0;
    //循环调用当前类及父类
        for (Category c = this; c != null; c = c.parent) {
            synchronized (c) {
                if (c.aai != null) {
          //调用AppenderAttachable类的
                    writes += c.aai.appendLoopOnAppenders(event);
                }
                if (!c.additive) {
                    break;
                }
            }
        }

        if (writes == 0) {
            repository.emitNoAppenderWarning(this);
        }
    }

}

1.3.7 AppenderAttachable:将日志记录到不同的Appender对象

public class AppenderAttachableImpl implements AppenderAttachable {
    public int appendLoopOnAppenders(LoggingEvent event) {
        int size = 0;
        Appender appender;

        if (appenderList != null) {
            size = appenderList.size();
            for (int i = 0; i < size; i++) {//循环
                appender = (Appender) appenderList.elementAt(i);
        //调用不同的Appender对象的Appender方法,将日志记录到不同的地方
                appender.doAppend(event);
            }
        }
        return size;
    }
}

1.3.8 AppenderSkeleton:实现Appender类,并提供抽放方法append,由不同的子类实现

public abstract class AppenderSkeleton implements Appender, OptionHandler {
    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();
            }
        }
    //对应的Append方法由子类实现
        this.append(event);
    }
}

1.3.9 WriterAppender

public class WriterAppender extends AppenderSkeleton {
    public void append(LoggingEvent event) {

        if (!checkEntryConditions()) {
            return;
        }
        subAppend(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();
        }
    }
}

1.3.10 ConsoleAppender:Appender的一个实现

public class ConsoleAppender extends WriterAppender {
public static final String SYSTEM_OUT = "System.out";
public static final String SYSTEM_ERR = "System.err";
protected String target;

public void activateOptions() {
      //设置默认的输出对象:System.out,System.err
if(this.target.equals("System.out")) {
this.setWriter(new OutputStreamWriter(System.out));
} else {
this.setWriter(new OutputStreamWriter(System.err));
}

}
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值