java中volatile关键字的含义:[url]http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html[/url]
Java transient关键字使用小记:[url]http://www.cnblogs.com/lanxuezaipiao/p/3369962.html[/url]
Log4j初始化详解:[url]http://donald-draper.iteye.com/blog/2332385[/url]
Log4j日志输出详解 :[url]http://donald-draper.iteye.com/blog/2332395[/url]
slf4j + Log4j的使用:[url]http://donald-draper.iteye.com/blog/2332407[/url]
上一篇简单学习了Log4j的使用,今天来看一下,日志初始化,
我们就从下面这一句来看:
查看Logger
来看LogManager的getLogger方法
//LogManager
//NOPLoggerRepository
//NOPLogger
而Logger继承Category
//Category
//Level
//Priority
我们在回到LogManager加载log4j属性文件,关键在这一句
这个LoggerRepository实际为NOPLoggerRepository
来看log4j.properties属性文件解析
//PropertyConfigurator
//配置RootCategory,rootLogger,appenders
来看 OptionConverter.findAndSubst
//返回key对应的属性
//NOPLoggerRepository,获取rootLogger
//PropertyConfigurator
//根据appenderName解析Appender
//OptionConverter.instantiateByKey
//PropertyConfigurator
// protected Hashtable registry;HashTable<String,Appender>
//将Appender放入registry
下面我们来看看logger.addAppender,都做了些什么
//AppenderAttachableImpl
总结:
[color=blue]从以上我们可以看出:log4j,通过LogManager的static语句块,加载配置log4j.properties,由OptionConverter去加载log4j.properties,并委托给PropertyConfigurator,去配置RootLogger,根据RootLogger获取Appender,然后根据属性文件初始化Appender,并添加到RootLogger的appender集合中。[/color]
Java transient关键字使用小记:[url]http://www.cnblogs.com/lanxuezaipiao/p/3369962.html[/url]
Log4j初始化详解:[url]http://donald-draper.iteye.com/blog/2332385[/url]
Log4j日志输出详解 :[url]http://donald-draper.iteye.com/blog/2332395[/url]
slf4j + Log4j的使用:[url]http://donald-draper.iteye.com/blog/2332407[/url]
上一篇简单学习了Log4j的使用,今天来看一下,日志初始化,
我们就从下面这一句来看:
private static Logger log = Logger.getLogger(testLog4j.class);
查看Logger
public class Logger extends Category
{
protected Logger(String name)
{
super(name);
}
//获取Logger
public static Logger getLogger(String name)
{
return LogManager.getLogger(name);
}
public static Logger getLogger(Class clazz)
{
return LogManager.getLogger(clazz.getName());
}
static
{
FQCN = (org.apache.log4j.Logger.class).getName();
}
}
来看LogManager的getLogger方法
//LogManager
public class LogManager
{
public static Logger getLogger(String name)
{
return getLoggerRepository().getLogger(name);
}
//获取本机LoggerRepository
public static 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);
}
return repositorySelector.getLoggerRepository();
}
public static final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";
public static final String DEFAULT_CONFIGURATION_KEY = "log4j.configuration";
public static final String CONFIGURATOR_CLASS_KEY = "log4j.configuratorClass";
public static final String DEFAULT_INIT_OVERRIDE_KEY = "log4j.defaultInitOverride";
private static Object guard = null;
private static RepositorySelector repositorySelector;
//加载log4j配置文件,先加载log4j.xml,如果log4j.xml不存在,
//则加载log4j.properties文件
static
{
Hierarchy h = new Hierarchy(new RootLogger(Level.DEBUG));
repositorySelector = new DefaultRepositorySelector(h);
String override = OptionConverter.getSystemProperty("log4j.defaultInitOverride", null);
if(override == null || "false".equalsIgnoreCase(override))
{
String configurationOptionStr = OptionConverter.getSystemProperty("log4j.configuration", null);
String configuratorClassName = OptionConverter.getSystemProperty("log4j.configuratorClass", null);
URL url = null;
if(configurationOptionStr == null)
{
url = Loader.getResource("log4j.xml");
if(url == null)
url = Loader.getResource("log4j.properties");
} 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
{
OptionConverter.selectAndConfigure(url, configuratorClassName, getLoggerRepository());
}
}
}
}
}
//DefaultRepositorySelector
public class DefaultRepositorySelector
implements RepositorySelector
{
public DefaultRepositorySelector(LoggerRepository repository)
{
this.repository = repository;
}
public LoggerRepository getLoggerRepository()
{
return repository;
}
final LoggerRepository repository;
}
//NOPLoggerRepository
public final class NOPLoggerRepository
implements LoggerRepository
{
//从这里看,Logger实际上为NOPLogger
public Logger getLogger(String name)
{
return new NOPLogger(this, name);
}
}
//NOPLogger
public final class NOPLogger extends Logger
{
public NOPLogger(NOPLoggerRepository repo, String name)
{
super(name);
repository = repo;
level = Level.OFF;
parent = this;
}
}
而Logger继承Category
public class Logger extends Category
{
protected Logger(String name)
{
super(name);
}
}
//Category
public class Category
implements AppenderAttachable
{
protected Category(String name)
{
additive = true;
this.name = name;
}
protected String name;
//volatile
protected volatile Level level;
protected volatile Category parent;
private static final String FQCN;
protected ResourceBundle resourceBundle;
protected LoggerRepository repository;
AppenderAttachableImpl aai;
protected boolean additive;
static
{
FQCN = (org.apache.log4j.Category.class).getName();
}
}
//Level
public class Level extends Priority
implements Serializable
{
protected Level(int level, String levelStr, int syslogEquivalent)
{
super(level, levelStr, syslogEquivalent);
}
public static final int TRACE_INT = 5000;
public static final Level OFF = new Level(2147483647, "OFF", 0);
public static final Level FATAL = new Level(50000, "FATAL", 0);
public static final Level ERROR = new Level(40000, "ERROR", 3);
public static final Level WARN = new Level(30000, "WARN", 4);
public static final Level INFO = new Level(20000, "INFO", 6);
public static final Level DEBUG = new Level(10000, "DEBUG", 7);
public static final Level TRACE = new Level(5000, "TRACE", 7);
public static final Level ALL = new Level(-2147483648, "ALL", 7);
static final long serialVersionUID = 3491141966387921974L;
}
//Priority
public class Priority
{
protected Priority()
{
level = 10000;
levelStr = "DEBUG";
syslogEquivalent = 7;
}
protected Priority(int level, String levelStr, int syslogEquivalent)
{
this.level = level;
this.levelStr = levelStr;
this.syslogEquivalent = syslogEquivalent;
}
//比较日志级别
public boolean isGreaterOrEqual(Priority r)
{
return level >= r.level;
}
transient int level;
transient String levelStr;
transient int syslogEquivalent;
public static final int OFF_INT = 2147483647;
public static final int FATAL_INT = 50000;
public static final int ERROR_INT = 40000;
public static final int WARN_INT = 30000;
public static final int INFO_INT = 20000;
public static final int DEBUG_INT = 10000;
public static final int ALL_INT = -2147483648;
public static final Priority FATAL = new Level(50000, "FATAL", 0);
public static final Priority ERROR = new Level(40000, "ERROR", 3);
public static final Priority WARN = new Level(30000, "WARN", 4);
public static final Priority INFO = new Level(20000, "INFO", 6);
public static final Priority DEBUG = new Level(10000, "DEBUG", 7);
}
我们在回到LogManager加载log4j属性文件,关键在这一句
OptionConverter.selectAndConfigure(url, configuratorClassName, getLoggerRepository());
这个LoggerRepository实际为NOPLoggerRepository
public class OptionConverter
{
public static 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";
//XML配置解析
if(clazz != null)
{
LogLog.debug("Preferred configurator class: " + clazz);
configurator = (Configurator)instantiateByClassName(clazz, org.apache.log4j.spi.Configurator.class, null);
} else
{
//java属性文件解析log4j.properties
configurator = new PropertyConfigurator();
}
//配置NOPLoggerRepository
configurator.doConfigure(url, hierarchy);
}
static String DELIM_START = "${";
static char DELIM_STOP = '}';
static int DELIM_START_LEN = 2;
static int DELIM_STOP_LEN = 1;
}
}
来看log4j.properties属性文件解析
//PropertyConfigurator
public class PropertyConfigurator
implements Configurator
{
protected Hashtable registry;
private LoggerRepository repository;
protected LoggerFactory loggerFactory;
static final String CATEGORY_PREFIX = "log4j.category.";
static final String LOGGER_PREFIX = "log4j.logger.";
static final String FACTORY_PREFIX = "log4j.factory";
static final String ADDITIVITY_PREFIX = "log4j.additivity.";
static final String ROOT_CATEGORY_PREFIX = "log4j.rootCategory";
static final String ROOT_LOGGER_PREFIX = "log4j.rootLogger";
static final String APPENDER_PREFIX = "log4j.appender.";
static final String RENDERER_PREFIX = "log4j.renderer.";
static final String THRESHOLD_PREFIX = "log4j.threshold";
private static final String THROWABLE_RENDERER_PREFIX = "log4j.throwableRenderer";
private static final String LOGGER_REF = "logger-ref";
private static final String ROOT_REF = "root-ref";
private static final String APPENDER_REF_TAG = "appender-ref";
public static final String LOGGER_FACTORY_KEY = "log4j.loggerFactory";
private static final String RESET_KEY = "log4j.reset";
private static final String INTERNAL_ROOT_NAME = "root";
public PropertyConfigurator()
{
registry = new Hashtable(11);
loggerFactory = new DefaultCategoryFactory();
}
//加载URL文件到Properties
public void doConfigure(URL configURL, LoggerRepository hierarchy)
{
Properties props;
InputStream istream;
props = new Properties();
istream = null;
URLConnection uConn = null;
URLConnection uConn = configURL.openConnection();
uConn.setUseCaches(false);
istream = uConn.getInputStream();
props.load(istream);
//加载URL文件到Properties
doConfigure(props, hierarchy);
}
//根据properties文件配置NOPLoggerRepository
public void doConfigure(Properties properties, LoggerRepository hierarchy)
{
repository = hierarchy;
String value = properties.getProperty("log4j.debug");
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("log4j.reset");
if(reset != null && OptionConverter.toBoolean(reset, false))
hierarchy.resetConfiguration();
String thresholdStr = OptionConverter.findAndSubst("log4j.threshold", properties);
if(thresholdStr != null)
{
hierarchy.setThreshold(OptionConverter.toLevel(thresholdStr, Level.ALL));
LogLog.debug("Hierarchy threshold set to [" + hierarchy.getThreshold() + "].");
}
//配置RootCategory,rootLogger,appenders
configureRootCategory(properties, hierarchy);
configureLoggerFactory(properties);
parseCatsAndRenderers(properties, hierarchy);
LogLog.debug("Finished configuring.");
registry.clear();
}
}
//配置RootCategory,rootLogger,appenders
void configureRootCategory(Properties props, LoggerRepository hierarchy)
{
String effectiveFrefix = "log4j.rootLogger";
String value = OptionConverter.findAndSubst("log4j.rootLogger", props);
if(value == null)
{
LogLog.debug("Could not find root logger information. Is this OK?");
} else
{
Logger root = hierarchy.getRootLogger();
synchronized(root)
{
parseCategory(props, root, effectiveFrefix, "root", value);
}
}
}
来看 OptionConverter.findAndSubst
//返回key对应的属性
public static String findAndSubst(String key, Properties props)
{
String value;
value = props.getProperty(key);
}
//NOPLoggerRepository,获取rootLogger
public Logger getRootLogger()
{
return new NOPLogger(this, "root");
}
//PropertyConfigurator
void parseCategory(Properties props, Logger logger, String optionKey, String loggerName, String value)
{
StringTokenizer st = new StringTokenizer(value, ",");
if(!value.startsWith(",") && !value.equals(""))
{
if(!st.hasMoreTokens())
return;
//获取rootLogger,日志级别
String levelStr = st.nextToken();
if("inherited".equalsIgnoreCase(levelStr) || "null".equalsIgnoreCase(levelStr))
{
if(loggerName.equals("root"))
LogLog.warn("The root logger cannot be set to null.");
else
logger.setLevel(null);
} else
{
//设置rootLogger,日志级别
logger.setLevel(OptionConverter.toLevel(levelStr, Level.DEBUG));
}
LogLog.debug("Category " + loggerName + " set to " + logger.getLevel());
}
//移除Appenders
logger.removeAllAppenders();
do
{
if(!st.hasMoreTokens())
break;
String appenderName = st.nextToken().trim();
if(appenderName != null && !appenderName.equals(","))
{
LogLog.debug("Parsing appender named \"" + appenderName + "\".");
//根据appenderName解析Appender
Appender appender = parseAppender(props, appenderName);
if(appender != null)
//添加appender
logger.addAppender(appender);
}
} while(true);
}
//根据appenderName解析Appender
Appender parseAppender(Properties props, String appenderName)
{
Appender appender = registryGet(appenderName);
if(appender != null)
{
LogLog.debug("Appender \"" + appenderName + "\" was already parsed.");
return appender;
}
//log4j.appender的前缀
String prefix = "log4j.appender." + appenderName;
//log4j.appender.appenderName.layout
String layoutPrefix = prefix + ".layout";
//加载Appender,Class,
//log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
appender = (Appender)OptionConverter.instantiateByKey(props, prefix, org.apache.log4j.Appender.class, null);
appender.setName(appenderName);
if(appender instanceof OptionHandler)
{
if(appender.requiresLayout())
{
//加载Layout,class,
//log4j.appender.D.layout = org.apache.log4j.PatternLayout
Layout layout = (Layout)OptionConverter.instantiateByKey(props, layoutPrefix, org.apache.log4j.Layout.class, null);
if(layout != null)
{
appender.setLayout(layout);
LogLog.debug("Parsing layout options for \"" + appenderName + "\".");
//设置layout的属性
PropertySetter.setProperties(layout, props, layoutPrefix + ".");
LogLog.debug("End of parsing for \"" + appenderName + "\".");
}
}
String errorHandlerPrefix = prefix + ".errorhandler";
String errorHandlerClass = OptionConverter.findAndSubst(errorHandlerPrefix, props);
if(errorHandlerClass != null)
{
ErrorHandler eh = (ErrorHandler)OptionConverter.instantiateByKey(props, errorHandlerPrefix, org.apache.log4j.spi.ErrorHandler.class, null);
if(eh != null)
{
appender.setErrorHandler(eh);
LogLog.debug("Parsing errorhandler options for \"" + appenderName + "\".");
parseErrorHandler(eh, errorHandlerPrefix, props, repository);
Properties edited = new Properties();
String keys[] = {
errorHandlerPrefix + "." + "root-ref", errorHandlerPrefix + "." + "logger-ref", errorHandlerPrefix + "." + "appender-ref"
};
Iterator iter = props.entrySet().iterator();
do
{
if(!iter.hasNext())
break;
java.util.Map.Entry entry = (java.util.Map.Entry)iter.next();
int i;
for(i = 0; i < keys.length && !keys[i].equals(entry.getKey()); i++);
if(i == keys.length)
edited.put(entry.getKey(), entry.getValue());
} while(true);
PropertySetter.setProperties(eh, edited, errorHandlerPrefix + ".");
LogLog.debug("End of errorhandler parsing for \"" + appenderName + "\".");
}
}
//设置Appender属性
PropertySetter.setProperties(appender, props, prefix + ".");
LogLog.debug("Parsed \"" + appenderName + "\" options.");
}
parseAppenderFilters(props, appenderName, appender);
//将Appender放入registry
registryPut(appender);
return appender;
}
//OptionConverter.instantiateByKey
public static Object instantiateByKey(Properties props, String key, Class superClass, Object defaultValue)
{
String className = findAndSubst(key, props);
if(className == null)
{
LogLog.error("Could not find value for key " + key);
return defaultValue;
} else
{
return instantiateByClassName(className.trim(), superClass, defaultValue);
}
}
//PropertyConfigurator
// protected Hashtable registry;HashTable<String,Appender>
//将Appender放入registry
void registryPut(Appender appender)
{
registry.put(appender.getName(), appender);
}
下面我们来看看logger.addAppender,都做了些什么
public class Category
implements AppenderAttachable
{
//添加Appender
public synchronized void addAppender(Appender newAppender)
{
if(aai == null)
aai = new AppenderAttachableImpl();
aai.addAppender(newAppender);
//通知repository,添加Appender事件
repository.fireAddAppenderEvent(this, newAppender);
}
//移除AllAppenders
public synchronized void removeAllAppenders()
{
if(aai != null)
{
Vector appenders = new Vector();
for(Enumeration iter = aai.getAllAppenders(); iter != null && iter.hasMoreElements(); appenders.add(iter.nextElement()));
aai.removeAllAppenders();
for(Enumeration iter = appenders.elements(); iter.hasMoreElements(); fireRemoveAppenderEvent((Appender)iter.nextElement()));
aai = null;
}
}
}
//AppenderAttachableImpl
public class AppenderAttachableImpl
implements AppenderAttachable
{
//添加Appender
public void addAppender(Appender newAppender)
{
if(newAppender == null)
return;
if(appenderList == null)
appenderList = new Vector(1);
if(!appenderList.contains(newAppender))
appenderList.addElement(newAppender);
}
//Vector<Appender>
protected Vector appenderList;
}
总结:
[color=blue]从以上我们可以看出:log4j,通过LogManager的static语句块,加载配置log4j.properties,由OptionConverter去加载log4j.properties,并委托给PropertyConfigurator,去配置RootLogger,根据RootLogger获取Appender,然后根据属性文件初始化Appender,并添加到RootLogger的appender集合中。[/color]