log4j 2是log4j的升级版
log4j 2简介:http://logging.apache.org/log4j/2.x/manual/index.html
1. 下载log4j 2
log4j 2官网:http://logging.apache.org/log4j/2.x/
log4j 2下载页面:http://logging.apache.org/log4j/2.x/download.html
我下载的是”apache-log4j-2.0-beta9-bin.zip”,解压该文件,将log4j-api-2.0-beta9.jar、log4j-core-2.0-beta9.jar导入项目,即可使用log4j 2
2. 初识log4j 2
- package log4j2;
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- public class Test01 {
- public static void main(String[] args) {
- Logger logger = LogManager.getLogger(Test01.class.getName());
- logger.trace("trace");
- logger.debug("debug");
- logger.info("hello");
- logger.warn("warn");
- logger.error("error");
- logger.fatal("fatal");
- }
- }
Output:
- 12:24:25.398 [main] ERROR log4j2.Test01 - error
- 12:24:25.401 [main] FATAL log4j2.Test01 - fatal
代码中写了6种输出,为什么只出来”error”,”fatal”呢?
原来log4j 2初始化时,自动从src目录加载配置文件。配置文件的格式有两种:json和xml
配置文件的优先级(从高到低):
log4j2-test.json(或log4j2-test.jsn)
log4j2-test.xml
log4j2.json(或log4j2.jsn)
log4j2.xml
默认配置文件
log4j 2初始化时,优先从src目录下找”log4j2-test.json(或log4j2-test.jsn)”,如果没找到,会继续找”log4j2-test.xml”,以此类推
刚才的例子中,src目录下没有配置文件,因此log4j 2将使用默认配置文件
默认配置文件由DefaultConfiguration类提供。DefaultConfiguration内容:
- * Licensed to the Apache Software Foundation (ASF) under one or more
- package org.apache.logging.log4j.core.config;
- import java.io.Serializable;
- import org.apache.logging.log4j.Level;
- import org.apache.logging.log4j.core.Appender;
- import org.apache.logging.log4j.core.Layout;
- import org.apache.logging.log4j.core.appender.ConsoleAppender;
- import org.apache.logging.log4j.core.layout.PatternLayout;
- import org.apache.logging.log4j.util.PropertiesUtil;
- /**
- * The default configuration writes all output to the Console using the default logging level. You configure default
- * logging level by setting the system property "org.apache.logging.log4j.level" to a level name. If you do not
- * specify the property, Log4j uses the ERROR Level. Log Events will be printed using the basic formatting provided
- * by each Message.
- */
- public class DefaultConfiguration extends BaseConfiguration {
- /**
- * The name of the default configuration.
- */
- public static final String DEFAULT_NAME = "Default";
- /**
- * The System Property used to specify the logging level.
- */
- public static final String DEFAULT_LEVEL = "org.apache.logging.log4j.level";
- /**
- * Constructor to create the default configuration.
- */
- public DefaultConfiguration() {
- setName(DEFAULT_NAME);
- final Layout<? extends Serializable> layout =
- PatternLayout.createLayout("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n", null, null, null, null);
- final Appender appender =
- ConsoleAppender.createAppender(layout, null, "SYSTEM_OUT", "Console", "false", "true");
- appender.start();
- addAppender(appender);
- final LoggerConfig root = getRootLogger();
- root.addAppender(appender, null, null);
- final String levelName = PropertiesUtil.getProperties().getStringProperty(DEFAULT_LEVEL);
- final Level level = levelName != null && Level.valueOf(levelName) != null ?
- Level.valueOf(levelName) : Level.ERROR;
- root.setLevel(level);
- }
- @Override
- protected void doConfigure() {
- }
- }
DefaultConfiguration提供的默认配置等同于如下配置:
- <?xml version="1.0" encoding="UTF-8"?>
- <Configuration status="WARN">
- <Appenders>
- <Console name="Console" target="SYSTEM_OUT">
- <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
- </Console>
- </Appenders>
- <Loggers>
- <Root level="error">
- <AppenderRef ref="Console"/>
- </Root>
- </Loggers>
- </Configuration>
log4j 2定义了8个事件级别:ALL,TRACE, DEBUG, INFO, WARN, ERROR ,FATAL,OFF(由低到高)
由于Root level设置为”error”,因此只有等于或高于”error”级别的事件才能输出。所以刚才的例子中只输出了”error”,”fatal”
3. log4j 2读取配置文件
log4j 2读取的配置文件可以分为三类:src下的配置文件、绝对路径的配置文件、相对路径的配置文件
3.1 log4j 2读取src下的配置文件
在src目录下创建log4j2.xml,复制log4j 2默认配置的内容到log4j2.xml,并将log4j2.xml里的Root level改为”trace”,内容如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <Configuration status="WARN">
- <Appenders>
- <Console name="Console" target="SYSTEM_OUT">
- <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
- </Console>
- </Appenders>
- <Loggers>
- <Root level="trace">
- <AppenderRef ref="Console"/>
- </Root>
- </Loggers>
- </Configuration>
再次运行Test01 ,输出如下:
- 13:24:03.939 [main] TRACE log4j2.Test01 - trace
- 13:24:03.942 [main] DEBUG log4j2.Test01 - debug
- 13:24:03.942 [main] INFO log4j2.Test01 - info
- 13:24:03.942 [main] WARN log4j2.Test01 - warn
- 13:24:03.942 [main] ERROR log4j2.Test01 - error
- 13:24:03.942 [main] FATAL log4j2.Test01 - fatal
3.2 log4j 2读取绝对路径的配置文件
将log4j2.xml拷贝到E盘下,并将其改名为Test02.xml,然后将Test02.xml里的Root level设置为”debug”
测试代码如下
- package log4j2;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- import org.apache.logging.log4j.core.config.ConfigurationFactory.ConfigurationSource;
- import org.apache.logging.log4j.core.config.Configurator;
- public class Test02 {
- public static void main(String[] args) throws FileNotFoundException {
- //绝对路径配置文件
- ConfigurationSource source = new ConfigurationSource();
- source.setLocation("E:\\Test02.xml");
- source.setFile(new File("E:\\Test02.xml"));
- source.setInputStream(new FileInputStream("E:\\Test02.xml"));
- Configurator.initialize(null, source);
- Logger logger = LogManager.getLogger(Test02.class.getName());
- logger.trace("trace");
- logger.debug("debug");
- logger.info("info");
- logger.warn("warn");
- logger.error("error");
- logger.fatal("fatal");
- }
- }
Output:
- 14:54:46.102 [main] DEBUG log4j2.Test02 - debug
- 14:54:46.105 [main] INFO log4j2.Test02 - info
- 14:54:46.105 [main] WARN log4j2.Test02 - warn
- 14:54:46.105 [main] ERROR log4j2.Test02 - error
- 14:54:46.105 [main] FATAL log4j2.Test02 - fatal
可以看到trace内容并没有输出,说明读取配置文件成功
3.3 log4j 2读取相对路径的配置文件
获取运行时路径的方法
- package log4j2;
- public class Test03 {
- public static void main(String[] args) {
- System.out.println("Working Directory = " +
- System.getProperty("user.dir"));
- }
- }
Output:
- Working Directory = E:\project\eclipse\Test
在”E:\project\eclipse\Test\bin\log4j2”新建Test03文件夹。
然后将log4j2.xml拷贝到”E:\project\eclipse\Test\bin\log4j2\Test03”下,并将其改名为Test03.xml,然后将Test03.xml里的Root level设置为”info”
测试代码如下:
- package log4j2;
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- import org.apache.logging.log4j.core.config.XMLConfigurationFactory;
- public class Test03 {
- public static void main(String[] args) {
- System.out.println("Working Directory = " +
- System.getProperty("user.dir"));
- //相对路径配置文件
- System.setProperty(XMLConfigurationFactory.CONFIGURATION_FILE_PROPERTY, "log4j2/Test03/Test03.xml");
- Logger logger = LogManager.getLogger(Test03.class.getName());
- logger.trace("trace");
- logger.debug("debug");
- logger.info("info");
- logger.warn("warn");
- logger.error("error");
- logger.fatal("fatal");
- }
- }
Output:
- Working Directory = E:\project\eclipse\Test
- 15:11:09.870 [main] INFO log4j2.Test01 - info
- 15:11:09.872 [main] WARN log4j2.Test01 - warn
- 15:11:09.873 [main] ERROR log4j2.Test01 - error
- 15:11:09.873 [main] FATAL log4j2.Test01 - fatal
可以看到trace,debug内容并没有输出,说明读取配置文件成功
下面的测试均采用log4j 2读取src下配置文件的方式
4. Appenders
Appender负责定义日志输出的目的地,它可以是控制台(ConsoleAppender)、文件(FileAppender)、以Email的形式发送出去(SMTPAppender)等
Log4j 2官网介绍了20种Appender:http://logging.apache.org/log4j/2.x/manual/appenders.html
下面介绍3种常用的Appender:ConsoleAppender、FileAppender、RollingFileAppender
4.1 ConsoleAppender
ConsoleAppender将输出写到System.err或System.out。上面测试例子中的Appender均为ConsoleAppender,输出写到了System.out。如果想将输出写到System.err,设置Console标签下的target为"SYSTEM_ERR "即可
4.2 FileAppender
FileAppender将输出写到指定文件,在File标签下设置fileName即可。fileName可以是绝对路径的文件也可以是相对路径的文件
写到绝对路径文件
修改src下的log4j2.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <Configuration status="WARN">
- <Appenders>
- <!--FileAppender-->
- <File name="File" fileName="E:\Test01.log">
- <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
- </File>
- </Appenders>
- <Loggers>
- <Root level="trace">
- <AppenderRef ref="File"/>
- </Root>
- </Loggers>
- </Configuration>
运行Test01,log将写到E:\Test01.log
写到相对路径文件
修改src下的log4j2.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <Configuration status="WARN">
- <Appenders>
- <!--FileAppender-->
- <File name="File" fileName="logs/Test01.log">
- <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
- </File>
- </Appenders>
- <Loggers>
- <Root level="trace">
- <AppenderRef ref="File"/>
- </Root>
- </Loggers>
- </Configuration>
运行Test01,log将写到E:\project\eclipse\Test\logs\Test01.log
4.3 RollingFileAppender
RollingFileAppender跟FileAppender的基本用法一样。但RollingFileAppender可以设置log文件的size(单位:KB/MB/GB)上限、数量上限,当log文件超过设置的size上限,会自动被压缩。RollingFileAppender可以理解为滚动输出日志,如果log4j 2记录的日志达到上限,旧的日志将被删除,腾出的空间用于记录新的日志
修改src下的log4j2.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <Configuration status="WARN">
- <Appenders>
- <!--RollingFile-->
- <RollingFile name="RollingFile" fileName="logs/Test.log"
- filePattern="logs/$${date:yyyy-MM}/Test-%d{MM-dd-yyyy}-%i.log.gz">
- <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
- <Policies>
- <TimeBasedTriggeringPolicy />
- <SizeBasedTriggeringPolicy size="1 KB"/>
- </Policies>
- <DefaultRolloverStrategy max="10"/>
- </RollingFile>
- </Appenders>
- <Loggers>
- <Root level="trace">
- <AppenderRef ref="RollingFile"/>
- </Root>
- </Loggers>
- </Configuration>
该配置设置日志写到Test.Log,如果Test.log的大小超过1KB,log4j 2会将Test.log制成压缩文件(压缩文件的命名格式是由filePattern设置的)。DefaultRolloverStrategy 标签的max设置压缩文件的上限(默认值为7)
将Test01的输出循环50次
- package log4j2;
- import java.io.FileNotFoundException;
- import java.io.InputStream;
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- import org.apache.logging.log4j.core.LoggerContext;
- import org.apache.logging.log4j.core.config.Configuration;
- import org.apache.logging.log4j.core.config.ConfigurationFactory.ConfigurationSource;
- import org.apache.logging.log4j.core.config.XMLConfigurationFactory;
- public class Test01 {
- public static void main(String[] args) throws FileNotFoundException {
- Logger logger = LogManager.getLogger(Test01.class.getName());
- for (int i = 0; i < 50; i++) {
- logger.trace("trace");
- logger.debug("debug");
- logger.info("info");
- logger.warn("warn");
- logger.error("error");
- logger.fatal("fatal");
- }
- }
- }
可以在E:\project\eclipse\Test\logs\2014-02看到如下压缩文件
5. Filters
Filter可以过滤log事件,并控制log输出
log4j 2定义了10种 Filter:http://logging.apache.org/log4j/2.x/manual/filters.html
下面介绍一下BurstFilter的用法
BurstFilter可以控制某一级别的log的并发情况
修改src下的log4j2.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <Configuration status="warn" name="MyApp" packages="">
- <Appenders>
- <RollingFile name="RollingFile" fileName="logs/app.log"
- filePattern="logs/app-%d{MM-dd-yyyy}.log.gz">
- <BurstFilter level="INFO" rate="16" maxBurst="100"/>
- <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
- <Policies>
- <TimeBasedTriggeringPolicy />
- <SizeBasedTriggeringPolicy size="1 KB"/>
- </Policies>
- <DefaultRolloverStrategy max="10"/>
- </RollingFile>
- </Appenders>
- <Loggers>
- <Root level="trace">
- <AppenderRef ref="RollingFile"/>
- </Root>
- </Loggers>
- </Configuration>
<BurstFilter level="INFO" rate="16" maxBurst="100"/>标签解释
level:BurstFilter过滤的事件级别
rate:每秒允许的log事件的平均值
maxBurst:当BurstFilter过滤的事件超过rate值,排队的log事件上限。超过此上限的log,将被丢弃。默认情况下maxBurst = 10*rate
按以上配置,假定每个log事件的执行时间较长,输出117个log事件(INFO级别)到RollingFileAppenders,BurstFilter会过滤得到INFO级别的log事件,之后会发生:16个log事件在执行,100个等待执行,1个被丢弃。
6. log4j 2指定某个类的log输出级别
在log4j2.xml设置Test01的输出级别
修改src下的log4j2.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <Configuration status="WARN">
- <Appenders>
- <Console name="Console" target="SYSTEM_OUT">
- <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
- </Console>
- </Appenders>
- <Loggers>
- <Logger name="log4j2.Test01" level="trace">
- <AppenderRef ref="Console"/>
- </Logger>
- <Root level="error">
- <AppenderRef ref="Console"/>
- </Root>
- </Loggers>
- </Configuration>
修改Test01
- package log4j2;
- import java.io.FileNotFoundException;
- import java.io.InputStream;
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- import org.apache.logging.log4j.core.LoggerContext;
- import org.apache.logging.log4j.core.config.Configuration;
- import org.apache.logging.log4j.core.config.ConfigurationFactory.ConfigurationSource;
- import org.apache.logging.log4j.core.config.XMLConfigurationFactory;
- public class Test01 {
- public static void main(String[] args) throws FileNotFoundException {
- Logger logger = LogManager.getLogger(Test01.class.getName());
- logger.trace("trace");
- logger.debug("debug");
- logger.info("info");
- logger.warn("warn");
- logger.error("error");
- logger.fatal("fatal");
- }
- }
运行Test01
Output:
- 16:12:08.662 [main] TRACE log4j2.Test01 - trace
- 16:12:08.662 [main] TRACE log4j2.Test01 - trace
- 16:12:08.665 [main] DEBUG log4j2.Test01 - debug
- 16:12:08.665 [main] DEBUG log4j2.Test01 - debug
- 16:12:08.665 [main] INFO log4j2.Test01 - info
- 16:12:08.665 [main] INFO log4j2.Test01 - info
- 16:12:08.665 [main] WARN log4j2.Test01 - warn
- 16:12:08.665 [main] WARN log4j2.Test01 - warn
- 16:12:08.666 [main] ERROR log4j2.Test01 - error
- 16:12:08.666 [main] ERROR log4j2.Test01 - error
- 16:12:08.666 [main] FATAL log4j2.Test01 - fatal
- 16:12:08.666 [main] FATAL log4j2.Test01 - fatal
可以看到Test01里的日志输出了两次
原来log4j 2的配置文件都有一个root logger,root logger的level为”error”,appender为”console”。如果配置文件中没有设置Test01 logger,那么Test01将使用root logger;如果配置文件中设置了Test01 logger,则Test01 logger(子logger)的appender先输出,但Test01 logger的事件还会传到root logger(父logger)的appender,然后再次输出。
为了避免重复输出,可以在Logger 标签下设置additivity为"false",禁止子logger在父logger的appender里输出。修改后的log4j2.xml:
- <?xml version="1.0" encoding="UTF-8"?>
- <Configuration status="WARN">
- <Appenders>
- <Console name="Console" target="SYSTEM_OUT">
- <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
- </Console>
- </Appenders>
- <Loggers>
- <Logger name="log4j2.Test01" level="trace" additivity="false">
- <AppenderRef ref="Console"/>
- </Logger>
- <Root level="error">
- <AppenderRef ref="Console"/>
- </Root>
- </Loggers>
- </Configuration>
Output:
- 16:30:52.339 [main] TRACE log4j2.Test01 - trace
- 16:30:52.342 [main] DEBUG log4j2.Test01 - debug
- 16:30:52.342 [main] INFO log4j2.Test01 - info
- 16:30:52.342 [main] WARN log4j2.Test01 - warn
- 16:30:52.342 [main] ERROR log4j2.Test01 - error
- 16:30:52.342 [main] FATAL log4j2.Test01 - fatal
7. log4j 2可以定时检测配置文件的变化
通过设置monitorInterval属性,即可设置log4j 2自动检测配置文件的时间间隔(单位:秒),最小间隔为5秒。log4j 2检测到配置文件有变化,会重新配置自己。
- <?xml version="1.0" encoding="UTF-8"?>
- <Configuration monitorInterval="30">
- </Configuration>
8. Status
文中的配置文件的开头都有如下设置
- <Configuration status="WARN">
status究竟有什么用处呢?
log4j 2定义的status级别有8个:ALL,TRACE, DEBUG, INFO, WARN, ERROR ,FATAL,OFF
举例:如果设置INFO 那么INFO靠右所有的都会显示
其实status属性是帮助开发者找错用的,它可以检测log4j 2的配置文件是否有错,也可以检测到死循环的logger
9.Layouts
Appenders标签内的PatternLayout标签控制log事件的输出格式
log4j 2官网的Layouts介绍:http://logging.apache.org/log4j/2.x/manual/layouts.html
log4j2的按天分日志文件
- <RollingFile name="error_appender" fileName="${LOG_HOME}/error.log" filePattern="${LOG_HOME}/error-%d{yyyy-MM-dd}.log">
- <PatternLayout pattern="%-d{yyyy-MM-dd HH:mm:ss} [%thread] %m%n"/>
- <Policies>
- <TimeBasedTriggeringPolicy modulate="true" interval="1"/>
- </Policies>
- </RollingFile>
按大小分
- <RollingFile name="error_appender" fileName="${LOG_HOME}/error.log" filePattern="${LOG_HOME}/error-%d{yyyy-MM-dd}-%i.log.gz">
- <PatternLayout pattern="%-d{yyyy-MM-dd HH:mm:ss} [%thread] %m%n"/>
- <SizeBasedTriggeringPolicy size="100 MB" />
- </RollingFile>
按分钟分
- <RollingRandomAccessFile name="_1min_appender" fileName="${MINUTE_HOME}/minute" filePattern="${MINUTE_HOME}/minute-%d{yyyy-MM-dd-HH-mm}.log">
- <PatternLayout pattern="%m%n"/>
- <Policies>
- <TimeBasedTriggeringPolicy interval="1" modulate="true" />
- </Policies>
- </RollingRandomAccessFile>
关键点在于 filePattern后的日期格式,以及TimeBasedTriggeringPolicy的interval,日期格式精确到哪一位,interval也精确到哪一个单位。
举例:${MINUTE_HOME}/minute-%d{yyyy-MM-dd-HH-mm}.log文件名最后是mm。那么如果interval是1就是每分钟类推
在log4J2.xml里配置的记录器
<Loggers>
<Logger name="HELLO" level="info" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="rollFile"/>
</Logger>
<Root level="ERROR">
<AppenderRef ref="Console"/>
<AppenderRef ref="rollFile"/>
</Root>
</Loggers>
Logger里边的HELLO是记录器的名字。你可以在代码里获取
Logger logger = LogManager.getFormatterLogger("HELLO");
logger.info("info");
root 是根记录器默认都用它