Spring Boot 统一日志处理
本文将介绍如何在 SpringBoot 中优雅地统一日志处理。
一、日志的重要性
日志对应用程序的重要性不言而喻,无论是记录运行情况还是追踪线上问题,都离不开对数据的分析。
二、日志框架
市面上的日志框架分为两类:日志门面(日志抽象层)和日志实现。
一般选用一个日志门面和一个日志实现组合为日志,并在代码中 “面向日志门面” 使用。
SpringBoot 默认使用 SLF4J 和 Logback 的组合。
三、简单使用
实例化 logger:
1
2
3
4
5
6
7public class 类名 {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(类名.class);
}
}调用 logger:
1
2
3
4
5
6
7
8public class 类名 {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(类名.class);
logger.info("Hello");
}
}
结合 Lombok:
1
2
3
4
5
6
7
8
@Log
public class 类名 {
public static void main(String[] args) {
log.info("Hello");
}
}
四、日志的配置
- 简单配置:日志的部分配置信息已经集成至 SpringBoot 中,可以通过修改 SpringBoot 的配置文件(porperties/yml)进行配置
- 深度配置:如果希望更深度地配置日志,还可以创建和编写日志的专用 xml 配置文件。
具体请看:
五、日志的持久化
日志的持久化一共有两种方式:文件持久化、数据库持久化
1. 文件持久化
修改 SpringBoot 配置文件:
1 |
|
2. 数据库持久化
创建日志专用配置文件,修改如下:
1 |
|
在数据库中新建表,SQL 语句如下:
1 |
|
六、AOP 统一处理
在实际开发中,我们可能会有大量的重复的日志记录需求,此时,我们便可以使用 AOP 来避免代码的重复书写。
假设我们希望记录每一次对接口的访问,具体做法如下:
创建切面类,配置增强方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16@Aspect
public class ControllerLogAspect {
@Pointcut("execution(* pers.codewld.imall.*.controller.*.*(..))")
public void controllerLog() {
}
@Around("controllerLog()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
// ···执行前增强···
result = joinPoint.proceed();
// ···执行后增强···
return result;
}
}获取被切入方法的基本信息,记录至日志中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23@Aspect
public class ControllerLogAspect {
@Pointcut("execution(···)")
public void controllerLog() {
}
@Around("controllerLog()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
result = joinPoint.proceed();
// 获取基本信息
String uri = request.getRequestURI();
String username = request.getRemoteUser();
// 记录至日志
Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
logger.info("url:" + uri + " username:" + username)
return result;
}
}
七、自定义数据库日志
日志框架自带的数据库持久化不够灵活,因此,我们实际上可以创建自己的数据库日志。
具体做法如下:
选择数据库,这里选用 MongoDB,相比于 MySQL 它更加灵活、更适用于日志的存储,同时将 “数据数据库” 和 “日志数据库” 分离也可以减少增加日志引发的性能损失
创建日志实体类
1
2
3
4
5
6
7
8
9public class Log {
@ApiModelProperty("URI")
private String uri;
@ApiModelProperty("操作用户")
private String username;
}创建日志 repository
创建日志 Service
在切面类中,将日志同时存储至 “日志” 和 “自定义数据库日志” 中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27@Aspect
public class ControllerLogAspect {
@Pointcut("execution(···)")
public void controllerLog() {
}
@Around("controllerLog()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
result = joinPoint.proceed();
// 获取基本信息
Log log = new Log();
log.setUri(request.getRequestURI());
log.setUsername(request.getRemoteUser());
// 记录至日志
Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
logger.info(log)
// 记录至自定义数据库日志
logService.add(log);
return result;
}
}