mirror of
https://gitee.com/huoyo/ko-time.git
synced 2025-12-07 01:08:26 +08:00
添加配置项
This commit is contained in:
parent
2360dfcd55
commit
b159bf2288
2
pom.xml
2
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>cn.langpy</groupId>
|
||||
<artifactId>ko-time</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
<name>koTime</name>
|
||||
<description>koTime</description>
|
||||
<licenses>
|
||||
|
||||
52
src/main/java/cn/langpy/kotime/config/DefaultConfig.java
Normal file
52
src/main/java/cn/langpy/kotime/config/DefaultConfig.java
Normal file
@ -0,0 +1,52 @@
|
||||
package cn.langpy.kotime.config;
|
||||
|
||||
|
||||
import cn.langpy.kotime.model.KoTimeConfig;
|
||||
import cn.langpy.kotime.util.Context;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@Configuration
|
||||
public class DefaultConfig {
|
||||
@Value("${koTime.log.language:chinese}")
|
||||
private String logLanguage;
|
||||
@Value("${koTime.log.enable:false}")
|
||||
private Boolean logEnable;
|
||||
@Value("${koTime.time.threshold:800.0}")
|
||||
private Double timeThreshold;
|
||||
|
||||
@PostConstruct
|
||||
public void function() {
|
||||
KoTimeConfig config = new KoTimeConfig();
|
||||
config.setLogEnable(logEnable);
|
||||
config.setLogLanguage(logLanguage);
|
||||
config.setTimeThreshold(timeThreshold);
|
||||
Context.setConfig(config);
|
||||
}
|
||||
|
||||
public Double getTimeThreshold() {
|
||||
return timeThreshold;
|
||||
}
|
||||
|
||||
public void setTimeThreshold(Double timeThreshold) {
|
||||
this.timeThreshold = timeThreshold;
|
||||
}
|
||||
|
||||
public String getLogLanguage() {
|
||||
return logLanguage;
|
||||
}
|
||||
|
||||
public void setLogLanguage(String logLanguage) {
|
||||
this.logLanguage = logLanguage;
|
||||
}
|
||||
|
||||
public Boolean getLogEnable() {
|
||||
return logEnable;
|
||||
}
|
||||
|
||||
public void setLogEnable(Boolean logEnable) {
|
||||
this.logEnable = logEnable;
|
||||
}
|
||||
}
|
||||
@ -2,8 +2,8 @@ package cn.langpy.kotime.controller;
|
||||
|
||||
import cn.langpy.kotime.model.RunTimeNode;
|
||||
import cn.langpy.kotime.model.SystemStatistic;
|
||||
import cn.langpy.kotime.service.RunTimeNodeService;
|
||||
import cn.langpy.kotime.util.Context;
|
||||
import cn.langpy.kotime.util.MethodType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
@ -20,16 +20,17 @@ import java.util.List;
|
||||
public class KoTimeController {
|
||||
@GetMapping
|
||||
public String index(Model model, HttpServletRequest request) {
|
||||
List<RunTimeNode> list = Context.get(MethodType.Controller);
|
||||
List<RunTimeNode> list = RunTimeNodeService.getControllers();
|
||||
model.addAttribute("list",list);
|
||||
SystemStatistic system = Context.getStatistic();
|
||||
SystemStatistic system = RunTimeNodeService.getRunStatistic();
|
||||
model.addAttribute("system",system);
|
||||
model.addAttribute("config",Context.getConfig());
|
||||
return "index";
|
||||
}
|
||||
@GetMapping("/getTree")
|
||||
@ResponseBody
|
||||
public RunTimeNode getTree(String methodName,Model model, HttpServletRequest request) {
|
||||
return Context.getTree(methodName);
|
||||
return RunTimeNodeService.getGraph(methodName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ public class ComputeTimeHandler {
|
||||
long begin = System.nanoTime();
|
||||
Object obj=pjp.proceed();
|
||||
long end =System.nanoTime();
|
||||
StackTraceElement stacks[] = Thread.currentThread().getStackTrace();
|
||||
if ("chinese".equals(computeTime.value())) {
|
||||
log.info("调用方法={},耗时={}毫秒",pjp.getTarget().getClass().getName()+"."+pjp.getSignature().getName(),(end-begin)/1000000);
|
||||
}else{
|
||||
|
||||
@ -2,8 +2,7 @@ package cn.langpy.kotime.handler;
|
||||
|
||||
|
||||
import cn.langpy.kotime.model.RunTimeNode;
|
||||
import cn.langpy.kotime.util.Common;
|
||||
import cn.langpy.kotime.util.Context;
|
||||
import cn.langpy.kotime.service.InvokeService;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
@ -11,7 +10,6 @@ import org.aspectj.lang.annotation.Pointcut;
|
||||
|
||||
@Aspect
|
||||
public interface ComputeTimeHandlerInterface {
|
||||
|
||||
@Pointcut("")
|
||||
void prog();
|
||||
|
||||
@ -21,9 +19,9 @@ public interface ComputeTimeHandlerInterface {
|
||||
Object obj=pjp.proceed();
|
||||
long end =System.nanoTime();
|
||||
String packName = this.getClass().getPackage().getName();
|
||||
RunTimeNode parent = Common.getParentRunTimeNode(packName);
|
||||
RunTimeNode current = Common.getCurrentRunTimeNode(pjp,((end-begin)/1000000.0));
|
||||
Context.set(parent,current);
|
||||
RunTimeNode parent = InvokeService.getParentRunTimeNode(packName);
|
||||
RunTimeNode current = InvokeService.getCurrentRunTimeNode(pjp,((end-begin)/1000000.0));
|
||||
InvokeService.createGraph(parent,current);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
41
src/main/java/cn/langpy/kotime/model/KoTimeConfig.java
Normal file
41
src/main/java/cn/langpy/kotime/model/KoTimeConfig.java
Normal file
@ -0,0 +1,41 @@
|
||||
package cn.langpy.kotime.model;
|
||||
|
||||
|
||||
public class KoTimeConfig {
|
||||
private String logLanguage;
|
||||
private Boolean logEnable;
|
||||
private Double timeThreshold;
|
||||
|
||||
public Double getTimeThreshold() {
|
||||
return timeThreshold;
|
||||
}
|
||||
|
||||
public void setTimeThreshold(Double timeThreshold) {
|
||||
this.timeThreshold = timeThreshold;
|
||||
}
|
||||
|
||||
public String getLogLanguage() {
|
||||
return logLanguage;
|
||||
}
|
||||
|
||||
public void setLogLanguage(String logLanguage) {
|
||||
this.logLanguage = logLanguage;
|
||||
}
|
||||
|
||||
public Boolean getLogEnable() {
|
||||
return logEnable;
|
||||
}
|
||||
|
||||
public void setLogEnable(Boolean logEnable) {
|
||||
this.logEnable = logEnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KoTimeConfig{" +
|
||||
"logLanguage='" + logLanguage + '\'' +
|
||||
"timeThreshold='" + timeThreshold + '\'' +
|
||||
", logEnable=" + logEnable +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@ -65,4 +65,17 @@ public class SystemStatistic {
|
||||
public void setNormalNum(Integer normalNum) {
|
||||
this.normalNum = normalNum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SystemStatistic{" +
|
||||
"name='" + name + '\'' +
|
||||
", avgRunTime=" + avgRunTime +
|
||||
", maxRunTime=" + maxRunTime +
|
||||
", minRunTime=" + minRunTime +
|
||||
", totalNum=" + totalNum +
|
||||
", delayNum=" + delayNum +
|
||||
", normalNum=" + normalNum +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
65
src/main/java/cn/langpy/kotime/service/InvokeService.java
Normal file
65
src/main/java/cn/langpy/kotime/service/InvokeService.java
Normal file
@ -0,0 +1,65 @@
|
||||
package cn.langpy.kotime.service;
|
||||
|
||||
|
||||
import cn.langpy.kotime.model.RunTimeNode;
|
||||
import cn.langpy.kotime.util.Common;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class InvokeService {
|
||||
|
||||
public static RunTimeNode getParentRunTimeNode(String packName) {
|
||||
String parentClassName = "";
|
||||
String parentMothodName = "";
|
||||
StackTraceElement[] stacks = Thread.currentThread().getStackTrace();
|
||||
StackTraceElement stack = Common.filter(stacks,packName);
|
||||
if (stack!=null) {
|
||||
parentClassName = stack.getClassName();
|
||||
parentMothodName = stack.getMethodName();
|
||||
}
|
||||
RunTimeNode parent = new RunTimeNode();
|
||||
parent.setClassName(parentClassName);
|
||||
parent.setMethodName(parentMothodName);
|
||||
parent.setName(parentClassName.substring(parentClassName.lastIndexOf(".")+1)+"."+parentMothodName);
|
||||
parent.setMethodType(Common.getMethodType(parentClassName));
|
||||
parent.setChildren(new ArrayList<>());
|
||||
return parent;
|
||||
}
|
||||
|
||||
public static RunTimeNode getCurrentRunTimeNode(ProceedingJoinPoint pjp, Double runTime) {
|
||||
String className = pjp.getTarget().getClass().getName();
|
||||
String methodName = pjp.getSignature().getName();
|
||||
RunTimeNode current = new RunTimeNode();
|
||||
current.setName(className.substring(className.lastIndexOf(".")+1)+"."+methodName);
|
||||
current.setClassName(className);
|
||||
current.setMethodName(methodName);
|
||||
current.setAvgRunTime(runTime);
|
||||
current.setChildren(new ArrayList<>());
|
||||
current.setMethodType(Common.getMethodType(pjp));
|
||||
return current;
|
||||
}
|
||||
|
||||
public static void createGraph(RunTimeNode parent, RunTimeNode current) {
|
||||
if (current.getMethodName().contains("$")) {
|
||||
return;
|
||||
}
|
||||
Common.showLog(current);
|
||||
String parentKey = parent.getClassName()+"."+parent.getMethodName();
|
||||
String currentKey = current.getClassName()+"."+current.getMethodName();
|
||||
if (".".equals(parentKey)) {
|
||||
RunTimeNodeService.addOrUpdate(currentKey,current);
|
||||
}else if (RunTimeNodeService.containsNode(parent)) {
|
||||
RunTimeNodeService.addOrUpdateChildren(parent,current);
|
||||
}else{
|
||||
List<RunTimeNode> list = new ArrayList<>();
|
||||
list.add(current);
|
||||
parent.setChildren(list);
|
||||
RunTimeNodeService.add(parentKey,parent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package cn.langpy.kotime.service;
|
||||
import cn.langpy.kotime.model.RunTimeNode;
|
||||
import cn.langpy.kotime.model.SystemStatistic;
|
||||
import cn.langpy.kotime.util.Context;
|
||||
import cn.langpy.kotime.util.GraphMap;
|
||||
import cn.langpy.kotime.util.MethodType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class RunTimeNodeService {
|
||||
|
||||
public static void addOrUpdate(String key, RunTimeNode runTimeNode) {
|
||||
if (GraphMap.containsKey(key)) {
|
||||
GraphMap.get(key).setAvgRunTime(runTimeNode.getAvgRunTime());
|
||||
}else{
|
||||
GraphMap.put(key,runTimeNode);
|
||||
}
|
||||
}
|
||||
|
||||
public static void add(String key, RunTimeNode runTimeNode) {
|
||||
GraphMap.put(key,runTimeNode);
|
||||
}
|
||||
|
||||
public static boolean containsKey(String key) {
|
||||
return GraphMap.containsKey(key);
|
||||
}
|
||||
public static boolean containsNode(RunTimeNode node) {
|
||||
String key = node.getClassName()+"."+node.getMethodName();
|
||||
return GraphMap.containsKey(key);
|
||||
}
|
||||
|
||||
public static RunTimeNode getRunTimeNode(String key) {
|
||||
return GraphMap.get(key);
|
||||
}
|
||||
|
||||
public static void addOrUpdateChildren(RunTimeNode parent, RunTimeNode current) {
|
||||
String parentKey = parent.getClassName()+"."+parent.getMethodName();
|
||||
RunTimeNode hisRunTimeNode = RunTimeNodeService.getRunTimeNode(parentKey);
|
||||
List<RunTimeNode> hisRunTimeNodeChildren = hisRunTimeNode.getChildren();
|
||||
if (hisRunTimeNodeChildren!=null) {
|
||||
if (hisRunTimeNodeChildren.contains(current)) {
|
||||
updateChildren(current,hisRunTimeNodeChildren);
|
||||
}else{
|
||||
hisRunTimeNodeChildren.add(current);
|
||||
}
|
||||
} else {
|
||||
List<RunTimeNode> list = new ArrayList<>();
|
||||
list.add(current);
|
||||
hisRunTimeNode.setChildren(list);
|
||||
}
|
||||
GraphMap.put(parentKey,hisRunTimeNode);
|
||||
}
|
||||
|
||||
public static void updateChildren(RunTimeNode child, List<RunTimeNode> hisRunTimeNodeChildren) {
|
||||
int hisLength = hisRunTimeNodeChildren.size();
|
||||
for (int i = 0; i < hisLength; i++) {
|
||||
if (hisRunTimeNodeChildren.get(i)==child) {
|
||||
child.setAvgRunTime((child.getAvgRunTime()+hisRunTimeNodeChildren.get(i).getAvgRunTime())/2.0);
|
||||
hisRunTimeNodeChildren.set(i,child) ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static SystemStatistic getRunStatistic() {
|
||||
List<RunTimeNode> controllerApis = GraphMap.get(MethodType.Controller);
|
||||
SystemStatistic systemStatistic = new SystemStatistic();
|
||||
int delayNum = (int)controllerApis.stream().filter(controllerApi -> controllerApi.getAvgRunTime() >= Context.getConfig().getTimeThreshold()).count();
|
||||
systemStatistic.setDelayNum(delayNum);
|
||||
int normalNum = (int)controllerApis.stream().filter(controllerApi -> controllerApi.getAvgRunTime() < Context.getConfig().getTimeThreshold()).count();
|
||||
systemStatistic.setNormalNum(normalNum);
|
||||
int totalNum = (int)controllerApis.stream().count();
|
||||
systemStatistic.setTotalNum(totalNum);
|
||||
Double max = controllerApis.stream().map(api->api.getAvgRunTime()).max(Double::compareTo).get();
|
||||
Double min = controllerApis.stream().map(api->api.getAvgRunTime()).min(Double::compareTo).get();
|
||||
Double avg = controllerApis.stream().map(api->api.getAvgRunTime()).collect(Collectors.averagingDouble(Double::doubleValue));
|
||||
systemStatistic.setMaxRunTime(max);
|
||||
systemStatistic.setMinRunTime(min);
|
||||
systemStatistic.setAvgRunTime(avg);
|
||||
return systemStatistic;
|
||||
}
|
||||
|
||||
public static List<RunTimeNode> getControllers() {
|
||||
List<RunTimeNode> list = GraphMap.get(MethodType.Controller);
|
||||
return list;
|
||||
}
|
||||
public static RunTimeNode getGraph(String methodName) {
|
||||
return GraphMap.getTree(methodName);
|
||||
}
|
||||
}
|
||||
@ -1,52 +1,30 @@
|
||||
package cn.langpy.kotime.util;
|
||||
|
||||
import cn.langpy.kotime.model.RunTimeNode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Slf4j
|
||||
public class Common {
|
||||
|
||||
public static RunTimeNode getParentRunTimeNode(String packName) {
|
||||
String parentClassName = "";
|
||||
String parentMothodName = "";
|
||||
StackTraceElement[] stacks = Thread.currentThread().getStackTrace();
|
||||
public static StackTraceElement filter(StackTraceElement[] stacks,String packName) {
|
||||
String[] packNameSplit = packName.split("\\.");
|
||||
String filter = packNameSplit.length>1 ? packNameSplit[0]+"."+packNameSplit[1] : packNameSplit[0];
|
||||
int stacksLength = stacks.length;
|
||||
for (int i = 0; i < stacksLength; i++) {
|
||||
StackTraceElement stack = stacks[i];
|
||||
if (stack.getClassName().startsWith(filter)&& !stack.getClassName().contains("$")) {
|
||||
parentClassName = stack.getClassName();
|
||||
parentMothodName = stack.getMethodName();
|
||||
break;
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
RunTimeNode parent = new RunTimeNode();
|
||||
parent.setClassName(parentClassName);
|
||||
parent.setMethodName(parentMothodName);
|
||||
parent.setName(parentClassName.substring(parentClassName.lastIndexOf(".")+1)+"."+parentMothodName);
|
||||
parent.setMethodType(getMethodType(parentClassName));
|
||||
parent.setChildren(new ArrayList<>());
|
||||
return parent;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static RunTimeNode getCurrentRunTimeNode(ProceedingJoinPoint pjp,Double runTime) {
|
||||
String className = pjp.getTarget().getClass().getName();
|
||||
String methodName = pjp.getSignature().getName();
|
||||
RunTimeNode current = new RunTimeNode();
|
||||
current.setName(className.substring(className.lastIndexOf(".")+1)+"."+methodName);
|
||||
current.setClassName(className);
|
||||
current.setMethodName(methodName);
|
||||
current.setAvgRunTime(runTime);
|
||||
current.setChildren(new ArrayList<>());
|
||||
current.setMethodType(getMethodType(pjp));
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
public static MethodType getMethodType(ProceedingJoinPoint pjp) {
|
||||
MethodType methodType = null;
|
||||
@ -64,7 +42,7 @@ public class Common {
|
||||
methodType = MethodType.Controller;
|
||||
}else if (className.contains("service")) {
|
||||
methodType = MethodType.Service;
|
||||
}else if (className.contains("dao") || className.contains("mapper")) {
|
||||
}else if (className.contains("dao") || className.contains("mapper")|| className.contains( "com.sun.proxy.$Proxy")) {
|
||||
methodType = MethodType.Dao;
|
||||
}else{
|
||||
methodType = MethodType.Others;
|
||||
@ -80,7 +58,7 @@ public class Common {
|
||||
methodType = MethodType.Controller;
|
||||
}else if (className.contains("service")) {
|
||||
methodType = MethodType.Service;
|
||||
}else if (className.contains("dao") || className.contains("mapper")) {
|
||||
}else if (className.contains("dao") || className.contains("mapper")|| className.contains( "com.sun.proxy.$Proxy")) {
|
||||
methodType = MethodType.Dao;
|
||||
}else{
|
||||
methodType = MethodType.Others;
|
||||
@ -88,4 +66,14 @@ public class Common {
|
||||
return methodType;
|
||||
}
|
||||
|
||||
public static void showLog(RunTimeNode current) {
|
||||
String currentKey = current.getClassName()+"."+current.getMethodName();
|
||||
if (Context.getConfig().getLogEnable() && "chinese".equals(Context.getConfig().getLogLanguage())) {
|
||||
log.info("调用方法="+currentKey+",耗时="+current.getAvgRunTime()+"毫秒");
|
||||
}else if (Context.getConfig().getLogEnable() && "english".equals(Context.getConfig().getLogLanguage())) {
|
||||
log.info("method="+currentKey+",runTime="+current.getAvgRunTime()+"ms");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1,112 +1,16 @@
|
||||
package cn.langpy.kotime.util;
|
||||
|
||||
import cn.langpy.kotime.model.RunTimeNode;
|
||||
import cn.langpy.kotime.model.SystemStatistic;
|
||||
import cn.langpy.kotime.model.KoTimeConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
public class Context {
|
||||
private static KoTimeConfig config;
|
||||
|
||||
private static Map<String, RunTimeNode> runTimeNodeMap;
|
||||
static {
|
||||
runTimeNodeMap = new HashMap<>();
|
||||
public static void setConfig(KoTimeConfig koTimeConfig) {
|
||||
config = koTimeConfig;
|
||||
}
|
||||
|
||||
|
||||
public static void set(RunTimeNode parent,RunTimeNode current) {
|
||||
|
||||
String parentKey = parent.getClassName()+"."+parent.getMethodName();
|
||||
String currentKey = current.getClassName()+"."+current.getMethodName();
|
||||
if (!currentKey.contains("$")) {
|
||||
log.info("调用方法="+currentKey+",耗时="+current.getAvgRunTime()+"毫秒");
|
||||
}else {
|
||||
return;
|
||||
}
|
||||
if (".".equals(parentKey)) {
|
||||
if (runTimeNodeMap.containsKey(currentKey)) {
|
||||
runTimeNodeMap.get(currentKey).setAvgRunTime(current.getAvgRunTime());
|
||||
}else{
|
||||
runTimeNodeMap.put(currentKey,current);
|
||||
}
|
||||
}else if (runTimeNodeMap.containsKey(parentKey)) {
|
||||
RunTimeNode hisRunTimeNode = runTimeNodeMap.get(parentKey);
|
||||
List<RunTimeNode> hisRunTimeNodeChildren = hisRunTimeNode.getChildren();
|
||||
if (hisRunTimeNodeChildren!=null) {
|
||||
if (hisRunTimeNodeChildren.contains(current)) {
|
||||
int hisLength = hisRunTimeNodeChildren.size();
|
||||
for (int i = 0; i < hisLength; i++) {
|
||||
if (hisRunTimeNodeChildren.get(i)==current) {
|
||||
current.setAvgRunTime((current.getAvgRunTime()+hisRunTimeNode.getChildren().get(i).getAvgRunTime())/2.0);
|
||||
hisRunTimeNodeChildren.set(i,current) ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
hisRunTimeNodeChildren.add(current);
|
||||
}
|
||||
} else {
|
||||
List<RunTimeNode> list = new ArrayList<>();
|
||||
list.add(current);
|
||||
hisRunTimeNode.setChildren(list);
|
||||
}
|
||||
runTimeNodeMap.put(parentKey,hisRunTimeNode);
|
||||
}else{
|
||||
List<RunTimeNode> list = new ArrayList<>();
|
||||
list.add(current);
|
||||
parent.setChildren(list);
|
||||
runTimeNodeMap.put(parentKey,parent);
|
||||
public static KoTimeConfig getConfig() {
|
||||
return config ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static RunTimeNode get(String key) {
|
||||
return runTimeNodeMap.get(key);
|
||||
}
|
||||
public static List<RunTimeNode> get(MethodType methodType) {
|
||||
return runTimeNodeMap.values().stream()
|
||||
.filter(runTimeNode -> runTimeNode.getMethodType()==methodType)
|
||||
.sorted(Comparator.reverseOrder())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
public static RunTimeNode getTree(String key) {
|
||||
RunTimeNode root = runTimeNodeMap.get(key);
|
||||
if (root==null) {
|
||||
return root;
|
||||
}
|
||||
root.setValue(root.getAvgRunTime());
|
||||
List<RunTimeNode> children = root.getChildren();
|
||||
if (children!=null&&children.size()>0) {
|
||||
children.forEach(child->{
|
||||
String childKey = child.getClassName()+"."+child.getMethodName();
|
||||
RunTimeNode newChild = getTree(childKey);
|
||||
if (newChild!=null) {
|
||||
child.setChildren(newChild.getChildren());
|
||||
child.setValue(child.getAvgRunTime());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
public static SystemStatistic getStatistic() {
|
||||
List<RunTimeNode> controllerApis = get(MethodType.Controller);
|
||||
SystemStatistic systemStatistic = new SystemStatistic();
|
||||
int delayNum = (int)controllerApis.stream().filter(controllerApi -> controllerApi.getAvgRunTime() >= 800).count();
|
||||
systemStatistic.setDelayNum(delayNum);
|
||||
int normalNum = (int)controllerApis.stream().filter(controllerApi -> controllerApi.getAvgRunTime() < 800).count();
|
||||
systemStatistic.setNormalNum(normalNum);
|
||||
int totalNum = (int)controllerApis.stream().count();
|
||||
systemStatistic.setTotalNum(totalNum);
|
||||
Double max = controllerApis.stream().map(api->api.getAvgRunTime()).max(Double::compareTo).get();
|
||||
Double min = controllerApis.stream().map(api->api.getAvgRunTime()).min(Double::compareTo).get();
|
||||
Double avg = controllerApis.stream().map(api->api.getAvgRunTime()).collect(Collectors.averagingDouble(Double::doubleValue));
|
||||
systemStatistic.setMaxRunTime(max);
|
||||
systemStatistic.setMinRunTime(min);
|
||||
systemStatistic.setAvgRunTime(avg);
|
||||
return systemStatistic;
|
||||
}
|
||||
}
|
||||
|
||||
57
src/main/java/cn/langpy/kotime/util/GraphMap.java
Normal file
57
src/main/java/cn/langpy/kotime/util/GraphMap.java
Normal file
@ -0,0 +1,57 @@
|
||||
package cn.langpy.kotime.util;
|
||||
|
||||
|
||||
import cn.langpy.kotime.model.RunTimeNode;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GraphMap {
|
||||
/*只需保证可见性,无需保证线程安全*/
|
||||
private volatile static Map<String, RunTimeNode> runTimeNodeMap;
|
||||
|
||||
static {
|
||||
runTimeNodeMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public static RunTimeNode get(String key) {
|
||||
return runTimeNodeMap.get(key);
|
||||
}
|
||||
|
||||
public static RunTimeNode put(String key, RunTimeNode runTimeNode) {
|
||||
return runTimeNodeMap.put(key,runTimeNode);
|
||||
}
|
||||
public static boolean containsKey(String key) {
|
||||
return GraphMap.runTimeNodeMap.containsKey(key);
|
||||
}
|
||||
|
||||
public static List<RunTimeNode> get(MethodType methodType) {
|
||||
return runTimeNodeMap.values().stream()
|
||||
.filter(runTimeNode -> runTimeNode.getMethodType()==methodType)
|
||||
.sorted(Comparator.reverseOrder())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static RunTimeNode getTree(String key) {
|
||||
RunTimeNode root = runTimeNodeMap.get(key);
|
||||
if (root==null) {
|
||||
return root;
|
||||
}
|
||||
root.setValue(root.getAvgRunTime());
|
||||
List<RunTimeNode> children = root.getChildren();
|
||||
if (children!=null&&children.size()>0) {
|
||||
children.forEach(child->{
|
||||
String childKey = child.getClassName()+"."+child.getMethodName();
|
||||
RunTimeNode newChild = getTree(childKey);
|
||||
if (newChild!=null) {
|
||||
child.setChildren(newChild.getChildren());
|
||||
child.setValue(child.getAvgRunTime());
|
||||
}
|
||||
});
|
||||
}
|
||||
return root;
|
||||
}
|
||||
}
|
||||
98
src/main/resources/static/config.js
Normal file
98
src/main/resources/static/config.js
Normal file
@ -0,0 +1,98 @@
|
||||
function getOption(data){
|
||||
return {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
triggerOn: 'mousemove'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'tree',
|
||||
// initialTreeDepth: 3,
|
||||
data: [data],
|
||||
top: '1%',
|
||||
left: '15%',
|
||||
bottom: '1%',
|
||||
right: '10%',
|
||||
roam: true,
|
||||
symbolSize: 20,
|
||||
itemStyle: {
|
||||
borderColor: 'green'
|
||||
},
|
||||
|
||||
label: {
|
||||
position: 'right',
|
||||
formatter: function(params){
|
||||
var bg = "titleBgGreen"
|
||||
if (params.value>800) {
|
||||
bg = "titleBgRed"
|
||||
}
|
||||
return [
|
||||
'{'+bg+'| 指标}',
|
||||
' {aa|}方法:'+params.name+" ",
|
||||
'{hr|}',
|
||||
' {aa|}耗时: '+params.data.avgRunTime+" ms ",
|
||||
'{hr|}',
|
||||
' {aa|}类型: '+params.data.methodType+" "
|
||||
].join('\n');
|
||||
},
|
||||
backgroundColor: '#ddd',
|
||||
borderColor: '#88e781',
|
||||
borderWidth: 1,
|
||||
borderRadius: 5,
|
||||
color: '#000',
|
||||
fontSize: 12,
|
||||
rich: {
|
||||
titleBgGreen: {
|
||||
align: 'left',
|
||||
backgroundColor: '#59977e',
|
||||
height: 20,
|
||||
borderRadius: [5, 5, 0, 0],
|
||||
padding: [0, 0, 0, 0],
|
||||
width: '100%',
|
||||
color: '#eee'
|
||||
},
|
||||
titleBgRed: {
|
||||
align: 'left',
|
||||
backgroundColor: '#dc1d16',
|
||||
height: 20,
|
||||
borderRadius: [5, 5, 0, 0],
|
||||
padding: [0, 0, 0, 0],
|
||||
width: '100%',
|
||||
color: '#eee'
|
||||
},
|
||||
hr: {
|
||||
borderColor: '#777',
|
||||
width: '100%',
|
||||
borderWidth: 0.5,
|
||||
height: 0
|
||||
},
|
||||
aa: {
|
||||
lineHeight: 20,
|
||||
borderColor: '#111111',
|
||||
height: 20,
|
||||
borderRadius: [5, 5, 0, 0],
|
||||
padding: [0, 0, 0, 0],
|
||||
width: '0%'
|
||||
|
||||
},
|
||||
t: {
|
||||
align: 'center'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
leaves: {
|
||||
label: {
|
||||
position: 'right',
|
||||
verticalAlign: 'middle',
|
||||
align: 'left'
|
||||
}
|
||||
},
|
||||
expandAndCollapse: true,
|
||||
animationDuration: 550,
|
||||
animationDurationUpdate: 750
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,15 +48,15 @@
|
||||
</fieldset>
|
||||
<ul class="site-doc-icon site-doc-anim">
|
||||
<li>
|
||||
<div class="layui-anim" style=" <#if system.avgRunTime gt 800 >background-color: #da3f0b;</#if>" data-anim="layui-anim-up">${system.avgRunTime}</div>
|
||||
<div class="layui-anim" style=" <#if system.avgRunTime gt config.timeThreshold >background-color: #da3f0b;</#if>" data-anim="layui-anim-up">${system.avgRunTime}</div>
|
||||
<div class="code">平均响应(ms)</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="layui-anim" style=" <#if system.maxRunTime gt 800 >background-color: #da3f0b;</#if>" data-anim="layui-anim-upbit">${system.maxRunTime}</div>
|
||||
<div class="layui-anim" style=" <#if system.maxRunTime gt config.timeThreshold >background-color: #da3f0b;</#if>" data-anim="layui-anim-upbit">${system.maxRunTime}</div>
|
||||
<div class="code">最大响应(ms)</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="layui-anim" style=" <#if system.minRunTime gt 800 >background-color: #da3f0b;</#if>" data-anim="layui-anim-scale">${system.minRunTime}</div>
|
||||
<div class="layui-anim" style=" <#if system.minRunTime gt config.timeThreshold >background-color: #da3f0b;</#if>" data-anim="layui-anim-scale">${system.minRunTime}</div>
|
||||
<div class="code">最小响应(ms)</div>
|
||||
</li>
|
||||
</ul>
|
||||
@ -68,7 +68,7 @@
|
||||
<div class="layui-colla-item" >
|
||||
<h2 class="layui-colla-title" id="${runtime.className}.${runtime.methodName}">
|
||||
${runtime.className}#${runtime.methodName} 
|
||||
<span class="layui-badge <#if runtime.avgRunTime gt 800 >layui-bg-red
|
||||
<span class="layui-badge <#if runtime.avgRunTime gt config.timeThreshold >layui-bg-red
|
||||
<#else>layui-bg-green
|
||||
</#if>">平均响应 ${runtime.avgRunTime} 毫秒</span>
|
||||
</h2>
|
||||
@ -100,18 +100,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">-->
|
||||
<!-- <legend>接口方法列表</legend>-->
|
||||
<!--</fieldset>-->
|
||||
|
||||
|
||||
|
||||
<script src="${ctx.contextPath}/static/layui/layui.js" charset="utf-8"></script>
|
||||
<script src="${ctx.contextPath}/static/jquery.min.js"></script>
|
||||
<script src="${ctx.contextPath}/static/echarts.min.js"></script>
|
||||
|
||||
<!--<script src="https://cdn.jsdelivr.net/npm/echarts@4/dist/echarts.min.js?_v_=1607268016278" rel="external nofollow" ></script>-->
|
||||
<!-- 注意:如果你直接复制所有代码到本地,上述js路径需要改成你本地的 -->
|
||||
<script src="${ctx.contextPath}/static/config.js"></script>
|
||||
<script >
|
||||
$(document).ready(function() {
|
||||
|
||||
@ -119,7 +112,6 @@
|
||||
var element = layui.element;
|
||||
var layer = layui.layer;
|
||||
|
||||
//监听折叠
|
||||
element.on('collapse(test)', function (data) {
|
||||
id = data.title['0'].id
|
||||
show(data.content['0'],id)
|
||||
@ -135,102 +127,7 @@
|
||||
echarts.util.each(data.children, function (datum, index) {
|
||||
index % 2 === 0 && (datum.collapsed = true);
|
||||
});
|
||||
|
||||
myChart.setOption(option = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
triggerOn: 'mousemove'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'tree',
|
||||
// initialTreeDepth: 3,
|
||||
data: [data],
|
||||
top: '1%',
|
||||
left: '15%',
|
||||
bottom: '1%',
|
||||
right: '10%',
|
||||
roam: true,
|
||||
symbolSize: 20,
|
||||
itemStyle: {
|
||||
borderColor: 'green'
|
||||
},
|
||||
|
||||
label: {
|
||||
position: 'right',
|
||||
formatter: function(params){
|
||||
var bg = "titleBgGreen"
|
||||
if (params.value>800) {
|
||||
bg = "titleBgRed"
|
||||
}
|
||||
return [
|
||||
'{'+bg+'| 指标}',
|
||||
' {aa|}方法:'+params.name+" ",
|
||||
'{hr|}',
|
||||
' {aa|}耗时: '+params.data.avgRunTime+" ms ",
|
||||
'{hr|}',
|
||||
' {aa|}类型: '+params.data.methodType+" "
|
||||
].join('\n');
|
||||
},
|
||||
backgroundColor: '#ddd',
|
||||
borderColor: '#88e781',
|
||||
borderWidth: 1,
|
||||
borderRadius: 5,
|
||||
color: '#000',
|
||||
fontSize: 12,
|
||||
rich: {
|
||||
titleBgGreen: {
|
||||
align: 'left',
|
||||
backgroundColor: '#59977e',
|
||||
height: 20,
|
||||
borderRadius: [5, 5, 0, 0],
|
||||
padding: [0, 0, 0, 0],
|
||||
width: '100%',
|
||||
color: '#eee'
|
||||
},
|
||||
titleBgRed: {
|
||||
align: 'left',
|
||||
backgroundColor: '#dc1d16',
|
||||
height: 20,
|
||||
borderRadius: [5, 5, 0, 0],
|
||||
padding: [0, 0, 0, 0],
|
||||
width: '100%',
|
||||
color: '#eee'
|
||||
},
|
||||
hr: {
|
||||
borderColor: '#777',
|
||||
width: '100%',
|
||||
borderWidth: 0.5,
|
||||
height: 0
|
||||
},
|
||||
aa: {
|
||||
lineHeight: 20,
|
||||
borderColor: '#111111',
|
||||
height: 20,
|
||||
borderRadius: [5, 5, 0, 0],
|
||||
padding: [0, 0, 0, 0],
|
||||
width: '0%'
|
||||
|
||||
},
|
||||
t: {
|
||||
align: 'center'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
leaves: {
|
||||
label: {
|
||||
position: 'right',
|
||||
verticalAlign: 'middle',
|
||||
align: 'left'
|
||||
}
|
||||
},
|
||||
expandAndCollapse: true,
|
||||
animationDuration: 550,
|
||||
animationDurationUpdate: 750
|
||||
}
|
||||
]
|
||||
});
|
||||
myChart.setOption(option = getOption(data));
|
||||
});
|
||||
}
|
||||
|
||||
@ -238,5 +135,6 @@
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user