Log4j2
log4j2相对于log4j 1.x有了脱胎换骨的变化,其官网宣称的优势有多线程下10几倍于log4j 1.x和logback的高吞吐量、可配置的审计型日志、基于插件架构的各种灵活配置等。
基本用法
Maven 配置
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8.2</version>
</dependency>
</dependencies>
Web 项目
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<scope>runtime</scope>
</dependency>
核心 jar 包
log4j-api-2.8.2.jar
log4j-core-2.8.2.jar
日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出。对于Loggers中level的定义同样适用。
v2.x 版本的配置方式,除了编码式的写入,还有XML、JSON、YAML 和 Properties(注意这个是v2.4之后重新支持的,配置方式类似 XML 和 JSON 不同于以往v1.x版本),配置文件 "on the classpath" 即可实现。
XML配置文件默认可以放在源码src目录下,log4j2.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 主要配置为error日志与debug日志分别打印文件,
errorLog按照分钟存档,debugLog按照日志文件大小存档,
最多保存10个。 -->
<configuration status="debug" monitorInterval="30">
<Properties>
<Property name="log.path">.</Property>
</Properties>
<appenders>
<!--Appender 1. 输出到Console,
指定输出格式和过滤器等级为ERROR -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="[%-5level][%d{yyyy-MM-dd HH:mm:ss}][%F:%L] - %m%n" />
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
</Console>
<!--Appender 2. 输出到滚动保存的文件,
触发保存日志文件的条件是日志文件大于3KB,
只保存最新的10个日志-->
<RollingFile name="debugLog" fileName="${log.path}/debug.log"
filePattern="${log.path}/debug-%i.log">
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="[%-5level][%d{yyyy-MM-dd HH:mm:ss}][%F:%L] - %m%n" />
<SizeBasedTriggeringPolicy size="3KB" />
<!-- DefaultRolloverStrategy 中的参数max,
可以限制 SizeBasedTriggeringPolicy中size超出后,
只保留max个存档-->
<DefaultRolloverStrategy max="10"/>
</RollingFile>
<!--Appender 3. 输出到滚动保存的文件,
触发保存日志文件的条件是每分钟第一次的日志事件。
ERROR日志是按分钟产生日志 -->
<RollingFile name="errorLog" fileName="${log.path}/error.log"
filePattern="${log.path}/error-%d{yyyy-MM-dd_HH-mm}.log">
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="[%-5level][%d{yyyy-MM-dd HH:mm:ss}][%C:%F:%L] - %m%n" />
<TimeBasedTriggeringPolicy />
</RollingFile>
</appenders>
<loggers>
<root level="trace">
<appender-ref ref="Console" />
<appender-ref ref="debugLog" />
<appender-ref ref="errorLog" />
</root>
</loggers>
</configuration>
Java测试代码:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4j2Testing {
private static Logger logger =
LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
public static void main(String[] args) {
// TODO Auto-generated method stub
for(int i=0; i<10; i++){
logger.trace("===root trace");
logger.debug("===root debug");
logger.info("===root info");
logger.warn("===root warn");
logger.error("===root error");
logger.fatal("===root fatal");
try {
Thread.sleep(10000);//等10秒钟
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
新增特性
- 定义变量、过滤设置、定时删除日志;
- 支持 JDK8 的 Lambda ;
- 定时重载配置文件;
- Asynchronous Loggers 是一个新增特性,可以实现完全异步也可以和同步混合使用;
- 兼容 Log4j 1.2、SLF4J、Commons Logging 和 java.util.logging (JUL) APIs 等各个日志工具;
Appender
Log4j2 提供 12 种 Appender
- FileAppender:普通地输出到本地文件;
- FlumeAppender:将几个不同源的日志汇集、集中到一处;
- JMSQueueAppender VS. JMSTopicAppender:与JMS相关的日志输出;
- RewriteAppender:对日志事件进行掩码或注入信息;
- RollingFileAppender:对日志文件进行封存(详细);
- RoutingAppender:在输出地之间进行筛选路由;
- SMTPAppender:将LogEvent发送到指定邮件列表;
- SocketAppender:将LogEvent以普通格式发送到远程主机;
- SyslogAppender:将LogEvent以RFC 5424格式发送到远程主机;
- AsynchAppender:将一个LogEvent异步地写入多个不同输出地;
- ConsoleAppender:将LogEvent输出到命令行;
- FailoverAppender:维护一个队列,系统将尝试向队列中的Appender依次输出LogEvent,直到有一个成功为止;
FileAppender
FileAppender用于将LogEvent写入到一个文件中,该文件由fileName参数指定。有几个重要的参数:
① fileName,String,指定写入的log文件的名称。 ② append,boolean,指定是否是追加写入(append=true,默认情况),还是覆盖写入(append=false)。 ③ bufferedIO,boolean,是否对数据进行缓冲到缓冲区满后再写入。测试显示,即使在启用immediateFlush的情况下,设置bufferedIO=true也能提高性能。 ④ locking,boolean,是否对文件上锁,当有多个线程可能同时写该文件时需要考虑上锁(在《异常处理反模式》中就提到要把在一起的日志输出语句写到一句,而不是拆成几句来避免并发线程导致的日志语句之间的错位)。但对文件上锁会影响系统的性能,所以需要谨慎使用。默认值是false。
FlumeAppender
FlumeAppender是一个可选的组件,它并不包含在core jar中,若要使用,需要额外加入log4j-flume-ng-2.0-beta4.jar包。FlumeAppender是配合Apache Flume来使用的。Apache Flume是一个能有效地将不同地方的大量日志数据收集、聚会到一起的一个系统。详细信息参见 【Apache Flume】
几个比较重要的参数: ① agents,Agent[],用来维护一个将接收log event的数组,如果数组中agent的数量大于1,那么将把第一个agent视为primary agent,剩下的为备选agent。当第一个agent无法连接时,将把log event发送给备选agent。 ② batchSize,integer,一次给agent发送的log event的个数。 ③ compress,boolean,当设置为true时,发送的message将使用gzip进行压缩。
JMSQueueAppender VS. JMSTopicAppender
JMSQueueAppender的作用是将格式化的log event发送到JMSQueue上,同样的,JMSTopicAppender的作用是将格式化的log event发送到JMSTopic上。JMSQueue和JMSTopic的区别是,JMSQueue只将一个message发送给一个consumer,而JMSTopic是将一个message发布(publish)给所有订阅了这个message的订阅者(subscribe)。更详细的两者间的区别可以 【戳这里】
几个重要的参数:
JMSQueueAppender:
① queueBindingName,String, 用来定位queue。 ② factoryBindingName,String, 用来定位产生上下文信息的QueueConnectionFactory。 【完整的参数设置和官方配置示例】
JMSTopicAppender:
① topicBindingName,String, 用来定位topic。 ② factoryBindingName,String, 用来定位产生上下文信息的QueueConnectionFactory。 【完整的参数设置和官方配置示例】
RewriteAppender
RewriteAppender可以让符合筛选条件的log event在被其他appender输出前被加工一下,比如对message中的密码进行掩码,或者向message中注入信息等。RewriteAppender需要一个RewritePolicy来指定重写的规则。
几个重要的参数: ① appender-ref,String,指定被重写后的log event将发往哪个appender。 ② rewritePolicy,RewritePolciy,用来描述重写log event的规则。
RewritePolicy:
RewritePolicy是一个接口,有一个需要实现的方法名为rewrite,该方法接收一个log event对象作为参数,然后经过函数处理后返回该log event或新建一个log event返回。
Log4j2中已实现的两种RewritePolicy有MapRewritePolicy和PropertiesRewritePolicy。
【完整的参数设置、已实现的RewritePolicy和官方配置示例】
RollingFileAppender
RollingFileAppender是一个非常有意思的输出器。它将log信息写入一个文件后,会判断是否满足封存文件的要求,若满足,则执行封存文件的动作。RollingFileAppender需要TriggeringPolicy来指定触发封存的条件,另外还需要RolloverStrategy来告诉输出器如何封存文件。
Log4j2中已提供的TriggeringPolicy有如下四种:
① CompositeTriggeringPolicy 复合型触发策略。即将多个触发条件逻辑或到一起,只要其中一个条件满足,则触发封存动作。
② OnStartup Triggering Policy 这一触发策略不需要参数设置,它会自行判断log文件的创建时间和JVM的启动时间。若log文件的创建时间早于JVM的启动时间,则将原来的log文件封存,然后创建一个新的空白log文件。
③ SizeBased Triggering Policy 这一触发策略基于对log文件大小的判断。当log文件大于设定的阈值时,将触发封存动作。可设定的log文件大小的单位有bytes、KB、MB或GB。
④ TimeBased Triggering Policy 基于时间的触发策略。该策略主要是完成周期性的log文件封存工作。有两个参数:
interval,integer型,指定两次封存动作之间的时间间隔。 modulate,boolean型,说明是否对封存时间进行调制。若modulate=true,则封存时间将以0点为边界进行偏移计算。比如,modulate=true,interval=4hours,那么假设上次封存日志的时间为03:00,则下次封存日志的时间为04:00,之后的封存时间依次为08:00,12:00,16:00,。。。
Log4j2中实现的RolloverStrategy为Default Rollover Strategy,它有三个参数可以设置,分别为:
fileIndex,String,有两个选择“max”或“min”。设置为“max”意味着将最新的日志信息封存在序号较大的封存文件中。“min”则相反。 min,integer,封存文件的序号的起始值。 max,integer,封存文件的序号的最大值。(超过最大值时,将有文件被删除) 相当于min和max两个参数设置了一个保存窗口,超出这个窗口的日志文件将会被删除。
【完整的参数设置、TriggeringPolicy和RolloverStrategy的用法示例】
RoutingAppender
通过路由规则来评价一个log event后,决定它下一个被发往的appender。RoutingAppender有一个重要的参数名为routes,是Routes型数据,用来描述该appender的路由规则。
SMTPAppender
SMTPAppender主要用来给指定的E-mail发送log event(这种情况一般用在event的安全级别超过ERROR或FATAL时,event的安全分级可以参考【此文】之日志记录小节)。SMTPAppender有很多重要的参数以完成log event发送到指定E-mail。
① bcc,String,由逗号分隔的几个盲抄送地址。(盲抄送就是说收件人的地址不会显示在邮件信息中) ② cc,String,由逗号分隔的几个明抄送地址。(明抄送就是说收件人的地址将显示在邮件信息中) ③ bufferSize,integer,信中所能包含的最大log event的数量。 ④ from,String,发件人的地址。 ⑤ layout,Layout,log event的布局格式。默认为SerializedLayout。 ⑥ replyTo,String,回信的地址。 ⑦ smtpHost,String,要发送到的SMTP的主机名。(此参数是必需的) ⑧ smtpPassword,String,通过SMTP服务器所需的密码。 ⑨ smtpPort,integer,SMTP服务的端口号。 ⑩ smtpProtocol,String,使用的协议。默认为"smtp"。
其他还有smtpUsername(通过SMTP server所需的用户名),to(接收者的邮件地址)等。
SocketAppender
将log event输出到一个远程服务器上(需指定服务器名和端口号),数据可以以任意指定的格式经由TCP或UDP协议发送。
SocketAppender中比较重要的参数有:
① host,String,指定服务器的主机名。(必需) ② immediateFlush,boolean,是否立即flush,还是等待缓存到一定大小后在flush。 ③ layout,Layout,log event输出的格式。 ④ port,integer,远程服务器坚挺log event的应用的端口号。 ⑤ protocol,String,发送log event所使用的协议,"TCP" 或"UDP"。 ⑥ reconnectionDelay,integer,当连接断开时,延迟等待的ms数。
SyslogAppender
SyslogAppender跟SocketAppender一样,是将log event发送到远程服务器上,但是使用的是BSD Syslog格式。关于Syslog格式可以【戳这里】
AsynchAppender
将一个LogEvent异步地写入多个不同输出地。在AsynchAppender中有一个参数,名为“appender-ref”,用来指定要发送到的appender的名称。AsynchAppender维护了一个队列,队列中存放了需要异步发送的LogEvent,队列中LogEvent的个数可以通过“bufferSize”参数来指定。另外,还有一个“blocking”参数来指定是否对AsynchAppender的LogEvent队列上锁,如果blocking=true,那么在队列满员的情况下,新到达的LogEvent将等待,直到有空位。若blocking=false,那么在队列满员的情况下,将把新到的LogEvent转到error appender。
ConsoleAppender
将LogEvent输出到命令行。有两个比较有意思的参数,一个是layout,用来指定输出字串的格式(format);另一个是target,用来指定输出的是 "SYSTEM_OUT" 还是 "SYSTEM_ERR",默认情况下是"SYSTEM_ERR"。
FailoverAppender
维护一个failover appenders队列,系统先尝试一个主appender(primary appender),若不成功,则尝试failover队列中的Appenders,直到有一个成功为止,或都不成功。比较重要的参数有:
primary(String型):用来指定主appender的名称。 failovers(String[]型):一个appender数组,指定的备选的其他appenders。 retryInterval(integer型):用来设定隔多少秒重新尝试主appender,默认为60秒。
项目中注意事项
通常我们的项目有时候是以jar包的形式发布出去,但是此时如果你直接使用lo4j2的api的话,相当于别人依赖你的jar的项目也必须加入log4j2的jar包。这样是高度耦合的。我们不建议这样使用,log4j2官方给出了适配slf4j,我们只需要在项目中加入以下依赖:
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.6.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
然后项目中,我们使用slf4j的api而不要使用lo4j2的api例如:
将LogManager.getLogger(xxx);替换为LoggerFactory.getLogger(xx);
异步日志配置
log4j2最强的是支持异步写日志。异步输出,官方有两种方案。第一种是采用配置开关,第二种则是基于异步标签。
注意:异步输出日志需要disruptor-3.3.0.jar或者以上的版本来支持。
配置开关
添加一个名字为:log4j2.component.properties文件,放到classpath下面,log4j2会在启动的时候自动加载。然后你的日志输出已经变成了异步输出了。(注意:这种情况,本人在main方法启动函数测试的时候,经常出现不成功,可能需要附加其他配置参数,我也推荐大家使用第二种方式)
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
异步标签
你只需要将你要异步输出的块改为 <AsyncLogger>
标签就行了。
详见 示例文件