SpringBoot日志

概念

  • 日志文件:日志文件是用于记录系统操作事件的文件集合,可分为调试日志和系统日志。具有处理历史数据、诊断问题的追踪以及理解系统的活动等重要作用。
    • 调试日志文件:软件开发中,我们经常需要去调试程序,做一些信息,状态的输出便于我们查询程序的运行状况,调试日志就可以帮我们记录下来方便查看
    • 系统日志:系统日志是记录系统中硬件、软件和系统问题的信息,同时还可以监视系统中发生的事件。用户可以通过它来检查错误发生的原因,或者寻找受到攻击时攻击者留下的痕迹。系统日志包括系统日志、应用程序日志和安全日志。

日志框架介绍

日志门面:

  • JCL
  • SLF4j

日志实现:

  • JUL
  • Logback
  • Log4j
  • Log4j2

日志门面就是在日志框架和应用程序之间架设一个沟通的桥梁(如JDBC),主要是为了给Java日志访问提供一套标准、规范的API框架。但是日志的配置文件还是写日志实现自身的配置文件

常用选择(SpringBoot底层也是这样的搭配):SLF4j(门面)+ Logback(实现)

SLF4j使用

最基本的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Slf4j
@SpringBootTest
class ApplicationTests {
@Test
void logTest() {
//级别由低到高
//可以调整输出的日志级别,这样就只会打印等于或大于该级别的日志
log.trace("trace级别");
log.debug("debug级别");
log.info("info级别");
log.warn("warning级别");
log.error("error级别");
}
}

效果:

image-20220725102611083

SpringBoot默认是INFO级别

相关配置

  • 修改级别:logging.level.包名=级别
  • 输出日志文件:可以配置logging.file=文件名/路径或者logging.path=目录
  • 修改输出日志的格式:logging.pattern.console/file=格式
  • 如果需要指定完整的配置,可以将logback的配置文件(logback.xml/logback-spring.xml)放在类路径下

通过AOP来打日志

如果一个一个接口的自己手动打日志相当麻烦,完全就可以通过注解+AOP的方式来打日志,这样也比较灵活方便,只需要给想打日志的方法上加上注解,aop会自动对方法进行代理增强,切入日志进来

自定义的日志注解
1
2
3
4
5
6
7
8
9
10
11
12
/***
* 日志标志注解(加了该注解会使用aop打印日志)
* @author wht
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SystemLog {
/**
*业务的简单描述
*/
String businessName();
}
配置切面类
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
@Component
@Aspect
@Slf4j
public class LogAspect {

@Pointcut("@annotation(com.wht.annotation.SystemLog)")
public void pt(){};

@Around("pt()")
public Object printLog(ProceedingJoinPoint joinPoint) throws Throwable {
Object res;
try {
handleBefore(joinPoint);
res = joinPoint.proceed();
handleAfter(res);
} finally {
log.info("=======END======="+System.lineSeparator());
}
return res;
}
//方法执行后的日志
private void handleAfter(Object res) {
log.info("Response :{}",JSON.toJSONString(res));

}
//执行前的日志
private void handleBefore(ProceedingJoinPoint joinPoint) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();

SystemLog systemLog = getSystemLog(joinPoint);

log.info("=======Start=======");
// 打印请求 URL
log.info("URL : {}",request.getRequestURI());
// 打印描述信息
log.info("BusinessName : {}",systemLog.businessName());
// 打印 Http method
log.info("HTTP Method : {}",request.getMethod() );
// 打印调用 controller 的全路径以及执行方法
log.info("Class Method : {}.{}", joinPoint.getSignature().getDeclaringTypeName(),((MethodSignature) joinPoint.getSignature()).getName());
// 打印请求的 IP
log.info("IP : {}",request.getRemoteHost());
// 打印请求入参
log.info("Request Args : {}", JSON.toJSONString(joinPoint.getArgs()));

}

private SystemLog getSystemLog(ProceedingJoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
SystemLog systemLog = methodSignature.getMethod().getAnnotation(SystemLog.class);
return systemLog;
}

}

注意需要导入AOP依赖:

1
2
3
4
5
<!-- AOP的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

测试:

1
2
3
4
5
@SystemLog(businessName = "测试校验")
@PostMapping("/insert")
public String insertTestUser(@RequestBody @Validated TestDemo testUser){
return "success";
}

效果:

image-20220726095213742