SpringBoot+log4j2+MDC+AOP记录requestId
前言
在AOP切面注入RequestId,拦截Controller、Service方法,打印入参出参耗时等,方便排查问题。
可以在服务上通过RequestId查询一次调用链日志:
可以使用 Linux grep 命令查询日志:
grep 命令用于查找文件里符合条件的字符串。 日志文件太大无法直接 cat 查看,可以用grep 常用参数:- -A<显示行数> : 除了显示符合范本样式的那一列之外,并显示该行之后的内容。
- -C<显示行数> : 除了显示符合样式的那一行之外,并显示该行之前后的内容。
- -E : 将样式为延伸的正则表达式来使用。
代码
Controller
/** * @author lihaoyang * @date 2021/3/17 */ @RestController public class HiController { @Autowired HiServiceImpl hiService; @GetMapping("get") public String get(String msg) { String rs = hiService.getHi(msg); return rs; } }
Service
@Service public class HiServiceImpl { public String getHi(String msg) { return "service: >>>>> " + msg; } }
切面类
RequestId切面
@Aspect @Component @Slf4j @Order(-10) public class ControllerRequestIdAspect { @Pointcut("execution(public * com.nb.log.controller..*.*(..))") public void controllerPoint() { } @Around("controllerPoint()") public Object doControllerPointAround(ProceedingJoinPoint joinPoint) throws Throwable { String requestId = UUID.randomUUID().toString(); MDC.put("requestId", requestId); Object result = null; try { result = joinPoint.proceed(); } finally { MDC.remove("requestId"); } return result; } }
Controller切面
package com.nb.log.aop; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; 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 java.util.Arrays; /** * controller切面 */ @Aspect @Slf4j @Component @Order(0) public class ControllerLogAspect { @Pointcut("execution(public * com.nb.log.controller..*.*(..))") public void controllerPoint() {} @Around("controllerPoint()") public Object doControllerAround(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); Object result = null; try { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); Object[] params = joinPoint.getArgs(); log.info("Controller层 className={}, methodName={}, params={},url={},ip={}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), Arrays.toString(params), request.getRequestURL(), IpUtil.getIpAddr(request)); result = joinPoint.proceed(); } finally { log.info("Controller层 耗时={}(ms), className={}, methodName={}, result={}", System.currentTimeMillis() - startTime, joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), JSONObject.toJSONString(result)); } return result; } }
Service切面
package com.nb.log.aop; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.util.Arrays; /** * service层切面日志 */ @Aspect @Slf4j @Order(0) @Component public class ServiceLogAspect { @Pointcut("execution(public * com.nb.log.service..*ServiceImpl.*(..))") public void servicePoint() { } @Around("servicePoint()") public Object doServiceAround(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); Object result = null; try { Object[] params = joinPoint.getArgs(); log.info("Service层 className={}, methodName={}, params={}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), Arrays.toString(params)); result = joinPoint.proceed(); } finally { log.info("Service层 耗时={}(ms), className={}, methodName={}", System.currentTimeMillis() - startTime, joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); } return result; } }
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration status="warn" monitorInterval="30"> <Properties> <property name="log_pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} [%level] -%X{filter} <%t|%C{1.}.%M(%L)> -%X{requestId} %m%n%exproperty> <property name="project">remix-collectorproperty> <property name="basePath">D:/log/${project}/property> <property name="rolling_file_name">${basePath}/%d{yyyy-MM-dd}-%iproperty> <property name="every_file_size">500 MBproperty> Properties> <appenders> <console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="${log_pattern}"/> console> <RollingFile name="RollingFile" fileName="${basePath}/${project}-info-${hostName}.log" filePattern="${basePath}/${project}-info-${hostName}-%d{yyyy-MM-dd}-%i.log"> <Filters> <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/> <ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="NEUTRAL"/> <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/> Filters> <PatternLayout pattern="${log_pattern}"/> <Policies> <TimeBasedTriggeringPolicy/> <SizeBasedTriggeringPolicy size="${every_file_size}"/> Policies> <DefaultRolloverStrategy> <Delete basePath="${basePath}" maxDepth="1"> <IfFileName glob="*.log" /> <IfLastModified age="3d"> IfLastModified> Delete> DefaultRolloverStrategy> RollingFile> <RollingFile name="RollingFileWarn" fileName="${basePath}/${project}-warn-${hostName}.log" filePattern="${rolling_file_name}-warn-${hostName}-%d{yyyy-MM-dd}-%i.log"> <Filters> <ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/> <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/> Filters> <PatternLayout pattern="${log_pattern}"/> <Policies> <TimeBasedTriggeringPolicy modulate="true" interval="24"/> <SizeBasedTriggeringPolicy/> Policies> <DefaultRolloverStrategy max="20"/> RollingFile> <RollingFile name="RollingFileError" fileName="${basePath}/${project}-error-${hostName}.log" filePattern="${rolling_file_name}-error-${hostName}-%d{yyyy-MM-dd}-%i.log"> <Filters> <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY" /> Filters> <PatternLayout pattern="${log_pattern}"/> <SizeBasedTriggeringPolicy size="${every_file_size}"/> RollingFile> appenders> <loggers> <logger name="druid.sql.Statement" level="debug" additivity="false"> <AppenderRef ref="Console"/> <AppenderRef ref="druidSqlAppender"/> <AppenderRef ref="invokeAppender"/> logger> <logger name="druid.sql.ResultSet" level="debug" additivity="false"> <AppenderRef ref="Console"/> <AppenderRef ref="druidSqlAppender"/> <AppenderRef ref="invokeAppender"/> logger> <logger name="com.nb.log.controller" level="INFO"> logger> <root level="info"> <appender-ref ref="Console"/> <appender-ref ref="RollingFile"/> <appender-ref ref="RollingFileWarn"/> <appender-ref ref="RollingFileError"/> root> loggers> configuration>
maven pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0modelVersion> <groupId>com.nbgroupId> <artifactId>nb-logartifactId> <version>0.0.1-SNAPSHOTversion> <name>nb-logname> <description>Demo project for Spring Bootdescription> <properties> <java.version>1.8java.version> <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding> <spring-boot.version>2.3.7.RELEASEspring-boot.version> properties> <dependencies> <dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-webartifactId> dependency> <dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-webartifactId> <exclusions> <exclusion> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-loggingartifactId> exclusion> exclusions> dependency> <dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-log4j2artifactId> dependency> <dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-aopartifactId> dependency> <dependency> <groupId>com.alibabagroupId> <artifactId>fastjsonartifactId> <version>1.2.75version> dependency> <dependency> <groupId>org.projectlombokgroupId> <artifactId>lombokartifactId> <version>1.18.18version> <scope>providedscope> dependency> <dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-testartifactId> <scope>testscope> <exclusions> <exclusion> <groupId>org.junit.vintagegroupId> <artifactId>junit-vintage-engineartifactId> exclusion> exclusions> dependency> dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-dependenciesartifactId> <version>${spring-boot.version}version> <type>pomtype> <scope>importscope> dependency> dependencies> dependencyManagement> <build> <plugins> <plugin> <groupId>org.apache.maven.pluginsgroupId> <artifactId>maven-compiler-pluginartifactId> <version>3.8.1version> <configuration> <source>1.8source> <target>1.8target> <encoding>UTF-8encoding> configuration> plugin> <plugin> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-maven-pluginartifactId> <version>2.3.7.RELEASEversion> <configuration> <mainClass>com.nb.log.NbLogApplicationmainClass> configuration> <executions> <execution> <id>repackageid> <goals> <goal>repackagegoal> goals> execution> executions> plugin> plugins> build> project>
完整代码
https://gitee.com/haoyangli/mdc-log.git