slf4j+log4j2使用及log4j2配置文件解析

零、一些问题的修改与更新

0.1 将日志自动保存到不同的日志文件(19-10-03更新)

·  自己在做项目的时候遇到了一个问题:重新运行项目,如何把日志保存到不同的log文件?
·  我之前写的那个模板有一个重大的问题:每次运行程序,只要日志文件没超过maxSize,log都只会记录到这个文件。但是调试的时候,这种操作令人十分不爽,因此,在查询了官网之后,给模板进行了修改。
修改如下:
·  因为在普通的字符串里无法使用pattern的语法,因此使用fileName="$${date:MM-dd-HH-ss}" 作为保存的日志名称,这样每次运行程序,日志必然会保存在不同的文件下。
·  实际上,我们完全可以构造两个FileAppender,这样就可以根据我们的需要来使用不同的日志文件记录方式了:本文的模板已更新,不喜可删。

一、什么是slf4j和log4j2

·  目前开源的日志框架有很多,如logback,log4j等,这面临了一个问题:当使用不同的日志框架或者这些日志框架面临了重大更新的时候,如果其实现函数有所改变,那么旧版本的框架就会崩溃,这很不利于项目的维护和新框架的推广。因此才诞生了例如slf4j这样的日志门面
·  日志门面,顾名思义就是日志框架对外的表现形式,理论上只要日志框架实现了日志门面的接口,不管其怎么更新,开发者都不需要对项目的依赖,或者项目的代码做出过多的改变。目前还在坚持更新且性能良好的日志门面非slf4j莫属,因此强烈建议使用slf4j作为我们书写日志的接口。
·  日志框架方面,logback是log4j的升级版,这两个框架与slf4j是一个开发者开发出来的,因此其整合十分之稳定。但是log4j2作为apache最新推出的日志框架,在异步记录日志的方面性能比logback要更加的优异,因此本着要用就用最好的的原则 ,使用lo4gj2作为日志记录的框架。
注:log4j2只是假借了log4j之名而已,log4j的真正升级版是logback。

二、 依赖

·  日志的环境依赖总共有4部分,分别是slf4j接口部分,log4j2的日志框架实现部分,log4j2异步日志插件部分以及slf4j与log4j2的桥接部分。

包名作用
slf4j-api目前的版本1.7就可。slf4j的接口包,我们对日志进行的所有操作都用的是这个包的API
log4j-core版本必须在2.1以上,是log4j2的核心包
log4j-api版本与核心包一致,log4j2的接口包,用来直接调用log4j2框架的,必须导入,不然无法与slf4j对接
log4j-web版本与核心包一致,用于web项目的log4j2,阻止web项目出现警告
com.lmax.disruptor版本随意,开启log4j2的异步日志记录的功能
log4j-slf4j-impl版本与核心包一致,用于slf4j与log4j对接,即用slf4j的接口实现操作日志

这里给出一份Maven完整依赖:

    <properties>
        <log4j2.version>2.11.2</log4j2.version>
        <slf4j.version>1.7.28</slf4j.version>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-web -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-web</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.lmax/disruptor -->
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>3.4.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</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>${log4j2.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

三、配置

·  看多很多的博客,都没有官网的配置全面,因此给出官网传送门:log4j2官网详细配置说明
·  本博客给出一种粘贴复制即可用的配置,并给出一些个人认为比较重要的说明。

3.1 配置文件

·  基本上所有的配置都写在了Properties里,因此,只需要改Properties就可以用了(建议自定义Logger,不建议修改Appenders)。
Apperders里定义了两种日志记录的格式:1. 在控制台输出name=“Console”,2. 在文件输出name=“File”。使用RollingRandomAccessFileAppender是因为其性能最好,且支持日志自动归档。

<?xml version="1.0" encoding="UTF-8"?>
<!-- https://www.cnblogs.com/hafiz/p/6170701.html-->
<Configuration status="WARN" name="MyApp">
	<Properties>
		<!--日志文件保存的路径-->
		<property name="filePath" value="src/logs/$${date:MM-dd-HH-mm-ss}-untitled.log"/>
		<property name="filePath_onlyOne" value="src/logs/untitled.log"/>
		<!--日志文件归档后保存的压缩文件路径-->
		<property name="filePattern" value="src/logs/$${date:yyyy-MM}/untitled-%d{yyyy-MM-dd-HH}-%i.log.zip"/>
		<!--日志文档超过多大时执行翻转(即:将旧文件压缩,并用新日志文件记录)-->
		<property name="maxSize" value="250 MB"/>
		<!--记录的日志文件超过多少时,旧文件会被删除-->
		<property name="maxFile" value="50"/>
		<!--打印日志的时候是否标注日志在项目的位置信息-->
		<property name="useLocation" value="true"/>
		<!--日志输出格式-->
		<property name="layoutPattern" value="%date %p %c{1.} [%thread] %location %message %exception%n"/>
	</Properties>
	<Appenders>
		<Console name="Console" target="SYSTEM_OUT">
			<PatternLayout pattern="${layoutPattern}"/>
		</Console>
<!--		-->
		<RollingRandomAccessFile name="File" fileName="${filePath}" filePattern="${filePattern}">
			<PatternLayout pattern="${layoutPattern}"/>
			<Policies>
				<!--基于时间的归档,一般不使用-->
				<!--这个6基于filePattern归档文件的时间,本文件归档的filePattern最后的HH表示小时,因此此文件每6个小时进行一次归档-->
				<!-- <TimeBasedTriggeringPolicy interval="6" modulate="true"/>-->
				<!--基于文件大小的归档-->
				<SizeBasedTriggeringPolicy size="${maxSize}"/>
			</Policies>
			<DefaultRolloverStrategy max="${maxFile}"/>
		</RollingRandomAccessFile>
		
		<RollingRandomAccessFile name="OneFile" fileName="${filePath_onlyOne}" filePattern="${filePattern}">
			<PatternLayout pattern="${layoutPattern}"/>
			<Policies>
				<!--基于文件大小的归档-->
				<SizeBasedTriggeringPolicy size="${maxSize}"/>
			</Policies>
			<DefaultRolloverStrategy max="${maxFile}"/>
		</RollingRandomAccessFile>
	</Appenders>
	<!--这个只能自行配置了-->
	<Loggers>
		<!--异步日志Root(与同步Root之间只能存在一个)-->
<!--		<AsyncRoot level="DEBUG" includeLocation="${useLocation}">-->
<!--			<AppenderRef ref="Console"/>-->
<!--			<AppenderRef ref="File"/>-->
<!--		</AsyncRoot>-->
<!--		        同步Root-->
		<Root level="INFO" >
			<AppenderRef ref="File"/>
			<AppenderRef ref="Console"/>
		</Root>
		<!--异步日志(与同步日志可同时存在)-->
		<!--name属性值请自定义-->
<!--		<AsyncLogger name="AsyncLogger" level="DEBUG" includeLocation="${useLocation}" additivity="false">-->
<!--			<AppenderRef ref="File"/>-->
<!--		</AsyncLogger>-->
<!--		同步日志-->
<!--		<Logger name="com.memoforward.dao" level="DEBUG" includeLocation="${useLocation}" additivity="false">-->
<!--			<AppenderRef ref="Console"/>-->
<!--		</Logger>-->
	</Loggers>
</Configuration>

3.2 配置的简单说明:

3.2.1 RollingRandomAccessFile标签

  • RollingRandomAccessFile的三个属性的含义:

    1. name:这个Appender的引用名
    2. fileName:日志文件的路径及名称(文件夹或文件不存在就自动创建)
    3. filePattern:日志归档后的文件的保存路径和名称(如果加了.zip就自动压缩)
  • RollingRandomAccessFile必须配置的两个字标签:

    1. TriggerPolicy:文件翻转触发机制。翻转的意思就是旧文件保存(归档),另起新文件进行记录。
      在上述配置文件中,其触发机制是SizeBasedTriggeringPolicy,即:当文件大小超过一定阈值后,进行自动保存
    2. RolloverStrategy:文件翻转策略。
      在上述配置文件中,其策略是默认策略,当归档的文件数量达到一定数值后,就自动删除旧文件(如果不配置,则默认为7)
  • 测试代码如下

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.Test;

public class Log4j2Test {
//    private static final Logger logger = LoggerFactory.getLogger(Log4j2Test.class);
    private static final Logger logger = LoggerFactory.getLogger("AsyncLogger");
    @Test
    public void testLog(){
        for(int i = 0; i < 500; i++){
            logger.error(Integer.toString(i));
        }
    }
}
  • 测试结果如下
    设置了保存的文件最大为1KB,最大保存文件数量为10,保存500条日志。每篇日志能保存9条语句。
    在这里插入图片描述
  • untitled.log输出如下
2019-08-28 19:16:52,248 ERROR AsyncLogger [main] Log4j2Test.testLog(Log4j2Test.java:11) 491 
2019-08-28 19:16:52,248 ERROR AsyncLogger [main] Log4j2Test.testLog(Log4j2Test.java:11) 492 
2019-08-28 19:16:52,248 ERROR AsyncLogger [main] Log4j2Test.testLog(Log4j2Test.java:11) 493 
2019-08-28 19:16:52,248 ERROR AsyncLogger [main] Log4j2Test.testLog(Log4j2Test.java:11) 494 
2019-08-28 19:16:52,248 ERROR AsyncLogger [main] Log4j2Test.testLog(Log4j2Test.java:11) 495 
2019-08-28 19:16:52,248 ERROR AsyncLogger [main] Log4j2Test.testLog(Log4j2Test.java:11) 496 
2019-08-28 19:16:52,249 ERROR AsyncLogger [main] Log4j2Test.testLog(Log4j2Test.java:11) 497 
2019-08-28 19:16:52,250 ERROR AsyncLogger [main] Log4j2Test.testLog(Log4j2Test.java:11) 498 
2019-08-28 19:16:52,250 ERROR AsyncLogger [main] Log4j2Test.testLog(Log4j2Test.java:11) 499 

·  可见,如果不设置翻转的机制,要么会在一个日志文件内记录所有的数据,要么仅会保存7条归档的日志。一般情况下,希望能把所有的归档日志文件都保存下来,因此RolloverStragety的值要设置的大一点。

3.2.2 Logger的配置

·  Logger分为同步和异步,只有一个RootLogger。异步的实现就是我们之前引入的那个com.lmax.disruptor包,当我们启用异步日志记录的时候,就会新建一个Disruptor对象,具体的日志记录流程建议参考这位大佬的文章:Log4j2中的同步日志与异步日志

  • Logger中属性的含义:

    1. name:在代码getLogger的名字,root没有此属性。
    2. level:日志的打印级别为"OFF>FATAL>ERROR>WARN>INFO>DEBUG>TRACE"。logger在记录日志的时候,只会记录level界别及以上的日志内容(OFF永远不会打印)。如设置了ERROR,只会打印FATAL和ERROR。
    3. includeLoacation:日志打印的时候是否会输出位置(打印位置会降低性能)。
    4. additivity:root没有,配置此属性值为true来避免重复打印(如果为false,root会重复打印一次相同级别的日志),至于为什么会重复打印,还是建议大家看一下官方文档,这里不赘述了。
  • Logger的子标签
    1.< AppenderRef ref=“xxx” > 表示这个logger将用到何种Appender,ref内写Appender的name属性值。

3.2.3 PatternLayout解释

·  本配置文件默认的layoutPattern为:%date %p %c{1.} [%thread] %location %message %exception%n
·  官网有特别特别详细的说明文档,我这个都是对着官网写出来的,特别好理解,强烈建议大家对看文档。传送门:log4j2的LayoutPattern;本博客就只介绍一下上面的这行配置。

格式说明
%date输出日期和时间:yyyy-MM-dd HH:mm:ss,SSS(年-月-日 时:分:秒,毫秒)
%p输出日志的打印级别
%c{1.}输出该日志所处的缩略类路径
%[thread]打印执行该日志记录的线程名
%location打印日志语句在项目代码中的位置
%message日志内容
%exception如果出现了异常,则打印异常
%n类似于/n,是换行符

四、总结

·  日志记录一直是一个很尴尬的点,感觉不难,但一直理解不是很深刻,其实我们最常用的就是把日志输出到控制台或者输出到文件,私以为只要把这两个方面搞明白了就行。以后做项目,尽量就用slf4j+log4j2来记录日志啦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值