AOP切面统一打印请求日志
日志输出效果
打印的参数:
- URL: 请求接口地址;
- HTTP Method: 请求的方法,是
POST
, GET
, 还是 DELETE
等;
- Class Method: 对应 Controller 的全路径以及调用的哪个方法;
- IP: 请求 IP 地址;
- Request Args: 请求入参,以 JSON 格式输出;
- Response Args: 响应出参,以 JSON 格式输出;
- Time-Consuming: 请求耗时;
添加依赖
1 2 3 4 5 6 7 8 9 10 11
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>2.0.14</version> </dependency>
|
executation表达式
execution()是最常用的切点函数,语法如下:
execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)
符号 |
含义 |
execution() |
表达式的主体 |
第一个”*“符号 |
表示返回值的类型任意 |
com.example.service.impl |
AOP所切的服务的包名,即,我们的业务部分 |
包名后面的”..“ |
表示当前包及子包 |
第二个”*“ |
表示类名,*即所有类 |
.*(..) |
表示任何方法名,括号表示参数,两个点表示任何参数类型 |
配置AOP切面
- @Aspect:声明该类为一个注解类;
- @Pointcut:定义一个切点,后面跟随一个表达式,表达式可以定义为某个 package 下的方法,也可以是自定义注解等;
- 切点定义好后,就是围绕这个切点做文章了:
- @Before: 在切点之前,织入相关代码;
- @After: 在切点之后,织入相关代码;
- @AfterReturning: 在切点返回内容后,织入相关代码,一般用于对返回值做些加工处理的场景;
- @AfterThrowing: 用来处理当织入的代码抛出异常后的逻辑处理;
- @Around: 在切入点前后织入代码,并且可以自由的控制何时执行切点;
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
| import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Component @Aspect @Slf4j public class LogAspect {
@Pointcut("execution(* com.example.test.controller..*.*(..))") public void pointCut() { }
@Around(value = "pointCut()") public Object aroundLogPrint(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); assert servletRequestAttributes != null; HttpServletRequest request = servletRequestAttributes.getRequest(); log.info("------------------------START------------------------"); log.info("URL: {}", request.getRequestURL().toString()); log.info("METHOD: {}", request.getMethod()); log.info("IP: {}", request.getRemoteAddr()); log.info("Request Args: {}", JSON.toJSONString(joinPoint.getArgs())); Object result = joinPoint.proceed(); log.info("Response: {}", JSON.toJSONString(result)); log.info("Time-Consuming: {}ms", System.currentTimeMillis() - startTime); log.info("------------------------END------------------------"); return result; } }
|
利用Lombok将日志输出为文件
日志等级
- slf4j日志级别有五种:ERROR、WARN、INFO、DEBUG、TRACE,级别从高到底
- 此外,还有一个级别 OFF,可用来关闭日志记录,使用级别 ALL 启用所有消息的日志记录
- ALL和DEBUG不建议使用,打印输出的日志过于多
导入Maven依赖
1 2 3 4 5 6 7 8 9 10 11
| <properties> <lombok.version>1.18.4</lombok.version> </properties>
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency>
|
配置文件
application.yml
1 2 3 4 5
| logging: config: classpath:config/logback-spring.xml
|
新建logback-spring.xml文件
yml文件中config路径是classpath:config/logback-spring.xml文件夹下的logback-spring.xml
新建logback-spring.xml完成后需要放在resources目录下新建config目录下
配置文件路径可根据实际自行调整
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 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
| <?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds"> <contextName>logback-spring</contextName> <property name="logging.path" value="运行日志" />
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" /> <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" /> <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" /> <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%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}}"/> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>debug</level> </filter> <encoder> <Pattern>${CONSOLE_LOG_PATTERN}</Pattern> <charset>UTF-8</charset> </encoder> </appender> <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${logging.path}/debug.log</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <charset>UTF-8</charset> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${logging.path}/debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>15</maxHistory> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>debug</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${logging.path}/info.log</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <charset>UTF-8</charset> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${logging.path}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>15</maxHistory> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>info</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${logging.path}/warn.log</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <charset>UTF-8</charset> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${logging.path}/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>15</maxHistory> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>warn</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${logging.path}/error.log</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <charset>UTF-8</charset> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${logging.path}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>15</maxHistory> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <springProfile name="dev"> <logger name="此位置填写自己的项目中全mapper\dao路径,用于在开发环境时将sql语句打印在控制台" level="debug"/> </springProfile> <root level="info"> <appender-ref ref="CONSOLE" /> <appender-ref ref="DEBUG_FILE" /> <appender-ref ref="INFO_FILE" /> <appender-ref ref="WARN_FILE" /> <appender-ref ref="ERROR_FILE" /> </root> <springProfile name="pro"> <root level="info"> <appender-ref ref="CONSOLE" /> <appender-ref ref="DEBUG_FILE" /> <appender-ref ref="INFO_FILE" /> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="WARN_FILE" /> </root> </springProfile> </configuration>
|
注:
1:xml文件中日志文件大小日志文件保留天数可根据实际情况按级别进行单独修改
2:文件中中value属性和name属性,需要根据自己项目实际情况修改
3:如果更改logback-spring.xml的文件名称,在文件中logback-springlogback-spring需要与文件名称对应
说明:Lombok的注解@Slf4j只是负责提供打印日志信息的一种注解方式,真正具体的日志实现方案是org.apache.log4