vlambda博客
学习文章列表

SLF4J与Log4j2的完美配合

上一篇讲述了“Log4j、SLF4J、Logback、Log4j2” 的来龙去脉,本篇将着重说明“SLF4J+Log4j2”的使用。参照官网学习,建议从头看完,当然,直接拖到最后看完整的“配置+详细行注释”也可


1、到maven仓库找 SLF4J 相关的依赖,这里直接撸 1.7.36 版

https://mvnrepository.com/artifact/org.slf4j/slf4j-api

得到的坐标如下

<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --><dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.36</version></dependency>


2、到maven仓库找 Log4j2 相关的依赖

https://mvnrepository.com/artifact/org.apache.logging.log4j

SLF4J与Log4j2的完美配合

得到的坐标如下

<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --><dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.17.2</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl --><dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.17.2</version> <scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-web --><dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-web</artifactId> <version>2.17.2</version></dependency>

另外,异步需要依赖下述的jar

<!-- https://mvnrepository.com/artifact/com.lmax/disruptor --><dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>3.4.2</version></dependency>


3、综上,总共需要的jar的坐标如下

<!-- slf4j的依赖 --><dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.36</version></dependency><!-- log4j的核心包 --><dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.17.2</version></dependency><!-- log4j与slf4j绑定的依赖 --><dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.17.2</version> </dependency><!-- log4j对web项目的支持 --><dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-web</artifactId> <version>2.17.2</version></dependency><!-- 实现异步的依赖 --><dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>3.4.2</version></dependency>


4、在项目中配置

https://logging.apache.org/log4j/2.x/manual/configuration.html

注意!直接在resource目录下配置 log4j2.xml 配置文件 (注意,如果文件名不叫 log4j2.xml ,那么还需要在 web.xml中指定配置文件路径)




先了解下配置文件中的几个关键节点:

1、Configuration - 配置文件最外层的节点

<Configuration name="ConfigTest" status="ERROR" monitorInterval="5"></Configuration>
  • name:当前配置文件的名称

  • status:Log4j内部事件的级别。有效值为“off”、“trace”、“debug”、“info”、“warn”、“error”、“fatal”和“all”。Log4j 会将有关初始化等一些内部操作的详细信息打印出来(trace,如果需要排查log4j自身问题,可以配置成这个)

 

2、Appenders - 将日志输出到指定地方,同时可以配置打印的策略、格式等

(1)日志输出到文件中(File)

<?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>

(2)日志输出到 Apache Cassandra 数据库(Cassandra)

<Configuration name="CassandraAppenderTest"> <Appenders> <Cassandra name="Cassandra" clusterName="Test Cluster" keyspace="test" table="logs" bufferSize="10" batched="true"> <SocketAddress host="localhost" port="9042"/> <ColumnMapping name="id" pattern="%uuid{TIME}" type="java.util.UUID"/> <ColumnMapping name="timeid" literal="now()"/> <ColumnMapping name="message" pattern="%message"/> <ColumnMapping name="level" pattern="%level"/> <ColumnMapping name="marker" pattern="%marker"/> <ColumnMapping name="logger" pattern="%logger"/> <ColumnMapping name="timestamp" type="java.util.Date"/> <ColumnMapping name="mdc" type="org.apache.logging.log4j.spi.ThreadContextMap"/> <ColumnMapping name="ndc" type="org.apache.logging.log4j.spi.ThreadContextStack"/> </Cassandra> </Appenders> <Loggers> <Logger name="org.apache.logging.log4j.cassandra" level="DEBUG"> <AppenderRef ref="Cassandra"/> </Logger> <Root level="ERROR"/> </Loggers></Configuration>

(3)日志输出到控制台(Console)

<?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>

(4)滚动文件输出(RollingFile)

<?xml version="1.0" encoding="UTF-8"?><Configuration status="warn" name="MyApp" packages=""> <Appenders> <RollingFile name="RollingFile" fileName="logs/app.log" filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz"> <PatternLayout> <Pattern>%d %p %c{1.} [%t] %m%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy /> <SizeBasedTriggeringPolicy size="250 MB"/> </Policies> </RollingFile> </Appenders> <Loggers> <Root level="error"> <AppenderRef ref="RollingFile"/> </Root> </Loggers></Configuration>

(5)滚动文件输出完整版及释义

SLF4J与Log4j2的完美配合

这里说几个关键的参数

  • append:默认为true。表示新记录写入时,是在原文件内容基础上追加,还是清除之前的

  • bufferedIO:默认为true。表示新记录会先写入缓冲区,当缓冲区数据满了之后,再将数据转移到磁盘上,这种方式可以提高性能

  • bufferSize:缓冲区大小,默认为8192字节 (注意,bufferedIO为true时,才会用到这个)

  • fileName:要写入的文件路径,如果文件不存在,会直接创建

  • immediateFlush:默认为true。每次写入数据后都会刷新。如果设置为false的话,日志会先放在缓冲区,那么最终写入到文件中时,可能存在延迟

  • policy:日志存档的策略,比如日志文件达到多大时,或者到达什么时间时

<?xml version="1.0" encoding="UTF-8"?><Configuration name="MyApp" status="ERROR" monitorInterval="5"> <Properties> <Property name="baseDir">logs</Property> </Properties> <Appenders> <RollingFile name="RollingFile" fileName="${baseDir}/app.log" filePattern="${baseDir}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz"> <PatternLayout pattern="%d %p %c{1.} [%t] %m%n" /> <Policies> <TimeBasedTriggeringPolicy /> <SizeBasedTriggeringPolicy size="250 MB"/> </Policies> <DefaultRolloverStrategy max="100">  <Delete basePath="${baseDir}" maxDepth="2"> <IfFileName glob="*/app-*.log.gz"> <IfLastModified age="P30D"> <IfAny> <IfAccumulatedFileSize exceeds="100 GB" /> <IfAccumulatedFileCount exceeds="10" /> </IfAny> </IfLastModified> </IfFileName> </Delete> </DefaultRolloverStrategy> </RollingFile> </Appenders> <Loggers> <Root level="error"> <AppenderRef ref="RollingFile"/> </Root> </Loggers></Configuration>

上面的意思是:

  • 日志路径为:logs/app.log (此处省略了应用部署的路径,直接按照上诉配置的话,路径是在tomcat的bin目录中)

  • 当文件达到250MB时 或者 过了6个小时,则会产生一个新文件

  • 历史文件会放入目录(这里以当前时间举例):logs/2022-05  历史文件会被压缩,完整文件名为:app-2022-05-08-22-1.log.gz、app-2022-05-08-22-2.log.gz

  • <DefaultRolloverStrategy max="100"> 这里的 max="100" 表示同一天存档文件最多100个,到达100个时,会删除之前的

  • <Delete basePath="${baseDir}" maxDepth="2"> 表示要删除文件所在的目录

  • <IfFileName glob="*/app-*.log.gz"> 表示要删除的文件,文件名需符合 */app-*.log.gz 这种格式

  • <IfLastModified age="P30D"> 表示删除30天以前的文件

  • <IfAccumulatedFileSize exceeds="100 GB" /> 表示,如果文件内容达到100GB,那么此文件不删除

  • <IfAccumulatedFileCount exceeds="10" /> 表示,最近的10个文件不删除

3、Loggers - 日志打印的配置 

这里的设置与上面的<Appenders>配置对应,注意观察这里

SLF4J与Log4j2的完美配合

Loggers 中用来配置Appenders中日志的级别,当有多个Appenders时,对应也可以配置多个AppenderRef,如下

<Loggers> <Root> <AppenderRef ref="RollingFile" level="info"/> <AppenderRef ref="Console" level="debug"/> </Root> </Loggers>


4、在代码中直接使用即可

!!注意引入的时候,引入slf4j相关的包

import org.slf4j.Logger;import org.slf4j.LoggerFactory;
public class Test {
private static Logger logger = LoggerFactory.getLogger(Test.class);
public static void main(String[] args) { String str = "哈哈"; logger.info("测试打日志,{}",str); }}


5、给出一个完整的配置(带注释)




参考

log4j2的官网

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