SpringBoot + Log4j2使用配置 (转)
2021-02-08 15:16
demo logs 30 MB
三个appender:console、infoLog、errorLog
-
console 通过ThresholdFilter过滤规则只输出info级别的错误(onMatch="ACCEPT" onMismatch="DENY" 匹配到的接受,没有匹配的走人)
-
infoLog 也通过ThresholdFilter的方式输出到日志,当然了append="true" 会在服务每次启动的时候追加日志
status和monitorInterval含义
我们看到,Configuration有2个属性status和monitorInterval,它们分别是log4j2自身组件的日志级别以及重新刷新配置文件的时间,通过配置status可以看到log4j2相关的日志,配置monitorInterval可以通过修改配置文件来改变日志配置。
log4j2的层次结构
从上面的log4j2.xml配置文件中,我们可以看到log4j2的配置文件中主要分为2块,一块为appender,描述了如何记录日志,另外一部分是log config,记录了哪种日志对应哪种级别。 而不同的LogConfig之间其实是有继承关系的,子LogConfig会继承parent的属性,而所有LogConfig都继承自Root LogConfig。所以即使只配置了root logger,你一样可以在任何地方通过LoggerFactory.getLogger获取一个logger对象,记录日志。
那么日志之间的继承关系是由什么决定的呢?看看上面的配置文件中root以外的2个logConfig,只有3个配置:日志级别,name以及appender,从直觉上看应当是name最可能决定了LogConfig的继承关系,其实也正是如此:com.foo是com.foo.Bar的父级;java是java.util的父级,是java.util.vector的祖先(注意name区分大小写)。
理解了这一点,我们就能理清log4j2配置的思路:先配置一个root,让所有需要使用日志的logger继承,然后对有特别需要的logger进行特殊的配置,比如我们希望org.springframework包只记录error以及warn级别的log,再比如,我们希望能显示mybatis执行的sql的日志,都可以进行个性化的配置。
appender的配置
appender是LogConfig的重要组成部分,一个LogConfig可以使用多个appender,一个appender也可以被多个LogConfig使用,appender多种多样,不同的appender也有不同的属性和配置,难以一一阐述,需要使用时可以直接查看文档来进行个性化配置。不过就filters可以单独拿出来讨论一下。
filter有两个重要属性onMatch和onMismatch。可以有DENY、ACCEPT或NEUTRAL配置:
- DENY说明不由当前appender处理
- ACCEPT说明由当前filter处理
- NEUTRAL说明如果按顺序还有其他filter则由其他filter处理,如果当前filter已经是最后一个filter,则由当前appender处理。
异步日志
配置方式
log4j2的官方文档建议记录程序行为日志异步日志,效率更高。因为异步日志使用的是无锁技术,所以需要引入Disruptor。然后可以通过配置异步的appender或Logger来实现异步日志
或
异步日志工作原理
AsyncAppender采用的是生产者消费者的模型进行异步地将Logging Event送到对应的Appender中。
-
a、 生产者
外部应用了Log4j的系统的实时线程,实时将Logging Event传送进AsyncAppender里 -
b、 中转:Buffer和DiscardSummary
-
c、 消费者:Dispatcher线程和appenders
工作原理:
1) Logging Event进入AsyncAppender,AsyncAppender会调用append方法,在append方法中会去把logging Event填入Buffer中,当消费能力不如生产能力时,AsyncAppender会把超出Buffer容量的Logging Event放到DiscardSummary中,作为消费速度一旦跟不上生成速度,中转buffer的溢出处理的一种方案。
2) AsyncAppender有个线程类Dispatcher,它是一个简单的线程类,实现了Runnable接口。它是AsyncAppender的后台线程。
Dispatcher所要做的工作是:
① 锁定Buffer,让其他要对Buffer进行操作的线程阻塞。
② 看Buffer的容量是否满了,如果满了就将Buffer中的Logging Event全部取出,并清空Buffer和DiscardSummary;如果没满则等待Buffer填满Logging Event,然后notify Disaptcher线程。
③ 将取出的所有Logging Event交给对应appender进行后面的日志信息推送。
以上是AsyncAppender类的两个关键点:append方法和Dispatcher类,通过这两个关键点实现了异步推送日志信息的功能,这样如果大量的Logging Event进入AsyncAppender,就可以游刃有余地处理这些日志信息了。
性能影响
log4j对系统性能的影响程度主要体现在以下几方面:
- a、输出的目的地
输出到控制台的速度比输出到文件系统的速度要慢。 - b、输出格式
输出格式不一样对性能也会有影响,如简单输出布局(SimpleLayout)比格式化输出布局(PatternLayout)输出速度要快。可以根据需要尽量采用简单输出布局格式输出日志信息。 - c、日志级别
输出级别越低输出的日志内容就越多,对系统系能影响很大。 - d、输出方式
输出方式的不同,对系统系能也是有一定影响的,采用异步输出方式比同步输出方式性能要高。 - e、输出事件
每次接收到日志输出事件就打印一条日志内容比当日志内容达到一定大小时打印系能要低。
缓存设置
设置日志输出为异步方式
-
同步情况
各线程直接获得输出流进行输出(线程间不需要同步)。 -
异步情况:
1.各线程将日志写到缓存,继续执行下面的任务(这里是异步的)
2.日志线程发现需要记日志时独占缓存(与此同时各线程等待,此时各线程是被阻塞住的),从缓存中取出日志信息,获得输出流进行输出,将缓存解锁(各线程收到提醒,可以接着写日志了)- a、将日志记录到本地文件
同样都是写本地文件Log4j本身有一个buffer处理入库,采用异步方式并不一定能提高性能(主要是如何配置好缓存大小);而线程间的同步开销则是非常大的!因此在使用本地文件记录日志时不建议使用异步方式。 - b、将日志记录到JMS
JMS本身是支持异步消息的,如果不考虑JMS消息创建的开销,也不建议使用异步方式。 - c、将日子记录到SOCKET
将日志通过Socket发送,纯网络IO操作不需要反馈,因此也不会耗时 - d、将日志记录到数据库
众所周知JDBC是几种方式中最耗时的:网络、磁盘、数据库事务,都使JDBC操作异常的耗时,在这里采用异步方式入库倒是一个不错的选择。 - e、将日志记录到SMTP 同JDBC
- a、将日志记录到本地文件
动态修改日志级别
动态修改日志级别是一个很实用的功能,关于如果动态修改日志级别,请参考美团的一篇文章:日志级别动态调整——小工具解决大问题
[参考]
log4j2 配置简要分析
Spring Boot系列之Log4j2的配置使用
springboot日志体系---log4j2
log4j日志输出性能优化-缓存、异步
文章标题:SpringBoot + Log4j2使用配置 (转)
文章链接:http://soscw.com/index.php/essay/52689.html