springcloud_k8s_panzhihuazhihuishequ/service_community/src/main/java/com/panzhihua/service_community/config/ParamOutAspect.java
New file @@ -0,0 +1,143 @@ package com.panzhihua.service_community.config; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; 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.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import com.alibaba.fastjson.JSONObject; import com.panzhihua.common.model.vos.R; import com.panzhihua.common.utlis.DateUtils; import lombok.extern.slf4j.Slf4j; /** * 应用模块名称 * <p> * 代码描述 * <p> * 拦截controller,输出入参、响应内容和响应时间 Copyright: Copyright (C) 2021 XXX, Inc. All rights reserved. * <p> * Company: 成都呐喊信息技术有限公司 * <p> * * @author manailin * @since 2021/8/24 15:30 */ @Slf4j @Aspect @Component public class ParamOutAspect { /** * 记录特定日志的声明 */ private final Logger slowClassAndMethodLog = LoggerFactory.getLogger("slowClassAndMethodLog"); /** * 设定方法的执行时间限制毫秒数 */ private long maxReduceTime = 100; @Pointcut("execution(* com.panzhihua.service_community.api..*.*(..)) || execution (public * com.panzhihua.service_community.service..* (..))") public void aspect() {} /** * [方法描述] 环绕通知,拦截controller,输出请求参数、响应内容和响应时间 * * @param joinPoint * @return java.lang.Object * @author manailin * @date 2021/8/24 17:04 */ @Around("aspect()") public Object processLog(ProceedingJoinPoint joinPoint) { log.info("进入方法性能检查方法"); Method method = ((MethodSignature)joinPoint.getSignature()).getMethod(); String className = method.getDeclaringClass().getName(); // 获取方法名称 String methodName = method.getName(); // 获取参数名称 LocalVariableTableParameterNameDiscoverer paramNames = new LocalVariableTableParameterNameDiscoverer(); String[] params = paramNames.getParameterNames(method); // 获取参数 Object[] args = joinPoint.getArgs(); // 过滤掉request和response,不能序列化 List<Object> filteredArgs = Arrays.stream(args) .filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse))) .collect(Collectors.toList()); JSONObject rqsJson = new JSONObject(); rqsJson.put("rqsMethod", methodName); rqsJson.put("rqsTime", DateUtils.getCurrentDateStr_MS()); if (ObjectUtils.isEmpty(filteredArgs)) { rqsJson.put("rqsParams", null); } else { // 拼接请求参数 Map<String, Object> rqsParams = IntStream.range(0, filteredArgs.size()).boxed() .collect(Collectors.toMap(j -> params[j], j -> filteredArgs.get(j))); rqsJson.put("rqsParams", rqsParams); } log.info(className + ":" + methodName + "请求信息为:" + rqsJson.toJSONString()); Object resObj = null; long startTime = System.currentTimeMillis(); try { // 执行原方法 resObj = joinPoint.proceed(args); } catch (Throwable e) { log.error(className + ":" + methodName + "方法执行异常!", e); // throw new ServiceException(methodName + "方法执行异常!"); } long endTime = System.currentTimeMillis(); if (resObj != null) { if (resObj instanceof R) { // 输出响应信息 R resJson = (R)resObj; // 打印耗时的信息 this.printExecTime(className , methodName,rqsJson,resJson, startTime, endTime); return resJson; } else { return resObj; } } else { return R.ok(); } } /** * [方法描述] 打印方法执行耗时的信息,如果超过了一定的时间,才打印 * * @param methodName * 执行方法名 * @param startTime * 执行开始时间 * @param endTime * 执行结束时间 * @author manailin * @date 2021/8/24 17:05 */ private void printExecTime(String className,String methodName, JSONObject rqsJson,R resJson, long startTime, long endTime) { long diffTime = endTime - startTime; if (diffTime > maxReduceTime) { slowClassAndMethodLog.info(className+":"+methodName + " 方法执行耗时:" + diffTime + " ms"); slowClassAndMethodLog.info(methodName + " 请求参数:" +rqsJson.toJSONString()); slowClassAndMethodLog.info(className + " 响应信息:" + JSONObject.toJSONString(resJson)); } // TODO 可以集成redis,将每个controller的执行时间追加到redis中,再用定时每周一次同步到库中 } } springcloud_k8s_panzhihuazhihuishequ/service_community/src/main/resources/logback-spring.xml
@@ -2,7 +2,7 @@ <configuration debug="false"> <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径--> <springProfile name="dev"> <property name="LOG_HOME" value="F:/log" /> <property name="LOG_HOME" value="F:\log"/> </springProfile> <springProfile name="test"> <property name="LOG_HOME" value="/mnt/data/gocd/log" /> @@ -48,4 +48,31 @@ <appender-ref ref="STDOUT" /> <appender-ref ref="FILE" /> </root> <!--慢接口和方法日志记录到不同的文件--> <appender name="slowClassAndMethodAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <File>${LOG_HOME}/slow_service_community.log</File> <append>true</append> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_HOME}/slow_service_community.%d.%i.log</fileNamePattern> <maxHistory>10</maxHistory> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern>%d{yyyy/MM/dd HH:mm:ss.SSS} %-5level [%thread] [%c{0}:%L] : %msg%n</pattern> <charset>UTF-8</charset> </encoder> </appender> <!--这是我们定义的慢接口和方法日志传入的名称--> <logger name="slowClassAndMethodLog" additivity="false" level="INFO"> <appender-ref ref="slowClassAndMethodAppender"/> </logger> </configuration> springcloud_k8s_panzhihuazhihuishequ/service_user/src/main/java/com/panzhihua/service_user/config/ParamOutAspect.java
New file @@ -0,0 +1,128 @@ package com.panzhihua.service_user.config; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.util.ObjectUtils; import com.alibaba.fastjson.JSONObject; import com.panzhihua.common.model.vos.R; import com.panzhihua.common.utlis.DateUtils; import lombok.extern.slf4j.Slf4j; /** * 应用模块名称 * <p> * 代码描述 * <p> * 拦截controller,输出入参、响应内容和响应时间 Copyright: Copyright (C) 2021 XXX, Inc. All rights reserved. * <p> * Company: 成都呐喊信息技术有限公司 * <p> * * @author manailin * @since 2021/8/24 15:30 */ @Slf4j // @Aspect // @Component public class ParamOutAspect { /** * 设定方法的执行时间限制毫秒数 */ private long maxReduceTime = 2000; @Pointcut("execution (public * com.panzhihua.service_user.api..* (..))||execution (public * com.panzhihua.service_user.service..* (..))") public void aspect() {} /** * [方法描述] 环绕通知,拦截controller,输出请求参数、响应内容和响应时间 * * @param joinPoint aspect() * @return java.lang.Object * @author manailin * @date 2021/8/24 17:04 */ @Around("aspect()") public Object processLog(ProceedingJoinPoint joinPoint) { log.info("进入方法性能检查方法"); Method method = ((MethodSignature)joinPoint.getSignature()).getMethod(); String className = joinPoint.getSignature().getDeclaringTypeName(); // 获取方法名称 String methodName = method.getName(); // 获取参数名称 LocalVariableTableParameterNameDiscoverer paramNames = new LocalVariableTableParameterNameDiscoverer(); String[] params = paramNames.getParameterNames(method); // 获取参数 Object[] args = joinPoint.getArgs(); // 过滤掉request和response,不能序列化 List<Object> filteredArgs = Arrays.stream(args) .filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse))) .collect(Collectors.toList()); JSONObject rqsJson = new JSONObject(); rqsJson.put("rqsMethod", methodName); rqsJson.put("rqsTime", DateUtils.getCurrentDateStr_MS()); if (ObjectUtils.isEmpty(filteredArgs)) { rqsJson.put("rqsParams", null); } else { // 拼接请求参数 Map<String, Object> rqsParams = IntStream.range(0, filteredArgs.size()).boxed() .collect(Collectors.toMap(j -> params[j], j -> filteredArgs.get(j))); rqsJson.put("rqsParams", rqsParams); } log.info(className + ":" + methodName + "请求信息为:" + rqsJson.toJSONString()); Object resObj = null; long startTime = System.currentTimeMillis(); try { // 执行原方法 resObj = joinPoint.proceed(); } catch (Throwable e) { log.error(className + ":" + methodName + "方法执行异常!", e); } long endTime = System.currentTimeMillis(); // 打印耗时的信息 this.printExecTime(className + ":" + methodName, startTime, endTime); if (resObj != null) { // 打印返回消息 log.info(className + ":" + methodName + "响应信息为:" + JSONObject.toJSON(resObj)); return resObj; } else { return R.ok(); } } /** * [方法描述] 打印方法执行耗时的信息,如果超过了一定的时间,才打印 * * @param classAndMethodName * 执行方法名 * @param startTime * 执行开始时间 * @param endTime * 执行结束时间 * @author manailin * @date 2021/8/24 17:05 */ private void printExecTime(String classAndMethodName, long startTime, long endTime) { long diffTime = endTime - startTime; if (diffTime > maxReduceTime) { log.info(classAndMethodName + " 方法执行耗时:" + diffTime + " ms"); } // TODO 可以集成redis,将每个controller的执行时间追加到redis中,再用定时每周一次同步到库中 } } springcloud_k8s_panzhihuazhihuishequ/service_user/src/main/resources/logback-spring.xml
@@ -48,4 +48,31 @@ <appender-ref ref="STDOUT" /> <appender-ref ref="FILE" /> </root> <!--慢接口和方法日志记录到不同的文件--> <appender name="slowClassAndMethodAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <File>${LOG_HOME}/slow_service_user.log</File> <append>true</append> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_HOME}/slow_service_user.%d.%i.log</fileNamePattern> <maxHistory>10</maxHistory> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern>%d{yyyy/MM/dd HH:mm:ss.SSS} %-5level [%thread] [%c{0}:%L] : %msg%n</pattern> <charset>UTF-8</charset> </encoder> </appender> <!--这是我们定义的慢接口和方法日志传入的名称--> <logger name="slowClassAndMethodLog" additivity="false" level="INFO"> <appender-ref ref="slowClassAndMethodAppender"/> </logger> </configuration> springcloud_k8s_panzhihuazhihuishequ/zuul/src/main/resources/logback-spring.xml
@@ -2,7 +2,7 @@ <configuration debug="false"> <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径--> <springProfile name="dev"> <property name="LOG_HOME" value="F:/log" /> <property name="LOG_HOME" value="F:\log"/> </springProfile> <springProfile name="test"> <property name="LOG_HOME" value="/mnt/data/gocd/log" />