目录
log4j2的介绍
Apache Log4j 2是对Log4j的升级版,参考了logback的一些优秀的设计,并且修复了一些问题,因此带 来了一些重大的提升,主要有:
- 异常处理,在 logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异 常处理机制。
- 性能提升, log4j2相较于log4j 和logback都具有很明显的性能提升,后面会有官方测试的数据。
- 自动重载配置,参考了 logback的设计,当然会提供自动刷新参数配置,最实用的就是我们在生产 上可以动态的修改日志的级别而不需要重启应用。
- 无垃圾机制, log4j2在大部分情况下,都可以使用其设计的一套无垃圾机制,避免频繁的日志收集 导致的jvm gc。
官网地址: https://logging.apache.org/log4j/2.x/
Log4j2的性能
Log4j2最牛的地方在于异步输出日志时的性能表现,Log4j2在多线程的环境下吞吐量与Log4j和 Logback的比较如下图。下图比较中Log4j2有三种模式:1)全局使用异步模式;2)部分Logger采用异步模式;3)异步Appender。可以看出在前两种模式下,Log4j2的性能较之Log4j和Logback有很大的 优势。
无垃圾记录
垃圾收集暂停是延迟峰值的常见原因,并且对于许多系统而言,花费大量精力来控制这些暂停。
许多日志库(包括以前版本的Log4j)在稳态日志记录期间分配临时对象,如日志事件对象,字符串, 字符数组,字节数组等。这会对垃圾收集器造成压力并增加GC暂停发生的频率。
从版本2.6开始,默认情况下Log4j以"无垃圾"模式运行,其中重用对象和缓冲区,并且尽可能不分配临 时对象。还有一个"低垃圾"模式,它不是完全无垃圾,但不使用ThreadLocal字段。
Log4j 2.6中的无垃圾日志记录部分通过重用ThreadLocal字段中的对象来实现,部分通过在将文本转换 为字节时重用缓冲区来实现。
从图中可以看出log4j2的性能是完全吊打其他日志框架的,而且log4j2的异步日志功能非常的强大,可以大大的减少日志系统对业务系统的负担。基于这些功能,所以现在主流的日志开发架构就是SLF4J+Log4j2这个组合,所以这个log4j2这个日志框架是必须要学会的
SpringBoot中的使用Log4j2
springboot框架在企业中的使用越来越普遍,springboot日志也是开发中常用的日志系统。springboot 默认就是使用SLF4J作为日志门面,logback作为日志实现来记录日志。所以如果我们要在springboot项目中使用Log4j2,需要内置的日志框架给去除。
分成三步,第一移除默认的日志框架,第二加入log4j2的依赖(启动器),第三编写配置文件
- 移除默认的日志框架
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!--排除默认spring-boot-starter-logging启动器--> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency>
- 加入log4j2的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency>
编写log4j2.xml配置文件'
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <!-- 定义全局变量,日志文件路径和格式 --> <Properties> <Property name="log.path">./dev</Property> <Property name="log.name">forlan-log4j2</Property> <Property name="file.pattern">%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{50} - %msg%n</Property> </Properties> <!-- 控制台输出配置 --> <Appenders> <Console name="STDOUT" target="SYSTEM_OUT"> <PatternLayout pattern="${file.pattern}"/> <ThresholdFilter level="DEBUG"/> </Console> <!-- 文件输出配置 --> <RollingFile name="INFO_FILE" fileName="${log.path}/${log.name}.info.log" filePattern="${log.path}/%d{yyyy-MM-dd}/${log.name}.info.%d{yyyy-MM-dd}-%i.log"> <PatternLayout pattern="${file.pattern}"/> <LevelMatchFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/> <!-- 每个文件最大10MB --> <SizeBasedTriggeringPolicy size="10MB"/> <!-- 最多保留30天的历史记录 --> <DefaultRolloverStrategy max="30"/> </RollingFile> <!-- 文件输出配置 --> <RollingFile name="ERROR_FILE" fileName="${log.path}/${log.name}.error.log" filePattern="${log.path}/%d{yyyy-MM-dd}/${log.name}.error.%d{yyyy-MM-dd}-%i.log"> <PatternLayout pattern="${file.pattern}"/> <LevelMatchFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/> <!-- 每个文件最大10MB --> <SizeBasedTriggeringPolicy size="10MB"/> <!-- 最多保留30天的历史记录 --> <DefaultRolloverStrategy max="30"/> </RollingFile> </Appenders> <!-- 设置root logger --> <Loggers> <Root level="INFO"> <AppenderRef ref="STDOUT"/> <AppenderRef ref="INFO_FILE"/> <AppenderRef ref="ERROR_FILE"/> </Root> </Loggers> </Configuration>
- 运行测试
@SpringBootTest public class Slf4jTest { // 声明日志对象 public final static Logger LOGGER = LoggerFactory.getLogger(Slf4jTest.class); @Test public void testQuick() throws Exception { //打印日志信息 LOGGER.error("error"); LOGGER.warn("warn"); LOGGER.info("info"); LOGGER.debug("debug"); LOGGER.trace("trace"); // 使用占位符输出日志信息 String name = "jack"; Integer age = 18; LOGGER.info("用户:{},{}", name, age); // 将系统异常信息写入日志 try { int i = 1 / 0; } catch (Exception e) { // e.printStackTrace(); LOGGER.info("出现异常:", e); } } }
出现入上图的结果就代表log4j2就配置成功了,主要注意那个dev的日志文件是否生成,这个日志文件是在前面的配置文件中配置的。
到这里log4j2的基本使用其实已经可以实现了,对于一些小的项目,这样子配置就可以了,但对于那些大型项目,log4j2还可以更加强大,那就是使用它的异步日志功能
log4j2的进阶--异步日志
logl4j2最大的特点就是异步日志,其性能的提升主要也是从异步日志中受益,我们来看看如何使用 log4j2的异步日志。
Log4j2 提供了两种实现日志的方式,一个是通过AsyncAppender,一个是通过AsyncLogger,分别对应 前面我们说的Appender组件和Logger组件。
log4j2的全局异步AsyncLogger性能最好,第二个是混合异步AsyncLogger,性能最差的是AsyncAppender(和同步日志相比没有什么性能提升。和logback性能一样)
如果使用异步日志,全局异步AsyncLogger、混合异步AsyncLogger、AsyncAppender,不要同时使用。否则会使用性能较低的一种异步方式
注意:配置异步日志需要添加依赖
<!--异步日志依赖-->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.4</version>
</dependency>
AsyncAppender方式
**AsyncAppender:**这种使用方式较为简单,只需要在我们上述的Appender中加入以下标签即可:
XML
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" monitorInterval="5">
<properties>
<property name="LOG_HOME">C:/Users/dell/Desktop/java11Test/logs</property>
</properties>
<Appenders>
<File name="File" fileName="${LOG_HOME}/myFile.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%-5level] %l --- %msg%n" />
</File>
<!-- AsyncAppender引用appender -->
<Async name="Async">
<AppenderRef ref="File"/>
</Async>
</Appenders>
<Loggers>
<Root level="INFO">
<!-- 直接引用AsyncAppender -->
<AppenderRef ref="Async" />
</Root>
</Loggers>
</Configuration>
AsyncLogger方式
AsyncLogger才是log4j2 的重头戏,也是官方推荐的异步方式。它可以使得调用Logger.log返回的 更快。你可以有两种选择:全局异步和混合异步。
全局异步 就是,所有的日志都异步的记录,在配置文件上不用做任何改动,只需要添加一个 log4j2.component.properties 配置;
Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
混合异步就是,你可以在应用中同时使用同步日志和异步日志,这使得日志的配置方式更加 灵活。
XML
<!--logger定义-->
<Loggers>
<!--自定义异步logger对象
includeLocation = "false" 关闭日志记录行好信息
additivity = "false" 不再继承rootlogger对象-->
<AsyncLogger name = "com.itcats" level = "trace" includeLocation = "false" additivity = "false">
<AppenderRef ref="Console"/>
</AsyncLogger>
<Root level = "trace">
<AppenderRef ref ="Console"/>
</Root>
</Loggers>
将以上配置配置到我们之前的log4j2.xml配置文件中,将之前的logger定义替换。此时我们com.itcats日志是异步的,root日志是同步的。
使用异步日志需要注意的问题:
1. 如果使用异步日志,AsyncAppender、AsyncLogger和全局日志,不要同时出现。性能会和 AsyncAppender一致,降至最低。
2. 设置includeLocation=false ,打印位置信息会急剧降低异步日志的性能,比同步日志还要慢
到这里我们的java日志框架基本就介绍完了