赞
踩
该切面仅用于请求日志记录,若有其他需求,在此基础上扩展即可,不多逼逼,直接上代码。
<!-- 切面 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
import com.alibaba.fastjson.JSON; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.List; import java.util.Objects; @Slf4j @Aspect @Component public class RequestAop { private static final String START_TIME = "request-start"; // 按需修改需要扫描的controller层 @Pointcut("execution(* com.example.controller..*.*(..))") public void pointCut() { //该方法仅用于扫描controller包下类中的方法,而不做任何特殊的处理。 } @Before("pointCut()") public void doBefore(JoinPoint joinPoint) { HttpServletRequest request = ((ServletRequestAttributes) Objects .requireNonNull(RequestContextHolder.getRequestAttributes())) .getRequest(); Long start = System.currentTimeMillis(); request.setAttribute(START_TIME, start); } @Around("pointCut()") @SneakyThrows public Object doAround(ProceedingJoinPoint joinPoint) { Object result = joinPoint.proceed(); try { // 获取方法名称 String method = joinPoint.getSignature().getName(); // 获取类名称 String className = joinPoint.getSignature().getDeclaringTypeName(); // 获取请求 HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); // 请求路径 String requestUrl = request.getRequestURL().toString(); // 获取请求参数进行打印 Signature signature = joinPoint.getSignature(); // 参数名数组 String[] parameterNames = ((MethodSignature) signature).getParameterNames(); // 构造参数组集合 List<Object> argList = new ArrayList<>(); for (Object arg : joinPoint.getArgs()) { // request/response无法使用toJSON if (arg instanceof HttpServletRequest) { argList.add("request"); } else if (arg instanceof HttpServletResponse) { argList.add("response"); } else { argList.add(JSON.toJSON(arg)); } } log.info("类名:[{}] 方法名:[{}] 请求URL:[{}] 请求参数:{} -> {} 请求结果:{}", className, method, requestUrl, JSON.toJSON(parameterNames), JSON.toJSON(argList), JSON.toJSON(result)); } catch (Exception e) { log.error("切面类参数获取失败: {}", e.getMessage()); } return result; } @After("pointCut()") public void doAfter(JoinPoint joinPoint) { HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); Long start = (Long) request.getAttribute(START_TIME); Long end = System.currentTimeMillis(); // 耗时 long costTime = end - start; // 方法名 String method = joinPoint.getSignature().getName(); log.info("方法名:[{}] 请求耗时:[{}ms]", method, costTime); } }
日志级别(Log Levels)是指日志消息的优先级或者重要程度,它用于对日志的不同类型和重要程度进行分类和过滤。
不同的日志框架可能使用不同的命名和数量的日志级别,但基本概念是相似的。以下是常见的几个标准日志级别:
1,TRACE(追踪)
:最低级别的日志,包含详细的调试信息,用于追踪代码的执行流程,如方法的输入参数、内部状态等。
2,DEBUG(调试)
:用于输出调试信息,在开发和调试阶段使用,帮助排查问题和跟踪代码执行情况以及验证程序的行为。
3,INFO(信息)
:提供程序运行过程中的重要信息,用于向用户提供一些关键的操作状态和进度,如程序启动关闭、配置项变更等。
4,WARN(警告)
:表示潜在的问题或异常情况,不会阻止程序继续执行,但可能会影响程序的正常运行,需要开发人员注意。
5,ERROR(错误)
:表示错误情况,通常表示某个功能或步骤无法正常完成,但程序仍然可以继续运行,需要开发人员关注和解决。
6,FATAL(致命)
:最高级别的日志,表示最严重的错误,表示程序无法继续运行,会导致应用程序的中断或崩溃,如系统崩溃。
特别说明:以上日志级别由上往下依次增强,而日志级别越高,控制台打印出的日志信息就越少,但打印出的日志信息越重要。
lombok
依赖引入lombok
后,在需要记录日志的类上添加@Slf4j
注解即可。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.32</version>
<scope>provided</scope>
</dependency>
在resources
下新建目录logs
,logs
下新建logback-spring.xml
文件。
仅配置了常用的info
和error
级别,其余按需配置即可。
<?xml version="1.0" encoding="utf-8"?> <configuration> <!-- 引入默认得配置文件 --> <include resource="org/springframework/boot/logging/logback/defaults.xml"/> <!-- 模块名标识日志名称 --> <springProperty scope="context" name="springAppName" source="spring.application.name"/> <!-- info日志单文件大小限制 --> <springProperty scope="context" name="logback.fileInfoLog.maxFileSize" source="logback.fileInfoLog.maxFileSize" defaultValue="1024MB" /> <!-- info日志最大保留时长单位天 --> <springProperty scope="context" name="logback.fileInfoLog.maxHistory" source="logback.fileInfoLog.maxHistory" defaultValue="30" /> <!-- info日志文件总大小,超过该大小,旧得即将删除 --> <springProperty scope="context" name="logback.fileInfoLog.totalSizeCap" source="logback.fileInfoLog.totalSizeCap" defaultValue="10GB" /> <!-- error日志单文件大小限制 --> <springProperty scope="context" name="logback.fileErrorLog.maxFileSize" source="logback.fileErrorLog.maxFileSize" defaultValue="1024MB" /> <!-- error日志最大保留时长单位天 --> <springProperty scope="context" name="logback.fileErrorLog.maxHistory" source="logback.fileErrorLog.maxHistory" defaultValue="30" /> <!-- error日志文件总大小,超过该大小,旧得即将删除 --> <springProperty scope="context" name="logback.fileErrorLog.totalSizeCap" source="logback.fileErrorLog.totalSizeCap" defaultValue="10GB" /> <!-- 日志目录 --> <springProperty scope="context" name="logback.rootDir" source="logback.rootDir" defaultValue="logs"/> <!-- 控制台输出得日志格式 --> <property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/> <!-- 日志文件输出得日志格式 --> <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p %t [%c:%L]-%m%n"/> <!-- 控制台输出 --> <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>${CONSOLE_LOG_PATTERN}</pattern> </layout> </appender> <!-- info日志得设定 --> <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender"> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>DENY</onMatch> <onMismatch>ACCEPT</onMismatch> </filter> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> </encoder> <file>${logback.rootDir}/${springAppName}.log</file> <!--滚动策略--> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy" > <!--路径--> <fileNamePattern>${logback.rootDir}/%d{yyyy-MM,aux}/%d{yyyy-MM-dd,aux}/${springAppName}-%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern> <maxFileSize>${logback.fileInfoLog.maxFileSize}</maxFileSize> <maxHistory>${logback.fileInfoLog.maxHistory}</maxHistory> <totalSizeCap>${logback.fileInfoLog.totalSizeCap}</totalSizeCap> <cleanHistoryOnStart>true</cleanHistoryOnStart> </rollingPolicy> </appender> <!-- 错误日志 --> <appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> </filter> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> </encoder> <file>${logback.rootDir}/${springAppName}-error.log</file> <!--滚动策略--> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy" > <!--路径--> <fileNamePattern>${logback.rootDir}/%d{yyyy-MM,aux}/%d{yyyy-MM-dd,aux}/${springAppName}-error-%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern> <maxFileSize>${logback.fileErrorLog.maxFileSize}</maxFileSize> <maxHistory>${logback.fileErrorLog.maxHistory}</maxHistory> <totalSizeCap>${logback.fileErrorLog.totalSizeCap}</totalSizeCap> <cleanHistoryOnStart>true</cleanHistoryOnStart> </rollingPolicy> </appender> <appender name="ASYNC_consoleLog" class="ch.qos.logback.classic.AsyncAppender"> <appender-ref ref="consoleLog"/> </appender> <appender name="ASYNC_fileInfoLog" class="ch.qos.logback.classic.AsyncAppender"> <appender-ref ref="fileInfoLog"/> </appender> <appender name="ASYNC_fileErrorLog" class="ch.qos.logback.classic.AsyncAppender"> <appender-ref ref="fileErrorLog"/> </appender> <root level="info"> <appender-ref ref="ASYNC_consoleLog" /> <appender-ref ref="ASYNC_fileInfoLog" /> <appender-ref ref="ASYNC_fileErrorLog" /> </root> </configuration>
application.yml
配置
# spring.application.name 必须配置
# 因为上述日志配置文件指定了项目启动后输出的日志文件命名,即为该配置
spring:
application:
name: LogApplication
logging:
# 指定自定义的配置文件
config: classpath:logs/logback-spring.xml
# 指定输出的日志级别
# trace < debug < info < warn < error
# 例如:指定输出级别为info,则trace和debug均不会输出
level:
root: info #该方式指定的是整个项目的日志输出级别
# com.example.controller: debug #也可以指定具体某个包下的日志输出级别
以上述配置为例,项目启动后会在项目下生成logs
目录,该目录下会有两个日志文件:LogApplication.log
和 LogApplication-error.log
,项目中所有log.error()
日志都会输出到LogApplication-error.log
,其余日志则输出到LogApplication.log
.
将指定的类产生的日志输出到指定的文件中。
示例:RequestAop
切面中产生的是所有的请求记录,将该类的日志放入指定的文件。
logback-spring.xml
新增配置,未添加请求日志文件的大小限制、存放时间等配置,若有需求,按info
、error
配置仿写即可。
<!-- 接口请求日志 --> <appender name="requestLog" class="ch.qos.logback.core.rolling.RollingFileAppender"> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>DENY</onMatch> <onMismatch>ACCEPT</onMismatch> </filter> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> </encoder> <!--此处配置输出文件名称为 应用名-request.log --> <file>${logback.rootDir}/${springAppName}-request.log</file> <!--滚动策略--> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy" > <!--路径--> <fileNamePattern>${logback.rootDir}/%d{yyyy-MM,aux}/%d{yyyy-MM-dd,aux}/${springAppName}-request-%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern> <maxFileSize>${logback.fileInfoLog.maxFileSize}</maxFileSize> <maxHistory>${logback.fileInfoLog.maxHistory}</maxHistory> <totalSizeCap>${logback.fileInfoLog.totalSizeCap}</totalSizeCap> <cleanHistoryOnStart>true</cleanHistoryOnStart> </rollingPolicy> </appender> <appender name="ASYNC_requestLog" class="ch.qos.logback.classic.AsyncAppender"> <appender-ref ref="requestLog"/> </appender> <!--将切面类所在包的位置配置上--> <logger name="com.example.aop.RequestAop" additivity="false" level="INFO"> <appender-ref ref="ASYNC_requestLog"/> </logger>
以上述配置为例,项目启动后会在项目下生成logs
目录,该目录下会有三个日志文件:LogApplication.log
、 LogApplication-error.log
、LogApplication-request.log
,项目中所有log.error()
日志都会输出到LogApplication-error.log
,RequestAop
切面类的日志会输出到LogApplication-request.log
,其余日志则输出到LogApplication.log
.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。