Log4j2日志框架在SpringBoot中的应用

1. SpringBoot自带的日志框架

SpringBoot默认的日志框架为LogBack

GitHub地址:

Logback:https://github.com/qos-ch/logback

感觉Logback作者有段时间没更新了

在启动项依赖中点进去可以依次看到包含依赖
<artifactId>spring-boot-starter-web</artifactId>

<artifactId>spring-boot-starter</artifactId>

<artifactId>spring-boot-starter-logging</artifactId>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<scope>compile</scope>
</dependency>

因为是默认配置好的,实际需要配置的并不多。

如果需要输出日志到文件,只需要在application.properties配置文件设置:logging.file或logging.path,如下:

logging.level.root=info
logging.file=D:\\log\\my.log

值得一提的是

Spring Boot官方建议使用“-spring”的命名规则对配置文件进行命名,如:logback-spring.xml而不是logback.xml。log4j2也是如此

也可以自定义日志名称,需要在application.properties配置即可,代如下:

logging.config=classpath:logging-config.xml

贴一个Logback的配置文件,其实log4j2的配置文件也是类似的。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

<!-- 日志根目录-->
<springProperty scope="context" name="LOG_HOME" source="logging.path" defaultValue="/data/logs/spring-boot-logback"/>

<!-- 日志级别 -->
<springProperty scope="context" name="LOG_ROOT_LEVEL" source="logging.level.root" defaultValue="DEBUG"/>

<!-- 标识这个"STDOUT" 将会添加到这个logger -->
<springProperty scope="context" name="STDOUT" source="log.stdout" defaultValue="STDOUT"/>

<!-- 日志文件名称-->
<property name="LOG_PREFIX" value="spring-boot-logback" />

<!-- 日志文件编码-->
<property name="LOG_CHARSET" value="UTF-8" />

<!-- 日志文件路径+日期-->
<property name="LOG_DIR" value="${LOG_HOME}/%d{yyyyMMdd}" />

<!--对日志进行格式化-->
<property name="LOG_MSG" value="- | [%X{requestUUID}] | [%d{yyyyMMdd HH:mm:ss.SSS}] | [%level] | [${HOSTNAME}] | [%thread] | [%logger{36}] | --> %msg|%n "/>

<!--文件大小,默认10MB-->
<property name="MAX_FILE_SIZE" value="50MB" />

<!-- 配置日志的滚动时间 ,表示只保留最近 10 天的日志-->
<property name="MAX_HISTORY" value="10"/>

<!--输出到控制台-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 输出的日志内容格式化-->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>${LOG_MSG}</pattern>
</layout>
</appender>

<!--输出到文件-->
<appender name="0" class="ch.qos.logback.core.rolling.RollingFileAppender">
</appender>

<!-- 定义 ALL 日志的输出方式:-->
<appender name="FILE_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日志文件路径,日志文件名称-->
<File>${LOG_HOME}/all_${LOG_PREFIX}.log</File>

<!-- 设置滚动策略,当天的日志大小超过 ${MAX_FILE_SIZE} 文件大小时候,新的内容写入新的文件, 默认10MB -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

<!--日志文件路径,新的 ALL 日志文件名称,“ i ” 是个变量 -->
<FileNamePattern>${LOG_DIR}/all_${LOG_PREFIX}%i.log</FileNamePattern>

<!-- 配置日志的滚动时间 ,表示只保留最近 10 天的日志-->
<MaxHistory>${MAX_HISTORY}</MaxHistory>

<!--当天的日志大小超过 ${MAX_FILE_SIZE} 文件大小时候,新的内容写入新的文件, 默认10MB-->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>

</rollingPolicy>

<!-- 输出的日志内容格式化-->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>${LOG_MSG}</pattern>
</layout>
</appender>

<!-- 定义 ERROR 日志的输出方式:-->
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 下面为配置只输出error级别的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<OnMismatch>DENY</OnMismatch>
<OnMatch>ACCEPT</OnMatch>
</filter>
<!--日志文件路径,日志文件名称-->
<File>${LOG_HOME}/err_${LOG_PREFIX}.log</File>

<!-- 设置滚动策略,当天的日志大小超过 ${MAX_FILE_SIZE} 文件大小时候,新的内容写入新的文件, 默认10MB -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

<!--日志文件路径,新的 ERR 日志文件名称,“ i ” 是个变量 -->
<FileNamePattern>${LOG_DIR}/err_${LOG_PREFIX}%i.log</FileNamePattern>

<!-- 配置日志的滚动时间 ,表示只保留最近 10 天的日志-->
<MaxHistory>${MAX_HISTORY}</MaxHistory>

<!--当天的日志大小超过 ${MAX_FILE_SIZE} 文件大小时候,新的内容写入新的文件, 默认10MB-->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>

<!-- 输出的日志内容格式化-->
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>${LOG_MSG}</Pattern>
</layout>
</appender>

<!-- additivity 设为false,则logger内容不附加至root ,配置以配置包下的所有类的日志的打印,级别是 ERROR-->
<logger name="org.springframework" level="ERROR" />
<logger name="org.apache.commons" level="ERROR" />
<logger name="org.apache.zookeeper" level="ERROR" />
<logger name="com.alibaba.dubbo.monitor" level="ERROR"/>
<logger name="com.alibaba.dubbo.remoting" level="ERROR" />

<!-- ${LOG_ROOT_LEVEL} 日志级别 -->
<root level="${LOG_ROOT_LEVEL}">

<!-- 标识这个"${STDOUT}"将会添加到这个logger -->
<appender-ref ref="${STDOUT}"/>

<!-- FILE_ALL 日志输出添加到 logger -->
<appender-ref ref="FILE_ALL"/>

<!-- FILE_ERROR 日志输出添加到 logger -->
<appender-ref ref="FILE_ERROR"/>
</root>

</configuration>

2. Log4j2日志框架

Log4j2是Log4j的升级,它比其前身Log4j 1.x(已停更)提供了重大改进,并提供了Logback中可用的许多改进,同时修复了Logback架构中的一些固有问题。比如:插件式结构、配置文件优化、异步日志等。

GitHub地址

log4j2:https://github.com/apache/logging-log4j2

可以看到的是更新还是很活跃的。

Spring Boot添加Log4j2依赖,需要排除Logback依赖,配置pom.xml代码如下:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

<!--排除自带logback依赖-->
<exclusions>
<exclusion>
<artifactId>org.springframework.boot</artifactId>
<groupId>spring-boot-starter-logging</groupId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency> <!-- 引入log4j2依赖 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

在配置好后启动我这边会警告类似信息

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/E:/mavenJarOnline/ch/qos/logback/logback-classic/1.1.9/logback-classic-1.1.9.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/E:/mavenJarOnline/org/slf4j/slf4j-log4j12/1.7.22/slf4j-log4j12-1.7.22.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]

警告告知logging有多个绑定,logback、log4j2两种实现,明明已经排除了logback的依赖…

将spring-boot-starter-logging的包在spring-boot-starter中直接排除掉可以解决

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

最后贴一下log4j2-spring.xml文件的配置

log4j2配置详解

<?xml version="1.0" encoding="UTF-8"?>
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration monitorInterval="5">
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->

<!--变量配置-->
<Properties>
<!-- 这里定义两个格式化输出格式,分别用于文件日志和控制台日志(带颜色)-->
<!-- %date表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符 -->
<property name="LOG_PATTERN" value="%date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger [%L] : %msg%n" />
<property name="LOG_PATTERN_HIGHLIGHT" value="%date{yyyy-MM-dd HH:mm:ss:SSS} %highlight{%5level} [%thread] %style{%logger}{bright,cyan} [%style{%L}{bright,blue}] : %msg%n" />

<!-- 定义日志存储的路径,不要配置相对路径 -->
<property name="FILE_PATH" value="D://log4j2Logs" />
<!-- 定义日志归档压缩包名字,通常设置为项目名 -->
<property name="FILE_NAME" value="exception_demo" />
</Properties>

<appenders>

<!--*********************控制台日志***********************-->
<console name="Console" target="SYSTEM_OUT">
<!--输出日志的格式-->
<PatternLayout pattern="${LOG_PATTERN_HIGHLIGHT}"/>
<!--控制台只输出level及其以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
</console>

<!--*********************文件日志***********************-->
<!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用-->
<File name="Filelog" fileName="${FILE_PATH}/test.log" append="false">
<PatternLayout pattern="${LOG_PATTERN}"/>
</File>

<!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log" filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<!--interval属性用来指定多久滚动一次,默认是1 hour-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
<DefaultRolloverStrategy max="15"/>
</RollingFile>

<!-- 这个会打印出所有的warn及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/warn.log" filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<!--interval属性用来指定多久滚动一次,默认是1 hour-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
<DefaultRolloverStrategy max="15"/>
</RollingFile>

<!-- 这个会打印出所有的error及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileError" fileName="${FILE_PATH}/error.log" filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<!--interval属性用来指定多久滚动一次,默认是1 hour-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
<DefaultRolloverStrategy max="15"/>
</RollingFile>

</appenders>

<!--Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。-->
<!--然后定义loggers,只有定义了logger并引入的appender,appender才会生效-->
<loggers>

<!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
<logger name="org.mybatis" level="info" additivity="false">
<AppenderRef ref="Console"/>
</logger>
<!--监控系统信息-->
<!--若是additivity设为false,则 子Logger 只会在自己的appender里输出,而不会在 父Logger 的appender里输出。-->
<Logger name="org.springframework" level="info" additivity="false">
<AppenderRef ref="Console"/>
</Logger>

<root level="info">
<appender-ref ref="Console"/>
<appender-ref ref="Filelog"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
</root>
</loggers>
</configuration>

3. Logger的使用

最简单的在类中使用就是

private static final Logger logger = LoggerFactory.getLogger(XXX.class);

//...
logger.debug("debug信息");
logger.info("info信息");
logger.error("error信息");

在项目运行后控制台输出如下

image-20200805232149495

可以在配置的文件夹下面看到生成的日志文本

image-20200808165938791

补充

IDEA更新后控制台彩色输出会失效,需要在右上角 -> Edit Configurations -> VM options中添加

-Dlog4j.skipJansi=false