slf4j+log4j2基础教程(拿来即用教程)

log4j2是apache著名日志框架log4j的升级,参考logback架构,并且修复了logback固有的一些问题。是一个很好的日志框架。我看了网上一些关于log4j2的教程,要么是光讲概念,要么是只贴代码,适合新手入门的教程比较少。本篇教程的目标是给那些初次使用log4j2的人一个快速入门、配置代码拿来就可用的指导。
log4j2官方文档大而全、有很多概念,往往给一个问题提供多种不同的解决方案。我结合自身使用体验,对工作开发中常用的日志配置提供我个人认为最好的那一种配置,只介绍一种配置,拿来即用,简单方便。


一、maven配置dependency
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-bom</artifactId>
			<version>2.11.1</version>
			<scope>import</scope>
			<type>pom</type>
		</dependency>
	</dependencies>
</dependencyManagement>
  • -dependency依赖配置如下
		<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.7.25</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-core</artifactId>
			<scope>runtime</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-slf4j-impl</artifactId>
			<scope>runtime</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-web -->
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-web</artifactId>
			<scope>runtime</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/com.lmax/disruptor -->
		<dependency>
			<groupId>com.lmax</groupId>
			<artifactId>disruptor</artifactId>
			<version>3.4.2</version>
			<scope>runtime</scope>
		</dependency>

注意:截止2018年11月2日,slf4j的最新版本是“1.8.0-beta2”,但是不能将上述配置中的slf4j版本改成“1.8”大版,因为“1.8”大版的slf4j修改了logger的绑定机制,需要日志框架做修改来适配“1.8”大版的slf4j,但是截止目前即使是最新版“2.11.1”的log4j也还没有做适配。所以如果将上述配置中的slf4j的版本改成“1.8”大版将会在服务器启动时看到如下警告,导致日志无法被正常记录:
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#noProviders for further details.
SLF4J: Class path contains SLF4J bindings targeting slf4j-api versions prior to 1.8.
SLF4J: Ignoring binding found at [jar:file:/C:/dev/deploy-dir/app/learn/learn/WEB-INF/lib/log4j-slf4j-impl-2.11.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#ignoredBindings for an explanation.
日后估计log4j会做适配,目前还是用“1.7”大版的slf4j搭配“2.11”大版的log4j吧。

slf4j不必多说,开发必备,实际工作开发中使用slf4j提供的api进行编码。log4j-core和log4j-slf4j-impl的scope配置为runtime,因为这两个包的代码只在运行时使用,实际编码中不会用到。配置com.lmax.disruptor依赖是因为log4j2异步logger需要,不必深究,只需知道如果使用log4j2的异步logger需要这个包就行了。官方原文:LMAX Disruptor technology. Asynchronous Loggers internally use the Disruptor, a lock-free inter-thread communication library, instead of queues, resulting in higher throughput and lower latency.log4j-web包是为了解决web环境下关闭服务器时可能会出现的log4j线程无法及时关闭的warn,估计很多人都碰到过这个警告,但是没在意过,解决方式很简单,导入log4j-web这个依赖就行了。
上面的配置直接粘贴,在pom.xml中复制就行了。

二、log4j2基础概念
三、一个完整的配置的例子
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="5">
	<!-- 将一些常用值提取出来,然后在文件的其他部分通过${}的形式引用,这些值可以随便定义 -->
	<Properties>
		<!-- 定义日志文件根目录 -->
		<Property name="logDir" value="logs123" />
		<!-- 定义日志的通用格式 -->
		<Property name="genericPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
		<!-- 定义日志分卷文件通用文件名形式 -->
		<Property name="genericFilePattern" value="%d{yyyy-MM-dd}-%i" />
	</Properties>
	<!-- appender们的定义 -->
	<Appenders>
		<!-- 定义一个console类型定定义,如果需要,可以以这个为原型粘贴复制修改再定义适合自己的 -->
		<Console name="consoleAppender" target="SYSTEM_OUT">
			<PatternLayout pattern="${genericPattern}" />
		</Console>
		<!-- 定义一个文件appender,如果需要,可以以这个为原型粘贴复制修改再定义适合自己的,该appender的详细解释会在教程接下来的部分给出 -->
		<RollingRandomAccessFile name="rollingRandomAccessFileAppender" fileName="${logDir}/app.log"
			filePattern="${logDir}/app-${genericFilePattern}.log.zip" append="true">
			<PatternLayout pattern="${genericPattern}" />
			<Policies>
				<TimeBasedTriggeringPolicy interval="1" />
				<SizeBasedTriggeringPolicy size="100 MB" />
			</Policies>
			<DefaultRolloverStrategy max="1000000" compressionLevel="9" />
		</RollingRandomAccessFile>
	</Appenders>
	<!-- 定义logger们 -->
	<Loggers>
		<!-- 定义根logger,根logger是必须的,这里我把根logger定义为异步的,也可为定义为普通的同步的,但是注意在同步根logger和异步根logger中只能存在一个,不能两个都配置 -->
		<asyncRoot level="info">
			<AppenderRef ref="consoleAppender" />
		</asyncRoot>
		<!-- 普通的根logger,注意,跟上面的异步跟root同时只能存在一个 -->
		<!-- <Root level="trace"> <AppenderRef ref="consoleAppender" /> </Root> -->
		<!-- 定义一个普通的logger,这里我定义为异步的 -->
		<asyncLogger name="com.foo.Bar" level="info" additivity="false">
			<AppenderRef ref="consoleAppender" />
			<AppenderRef ref="rollingRandomAccessFileAppender" />
		</asyncLogger>
		<!-- 定义一个普通的logger -->
		<Logger name="com.foo.Bar.common" level="info" additivity="false">
			<AppenderRef ref="consoleAppender" />
			<AppenderRef ref="rollingRandomAccessFileAppender" />
		</Logger>
	</Loggers>
</Configuration>

测试用的java代码

package com.szq.learn.log4j2learn;

import java.time.LocalDateTime;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class App {

    /**
     * 这里通过logger的名字来获取logger,LoggerFactory和Logger都是slf4j包里的,
     * 没有用到log4j2的任何类,这就是把log4j2的scope配置为runtime的原因
     */
    private static Logger logger = LoggerFactory.getLogger("com.foo.Bar");

    public static void main(String[] args) throws Exception {
        System.out.printf("\n-- START %s\n", LocalDateTime.now());
        try {
            while (true) {
                logger.info("show something " + LocalDateTime.now());
            }
        } finally {
            System.out.printf("\n-- DONE %s\n", LocalDateTime.now());
        }
    }
}

四、上述完整配置例子的详解

log4j2的官网有很多配置可选,但是平常工作开发中大多用不到。开头已经说过,只介绍**"一种"配置,秉承这种思想,我解释下“三”中的配置示例。

其实
“三”**的配置示例可以当做模板来用,粘贴复制再修改修改就可以满足大部分工作开发中的需求。

  1. 首先看<Configuration>元素,log4j2框架自己也有一系列日志,比如框架初始化日志或者初始化失败日志什么的。status表示应该记录哪个等级的log4j2自身的日志,一般情况下WARN就行,如果出现了了WARN等级的日志,说明你的log4j2框架的用法有问题,就要及时排查排查了。log4j2支持自动更新配置文件,也就是说不用重启服务器,直接改log4j2的配置文件,它就能自动重新加载,起作用,完全碾压log4j,monitorInterval表示应该多久检测一次更新,单位:,默认5秒。
  2. 再看<Properties>,它里面包含<Property>,就是把一些通用的值提出来,在配置的其他地方已${}的形式引用而已。
  3. <Appenders>元素,官方文档表示有还有一种异步appender,但是效能提升及其有限,而且在多线程情况下有可能出现问题,所以不建议使用,本教程不讨论那个。官方文档有很多种类型的appender,但是平常工作中常用的也就是console类型和file类型的,console类型appender输出到控制台,方便开发调试用,file类型appender类型输出到文件,用在生产环境记录日志。console类型appender没得选,只有这一种,结构很简单,不用多说。file类型appender有多种类型,本教程建议使用<RollingRandomAccessFile>类型,因为这种类型的fileAppender有缓存功能,效率比RollingFile高(网上很多教程都是几年前的了,用的还是RollingFile),所以只讨论这种类型。fileName表示日志文件名,filePattern表示日志文件分卷的分卷文件的文件名(日志文件分卷就是某些情况,比如每天生成一个文件,或者单个日志文件超过100MB时自动分成多个日志文件),filePattern如果以.zip结尾表示启用压缩功能,那些分卷好的日志文件会被压缩,某些情况会很有用。如果不想启用压缩功能,就不要以.zip或者其他压缩文件后缀结尾。PatternLayout表示日志格式,不必多说。Policies是触发日志文件分卷的条件。TimeBasedTriggeringPolicy表示按照时间来分卷,interval表示时间间隔,时间单位有点诡异,不是明确设置的,而是从filePattern推导的,是filePattern中最小的时间的单位,比如上述示例中的filePattern为%d{yyyy-MM-dd},这个日期时间格式必须符合java日期时间规范,其中最小日期单位为dd,也就是天,推导出来也就是1天分一个日志文件出来,如果filePattern的配置为%d{yyyy-MM-dd HH:mm},最小单位是mm,也就是分钟,那就是1分钟分一个日志文件出来,如果interval为3,那就是3天一个日志文件和3分钟一个日志文件,推导规则就是如此。SizeBasedTriggeringPolicy表示日志文件大小超过多大时对其进行分卷,size表示日志大小,单位推荐写MB,数值为大于0的整数,100 MB中间有个空格,推荐写上。DefaultRolloverStrategy表示分卷策略,只需要记住这个必须要配就行了,不必深究,max表示最多可以有多少个分卷文件,默认为7个,超出7个的日志分卷文件将被删除,也就是说可能导致重要日志丢失,所以该参数配大点,100000应该够了,compressionLevel表示压缩等级,值为0-9,只在filePattern以.zip结尾,也就是说压缩格式为zip时起作用,这也是为什么前面说建议压缩格式为zip。0表示不压缩,只打包为zip格式,9表示最高压缩比(个人测试1MB日志文件某些情况下能压缩到4KB左右)。如果不想启用压缩功能,前面说过,日志filePattern不以.zip结尾就行了,这时compressionLevel是不起作用的。
  4. 表示配置各种logger的地方。根logger是必需的,可配置为普通的,也可配置问异步的,但是只能配置一种,不能两种都配置。其他的普通logger配置很简单,不必多说,可根据需要配置为普通logger或者异步logger,至于选择异步的还是普通的,教程前半部分已经说过,如果日志记录代码跟业务逻辑代码是有关系的,最好选普通logger,如果真的只是单纯为了记个日志,建议配置异步logger。根logger没有additivity属性,普通logger和异步logger有additivity属性。additivity设置为false是为了防止当前logger向父logger发送日志,导致日志被重复记录。至于log4j2的logger的父子关系,可以看这里http://logging.apache.org/log4j/2.x/manual/architecture.html。总的来说就是类似java体系的父子关系,根logger相当于是java体系中的Object类,是所有logger的父logger,所以所有logger的日志都会被添加到根logger中,所以给每个(除了根logger)添加additivity="false"是很有必要的,可以避免记录大量重复的日志。

##原创不易,转帖请注明出处—shizhongqi


  • 14
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值