Log4j2的正确使用姿势
Log4j2官方网站
https://logging.apache.org/log4j/2.x/
<Configuration status="WARN"><Appenders><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></Console></Appenders><Loggers><Root level="error"><AppenderRef ref="Console"/></Root></Loggers></Configuration>
| 节点名称 | 含义 |
配置项 |
| Configuration | 配置的根节点,有两个子节点:Appenders和Loggers(表明可以定义多个Appender和Logger)。 |
该节点有两个配置项 status:用于指定log4j2本身的日志打印级别,日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出。 monitorinterval:用于指定log4j自动重新配置的监测间隔时间,单位是秒(s),最小是5s。 |
| Appenders | 负责将日志输出到目的地(这个目的地可以是控制台,文件,数据库,甚至是邮件),定义输出内容,输出格式,输出方式,日志保存策略等。 |
log4j2支持的appender种类非常多,完整的appender可通过官方网站进行查询。其中,比较常见的appender有:ConsoleAppender、FileAppender、RandomAccessFileAppender、RollingFileAppender、RollingRandomAccessFileAppender,另外,还提供异步的AsyncAppender,实现异步处理日志事件。 |
| Loggers | LogEvent生产的源头, 只有定义了logger并引入的appender,appender才会生效。 |
常见的有两种:Root和Logger。 |
appender分类
http://logging.apache.org/log4j/2.x/manual/appenders.html
常见的appender的配置
-
ConsoleAppender
使用该appender可以将日志信息输出到控制台,典型的配置如下:
<?xml version="1.0" encoding="UTF-8"?><Configuration status="warn" name="MyApp" packages=""><Appenders><Console name="STDOUT" target="SYSTEM_OUT"><PatternLayout pattern="%m%n"/></Console></Appenders><Loggers><Root level="error"><AppenderRef ref="STDOUT"/></Root></Loggers></Configuration>
filter:设置过滤器。
layout:设置输出样式。
name:Appender的名字
target:输出方法,SYSTEM_OUT或者SYSTEM_ERR。默认SYSTEM_OUT。
-
FileAppender
FileAppender用于将LogEvent写入到一个文件中,该文件由fileName参数指定。
<?xml version="1.0" encoding="UTF-8"?><Configuration status="warn" name="MyApp" packages=""><Appenders><File name="MyFile" fileName="logs/app.log"><PatternLayout><Pattern>%d %p %c{1.} [%t] %m%n</Pattern></PatternLayout></File></Appenders><Loggers><Root level="error"><AppenderRef ref="MyFile"/></Root></Loggers></Configuration>
-
fileName:指定写入的log文件的名称。 -
append:指定是否是追加写入(append=true,默认情况),还是覆盖写入(append=false)。 -
layout:输出文件的名称格式。 -
bufferedIO:是否对数据进行缓冲到缓冲区满后再写入。测试显示,即使在启用immediateFlush的情况下,设置bufferedIO=true也能提高性能。 -
bufferSize:当bufferedIO=true时,缓冲区的大小,默认是8192bytes。 -
locking:是否对文件上锁,当有多个线程可能同时写该文件时需要考虑上锁(在《异常处理反模式》中就提到要把在一起的日志输出语句写到一句,而不是拆成几句来避免并发线程导致的日志语句之间的错位)。但对文件上锁会影响系统的性能,所以需要谨慎使用。默认值是false。 -
immediateFlush:是否立即将数据刷入磁盘,能够最大程度保证数据的完整性,但是对性能会有一定的影响,默认值为true。
-
RandomAccessFileAppender
RandomAccessFile介绍
https://www.cnblogs.com/jyy599/p/12076662.html
<Configuration status="warn" name="MyApp" packages=""><Appenders><RandomAccessFile name="MyFile" fileName="logs/app.log"><PatternLayout><Pattern>%d %p %c{1.} [%t] %m%n</Pattern></PatternLayout></RandomAccessFile></Appenders><Loggers><Root level="error"><AppenderRef ref="MyFile"/></Root></Loggers></Configuration>
bufferSize:缓存空间大小,默认为256M。
-
RollingFileAppender
RollingFileAppender是一种OutputStreamAppender。它除了将日志输出到文件外,还会根据TriggeringPolicy和RolloverPolicy生成新的日志文件。
一个RollingFileAppender需要两个策略的支持,分别是TriggeringPolicy和RolloverPolicy。TriggeringPolicy定义何时应该生成新的日志文件而RolloverPolicy则决定如何生成新的日志文件。RollingFileAppender不支持文件锁。
如下配置:有两个trigger,表示每小时生成一个文件或者当文件大小达到250MB时生成一个新的文件;有一个RolloverPolicy,表示最多保持文件数量为10,达到最大值后,旧的文件将被删除。
<Configuration status="warn" name="MyApp" packages=""><Appenders><RollingFile name="RollingFile" filePattern="logs/app-%d{yyyy-MM-dd-HH}-%i.log.gz"><PatternLayout><Pattern>%d %p %c{1.} [%t] %m%n</Pattern></PatternLayout><Policies><CronTriggeringPolicy schedule="0 0 * * * ?"/><SizeBasedTriggeringPolicy size="250 MB"/></Policies><DefaultRolloverStrategy max="10"/></RollingFile></Appenders><Loggers><Root level="error"><AppenderRef ref="RollingFile"/></Root></Loggers></Configuration>
-
fileName:指定写入的log文件的名称。 -
filePattern: 压缩日志文件的文件名的模式。 该模式的格式取决于所使用的RolloverPolicy。 DefaultRolloverPolicy将接受兼容SimpleDateFormat的日期/时间模式和/或者%i(代表整数计数器)。 -
append:指定是否是追加写入(append=true,默认情况),还是覆盖写入(append=false)。 -
layout:输出文件的名称格式。 -
bufferedIO:是否对数据进行缓冲到缓冲区满后再写入。测试显示,即使在启用immediateFlush的情况下,设置bufferedIO=true也能提高性能。 bufferSize:当bufferedIO=true时,缓冲区的大小,默认是8192bytes。
immediateFlush:是否立即将数据刷入磁盘,能够最大程度保证数据的完整性,但是对性能会有一定的影响,默认值为true。
policy:用于决定是否发生rollover的策略,类型为TriggeringPolicy。常见的policy如下:
strategy:用于决定压缩文件的名称和路径,类型为RolloverStrategy。
详细的RollingFileAppender介绍参考
http://www.voidcn.com/article/p-kztvqvrr-re.html
-
RollingRandomAccessFileAppender
RollingRandomAccessFileAppender类似于标准的 RollingFileAppender, 除了它总是被缓冲(这不能被关闭),并且在内部它使用ByteBuffer + RandomAccessFile 而不是BufferedOutputStream。与RollingFileAppender相比,当“bufferedIO = true”,性能提升了20-200%。
-
AsyncAppender
<Configuration status="warn" name="MyApp" packages=""><Appenders><File name="MyFile" fileName="logs/app.log"><PatternLayout><Pattern>%d %p %c{1.} [%t] %m%n</Pattern></PatternLayout></File><Async name="Async"><AppenderRef ref="MyFile"/></Async></Appenders><Loggers><Root level="error"><AppenderRef ref="Async"/></Root></Loggers></Configuration>
AppenderRef:指定需要异步执行的appender的名称,上文中介绍的appender皆可。
blocking:指定是否对AsynchAppender的LogEvent队列上锁,如果blocking=true,那么在队列满员的情况下,新到达的LogEvent将等待,直到有空位。若blocking=false,那么在队列满员的情况下,将把新到的LogEvent转到error appender。默认为true。
shutdownTimeout:当线程被关闭时,需要等待多时毫秒,保证队列中的logEvent事件被刷入到磁盘上。默认值为0,代表无限期等待。
errorRef:当blocking=false时,LogEvent会转入该appender;当blocking=true时,如果队列已满,并且QueueFullPolicy定义为DefaultAsyncQueueFullPolicy,则LogEvent会转入该appender。
BlockingQueueFactory:可自定义队列,默认提供如下队列。
bufferSize:队列中LogEvent的个数,默认是1024,如果使用的是disruptor队列的话,该值需要是2的幂次方。当LogEvent数量超过定义值后,会根据定义的FullPolicy策略决定日志如何处理。
如流程图所示,首先会判断用户是否设置了blocking选项,默认是true,如果设置为 false,则Appender直接会ToErrorAppender,如果用户没有配置或者配置为true,则会按照一定的策略来处理这些消息。策略可以分为2种:
DefaultAsyncQueueFullPolicy:等待队列,转为同步操作策略。
DiscardingAsyncQueueFullPolicy:按照日志等级抛弃日志策略。
//如果使用了Disruptor队列,强烈建议配置该项,避免由于日志过多导致内存泄露//56 * 1024 = 57344,单位为bytesasyncLoggerRingBufferSize=57344//以下如果两者都配置了,则第二种方式将会覆盖第一种方式的配置log4j2.AsyncQueueFullPolicy=Discardlog4j2.AsyncQueueFullPolicy=Discard;log4j2.DiscardThreshold=INFO
常见的logger的配置
Root
<loggers><!--过滤掉spring和mybatis的一些无用的DEBUG信息--><!--Logger节点用来单独指定日志的形式,name为包路径,比如要为org.springframework包下所有日志指定为INFO级别等。--><logger name="org.springframework" level="INFO"></logger><logger name="org.mybatis" level="INFO"></logger><!-- Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出 --><root level="all"><appender-ref ref="Console"/><appender-ref ref="RollingFileInfo"/><appender-ref ref="RollingFileWarn"/><appender-ref ref="RollingFileError"/></root><!--AsyncLogger :异步日志,LOG4J有三种日志模式,全异步日志,混合模式,同步日志,性能从高到底,线程越多效率越高,也可以避免日志卡死线程情况发生--><!--additivity="false" : additivity设置事件是否在root logger输出,为了避免重复输出,可以在Logger 标签下设置additivity为”false”--><AsyncLogger name="AsyncLogger" level="trace" includeLocation="true" additivity="false"><appender-ref ref="RollingFileError"/></AsyncLogger></loggers>
level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF。
AppenderRef:Root的子节点,用来指定该日志输出到哪个Appender。
includeLocation:如果你的layouts或custom过滤器需要location信息,你需要在所有相关日志记录器(包括根日志记录器)的配置中设置“includeLocation=true”,默认为false.
Logger
Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。
level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF。不指定默认为ERROR。
AppenderRef:Root的子节点,用来指定该日志输出到哪个Appender。
name:用来指定该Logger所适用的类或者类所在的包全路径,继承自Root节点。一般是项目包名或者框架的包名,比如:com.jourwon,org.springframework。
additivity:这个属性的意思是需不需要打印此logger继承的父logger,如果是false则只打印当前logger;如果是true则继续打印上一层的logger,直到root。
includeLocation:如果你的layouts或custom过滤器需要location信息,你需要在所有相关日志记录器(包括根日志记录器)的配置中设置“includeLocation=true”,默认为false。
AsyncLogger
includeLocation:如果你的layouts或custom过滤器需要location信息,你需要在所有相关日志记录器(包括根日志记录器)的配置中设置“includeLocation=true”,默认为false。
Log4j2使用示例
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.30</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.30</version></dependency>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --><!--status="WARN" :用于设置log4j2自身内部日志的信息输出级别,默认是OFF--><!--monitorInterval="30" :间隔秒数,自动检测配置文件的变更和重新配置本身--><configuration status="WARN" monitorInterval="30"><Properties><!--自定义一些常量,之后使用${变量名}引用--><Property name="logFilePath">log</Property><Property name="logFileName">test.log</Property></Properties><!--appenders:定义输出内容,输出格式,输出方式,日志保存策略等,常用其下三种标签[console,File,RollingFile]--><appenders><!--console :控制台输出的配置--><console name="Console" target="SYSTEM_OUT"><!--PatternLayout :输出日志的格式,LOG4J2定义了输出代码,详见第二部分--><PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/></console><!--File :同步输出日志到本地文件--><!--append="false" :根据其下日志策略,每次清空文件重新输入日志,可用于测试--><File name="log" fileName="${logFilePath}/${logFileName}" append="false"><PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/></File><!--SMTP :邮件发送日志--><SMTP name="Mail" subject="****SaaS系统正式版异常信息" to="[email protected]" from="[email protected]" smtpUsername="[email protected]" smtpPassword="LENG****1234" smtpHost="mail.lengjing.info" smtpDebug="false" smtpPort="25" bufferSize="10"><PatternLayout pattern="[%-5p]:%d{YYYY-MM-dd HH:mm:ss} [%t] %c{1}:%L - %msg%n" /></SMTP><!-- ${sys:user.home} :项目路径 --><RollingFile name="RollingFileInfo" fileName="${sys:user.home}/logs/info.log"filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log"><!--ThresholdFilter :日志输出过滤--><!--level="info" :日志级别,onMatch="ACCEPT" :级别在info之上则接受,onMismatch="DENY" :级别在info之下则拒绝--><ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/><PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/><!-- Policies :日志滚动策略--><Policies><!-- TimeBasedTriggeringPolicy :时间滚动策略,默认0点小时产生新的文件,interval="6" : 自定义文件滚动时间间隔,每隔6小时产生新文件, modulate="true" : 产生文件是否以0点偏移时间,即6点,12点,18点,0点--><TimeBasedTriggeringPolicy interval="6" modulate="true"/><!-- SizeBasedTriggeringPolicy :文件大小滚动策略--><SizeBasedTriggeringPolicy size="100 MB"/></Policies><!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 --><DefaultRolloverStrategy max="20"/></RollingFile><RollingFile name="RollingFileWarn" fileName="${sys:user.home}/logs/warn.log"filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log"><ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/><PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/><Policies><TimeBasedTriggeringPolicy/><SizeBasedTriggeringPolicy size="100 MB"/></Policies></RollingFile><RollingFile name="RollingFileError" fileName="${sys:user.home}/logs/error.log"filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log"><ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/><PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/><Policies><TimeBasedTriggeringPolicy/><SizeBasedTriggeringPolicy size="100 MB"/></Policies></RollingFile></appenders><!--然后定义logger,只有定义了logger并引入的appender,appender才会生效--><loggers><!--过滤掉spring和mybatis的一些无用的DEBUG信息--><!--Logger节点用来单独指定日志的形式,name为包路径,比如要为org.springframework包下所有日志指定为INFO级别等。--><logger name="org.springframework" level="INFO"></logger><logger name="org.mybatis" level="INFO"></logger><!-- Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出 --><root level="all"><appender-ref ref="Console"/><appender-ref ref="RollingFileInfo"/><appender-ref ref="RollingFileWarn"/><appender-ref ref="RollingFileError"/></root><!--AsyncLogger :异步日志,LOG4J有三种日志模式,全异步日志,混合模式,同步日志,性能从高到底,线程越多效率越高,也可以避免日志卡死线程情况发生--><!--additivity="false" : additivity设置事件是否在root logger输出,为了避免重复输出,可以在Logger 标签下设置additivity为”false”--><AsyncLogger name="AsyncLogger" level="trace" includeLocation="true" additivity="false"><appender-ref ref="RollingFileError"/></AsyncLogger></loggers></configuration>
以AsyncLogger为例
package com.example.log4jtest.demo;import org.junit.Test;import org.junit.runner.RunWith;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;/*** Created by jwnba24_er on 2021/2/13.*/@RunWith(SpringRunner.class)@SpringBootTest(classes = DemoApplication.class)public class LogTest {private static final Logger logger = LoggerFactory.getLogger("AsyncLogger");@Testpublic void testLog(){logger.error("===this is test log info===");}}
2021-02-13 21:26:01.491 ERROR 38202 --- [ main] AsyncLogger : ===this is test log info===
import org.slf4j.Logger;import org.slf4j.LoggerFactory;private static final Logger logger = LoggerFactory.getLogger(Abc.class);
if (logger.isDebugEnabled()) {logger.debug("Processing trade with id: " + id + " and symbol: " + symbol);}
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
<logger name="com.taobao.dubbo.config" additivity="false">
logger.error(各类参数或者对象 toString + "_" + e.getMessage(), e);
