SpringBoot系列:日志框架-Log4j2
目标
- 异步输出日志
- 根据业务不同分类输入到不同的日志文件中
- 自动压缩日志文件并归档
- 动态修改日志等级
开发环境
- spring boot 2.0.4.RELEASE
- JDK 1.8
Log4j2介绍
创建spring boot
添加maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itxiaoer</groupId>
<artifactId>demo-spring-cloud-log4j2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo-spring-cloud-log4j2</name>
<description>Demo log4j2 for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--去掉默认的日志框架-->
<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-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--异步支持-->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
添加log4j2.xml文件
在resources下创建log4j2.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="TRACE" monitorinterval="5">
<!--配置常量-->
<Properties>
<Property name="baseDir">logs</Property>
</Properties>
<Appenders>
<!--这个输出控制台的配置-->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用-->
<!--append = true : 保留启动前的日志,追加新日志,false: 清空原有日志-->
<File name="log" fileName="${baseDir}/all.log" append="true">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</File>
<RollingFile name="RollingFile_1" fileName="${baseDir}/logs_1/info.log"
filePattern="${baseDir}/logs_1/$${date:yyyy-MM}/info-%d{yyyy-MM-dd HH-mm}-%i.log.gz">
<!--只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
<Policies>
<!--4分钟rollover一次-->
<TimeBasedTriggeringPolicy interval="4"/>
<!--文件大小-->
<SizeBasedTriggeringPolicy size="1 MB"/>
</Policies>
<!--文件数量-->
<DefaultRolloverStrategy max="3"/>
</RollingFile>
<!--删除历史日志文件-->
<RollingRandomessFile name="RollingFile_2" fileName="${baseDir}/logs_2/info.log"
filePattern="${baseDir}/logs_2/$${date:yyyy-MM}/info-%d{yyyy-MM-dd HH-mm}-%i.log.gz">
<!--只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
<Policies>
<!--1分钟rollover一次-->
<TimeBasedTriggeringPolicy interval="1"/>
<!--文件大小-->
<SizeBasedTriggeringPolicy size="1 MB"/>
</Policies>
<!--文件数量-->
<DefaultRolloverStrategy>
<Delete basePath="${baseDir}/logs_2" maxDepth="2">
<IfFileName glob="*/info-*.log.gz"/>
<IfLastModified age="5m"/>
</Delete>
</DefaultRolloverStrategy>
</RollingRandomessFile>
<!--pay-->
<RollingFile name="payRollingFile" fileName="${baseDir}/pay/info.log"
filePattern="${baseDir}/pay/$${date:yyyy-MM}/info-%d{yyyy-MM-dd HH-mm}-%i.log.gz">
<!--只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
<Policies>
<!--1分钟rollover一次-->
<TimeBasedTriggeringPolicy interval="1"/>
<!--文件大小-->
<SizeBasedTriggeringPolicy size="1 MB"/>
</Policies>
<!--文件数量-->
<DefaultRolloverStrategy>
<Delete basePath="${baseDir}/pay" maxDepth="2">
<IfFileName glob="*/info-*.log.gz"/>
<IfLastModified age="5m"/>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
<!--pay-->
<RollingFile name="bizRollingFile" fileName="${baseDir}/biz/info.log"
filePattern="${baseDir}/biz/$${date:yyyy-MM}/info-%d{yyyy-MM-dd HH-mm}-%i.log.gz">
<!--只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
<Policies>
<!--1分钟rollover一次-->
<TimeBasedTriggeringPolicy interval="1"/>
<!--文件大小-->
<SizeBasedTriggeringPolicy size="1 MB"/>
</Policies>
<!--文件数量-->
<DefaultRolloverStrategy>
<Delete basePath="${baseDir}/biz" maxDepth="2">
<IfFileName glob="*/info-*.log.gz"/>
<IfLastModified age="5m"/>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<Loggers>
<!--pay包下的日志输入到pay目录下-->
<Logger name="com.itxiaoer.logging.pay" level="trace" additivity="false">
<AppenderRef ref="payRollingFile"/>
</Logger>
<!--biz包下的日志输入到biz目录下-->
<AsyncLogger name="com.itxiaoer.logging.biz" level="trace" additivity="false" includeLocation="true">
<AppenderRef ref="bizRollingFile"/>
</AsyncLogger>
<Root level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="log"/>
<AppenderRef ref="RollingFile_1"/>
<AppenderRef ref="RollingFile_2"/>
</Root>
</Loggers>
</Configuration>
启用定时任务
package com.itxiaoer.logging;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* @author : liuyk
*/
@EnableScheduling
@SpringBootApplication
public class DemoSpringCloudLog4j2Application {
public static void main(String[] args) {
SpringApplication.run(DemoSpringCloudLog4j2Application.class, args);
}
}
创建定时任务类
- PayJob
package com.itxiaoer.logging.pay;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* @author : liuyk
*/
@Slf4j
@Component
public class PayJob {
/**
* 2秒钟执行1次
*/
@Scheduled(fixedRate = 5 * 1000)
public void logging() {
String now = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(LocalDateTime.now());
log.info(now);
log.debug(now);
log.error(now);
}
}
- BizJob
package com.itxiaoer.logging.biz;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* @author : liuyk
*/
@Slf4j
@Component
public class BizJob {
/**
* 2秒钟执行1次
*/
@Scheduled(fixedRate = 2 * 1000)
public void logging() {
String now = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(LocalDateTime.now());
log.trace(now);
log.debug(now);
log.info(now);
log.debug(now);
log.error(now);
}
}
动态修改日志等级
添加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
说明
spring-boot-actuator模块提供了一个监控和管理生产环境的模块,可以使用http、jmx、ssh、telnet等来管理和监控应用。审计(Auditing)、 健康(health)、数据采集(metrics gathering)会自动加入到应用里面。
修改application.yml
management:
endpoints:
web:
exposure:
include: loggers
启动,查看日志
16:57:30.850 [main] INFO org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping - Mapped "{[/actuator/loggers],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
16:57:30.851 [main] INFO org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping - Mapped "{[/actuator/loggers/{name}],methods=[POST],consumes=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
16:57:30.852 [main] INFO org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping - Mapped "{[/actuator/loggers/{name}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
16:57:30.852 [main] INFO org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping - Mapped "{[/actuator],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto protected java.util.Map<java.lang.String, java.util.Map<java.lang.String, org.springframework.boot.actuate.endpoint.web.Link>> org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping.links(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
访问
http://127.0.0.1:8080/actuator/loggers
{
"levels": ["OFF", "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"],
"loggers": {
"ROOT": {
"configuredLevel": "INFO",
"effectiveLevel": "INFO"
},
"com.itxiaoer.logging.biz": {
"configuredLevel": "TRACE",
"effectiveLevel": "TRACE"
},
"com.itxiaoer.logging.pay": {
"configuredLevel": "TRACE",
"effectiveLevel": "TRACE"
}
}
}
修改日志级别
- 请求地址 http://127.0.0.1:8080/actuator/loggers/{name}
说明
- 修改请求方式为POST
- name为要修改的日志名称,比如com.itxiaoer.logging.biz
- 修改请求体格式为 {"configuredLevel": "DEBUG"}
- curl方式修改
curl -H "Content-Type: application/json" -X POST --data "{\"configuredLevel\": \"DEBUG\"}" http://127.0.0.1:8080/actuator/loggers/com.itxiaoer.logging.biz
- PostMan工具修改
查看日志级别
http://127.0.0.1:8080/actuator/loggers/{name}
说明
- 查看请求方式为GET
- name为要查看的日志名称,比如com.itxiaoer.logging.biz
{
"configuredLevel": "INFO",
"effectiveLevel": "INFO"
}