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));
}
}
}