mirror of
https://gitee.com/huoyo/ko-time.git
synced 2025-12-06 16:58:26 +08:00
release:v2.5.0
This commit is contained in:
parent
a784a7834f
commit
5527f2808e
@ -9,7 +9,7 @@
|
||||
<div align="center">
|
||||
<img src='https://gitee.com/huoyo/ko-time/badge/star.svg'>
|
||||
<img src='https://img.shields.io/github/stars/huoyo/ko-time.svg?&label=Stars&logo=github'>
|
||||
<img src='https://shields.io/badge/version-2.4.9-green.svg'>
|
||||
<img src='https://shields.io/badge/version-2.5.0-green.svg'>
|
||||
<img src='https://shields.io/badge/author-Chang Zhang-dbab09.svg'>
|
||||
<img src='https://shields.io/badge/dependencies-Spring|aspectjweaver|tomcat|UIKit|Metricflow-r.svg'>
|
||||
</div>
|
||||
@ -21,7 +21,8 @@
|
||||
- ✅ Find exceptions occurred in methods
|
||||
- ✅ Email you after finding an overtime method
|
||||
- ✅ Hot update online:you needn't restart it
|
||||
- ✅ Thread manage:show threads information
|
||||
- ✅ Thread manage:show threads information,the deadlocks included
|
||||
- ✅ JVM Space:Eden、Survivor、OldGen and Metaspace
|
||||
- ✅ Easy to use:you needn't additional learning costs
|
||||
- ✅ Enough to add a pom dependency:you needn't additional deployment costs
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
<div align="center">
|
||||
<img src='https://gitee.com/huoyo/ko-time/badge/star.svg'>
|
||||
<img src='https://img.shields.io/github/stars/huoyo/ko-time.svg?&label=Stars&logo=github'>
|
||||
<img src='https://shields.io/badge/version-2.4.9-green.svg'>
|
||||
<img src='https://shields.io/badge/version-2.5.0-green.svg'>
|
||||
<img src='https://shields.io/badge/author-Chang Zhang-dbab09.svg'>
|
||||
<img src='https://shields.io/badge/dependencies-Spring|aspectjweaver|tomcat|UIKit|Metricflow-r.svg'>
|
||||
</div>
|
||||
@ -30,7 +30,8 @@
|
||||
- ✅ Find exceptions occurred in methods
|
||||
- ✅ Email you after finding an overtime method
|
||||
- ✅ Hot update online:you needn't restart it
|
||||
- ✅ Thread manage:show threads information
|
||||
- ✅ Thread manage:show threads information,the deadlocks included
|
||||
- ✅ JVM Space:Eden、Survivor、OldGen and Metaspace
|
||||
- ✅ Easy to use:you needn't additional learning costs
|
||||
- ✅ Enough to add a pom dependency:you needn't additional deployment costs
|
||||
|
||||
@ -44,7 +45,8 @@
|
||||
- ✅ 追踪系统异常,精确定位到方法
|
||||
- ✅ 接口超时邮件通知,无需实时查看
|
||||
- ✅ 线上热更新:无需重启更新代码
|
||||
- ✅ 线程管理:线程实时统计与状态查看
|
||||
- ✅ 线程管理:线程实时统计与状态查看以及死锁检测
|
||||
- ✅ JVM空间统计:Eden、Survivor、OldGen and Metaspace
|
||||
- ✅ 使用简单,无技术学习成本
|
||||
- ✅ pom依赖即可,无代码侵入,无多余部署成本
|
||||
|
||||
|
||||
@ -86,7 +86,7 @@ public class SaveResourceConfig implements CommandLineRunner {
|
||||
classRoute = cvalues[0];
|
||||
}
|
||||
RequestMapping methodAnnotation = method.getMethodAnnotation(RequestMapping.class);
|
||||
if (requestMapping == null) {
|
||||
if (methodAnnotation == null) {
|
||||
return null;
|
||||
}
|
||||
String[] mvalues = methodAnnotation.value();
|
||||
|
||||
@ -12,8 +12,6 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
|
||||
@ -1 +1 @@
|
||||
ko-time.version=2.4.9
|
||||
ko-time.version=2.5.0
|
||||
@ -1,343 +0,0 @@
|
||||
function checkLogin() {
|
||||
$.get(contextPath+'/koTime/isLogin?kotoken=' + globalToken+"&project="+globalProject, function (data) {
|
||||
globalIsLogin = data['isLogin'] == 1 ? true : false;
|
||||
});
|
||||
if (globalNeedLogin == true && globalIsLogin == false) {
|
||||
UIkit.modal(document.getElementById("modal-login")).show();
|
||||
return;
|
||||
}
|
||||
;
|
||||
}
|
||||
|
||||
function loadConfig(){
|
||||
$.get(contextPath+'/koTime/getConfig?kotoken='+globalToken+"&project="+globalProject, function (data) {
|
||||
// let exceptionEnable = data['exceptionEnable'];
|
||||
//
|
||||
// let exceptionEnableDom = document.getElementById('exceptionEnable');
|
||||
// exceptionEnableDom.checked = exceptionEnable;
|
||||
//
|
||||
|
||||
let kotimeEnable = data['enable'];
|
||||
// let kotimeEnableDom = document.getElementById('kotimeEnable');
|
||||
// kotimeEnableDom.checked = kotimeEnable;
|
||||
|
||||
let apiTip = document.getElementById('apiTip');
|
||||
apiTip.innerHTML = kotimeEnable==true?"接口根据调用情况统计,未调用的接口无法被统计到,请先调用接口":"方法调用监测已关闭,数据将不会更新,需要开启请到配置面板";
|
||||
|
||||
let threshold = data['threshold'];
|
||||
let timeThresholdDom = document.getElementById('timeThreshold');
|
||||
timeThresholdDom.value = threshold;
|
||||
|
||||
// let logEnable = data['logEnable'];
|
||||
// let logEnableDom = document.getElementById('logEnable');
|
||||
// logEnableDom.checked = logEnable;
|
||||
|
||||
let language = data['language'];
|
||||
$("#languageSwitch").val(language)
|
||||
});
|
||||
}
|
||||
|
||||
function addConfigEvent(){
|
||||
|
||||
|
||||
document.getElementById('languageSwitch').onchange = function(){
|
||||
let selectedObj = document.getElementById('languageSwitch');
|
||||
$.ajax({type:'POST',url:contextPath+'/koTime/updateConfig?kotoken='+globalToken+"&project="+globalProject,data:JSON.stringify({language:selectedObj.options[selectedObj.selectedIndex].value}),dataType:'json', headers: {'Content-Type': 'application/json' }});
|
||||
};
|
||||
|
||||
document.getElementById("timeThresholdYes").onclick = function(){
|
||||
$.ajax({type:'POST',url:contextPath+'/koTime/updateConfig?kotoken='+globalToken+"&project="+globalProject,data:JSON.stringify({threshold:document.getElementById('timeThreshold').value}),dataType:'json', headers: {'Content-Type': 'application/json' }});
|
||||
};
|
||||
}
|
||||
|
||||
function loadStatistic(){
|
||||
$.get(contextPath+'/koTime/getStatistic?kotoken='+globalToken+"&project="+globalProject, function (data) {
|
||||
let totalNum = data['totalNum'];
|
||||
let systemTotalNum = document.getElementById("systemTotalNum");
|
||||
systemTotalNum.innerHTML=totalNum;
|
||||
|
||||
let normalNum = data['normalNum'];
|
||||
let systemNormalNum = document.getElementById("systemNormalNum");
|
||||
systemNormalNum.innerHTML=normalNum;
|
||||
|
||||
let delayNum = data['delayNum'];
|
||||
let systemDelayNum = document.getElementById("systemDelayNum");
|
||||
systemDelayNum.innerHTML=delayNum;
|
||||
if (delayNum>0) {
|
||||
document.getElementById("systemDelayNum-div").className+=' uk-label-danger';
|
||||
}else {
|
||||
document.getElementById("systemDelayNum-div").className+=' uk-label-success';
|
||||
};
|
||||
|
||||
let avgRunTime = data['avgRunTime'];
|
||||
let systemAvgRunTime = document.getElementById("systemAvgRunTime");
|
||||
systemAvgRunTime.innerHTML=avgRunTime;
|
||||
if (avgRunTime>globalThreshold) {
|
||||
document.getElementById("systemAvgRunTime-div").className+=' uk-label-danger';
|
||||
}else {
|
||||
document.getElementById("systemAvgRunTime-div").className+=' uk-label-success';
|
||||
};
|
||||
|
||||
let maxRunTime = data['maxRunTime'];
|
||||
let systemMaxRunTime = document.getElementById("systemMaxRunTime");
|
||||
systemMaxRunTime.innerHTML=maxRunTime;
|
||||
if (maxRunTime>globalThreshold) {
|
||||
document.getElementById("systemMaxRunTime-div").className+=' uk-label-danger';
|
||||
}else {
|
||||
document.getElementById("systemMaxRunTime-div").className+=' uk-label-success';
|
||||
};
|
||||
|
||||
|
||||
let minRunTime = data['minRunTime'];
|
||||
let systemMinRunTime = document.getElementById("systemMinRunTime");
|
||||
systemMinRunTime.innerHTML=minRunTime;
|
||||
if (minRunTime>globalThreshold) {
|
||||
document.getElementById("systemMinRunTime-div").className+=' uk-label-danger';
|
||||
}else {
|
||||
document.getElementById("systemMinRunTime-div").className+=' uk-label-success';
|
||||
};
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function loadApis(){
|
||||
let searchText = $("#searchText").val();
|
||||
$.get(contextPath+'/koTime/getApis?question='+searchText+'&kotoken='+globalToken+"&project="+globalProject, function (data) {
|
||||
let element = document.getElementById('apiList');
|
||||
html = '';
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let id = data[i]['id'];
|
||||
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 apiId = className+"."+methodName;
|
||||
let color = avgRunTime>globalThreshold?'danger':'success';
|
||||
if (methodType=='Controller' && routeName!=null && routeName!='') {
|
||||
html += "<li onclick=\"showMethods('"+id+"')\" style='color: #333;font-weight: 400;font-size: 14px;' id=\""+apiId+"-list\">"+ className+"#<span style='font-size: 16px;font-weight: 500;'>"+methodName+"</span> (<span style='font-size: 14px;font-weight: 430;color:#032b11'>"+routeName+"</span>)   <span style='font-size: 10px;' class=\"uk-label uk-label-"+color+"\">avg "+avgRunTime+" ms</span></li>";
|
||||
}else{
|
||||
html += "<li onclick=\"showMethods('"+id+"')\" style='color: #333;font-weight: 400;font-size: 14px;' id=\""+apiId+"-list\">"+ className+"#<span style='font-size: 16px;font-weight: 500;'>"+methodName+"</span>   <span style='font-size: 10px;' class=\"uk-label uk-label-"+color+"\">avg "+avgRunTime+" ms</span></li>";
|
||||
}
|
||||
};
|
||||
element.innerHTML = html;
|
||||
});
|
||||
}
|
||||
|
||||
function loadExceptions(){
|
||||
$.get(contextPath+'/koTime/getExceptions?kotoken='+globalToken+"&project="+globalProject, function (data) {
|
||||
let element = document.getElementById('exceptionList');
|
||||
html = '';
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let id = data[i]['id'];
|
||||
let className = data[i]['className'];
|
||||
let message = data[i]['message'];
|
||||
html += "<li onclick=\"showExceptions('"+id+"','"+message+"')\" style='' id=\""+id+"\"><span style='font-size: 16px;font-weight: 500;'>"+className+"</span>   <span style='font-size: 10px;' class=\"uk-label uk-label-danger\">"+message+"</span></li>";
|
||||
};
|
||||
element.innerHTML = html;
|
||||
});
|
||||
}
|
||||
|
||||
let methodParamMap = new Map();
|
||||
function paramGraph(e) {
|
||||
let clickNode = e.currentTarget;
|
||||
if (clickNode==null){
|
||||
return
|
||||
};
|
||||
let clickNodeId = clickNode.id;
|
||||
if (methodParamMap.has(clickNodeId+"ana")) {
|
||||
graph.removeNode(clickNodeId+"ana")
|
||||
methodParamMap.delete(clickNodeId+"ana")
|
||||
}else {
|
||||
$.get(contextPath+'/koTime/getParamGraph?kotoken='+globalToken+"&methodId="+clickNodeId.replace('node','')+"&project="+globalProject, function (data) {
|
||||
let datas = []
|
||||
for(let key in data) {
|
||||
datas.push( {"name":key+":avg "+data[key]['avgRunTime']+" ms"})
|
||||
};
|
||||
let paramGraphData = {
|
||||
"id":clickNodeId+"ana",
|
||||
"from":clickNodeId,
|
||||
"title":{'name':"Combination of parameters"},
|
||||
"data":datas,
|
||||
'style':{
|
||||
'title-color':'#427b72',
|
||||
'border-color':'#427b72',
|
||||
'data-font-size':'10px',
|
||||
'title-font-size':'12px'
|
||||
}
|
||||
}
|
||||
let clickNodeX = Number(clickNode.getAttribute("x"));
|
||||
let clickNodeY = Number(clickNode.getAttribute("y"));
|
||||
graph.createNode(paramGraphData,clickNodeX,clickNodeY-100);
|
||||
// graph.createNode(paramGraphData,e.x+150,e.y-30);
|
||||
methodParamMap.set(clickNodeId+"ana","")
|
||||
});
|
||||
}
|
||||
}
|
||||
function formData(data) {
|
||||
if (data['avgRunTime']>globalThreshold) {
|
||||
data['style'] = {
|
||||
'title-color':'#c71335',
|
||||
'border-color':'#c71335',
|
||||
'data-font-size':'10px',
|
||||
'title-font-size':'12px'
|
||||
}
|
||||
}
|
||||
else{
|
||||
data['style'] = {
|
||||
'title-color':'#375d46',
|
||||
'border-color':'#375d46',
|
||||
'data-font-size':'10px',
|
||||
'title-font-size':'12px'
|
||||
}
|
||||
};
|
||||
data['title'] = {'name':data['name']};
|
||||
data['data'] = [
|
||||
{'name':'<span style="color:gray">type:</span>'+data['methodType']},
|
||||
{'name':'<span style="color:gray">avg time:</span>'+data['avgRunTime']+' ms'},
|
||||
{'name':'<span style="color:gray">max time:</span>'+data['maxRunTime']+' ms'},
|
||||
{'name':'<span style="color:gray">min time:</span>'+data['minRunTime']+' ms'}
|
||||
];
|
||||
if (data['exceptionNum']!=null && data['exceptionNum']>0) {
|
||||
data['data'].push({'name':'<span style="color:gray">number of exception:</span>'+data['exceptionNum']+' 个'});
|
||||
}
|
||||
data["dblclick"]="paramGraph";
|
||||
return data;
|
||||
};
|
||||
|
||||
|
||||
function showMethods(name) {
|
||||
let exceptionDetailDom = document.getElementById('layerDemo');
|
||||
exceptionDetailDom.innerHTML = "";
|
||||
let options = {
|
||||
'link-start-offsetx':8,
|
||||
'link-start-offsety':0,
|
||||
'link-end-offsetx':+10,
|
||||
'link-end-offsety':0,
|
||||
'link-width-offset':0
|
||||
};
|
||||
graph = new MetricFlow("layerDemo",options);
|
||||
graph.threshold = globalThreshold;
|
||||
UIkit.notification.closeAll();
|
||||
UIkit.modal(document.getElementById("modal-method")).show();
|
||||
|
||||
$.get(contextPath+'/koTime/getTree?methodName=' + name+'&kotoken='+globalToken+"&project="+globalProject, function (data) {
|
||||
let rootX = 100;
|
||||
let rootY = $(window).get(0).innerHeight / 2-50;
|
||||
data['x'] = rootX;
|
||||
data['y'] = rootY;
|
||||
graph.createNodes(data,formData);
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
function showExceptions(id,message) {
|
||||
$.get(contextPath+'/koTime/getMethodsByExceptionId?exceptionId=' + id+'&message='+message+'&kotoken='+globalToken+"&project="+globalProject, function (data) {
|
||||
let html = '';
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
html +=
|
||||
"<ul class=\"uk-list uk-list-divider\">\n" +
|
||||
"\t<li id=\"exception-class\">Class:"+data[i].occurClassName+"</li>\n" +
|
||||
"\t<li id=\"exception-method\">Method:"+data[i].methodName+"</li>\n" +
|
||||
"\t<li id=\"exception-line\">Line:<span class=\"uk-label uk-label-success\">"+data[i].location+"</span></li>\n" +
|
||||
"\t<li id=\"exception-message\">Exception message:<span class=\"uk-label uk-label-danger\">"+data[i].message+"</span></li>\n" +
|
||||
"</ul>"
|
||||
if (data.length-1>i) {
|
||||
html +='<hr class="uk-divider-icon">'
|
||||
}
|
||||
};
|
||||
|
||||
let exceptionDetailDom = document.getElementById('exception-detail');
|
||||
exceptionDetailDom.innerHTML = html;
|
||||
UIkit.notification.closeAll();
|
||||
UIkit.modal(document.getElementById("modal-exception")).show();
|
||||
});
|
||||
};
|
||||
|
||||
function login() {
|
||||
let userId = $("#userName").val()
|
||||
let password = $("#userPassword").val()
|
||||
if (userId==undefined || userId.length<1 || password==undefined || password.length<1 ) {
|
||||
UIkit.notification.closeAll()
|
||||
UIkit.notification("<font color='red'>请正确输入用户名和密码</font>",{});
|
||||
return
|
||||
}
|
||||
$.ajax({
|
||||
type:'POST',
|
||||
url:contextPath+"/koTime/login",
|
||||
data:JSON.stringify({'userName':userId,'password':password}),
|
||||
dataType:'json',
|
||||
headers: {'Content-Type': 'application/json' },
|
||||
success:function (re) {
|
||||
if (re['state']==1) {
|
||||
UIkit.notification("<font color='green'>Login was successful</font>",{});
|
||||
UIkit.notification.closeAll()
|
||||
sessionStorage.setItem("kotimeToken", re["token"]);
|
||||
location.reload();
|
||||
}else {
|
||||
UIkit.notification("<font color='red'>Error user or password</font>",{});
|
||||
}
|
||||
},
|
||||
error:function (re) {
|
||||
console.log(re)
|
||||
}
|
||||
});
|
||||
}
|
||||
function searchTip(e){
|
||||
let question = $('#searchText').val()
|
||||
$.get(contextPath+'/koTime/getApiTips?question='+question+'&kotoken='+globalToken+"&project="+globalProject, function (data) {
|
||||
$("#condidates").html("")
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let name = data[i];
|
||||
$("#condidates").append('<option value="'+name+'"/>');
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function loadProjects(){
|
||||
$.get(contextPath+'/koTime/getProjects?kotoken='+globalToken+"&project=all", function (data) {
|
||||
$("#projects").html("")
|
||||
$("#projects").append('<option selected hidden disabled value="">Select you project</option>');
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let name = data[i];
|
||||
$("#projects").append(`<option value="${name}">${name}</option>`);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function searchApis(e) {
|
||||
if (e.keyCode == 13) {
|
||||
let question = $('#searchText').val()
|
||||
$.get(contextPath+'/koTime/getApis?question='+question+'&kotoken='+globalToken+"&project="+globalProject, function (data) {
|
||||
let element = document.getElementById('apiList');
|
||||
html = '';
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let id = data[i]['id'];
|
||||
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 apiId = className+"."+methodName;
|
||||
let color = avgRunTime>globalThreshold?'danger':'success';
|
||||
|
||||
if (methodType=='Controller' && routeName!=null && routeName!='') {
|
||||
html += "<li onclick=\"showMethods('"+id+"')\" style='color: #333;font-weight: 400;font-size: 14px;' id=\""+apiId+"-list\">"+ className+"#<span style='font-size: 16px;font-weight: 500;'>"+methodName+"</span> (<span style='font-size: 14px;font-weight: 430;color:#032b11'>"+routeName+"</span>)   <span style='font-size: 10px;' class=\"uk-label uk-label-"+color+"\">avg "+avgRunTime+" ms</span></li>";
|
||||
}else{
|
||||
html += "<li onclick=\"showMethods('"+id+"')\" style='color: #333;font-weight: 400;font-size: 14px;' id=\""+apiId+"-list\">"+ className+"#<span style='font-size: 16px;font-weight: 500;'>"+methodName+"</span>   <span style='font-size: 10px;' class=\"uk-label uk-label-"+color+"\">avg "+avgRunTime+" ms</span></li>";
|
||||
}
|
||||
};
|
||||
element.innerHTML = html;
|
||||
});
|
||||
$('#searchText').val('');
|
||||
}
|
||||
}
|
||||
|
||||
function getProjectName(){
|
||||
globalProject = document.querySelector("#projects").value;
|
||||
loadStatistic();
|
||||
loadApis();
|
||||
loadExceptions();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user