diff --git a/.gitignore b/.gitignore index aeca68d..9c1bba4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ target/ *.log /.idea/ /.idea/ +/.idea/ diff --git a/pom.xml b/pom.xml index 621aafc..31167e7 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ cn.langpy ko-time - 2.4.7 + 2.4.8 KoTime A springboot tool for tracking the paths of the methods,which can help you find method's performances easily. diff --git a/src/main/java/cn/langpy/kotime/config/SaveResourceConfig.java b/src/main/java/cn/langpy/kotime/config/SaveResourceConfig.java index 77ec8d4..5cc8c67 100644 --- a/src/main/java/cn/langpy/kotime/config/SaveResourceConfig.java +++ b/src/main/java/cn/langpy/kotime/config/SaveResourceConfig.java @@ -1,30 +1,44 @@ package cn.langpy.kotime.config; +import cn.langpy.kotime.model.MethodNode; import cn.langpy.kotime.service.GraphService; import cn.langpy.kotime.util.Context; import cn.langpy.kotime.util.KoUtil; +import cn.langpy.kotime.util.MethodType; +import org.springframework.aop.MethodMatcher; +import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor; import org.springframework.boot.CommandLineRunner; +import org.springframework.context.ApplicationContext; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import javax.annotation.Resource; import javax.sql.DataSource; +import java.util.Map; import java.util.logging.Logger; @Component public class SaveResourceConfig implements CommandLineRunner { private static Logger log = Logger.getLogger(SaveResourceConfig.class.toString()); - + @Resource + private ApplicationContext applicationContext; + @Resource + private AspectJExpressionPointcutAdvisor aspectJExpressionPointcutAdvisor; @Override public void run(String... args) throws Exception { DataSource dataSource = KoUtil.getDataSource(); if (null != dataSource) { - log.info("kotime=>Setting the finnal DataSource for kotime so that previous DataSources will be invalid."); + log.info("kotime=>Setting the final DataSource for kotime so that previous DataSources will be invalid."); Context.setDataSource(dataSource); } StringRedisTemplate redisTemplate = KoUtil.getStringRedisTemplate(); if (null != redisTemplate) { - log.info("kotime=>Setting the finnal StringRedisTemplate for kotime so that previous StringRedisTemplate will be invalid."); + log.info("kotime=>Setting the final StringRedisTemplate for kotime so that previous StringRedisTemplate will be invalid."); Context.setStringRedisTemplate(redisTemplate); } @@ -35,5 +49,47 @@ public class SaveResourceConfig implements CommandLineRunner { } KoUtil.clearCaches(); + acquireControllers(); } + private void acquireControllers() { + RequestMappingHandlerMapping handlerMapping = applicationContext.getBean(RequestMappingHandlerMapping.class); + Map handlerMethods = handlerMapping.getHandlerMethods(); + GraphService graphService = GraphService.getInstance(); + MethodMatcher methodMatcher = aspectJExpressionPointcutAdvisor.getPointcut().getMethodMatcher(); + for (Map.Entry methodEntry : handlerMethods.entrySet()) { + HandlerMethod handlerMethod = methodEntry.getValue(); + boolean matches = methodMatcher.matches(handlerMethod.getMethod(), handlerMethod.getClass()); + if (matches) { + MethodNode methodNode = toMethodNode(handlerMethod); + graphService.addMethodNode(methodNode); + } + } + } + + private MethodNode toMethodNode(HandlerMethod method) { + Class beanType = method.getBeanType(); + RequestMapping requestMapping = beanType.getAnnotation(RequestMapping.class); + String[] cvalues = requestMapping.value(); + String classRoute = ""; + if (cvalues != null && cvalues.length > 0) { + classRoute = cvalues[0]; + } + RequestMapping methodAnnotation = method.getMethodAnnotation(RequestMapping.class); + String[] mvalues = methodAnnotation.value(); + String methodRoute = ""; + if (mvalues != null && mvalues.length > 0) { + methodRoute = mvalues[0]; + } + String route = classRoute+methodRoute; + MethodNode methodNode = new MethodNode(); + methodNode.setId(beanType.getName() + "." + method.getMethod().getName()); + methodNode.setClassName(beanType.getName()); + methodNode.setMethodName(method.getMethod().getName()); + methodNode.setName( beanType.getSimpleName()+ "." + method.getMethod().getName()); + methodNode.setRouteName(route); + methodNode.setMethodType(MethodType.Controller); + return methodNode; + } + + } diff --git a/src/main/java/cn/langpy/kotime/constant/KoSqlConstant.java b/src/main/java/cn/langpy/kotime/constant/KoSqlConstant.java index 344a992..378d733 100644 --- a/src/main/java/cn/langpy/kotime/constant/KoSqlConstant.java +++ b/src/main/java/cn/langpy/kotime/constant/KoSqlConstant.java @@ -28,9 +28,9 @@ public class KoSqlConstant { public final static String updateParamsAna = "UPDATE ko_param_ana SET avg_run_time=?, max_run_time=?, min_run_time=? WHERE source_id=? and params=?"; - public final static String queryControllers = "select m.id,name,class_name,method_name,method_type,route_name,r.avg_run_time,r.max_run_time,r.min_run_time,r.call_num " + + public final static String queryControllers = "select m.id,name,class_name,method_name,method_type,route_name,ifnull(r.avg_run_time,0.0) avg_run_time,ifnull(r.max_run_time,0.0) max_run_time,ifnull(r.min_run_time,0.0) min_run_time,ifnull(r.call_num,0) call_num " + "from ko_method_node m " + - "join ko_method_relation r on m.id = r.target_id " + + "left join ko_method_relation r on m.id = r.target_id " + "where m.method_type='Controller'"; public final static String searchMethodsByName = "select m.id,name,class_name,method_name,method_type,route_name,r.avg_run_time,r.max_run_time,r.min_run_time,r.call_num " + diff --git a/src/main/java/cn/langpy/kotime/controller/KoTimeController.java b/src/main/java/cn/langpy/kotime/controller/KoTimeController.java index 964451e..965e3c4 100644 --- a/src/main/java/cn/langpy/kotime/controller/KoTimeController.java +++ b/src/main/java/cn/langpy/kotime/controller/KoTimeController.java @@ -49,7 +49,7 @@ public class KoTimeController { @GetMapping("/getApis") @ResponseBody @Auth - public List getApis(String question) { + public List getApis(String question,String orderBy,String sort) { GraphService graphService = GraphService.getInstance(); List list = null; if (StringUtils.hasText(question)) { @@ -57,7 +57,18 @@ public class KoTimeController { } else { list = graphService.getControllers(); } - Collections.sort(list); + + Collections.sort(list, (o1, o2) -> { + int sortValue = -1; + if ("asc".equals(sort)) { + sortValue = 1; + } + if ("callNum".equals(orderBy)) { + return o1.getCallNum().compareTo(o2.getCallNum())* sortValue; + }else { + return o1.getAvgRunTime().compareTo(o2.getAvgRunTime())* sortValue; + } + }); return list; } diff --git a/src/main/java/cn/langpy/kotime/data/MemoryBase.java b/src/main/java/cn/langpy/kotime/data/MemoryBase.java index 7e9b0ba..55f481f 100644 --- a/src/main/java/cn/langpy/kotime/data/MemoryBase.java +++ b/src/main/java/cn/langpy/kotime/data/MemoryBase.java @@ -11,6 +11,7 @@ import java.lang.reflect.Parameter; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import static java.util.stream.Collectors.toList; @@ -238,7 +239,11 @@ public class MemoryBase implements GraphService { if (relations.isPresent()) { relation = relations.get(); } else { - continue; + relation = new MethodRelation(); + relation.setCallNum(0); + relation.setAvgRunTime(0.0); + relation.setMaxRunTime(0.0); + relation.setMinRunTime(0.0); } MethodInfo methodInfo = new MethodInfo(); methodInfo.setId(methodNode.getId()); @@ -277,7 +282,11 @@ public class MemoryBase implements GraphService { if (relations.isPresent()) { relation = relations.get(); } else { - continue; + relation = new MethodRelation(); + relation.setCallNum(0); + relation.setAvgRunTime(0.0); + relation.setMaxRunTime(0.0); + relation.setMinRunTime(0.0); } MethodInfo methodInfo = new MethodInfo(); methodInfo.setId(methodNode.getId()); @@ -381,7 +390,17 @@ public class MemoryBase implements GraphService { rootInfo.setMethodName(methodNode.getMethodName()); rootInfo.setMethodType(methodNode.getMethodType()); rootInfo.setRouteName(methodNode.getRouteName()); - MethodRelation methodRelation = methodRelations.values().stream().filter(relation -> relation.getTargetId().equals(methodId)).findFirst().get(); + Optional methodRelationStream = methodRelations.values().stream().filter(relation -> relation.getTargetId().equals(methodId)).findFirst(); + MethodRelation methodRelation; + if (!methodRelationStream.isPresent()) { + methodRelation = new MethodRelation(); + methodRelation.setCallNum(0); + methodRelation.setAvgRunTime(0.0); + methodRelation.setMaxRunTime(0.0); + methodRelation.setMinRunTime(0.0); + }else { + methodRelation = methodRelationStream.get(); + } rootInfo.setValue(methodRelation.getAvgRunTime()); rootInfo.setAvgRunTime(methodRelation.getAvgRunTime()); rootInfo.setMaxRunTime(methodRelation.getMaxRunTime()); diff --git a/src/main/java/cn/langpy/kotime/data/RedisBase.java b/src/main/java/cn/langpy/kotime/data/RedisBase.java index b84dd58..2b2e544 100644 --- a/src/main/java/cn/langpy/kotime/data/RedisBase.java +++ b/src/main/java/cn/langpy/kotime/data/RedisBase.java @@ -232,7 +232,11 @@ public class RedisBase implements GraphService { if (relations.isPresent()) { relation = relations.get(); } else { - continue; + relation = new MethodRelation(); + relation.setCallNum(0); + relation.setAvgRunTime(0.0); + relation.setMaxRunTime(0.0); + relation.setMinRunTime(0.0); } MethodInfo methodInfo = new MethodInfo(); methodInfo.setId(methodNode.getId()); @@ -279,7 +283,11 @@ public class RedisBase implements GraphService { if (relations.isPresent()) { relation = relations.get(); } else { - continue; + relation = new MethodRelation(); + relation.setCallNum(0); + relation.setAvgRunTime(0.0); + relation.setMaxRunTime(0.0); + relation.setMinRunTime(0.0); } MethodInfo methodInfo = new MethodInfo(); methodInfo.setId(methodNode.getId()); @@ -420,8 +428,18 @@ public class RedisBase implements GraphService { rootInfo.setMethodType(methodNode.getMethodType()); rootInfo.setRouteName(methodNode.getRouteName()); List methodRelationList = searchList(methodRelationPre, MethodRelation.class); + Optional methodRelationStream = methodRelationList.stream().filter(relation -> relation.getTargetId().equals(methodId)).findFirst(); + MethodRelation methodRelation; + if (!methodRelationStream.isPresent()) { + methodRelation = new MethodRelation(); + methodRelation.setCallNum(0); + methodRelation.setAvgRunTime(0.0); + methodRelation.setMaxRunTime(0.0); + methodRelation.setMinRunTime(0.0); + }else { + methodRelation = methodRelationStream.get(); + } - MethodRelation methodRelation = methodRelationList.stream().filter(relation -> relation.getTargetId().equals(methodId)).findFirst().get(); rootInfo.setValue(methodRelation.getAvgRunTime()); rootInfo.setAvgRunTime(methodRelation.getAvgRunTime()); rootInfo.setMaxRunTime(methodRelation.getMaxRunTime()); diff --git a/src/main/java/cn/langpy/kotime/handler/AuthHandler.java b/src/main/java/cn/langpy/kotime/handler/KoAuthHandler.java similarity index 95% rename from src/main/java/cn/langpy/kotime/handler/AuthHandler.java rename to src/main/java/cn/langpy/kotime/handler/KoAuthHandler.java index 7da43a3..015dea5 100644 --- a/src/main/java/cn/langpy/kotime/handler/AuthHandler.java +++ b/src/main/java/cn/langpy/kotime/handler/KoAuthHandler.java @@ -24,8 +24,8 @@ import java.util.logging.Logger; */ @Aspect @Component -public class AuthHandler { - private static Logger log = Logger.getLogger(AuthHandler.class.toString()); +public class KoAuthHandler { + private static Logger log = Logger.getLogger(KoAuthHandler.class.toString()); @Pointcut(KoConstant.authRange) public void preProcess() { diff --git a/src/main/resources/kostatic/common.css b/src/main/resources/kostatic/common.css index 945da80..615405a 100644 --- a/src/main/resources/kostatic/common.css +++ b/src/main/resources/kostatic/common.css @@ -2,6 +2,7 @@ color: #333; font-weight: 400; font-size: 14px; + cursor: pointer; } .common-li-bolder { diff --git a/src/main/resources/kotime.html b/src/main/resources/kotime.html index 0efadb5..6637670 100644 --- a/src/main/resources/kotime.html +++ b/src/main/resources/kotime.html @@ -70,12 +70,15 @@ } function loadApis() { - let searchText = $("#searchText").val(); - get(concatToken('contextPath/koTime/getApis?question=' + searchText), function (data) { + let searchDom = getDom("searchText"); + let searchText = searchDom.value; + let apiSortName = getDom('apiSortName') + let apiSortType = getDom('apiSortType') + get(concatToken(`contextPath/koTime/getApis?question=${searchText}&orderBy=${apiSortName.value}&sort=${apiSortType.value}`), function (data) { + searchDom.value=''; let element = getDom('apiList'); html = ''; for (let i = 0; i < data.length; i++) { - let simName = data[i]['name'].replace('.','#'); let className = data[i]['className']; let methodName = data[i]['methodName']; let avgRunTime = data[i]['avgRunTime']; @@ -85,25 +88,17 @@ let apiId = className + "." + methodName; let color = avgRunTime > globalThreshold ? 'danger' : 'success'; - if (methodType == 'Controller' && routeName != null && routeName != '') { - if (abbreviationEnable) { - html += "
  • " + simName + " (" + routeName + ")   {{tab.interface.interface-list.avg-tip}} " + avgRunTime + " ms" + - "   {{tab.interface.interface-list.call-num-tip}} " + callNum + "
  • "; - }else { - html += "
  • " + className + "#" + methodName + " (" + routeName + ")   {{tab.interface.interface-list.avg-tip}} " + avgRunTime + " ms" + - "   {{tab.interface.interface-list.call-num-tip}} " + callNum + "
  • "; - } - } else { - if (abbreviationEnable) { - html += "
  • " + simName + "   {{tab.interface.interface-list.avg-tip}} " + avgRunTime + " ms" + - "   {{tab.interface.interface-list.call-num-tip}} " + callNum + "
  • "; - }else { - html += "
  • " + className + "#" + methodName + "   {{tab.interface.interface-list.avg-tip}} " + avgRunTime + " ms" + - "   {{tab.interface.interface-list.call-num-tip}} " + callNum + "
  • "; - } + if (abbreviationEnable) { + className = data[i]['name'].split('.')[0]; } - } - ; + if (methodType == 'Controller' && routeName != null && routeName != '') { + html += "
  • " + className + "#" + methodName + " (" + routeName + ")   {{tab.interface.interface-list.avg-tip}} " + avgRunTime + " ms" + + "   {{tab.interface.interface-list.call-num-tip}} " + callNum + "
  • "; + } else { + html += "
  • " + className + "#" + methodName + "   {{tab.interface.interface-list.avg-tip}} " + avgRunTime + " ms" + + "   {{tab.interface.interface-list.call-num-tip}} " + callNum + "
  • "; + } + }; element.innerHTML = html; }); } @@ -423,43 +418,7 @@ function searchApis(e) { if (e.keyCode == 13) { - let question = $('#searchText').val() - get(concatToken('contextPath/koTime/getApis?question=' + question), function (data) { - let element = getDom('apiList'); - html = ''; - for (let i = 0; i < data.length; i++) { - let simName = data[i]['name'].replace('.','#'); - let className = data[i]['className']; - let methodName = data[i]['methodName']; - let avgRunTime = data[i]['avgRunTime']; - let methodType = data[i]['methodType']; - let routeName = data[i]['routeName']; - let callNum = data[i]['callNum']; - let apiId = className + "." + methodName; - let color = avgRunTime > globalThreshold ? 'danger' : 'success'; - - if (methodType == 'Controller' && routeName != null && routeName != '') { - if (abbreviationEnable) { - html += "
  • " + simName + " (" + routeName + ")   {{tab.interface.interface-list.avg-tip}} " + avgRunTime + " ms" + - "   {{tab.interface.interface-list.call-num-tip}} " + callNum + "
  • "; - }else { - html += "
  • " + className + "#" + methodName + " (" + routeName + ")   {{tab.interface.interface-list.avg-tip}} " + avgRunTime + " ms" + - "   {{tab.interface.interface-list.call-num-tip}} " + callNum + "
  • "; - } - } else { - if (abbreviationEnable) { - html += "
  • " + simName + "   {{tab.interface.interface-list.avg-tip}} " + avgRunTime + " ms" + - "   {{tab.interface.interface-list.call-num-tip}} " + callNum + "
  • "; - }else { - html += "
  • " + className + "#" + methodName + "   {{tab.interface.interface-list.avg-tip}} " + avgRunTime + " ms" + - "   {{tab.interface.interface-list.call-num-tip}} " + callNum + "
  • "; - } - } - } - ; - element.innerHTML = html; - }); - $('#searchText').val(''); + loadApis() } } @@ -670,6 +629,9 @@ UIkit.notification.closeAll(); UIkit.modal(getDom("modal-thread")).show(); } + function changeApiSort() { + loadApis(); + } $(document).ready(function () { refreshData(); @@ -682,7 +644,7 @@ -