From a22c110d080fe4387cd7b29a9bd36a727eb5944a Mon Sep 17 00:00:00 2001 From: manailin <261030956@qq.com> Date: 星期三, 08 十二月 2021 09:49:36 +0800 Subject: [PATCH] [新增]打印业务慢日志 --- springcloud_k8s_panzhihuazhihuishequ/service_community/src/main/resources/logback-spring.xml | 29 ++++ springcloud_k8s_panzhihuazhihuishequ/service_community/src/main/java/com/panzhihua/service_community/config/ParamOutAspect.java | 143 +++++++++++++++++++++++ springcloud_k8s_panzhihuazhihuishequ/service_user/src/main/resources/logback-spring.xml | 27 ++++ springcloud_k8s_panzhihuazhihuishequ/service_user/src/main/java/com/panzhihua/service_user/config/ParamOutAspect.java | 128 +++++++++++++++++++++ springcloud_k8s_panzhihuazhihuishequ/zuul/src/main/resources/logback-spring.xml | 2 5 files changed, 327 insertions(+), 2 deletions(-) diff --git a/springcloud_k8s_panzhihuazhihuishequ/service_community/src/main/java/com/panzhihua/service_community/config/ParamOutAspect.java b/springcloud_k8s_panzhihuazhihuishequ/service_community/src/main/java/com/panzhihua/service_community/config/ParamOutAspect.java new file mode 100644 index 0000000..7d1df28 --- /dev/null +++ b/springcloud_k8s_panzhihuazhihuishequ/service_community/src/main/java/com/panzhihua/service_community/config/ParamOutAspect.java @@ -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中,再用定时每周一次同步到库中 + } + +} diff --git a/springcloud_k8s_panzhihuazhihuishequ/service_community/src/main/resources/logback-spring.xml b/springcloud_k8s_panzhihuazhihuishequ/service_community/src/main/resources/logback-spring.xml index 57c5249..a9d9b88 100644 --- a/springcloud_k8s_panzhihuazhihuishequ/service_community/src/main/resources/logback-spring.xml +++ b/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> \ No newline at end of file diff --git a/springcloud_k8s_panzhihuazhihuishequ/service_user/src/main/java/com/panzhihua/service_user/config/ParamOutAspect.java b/springcloud_k8s_panzhihuazhihuishequ/service_user/src/main/java/com/panzhihua/service_user/config/ParamOutAspect.java new file mode 100644 index 0000000..9eacc10 --- /dev/null +++ b/springcloud_k8s_panzhihuazhihuishequ/service_user/src/main/java/com/panzhihua/service_user/config/ParamOutAspect.java @@ -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中,再用定时每周一次同步到库中 + } + +} diff --git a/springcloud_k8s_panzhihuazhihuishequ/service_user/src/main/resources/logback-spring.xml b/springcloud_k8s_panzhihuazhihuishequ/service_user/src/main/resources/logback-spring.xml index c883696..12cb9aa 100644 --- a/springcloud_k8s_panzhihuazhihuishequ/service_user/src/main/resources/logback-spring.xml +++ b/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> \ No newline at end of file diff --git a/springcloud_k8s_panzhihuazhihuishequ/zuul/src/main/resources/logback-spring.xml b/springcloud_k8s_panzhihuazhihuishequ/zuul/src/main/resources/logback-spring.xml index b89e4fb..21f452a 100644 --- a/springcloud_k8s_panzhihuazhihuishequ/zuul/src/main/resources/logback-spring.xml +++ b/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" /> -- Gitblit v1.7.1