log4j源码分析

来源:互联网 发布:推广软件返现金 编辑:程序博客网 时间:2024/06/05 20:44

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 {staticpublic Logger getLogger(Class clazz) {      //对应的Logger对象通过LogManager的静态方法获取return LogManager.getLogger(clazz.getName());}} 

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

public class LogManager {publicstatic Logger getLogger(final String name) {return getLoggerRepository().getLogger(name);}staticpublic 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.errif(this.target.equals("System.out")) {this.setWriter(new OutputStreamWriter(System.out));} else {this.setWriter(new OutputStreamWriter(System.err));}}}
0 0
原创粉丝点击