天天看点

java日志大全-第5篇:Log4j2

作者:不开心就撸代码

一、log4j2的使用

Apache Log4j 2是对Log4j的升级版,参考了logback的一些优秀的设计,并且修复了一些问题,因此带来了一些重大的提升,主要有:

l 异常处理,在logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异常处理机制。

l 性能提升, log4j2相较于log4j 和logback都具有很明显的性能提升,后面会有官方测试的数据。

l 自动重载配置,参考了logback的设计,当然会提供自动刷新参数配置,最实用的就是我们在生产上可以动态的修改日志的级别而不需要重启应用。

l 无垃圾机制,log4j2在大部分情况下,都可以使用其设计的一套无垃圾机制,避免频繁的日志收集导致的jvm gc。

官网: https://logging.apache.org/log4j/2.x/

1. Log4j2入门

目前市面上最主流的日志门面就是SLF4J,虽然Log4j2也是日志门面,因为它的日志实现功能非常强大,性能优越。所以大家一般还是将Log4j2看作是日志的实现,Slf4j + Log4j2应该是未来的大势所趋。

Ø 添加依赖

<!-- Log4j2 门面API-->
<dependency>
 <groupId>org.apache.logging.log4j</groupId>
 <artifactId>log4j-api</artifactId>
 <version>2.11.1</version>
</dependency>
<!-- Log4j2 日志实现 -->
<dependency>
 <groupId>org.apache.logging.log4j</groupId>
 <artifactId>log4j-core</artifactId>
 <version>2.11.1</version>
</dependency>           

Ø 代码

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Test;

public class Demo1 {

 private static final Logger LOGGER = LogManager.getLogger(Demo1.class);

   @Test
   public void test1(){
     LOGGER.fatal("fatal");
     LOGGER.error("error"); //默认error级别
     LOGGER.warn("warn");
     LOGGER.info("info");
     LOGGER.debug("debug");
     LOGGER.trace("trace");
   }
}           
输出:
java日志大全-第5篇:Log4j2

2. 使用slf4j作为日志的门面,使用log4j2作为日志的实现

Ø 添加依赖

<!-- Log4j2 门面API-->
<dependency>
 <groupId>org.apache.logging.log4j</groupId>
 <artifactId>log4j-api</artifactId>
 <version>2.11.1</version>
</dependency>
<!-- Log4j2 日志实现 -->
<dependency>
 <groupId>org.apache.logging.log4j</groupId>
 <artifactId>log4j-core</artifactId>
 <version>2.11.1</version>
</dependency>

<!--使用slf4j作为日志的门面,使用log4j2来记录日志 -->
<dependency>
 <groupId>org.slf4j</groupId>
 <artifactId>slf4j-api</artifactId>
 <version>1.7.25</version>
</dependency>
<!--为slf4j绑定日志实现 log4j2的适配器 -->
<dependency>
 <groupId>org.apache.logging.log4j</groupId>
 <artifactId>log4j-slf4j-impl</artifactId>
 <version>2.10.0</version>
</dependency>           

配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<!--
 status="warn" 日志框架本身的输出日志级别
 monitorInterval="5" 自动加载配置文件的间隔时间,不低于 5 秒
-->
<Configuration status="debug" monitorInterval="5">
 <!-- 配置集中管理的属性 通过 ${name} 进行引用 -->
 <properties>
 <!--日志输出的位置-->
 <property name="log_home">d://logs</property>
 <!--输出的格式-->
 <property name="pattern">%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n</property>
 </properties>

 <!--日志处理-->
 <Appenders>
 <!--控制台输出-->
 <Console name="Console" target="SYSTEM_ERR">
 <!--输出的格式-->
 <PatternLayout pattern="${pattern}" />
 </Console>

 <!--文件输出-->
 <File name="File" fileName="${log_home}/fileLog.log">
 <PatternLayout pattern="${pattern}" />
 </File>

 <!--使用随机读写流日志文件输出 appender,性能提高-->
 <RandomAccessFile name="accessFile" fileName="${log_home}/accessLog.log">
 <PatternLayout pattern="${pattern}" />
 </RandomAccessFile>

 <!--按照一定规则拆分的日志文件-->
 <RollingFile name="rollingFile" fileName="${log_home}/rollLog.log"
 filePattern="${log_home}/${date:yyyy-MM-dd}/myrollog-%d{yyyy-MM-dd-HH-mm}-%i.log">
 <!--日志级别过滤器-->
 <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />
 <!--日志消息格式-->
 <PatternLayout pattern="${pattern}" />
 <Policies>
 <!--在系统启动时,出发拆分规则,生产一个新的日志文件-->
 <OnStartupTriggeringPolicy />
 <!--按照文件大小拆分,10MB -->
 <SizeBasedTriggeringPolicy size="1MB" />
 <!--按照时间节点拆分,规则根据filePattern定义的-->
 <TimeBasedTriggeringPolicy />
 </Policies>
 <!--在同一个目录下,文件的个数限定为 30 个,超过进行覆盖-->
 <DefaultRolloverStrategy max="30" />
 </RollingFile>
 </Appenders>

 <!--logger定义-->
 <Loggers>
 <Root level="trace">
 <!--指定日志使用的处理器-->
 <AppenderRef ref="Console" />
 <AppenderRef ref="rollingFile" />
<!-- <AppenderRef ref="File" />-->
<!-- <AppenderRef ref="accessFile" />-->
 </Root>
 </Loggers>
</Configuration>           

3. 异步日志

Log4j2提供了两种实现日志的方式,一个是通过AsyncAppender,一个是通过AsyncLogger,分别对应前面我们说的Appender组件和Logger组件。

Ø 依赖

<!--异步日志依赖-->
<dependency>
 <groupId>com.lmax</groupId>
 <artifactId>disruptor</artifactId>
 <version>3.3.4</version>
</dependency>           

Ø 配置文件:Appender组件方式

<?xml version="1.0" encoding="UTF-8"?>
<!--
 status="warn" 日志框架本身的输出日志级别
 monitorInterval="5" 自动加载配置文件的间隔时间,不低于 5 秒
-->
<Configuration status="debug" monitorInterval="5">
 <!-- 配置集中管理的属性 通过 ${name} 进行引用 -->
 <properties>
 <!--日志输出的位置-->
 <property name="log_home">d://logs</property>
 <!--输出的格式-->
 <property name="pattern">%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n</property>
 </properties>

 <!--日志处理-->
 <Appenders>
 <!--控制台输出-->
 <Console name="Console" target="SYSTEM_ERR">
 <!--输出的格式-->
 <PatternLayout pattern="${pattern}" />
 </Console>

 <!--文件输出-->
 <File name="File" fileName="${log_home}/fileLog.log">
 <PatternLayout pattern="${pattern}" />
 </File>

 <Async name="async">
 <AppenderRef ref="File"/>
 </Async>
 </Appenders>

 <!--logger定义-->
 <Loggers>
 <Root level="trace">
 <!--指定日志使用的处理器-->
 <AppenderRef ref="Console" />
 <AppenderRef ref="async" />
 </Root>
 </Loggers>
</Configuration>           

Ø 配置文件:AsyncLogger组件方式

AsyncLogger才是log4j2 的重头戏,也是官方推荐的异步方式。它可以使得调用Logger.log返回的更快。你可以有两种选择:全局异步和混合异步。

² 全局异步就是,所有的日志都异步的记录,在配置文件上不用做任何改动,只需要添加一个 log4j2.component.properties 配置;

Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector           

² 混合异步就是,你可以在应用中同时使用同步日志和异步日志,这使得日志的配置方式更加灵活。

<?xml version="1.0" encoding="UTF-8"?>
<!--
 status="warn" 日志框架本身的输出日志级别
 monitorInterval="5" 自动加载配置文件的间隔时间,不低于 5 秒
-->
<Configuration status="debug" monitorInterval="5">
 <!-- 配置集中管理的属性 通过 ${name} 进行引用 -->
 <properties>
 <!--日志输出的位置-->
 <property name="log_home">d://logs</property>
 <!--输出的格式-->
 <property name="pattern">%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n</property>
 </properties>

 <!--日志处理-->
 <Appenders>
 <!--控制台输出-->
 <Console name="Console" target="SYSTEM_ERR">
 <!--输出的格式-->
 <PatternLayout pattern="${pattern}" />
 </Console>

 <!--文件输出-->
 <File name="File" fileName="${log_home}/fileLog.log">
 <PatternLayout pattern="${pattern}" />
 </File>

 <Async name="async">
 <AppenderRef ref="File"/>
 </Async>
 </Appenders>

 <!--logger定义-->
 <Loggers>
 <!--自定义异步 logger 对象
 includeLocation="false" 关闭日志记录的行号信息
 additivity="false" 不在继承 rootlogger 对象
 -->
 <AsyncLogger name="com.hk" level="info" includeLocation="false" additivity="false">
 <AppenderRef ref="File" />
 </AsyncLogger>

 <Root level="trace">
 <!--指定日志使用的处理器-->
 <AppenderRef ref="Console" includeLocation="true"/>
 </Root>
 </Loggers>
</Configuration>           

如上配置: com.hk日志是异步的,root日志是同步的。

使用异步日志需要注意的问题:

1. 如果使用异步日志,AsyncAppender、AsyncLogger和全局日志,不要同时出现。性能会和AsyncAppender一致,降至最低。

2. 设置includeLocation=false ,打印位置信息会急剧降低异步日志的性能,比同步日志还要慢。