日志级别
log4j有6个日志级别:fatal(严重)-->error(错误)-->warn(警告)-->info(运行信息)-->debug(调试)-->trace(追踪)
日志级别从左到右依次递减
一、不使用配置文件
步骤:首先通过BasicConfigurator.configure()初始化默认的配置信息,接着创建日志记录器,最后输出日志。和JUL日志的类似
代码:
public void logTest() {
//初始化配置信息
BasicConfigurator.configure();
//创建日志记录器
Logger logger = Logger.getLogger(Log4jTest.class);
//输出日志
logger.fatal("fatal:严重错误"); //一般会造成系统崩溃
logger.error("error:错误信息"); //不会影响系统运行
logger.warn("warn:警告信息"); //可能会发生问题
logger.info("info:运行信息"); //数据连接,网络连接,io操作等
logger.debug("debug:调试信息"); //调试过程信息 (默认级别)
logger.trace("trace:追踪信息"); //记录程序的流程信息
}
输出结果:
0 [main] FATAL forTest.Log4jTest - fatal:严重错误
0 [main] ERROR forTest.Log4jTest - error:错误信息
0 [main] WARN forTest.Log4jTest - warn:警告信息
0 [main] INFO forTest.Log4jTest - info:运行信息
0 [main] DEBUG forTest.Log4jTest - debug:调试信息
通过BasicConfigurator.configure()我们查看源代码找到configure方法
/**
Add a {@link ConsoleAppender} that uses {@link PatternLayout}
using the {@link PatternLayout#TTCC_CONVERSION_PATTERN} and
prints to <code>System.out</code> to the root category. */
static
public
void configure() {
Logger root = Logger.getRootLogger();
root.addAppender(new ConsoleAppender(
new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));
}
1、可以发现在初始化的时候是创建了一个RootLogger的顶级父元素logger对象,同时添加了一个Appender对象,这是用来定义输出方式的。这里的ConsoleAppender是指定控制台输出,并且通过PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)设置了输出格式。
默认的日志输出级别为debug
二、使用配置文件
程序代码:
public void logQuickTest() {
//开启log4j内置日志
LogLog.setInternalDebugging(true);
//创建日志记录器
Logger logger = Logger.getLogger(Log4jTest.class);
/* 输出日志文件测试
for(int i=0;i<10000;i++) {
//输出日志
logger.fatal("fatal:严重错误"); //一般会造成系统崩溃
logger.error("error:错误信息"); //不会影响系统运行
logger.warn("warn:警告信息"); //可能会发生问题
logger.info("info:运行信息"); //数据连接,网络连接,io操作等
logger.debug("debug:调试信息"); //调试过程信息 (默认级别)
logger.trace("trace:追踪信息"); //记录程序的流程信息
}*/
//输出日志
logger.fatal("fatal:严重错误"); //一般会造成系统崩溃
logger.error("error:错误信息"); //不会影响系统运行
logger.warn("warn:警告信息"); //可能会发生问题
logger.info("info:运行信息"); //数据连接,网络连接,io操作等
logger.debug("debug:调试信息"); //调试过程信息 (默认级别)
logger.trace("trace:追踪信息"); //记录程序的流程信息
}
这里并没有使用 BasicConfigurator.configure() 初始化,原理我们通过源码查找,这里先跳过log4j内置日志的讲解,最后再来看,直接看到Logger logger = Logger.getLogger(Log4jTest.class)
进入到getLogger方法中
static
public
Logger getLogger(Class clazz) {
return LogManager.getLogger(clazz.getName());
}
我们发现了返回对象是LogManager.getLogger(clazz.getName()),说明很有可能和LogManager类有关系,直接进入LogManager类中,查看LogManager类
在其的静态属性中发现了默认的文件名属性,并且DEFAULT_CONFIGURATION_FILE官方注明是过时的了,他们推荐的使用log4j.xml。不过这里我们还是使用log4j.properties
static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";
也就是log4j.properties和log4j.xml
然后找到下面的静态代码块
static {
// By default we use a DefaultRepositorySelector which always returns 'h'.
Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
repositorySelector = new DefaultRepositorySelector(h);
/** Search for the properties file log4j.properties in the CLASSPATH. */
String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
null);
// if there is no default init override, then get the resource
// specified by the user or the default config file.
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;
// if the user has not specified the log4j.configuration
// property, we search first for the file "log4j.xml" and then
// "log4j.properties"
if(configurationOptionStr == null) {
url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
if(url == null) {
url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
}
} else {
try {
url = new URL(configurationOptionStr);
} catch (MalformedURLException ex) {
// so, resource is not a URL:
// attempt to get the resource from the class path
url = Loader.getResource(configurationOptionStr);
}
}
// If we have a non-null url, then delegate the rest of the
// configuration to the OptionConverter.selectAndConfigure
// method.
if(url != null) {
LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
try {
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.");
}
}
在上面的源代码中,我们可以看到
/** Search for the properties file log4j.properties in the CLASSPATH. */
String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
null);
通过注释我们可以理解,从这里开始寻找配置文件,紧接着下面是一些判断,再接着出现下面的语句:
如果我们没有配置log4j.configuration,我们首先会查找log4j.xml,然后再查找log4j.properties,也就是我们自定义的配置文件。
并通过加载器获取路径 url = Loader.getResource(DEFAULT_CONFIGURATION_FILE)
// if the user has not specified the log4j.configuration
// property, we search first for the file "log4j.xml" and then
// "log4j.properties"
if(configurationOptionStr == null) {
url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
if(url == null) {
url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
}
} else {
try {
url = new URL(configurationOptionStr);
} catch (MalformedURLException ex) {
// so, resource is not a URL:
// attempt to get the resource from the class path
url = Loader.getResource(configurationOptionStr);
}
}
到这里,就知道了log4j初始化配置文件的原理了。如果我们没有配置文件,我们要通过BasicConfigurator.configure() 初始化,在BasicConfigurator.configure()中创建了一个RootLogger的顶级父元素logger对象,同时添加了一个Appender对象,如果我们有配置文件,log4j就会进行查找,然后就可以加载到我们配置的logger和appender了。
下面是配置文件的详细配置
# 顶级父元素配置console、file、rollingfile、dailyfile
log4j.rootLogger = trace,console,file
# 自定义logger,级别覆盖,logger继承
log4j.logger.forTest.Log4jTest = info,rollingfile
# 控制台输出配置
log4j.appender.console = org.apache.log4j.ConsoleAppender
# log4j.appender.console.layout = org.apache.log4j.SimpleLayout
# 配置layout格式
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 配置Pattern属性conversionPattern
log4j.appender.console.layout.conversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS}[%p]%r %l %m%n
# 文件输出配置 FileAppender
log4j.appender.file = org.apache.log4j.FileAppender
# 配置layout格式类型
log4j.appender.file.layout = org.apache.log4j.PatternLayout
# 配置Pattern属性conversionPattern指定输出格式
log4j.appender.file.layout.conversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS}[%p]%r %l %m%n
# 配置文件保存路径
log4j.appender.file.file = H:/test/forTest/log4jn.log
# 指定日志文件内容的字符集
log4j.appender.file.encoding = UTF-8
# RollingFileAppender
# 按照文件大小拆分日志文件
log4j.appender.rollingfile = org.apache.log4j.RollingFileAppender
# 配置layout格式类型
log4j.appender.rollingfile.layout = org.apache.log4j.PatternLayout
# 配置Pattern属性conversionPattern指定输出格式
log4j.appender.rollingfile.layout.conversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS}[%p]%r %l %m%n
# 配置文件保存路径
log4j.appender.rollingfile.file = H:/test/forTest/log4j.log
# 指定日志文件内容的字符集
log4j.appender.rollingfile.encoding = UTF-8
# 指定允许的单个日志文件大小
log4j.appender.rollingfile.maxFileSize = 1MB
# 指定最多的日志文件数目,超过则覆盖存在最久的日志信息
log4j.appender.rollingfile.maxBackupIndex = 10
# DailyRollingFileAppender
# 按照时间拆分日志文件
log4j.appender.dailyfile = org.apache.log4j.DailyRollingFileAppender
# 配置layout格式类型
log4j.appender.dailyfile.layout = org.apache.log4j.PatternLayout
# 配置Pattern属性conversionPattern指定输出格式
log4j.appender.dailyfile.layout.conversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS}[%p]%r %l %m%n
# 配置文件保存路径
log4j.appender.dailyfile.file = H:/test/forTest/log4j.log
# 指定日志文件内容的字符集
log4j.appender.dailyfile.encoding = UTF-8
# 指定拆分单位
log4j.appender.dailyfile.datePattern = '.'yyyy-MM-dd-HH-mm-ss
log4j.appender.console.layout.conversionPattern中的字母表示:
# %m 输出代码中指定的日志信息
# %p 日志级别
# %n 换行符
# %r 输出日志的时间,单位毫秒
# %c 语句所属的类名
# %t 输出此日志信息的线程名
# %d 当前服务器时间
# %l 当前日志发生位置包括:类名、线程、所在代码行数
# %F 日志消息产生时所在的文件名
# %L 输出代码的行号
# %% 输出%
# %5c 在%和字符之间加上数字控制字符长度
配置文件中的相应属性都可以在相关的appender中查看,例如RollingFileAppender我们可以在源代码中找到所有属性
/**
The default maximum file size is 10MB.
*/
protected long maxFileSize = 10*1024*1024;
/**
There is one backup file by default.
*/
protected int maxBackupIndex = 1;
private long nextRollover = 0;
其他的类似。他们之间的继承关系也能在源代码中查看。
最后来看log4j内置日志:LogLog.setInternalDebugging(true)默认是关闭的,将属性设为true即可下面是内置日志的输出:
log4j: Trying to find [log4j.xml] using context classloader sun.misc.Launcher$AppClassLoader@14ae5a5.
log4j: Trying to find [log4j.xml] using sun.misc.Launcher$AppClassLoader@14ae5a5 class loader.
log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource().
log4j: Trying to find [log4j.properties] using context classloader sun.misc.Launcher$AppClassLoader@14ae5a5.
log4j: Using URL [file:/H:/test/forTest/bin/log4j.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/H:/test/forTest/bin/log4j.properties
log4j: Parsing for [root] with value=[trace,console].
log4j: Level token is [trace].
log4j: Category root set to TRACE
log4j: Parsing appender named "console".
log4j: Parsing layout options for "console".
log4j: Setting property [conversionPattern] to [%d{yyyy-MM-dd HH:mm:ss.SSS}[%p]%r %l %m%n].
log4j: End of parsing for "console".
log4j: Parsed "console" options.
log4j: Parsing for [forTest.Log4jTest] with value=[info,file].
log4j: Level token is [info].
log4j: Category forTest.Log4jTest set to INFO
log4j: Parsing appender named "file".
log4j: Parsing layout options for "file".
log4j: Setting property [conversionPattern] to [%d{yyyy-MM-dd HH:mm:ss.SSS}[%p]%r %l %m%n].
log4j: End of parsing for "file".
log4j: Setting property [file] to [H:/test/forTest/log4jn.log].
log4j: Setting property [encoding] to [UTF-8].
log4j: setFile called: H:/test/forTest/log4jn.log, true
log4j: setFile ended
log4j: Parsed "file" options.
log4j: Handling log4j.additivity.forTest.Log4jTest=[null]
log4j: Finished configuring.
从上面的输出我们可以知道,内置日志就是log4j从创建日志记录器开始的执行步骤包括配置文件的查找与读取,配置信息的执行,与我们上面讲的大致相同,通过内置日志我们可以清楚的了解到log4j的执行过程,便于我们分析,当过程出错时可以清晰地找到问题所在。
注意:在自定义logger中,级别是覆盖顶级父元素的级别的,但是appender是继承的。