铺垫不多说,直接上。
有一点是必须说明的,相信很多朋友都不看文字,直接浏览代码和图片,所以多谢一些文字,也不会影响直接寻求答案的高手,但总会对一部分人有帮助。
相信有很多猿友跟我一样,更熟悉使用log4j、logback以及与slf4j一起使用进行log输出。
那为什么我要来研究log4j2呢,因为我们的log输出遇到了瓶颈。
百度到这样一张性能图,也简单做了循环测试,性能没有图上夸张,但随着线程数和输出数量增加log4j2的性能优势越发显现。
千万不要只输出一条log就得出结论:性能差不多,没有必要使用(这是错误的)。
下面来介绍log4j2
如果能读懂英文文献,请直接看这里。http://logging.apache.org/log4j/2.x/manual/appenders.html
下面继续。
先来写一个main方法,做简单的介绍,后面有在web中的应用。
目前需要两个jar包(还需要一些其他的基础jar包),log4j-api-2.5.jar、log4j-core-2.5.jar(目前20160401的最新版本)
备注:日志级别顺序为 TRACE < DEBUG < INFO < WARN < ERROR < FATAL
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class TestMain {
static Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
public static void main(String[] args) {
logger.trace("trace message");
logger.debug("debug message");
logger.info("info message");
logger.warn("warn message");
logger.error("error message");
logger.fatal("fatal message");
System.out.println("Hello World!");
}
}
直接执行main方法,即可输出以下内容。默认的输出等级是error。
09:25:54.066 [main] ERROR - error message
09:25:54.066 [main] FATAL - fatal message
Hello World!
下面进行log4j2在web中的应用,环境:tomcat7,jdk1.7,SrpingMVC
需要新增一个jar包,为web提供支持:log4j-web-2.5.jar
在web.xml中添加以下内容
<!-- log4j2-begin -->
<listener>
<listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>
</listener>
<filter>
<filter-name>log4jServletFilter</filter-name>
<filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>log4jServletFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<!-- log4j2-end -->
放在在src根目录,编译完classpath的根目录(注意!不在web中指定log4j2.xml的位置的话,必须放到classpath的根目录)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<Configuration status="off" monitorInterval="3600">
<properties>
<property name="LOG_HOME">G:/logstest</property>
<property name="FILE_NAME">running-log</property>
</properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
</Console>
<RollingRandomAccessFile name="running-log"
fileName="${LOG_HOME}/${FILE_NAME}.log" filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout
pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread][%file:%line] - %msg%n" />
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="1000" />
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<Logger name="com.shbc.batch" additivity="false">
<AppenderRef ref="running-log" />
<AppenderRef ref="Console" />
</Logger>
<Root level="error">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
下面对配置文件标签进行说明
<!DOCTYPE xml> :是为了声明DOCTYPE,如果不做此行也没有问题,第一行会报一个警告,不是强迫症患者可以忽略此行。
Configuration:是声明配置文件的开始。
其中status=off表示不输出log4j2本身的event信息。monitorInterval="3600"每隔一小时会扫描配置文件是否变更,自动重配。
properties:是定义一些常量
Appenders:定义输出目的地。
Console:控制台输出
PatternLayout:输出格式
ThresholdFilter:这个很重要,单独拿出来说,这个定义的是输出等级。
log4j2的输出等级可以在多个地方定义,其中以Logger中第一的优先级最高,也就是说在Logger中第一的level会覆盖其他地方定义的level。
那么,想让log分等级输出到不同的文件,或者输出多份文件,或者输出到Console和文件等不同位置时,最好是在本标签中定义等级,不要再Logger中定义。
level="error" onMatch="ACCEPT" onMismatch="DENY",表示error以上输出,error以下不输出。这句话直译就是,输出等级是error,如果匹配高于就接受输出,如果匹配低于就拒绝输出。
注意:上面的配置方法中,即使把ThresholdFilter中的level改成info,debug也不会输出error以下的log,因为root logger等级是error。上面已经说过了,Logger的等级高于ThresholdFilter的等级。
RollingRandomAccessFile:表示以文件的形式输出,带有自动压缩功能。
TimeBasedTriggeringPolicy: 定时压缩 <SizeBasedTriggeringPolicy size="10 MB" />:文件大小达到10M时压缩
<DefaultRolloverStrategy max="1000" />:最多保存1000份文件,大于1000自动删除
Loggers:需要输出的Appender
additivity:additivity="true" 这里注意一下,因为下面还有一个root logger,任何其它的logger最终都相当于继承自root logger,所以“com.cnblogs.yjmyzz.App2”这个logger中,如果记录了error及以上级别的日志,除了文件里会记录外,root logger也会生效,即:控制台也会输出一次。如果把additivity="true" 中的true,改成false,root logger就不会再起作用,即只会记录在文件里,控制台无输出。
关于logger的name属性有很多规则,只说两点:
①一般可以随便定义,LogManager.getLogger()中需要添加参数,一般都是AAA.class
②如果没有参数,或者参数是LogManager.ROOT_LOGGER_NAME,那么回来扫描name,如果name是com.aa.bb这种格式的话,那么只有在这个包下的log才会被输出,如果定义了rootlogger的话,error以上的也会被输出。
还有一点需要注意的是,如果需要和mybatis结合使用的话,mybatis版本请选择3.2.8以上的版本(官方说的,本人测试3.3.0没有此bug3.2.8没测,3.2.7冲突),否则会冲突。
希望本文对大家有帮助