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,单位为bytes
asyncLoggerRingBufferSize=57344
//以下如果两者都配置了,则第二种方式将会覆盖第一种方式的配置
log4j2.AsyncQueueFullPolicy=Discard
log4j2.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");
@Test
public 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);