add:load index.html from the static configurations

This commit is contained in:
huoyo 2024-09-02 22:32:37 +08:00
parent 0d69b3eab8
commit 94411eb3a8
12 changed files with 1008 additions and 1533 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ target/
.txlcn
*.log
/.idea/
/.idea/

View File

@ -6,7 +6,7 @@
<groupId>cn.langpy</groupId>
<artifactId>ko-time</artifactId>
<version>2.4.4</version>
<version>2.4.5</version>
<name>KoTime</name>
<description>A springboot tool for tracking the paths of the methods,which can help you find method's performances easily.</description>
<licenses>

View File

@ -9,12 +9,11 @@ public class KoConstant {
public final static String exceptionTitleStyle = "exceptionTitleStyle";
public final static String globalThreshold = "globalThresholdValue";
public final static String globalNeedLogin = "globalNeedLoginValue";
public final static String globalIsLogin = "globalIsLoginValue";
public final static String contextPath = "contextPath";
public final static String kotimeViewer = "kotime.html";
public final static String kotimeViewerEn = "kotime-en.html";
public final static String loginName = "kotimeUserName";
@Deprecated
public static String getViewName(String language) {
if (!StringUtils.hasText(language)) {
language = Context.getConfig().getLanguage();

View File

@ -0,0 +1,188 @@
package cn.langpy.kotime.controller;
import cn.langpy.kotime.constant.KoConstant;
import cn.langpy.kotime.model.*;
import cn.langpy.kotime.util.Context;
import cn.langpy.kotime.util.InvalidAuthInfoException;
import cn.langpy.kotime.util.KoUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.io.*;
import java.util.*;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* zhangchang
*/
@Controller
@RequestMapping("/koTime")
public class KoInitController {
private static Logger log = Logger.getLogger(KoInitController.class.toString());
@Value("${ko-time.user-name:}")
private String userName;
@Value("${ko-time.password:}")
private String password;
private final Pattern pattern = Pattern.compile("\\{\\{[a-zA-Z0-9\\.-]+\\}\\}");
private final String uiKitCssText = getResourceText("kostatic/uikit.min.css");
private final String uiKitJsText = getResourceText("kostatic/uikit.min.js");
private final String metricFlowJsText = getResourceText("kostatic/Metricflow.js");
private final String jQueryJsText = getResourceText("kostatic/JQuery.min.js");
private final String uiKitIconsJs = getResourceText("kostatic/uikit-icons.js");
private final String KoTimeUtil = getResourceText("kostatic/util.js");
@PostMapping("/login")
@ResponseBody
public Map login(@RequestBody UserInfo userInfo) {
if (null == userInfo || !StringUtils.hasText(userInfo.getUserName()) || !StringUtils.hasText(userInfo.getPassword())) {
throw new InvalidAuthInfoException("failed to login for kotime,please fill userName and password!");
}
Map map = new HashMap();
if (userName.equals(userInfo.getUserName()) && password.equals(userInfo.getPassword())) {
String token = KoUtil.login(userInfo.getUserName());
map.put("state", 1);
map.put("token", token);
return map;
}
map.put("state", 0);
return map;
}
@GetMapping("/isLogin")
@ResponseBody
public Map isLogin(String kotoken) {
Map map = new HashMap();
map.put("state", 1);
boolean checkLogin = false;
if (StringUtils.hasText(kotoken)) {
if (kotoken.equals(Context.getConfig().getStaticToken())) {
checkLogin = true;
} else {
checkLogin = KoUtil.isLogin(kotoken);
}
}
map.put("isLogin", checkLogin ? 1 : 0);
return map;
}
@GetMapping
public void index(String kotoken, String charset, String language, HttpServletResponse response, HttpServletRequest request) {
if (!Context.getConfig().getEnable()) {
return;
}
if (!StringUtils.hasText(charset)) {
charset = "utf-8";
}
response.setContentType("text/html;charset=" + charset);
ClassPathResource classPathResource = new ClassPathResource(KoConstant.kotimeViewer);
try (
InputStream inputStream = classPathResource.getInputStream();
InputStreamReader streamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader reader = new BufferedReader(streamReader);
PrintWriter out = response.getWriter()) {
Properties languageDict = KoUtil.getLanguageDict(language);
String context = request.getContextPath();
if (StringUtils.hasText(Context.getConfig().getContextPath())) {
context = Context.getConfig().getContextPath();
}
StringBuilder stringBuilder = new StringBuilder();
String line = "";
while ((line = reader.readLine()) != null) {
line = formatStaticResource(line,context,kotoken);
line = formatLanguageDesc(line, languageDict);
stringBuilder.append(line + "\n");
}
line = stringBuilder.toString();
out.write(line);
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
private String formatStaticResource(String line,String context,String kotoken) {
boolean staticTokenVisit = false;
if (StringUtils.hasText(kotoken)) {
staticTokenVisit = true;
}
if (line.indexOf(KoConstant.globalThreshold) > -1) {
line = line.replace(KoConstant.globalThreshold, Context.getConfig().getThreshold() + "");
} else if (line.indexOf(KoConstant.globalNeedLogin) > -1) {
line = line.replace(KoConstant.globalNeedLogin, Context.getConfig().getAuthEnable() + "");
} else if (line.indexOf(KoConstant.contextPath) > -1) {
line = line.replace(KoConstant.contextPath, context);
} else if (line.indexOf(KoConstant.exceptionTitleStyle) > -1) {
line = line.replace(KoConstant.exceptionTitleStyle, Context.getConfig().getExceptionEnable() == true ? "" : "display:none;");
} else if (line.indexOf("UIKitCss") > -1) {
line = line.replace("UIKitCss", uiKitCssText);
} else if (line.indexOf("UIKitJs") > -1) {
line = line.replace("UIKitJs", uiKitJsText);
} else if (line.indexOf("MetricFlowJs") > -1) {
line = line.replace("MetricFlowJs", metricFlowJsText);
} else if (line.indexOf("jQueryJs") > -1) {
line = line.replace("jQueryJs", jQueryJsText);
} else if (line.indexOf("uiKitIconsJs") > -1) {
line = line.replace("uiKitIconsJs", uiKitIconsJs);
} else if (line.indexOf("staticTokenVisitValue") > -1) {
line = line.replace("staticTokenVisitValue", staticTokenVisit + "");
} else if (line.indexOf("staticTokenValue") > -1) {
line = line.replace("staticTokenValue", "'" + kotoken + "'");
} else if (line.indexOf("KoTimeUtil") > -1) {
line = line.replace("KoTimeUtil", KoTimeUtil);
} else if (line.indexOf("koTimeVersionValue") > -1) {
line = line.replace("koTimeVersionValue", "'" + KoUtil.getVerssion()+ "'");
}
return line;
}
private String formatLanguageDesc(String line, Properties languageDict) {
String languageKey = getLanguageKey(line);
if (languageKey != null) {
String key = languageKey.replaceAll("\\{|\\}", "");
String value = languageDict.getProperty(key);
line = line.replace(languageKey, value);
}
return line;
}
private String getLanguageKey(String line) {
Matcher m = pattern.matcher(line);
String key = null;
if (m.find()) {
key = m.group(0);
}
return key;
}
private String getResourceText(String fileName) {
ClassPathResource classPathResource = new ClassPathResource(fileName);
try (InputStream inputStream = classPathResource.getInputStream();
InputStreamReader streamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader reader = new BufferedReader(streamReader)) {
String line = "";
StringBuilder stringBuilder = new StringBuilder();
while ((line = reader.readLine()) != null) {
stringBuilder.append(line + "\n");
}
return stringBuilder.toString();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
}

View File

@ -2,24 +2,17 @@ package cn.langpy.kotime.controller;
import cn.langpy.kotime.annotation.Auth;
import cn.langpy.kotime.config.DefaultConfig;
import cn.langpy.kotime.constant.KoConstant;
import cn.langpy.kotime.model.*;
import cn.langpy.kotime.service.ClassService;
import cn.langpy.kotime.service.GraphService;
import cn.langpy.kotime.service.SysUsageService;
import cn.langpy.kotime.service.ThreadUsageService;
import cn.langpy.kotime.util.Context;
import cn.langpy.kotime.util.InvalidAuthInfoException;
import cn.langpy.kotime.util.KoUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.logging.Logger;
@ -33,132 +26,7 @@ import static cn.langpy.kotime.model.ThreadInfo.COMPARATOR;
@Controller
@RequestMapping("/koTime")
public class KoTimeController {
@Value("${ko-time.user-name:}")
private String userName;
@Value("${ko-time.password:}")
private String password;
private static Logger log = Logger.getLogger(KoTimeController.class.toString());
private final String uiKitCssText = getResourceText("kostatic/uikit.min.css");
private final String uiKitJsText = getResourceText("kostatic/uikit.min.js");
private final String metricFlowJsText = getResourceText("kostatic/Metricflow.js");
private final String jQueryJsText = getResourceText("kostatic/JQuery.min.js");
private final String uiKitIconsJs = getResourceText("kostatic/uikit-icons.js");
@PostMapping("/login")
@ResponseBody
public Map login(@RequestBody UserInfo userInfo) {
if (null == userInfo || !StringUtils.hasText(userInfo.getUserName()) || !StringUtils.hasText(userInfo.getPassword())) {
throw new InvalidAuthInfoException("failed to login for kotime,please fill userName and password!");
}
Map map = new HashMap();
if (userName.equals(userInfo.getUserName()) && password.equals(userInfo.getPassword())) {
String token = KoUtil.login(userInfo.getUserName());
map.put("state", 1);
map.put("token", token);
return map;
}
map.put("state", 0);
return map;
}
@GetMapping("/isLogin")
@ResponseBody
public Map isLogin(String kotoken) {
Map map = new HashMap();
map.put("state", 1);
boolean checkLogin = false;
if (StringUtils.hasText(kotoken)) {
if (kotoken.equals(Context.getConfig().getStaticToken())) {
checkLogin = true;
} else {
checkLogin = KoUtil.isLogin(kotoken);
}
}
map.put("isLogin", checkLogin ? 1 : 0);
return map;
}
@GetMapping
public void index(String kotoken, String test,String charset, String language,HttpServletResponse response, HttpServletRequest request) {
if (!Context.getConfig().getEnable()) {
return;
}
if (null != test) {
return;
}
boolean staticTokenVisit = false;
if (StringUtils.hasText(kotoken)) {
staticTokenVisit = true;
}
if (!StringUtils.hasText(charset)) {
charset = "utf-8";
}
response.setContentType("text/html;charset="+charset);
ClassPathResource classPathResource = new ClassPathResource(KoConstant.getViewName(language));
try (
InputStream inputStream = classPathResource.getInputStream();
InputStreamReader streamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader reader = new BufferedReader(streamReader);
PrintWriter out = response.getWriter()) {
String context = request.getContextPath();
if (StringUtils.hasText(Context.getConfig().getContextPath())) {
context = Context.getConfig().getContextPath();
}
StringBuilder stringBuilder = new StringBuilder();
String line = "";
while ((line = reader.readLine()) != null) {
if (line.indexOf(KoConstant.globalThreshold) > -1) {
line = line.replace(KoConstant.globalThreshold, Context.getConfig().getThreshold() + "");
} else if (line.indexOf(KoConstant.globalNeedLogin) > -1) {
line = line.replace(KoConstant.globalNeedLogin, Context.getConfig().getAuthEnable() + "");
} else if (line.indexOf(KoConstant.contextPath) > -1) {
line = line.replace(KoConstant.contextPath, context);
} else if (line.indexOf(KoConstant.exceptionTitleStyle) > -1) {
line = line.replace(KoConstant.exceptionTitleStyle, Context.getConfig().getExceptionEnable() == true ? "" : "display:none;");
} else if (line.indexOf("UIKitCss") > -1) {
line = line.replace("UIKitCss", uiKitCssText);
} else if (line.indexOf("UIKitJs") > -1) {
line = line.replace("UIKitJs", uiKitJsText);
} else if (line.indexOf("MetricFlowJs") > -1) {
line = line.replace("MetricFlowJs", metricFlowJsText);
} else if (line.indexOf("jQueryJs") > -1) {
line = line.replace("jQueryJs", jQueryJsText);
} else if (line.indexOf("uiKitIconsJs") > -1) {
line = line.replace("uiKitIconsJs", uiKitIconsJs);
} else if (line.indexOf("staticTokenVisitValue") > -1) {
line = line.replace("staticTokenVisitValue", staticTokenVisit + "");
} else if (line.indexOf("staticTokenValue") > -1) {
line = line.replace("staticTokenValue", "'" + kotoken + "'");
}
stringBuilder.append(line + "\n");
}
line = stringBuilder.toString();
out.write(line);
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
private String getResourceText(String fileName) {
ClassPathResource classPathResource = new ClassPathResource(fileName);
try (InputStream inputStream = classPathResource.getInputStream();
InputStreamReader streamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader reader = new BufferedReader(streamReader)) {
String line = "";
StringBuilder stringBuilder = new StringBuilder();
while ((line = reader.readLine()) != null) {
stringBuilder.append(line + "\n");
}
return stringBuilder.toString();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
@GetMapping("/getConfig")

View File

@ -5,14 +5,21 @@ import cn.langpy.kotime.model.InvokedInfo;
import cn.langpy.kotime.model.MethodNode;
import cn.langpy.kotime.service.InvokedQueue;
import cn.langpy.kotime.service.MethodNodeService;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import javax.sql.DataSource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.logging.Logger;
import java.util.stream.Collectors;
public class KoUtil {
private static Logger log = Logger.getLogger(KoUtil.class.toString());
private final static String koTimeSecret = UUID.randomUUID().toString().replace("-", "");
private final static List<Integer> choices = randomSecretIndexs();
@ -215,5 +222,47 @@ public class KoUtil {
return Arrays.stream(split1).collect(Collectors.toList());
}
public static Properties getLanguageDict(String language) {
Properties properties = new Properties();
if (!StringUtils.hasText(language)) {
language = Context.getConfig().getLanguage();
}
ClassPathResource classPathResource = new ClassPathResource("kostatic/dict/"+language+".properties");
try (
InputStream inputStream = classPathResource.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)
) {
properties.load(inputStreamReader);
} catch (UnsupportedEncodingException e) {
log.severe("kotime=>"+Context.getConfig().getLanguage()+".properties requires utf-8.");
e.printStackTrace();
} catch (FileNotFoundException e){
log.warning("kotime=>No "+Context.getConfig().getLanguage()+".properties found so that you can not use language properties to set.");
}catch (IOException e) {
e.printStackTrace();
}
return properties;
}
public static String getVerssion() {
Properties properties = new Properties();
ClassPathResource classPathResource = new ClassPathResource("koapp.properties");
try (
InputStream inputStream = classPathResource.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)
) {
properties.load(inputStreamReader);
} catch (UnsupportedEncodingException e) {
log.severe("kotime=>koapp.properties requires utf-8.");
e.printStackTrace();
} catch (FileNotFoundException e){
log.warning("kotime=>No koapp.properties found.");
}catch (IOException e) {
e.printStackTrace();
}
return properties.getProperty("ko-time.version");
}
}

View File

@ -0,0 +1 @@
ko-time.version=2.4.5

View File

@ -0,0 +1,103 @@
kotime-title=KoTime调用链路追踪
kotime-confirm=确定
kotime-refresh=刷新数据
tab.summary=总览
tab.interface=接口列表
tab.exception=异常列表
tab.thread=线程列表
tab.hotupdate=热更新
tab.configuration=配置
tab.support=技术支持
tab.summary.interface-metric=接口统计
tab.summary.response-metric=响应统计
tab.summary.sysusage-metric=系统使用情况
tab.summary.bottom-normal-tip=接口根据调用情况统计,未调用的接口无法被统计到,请先调用接口
tab.summary.bottom-close-tip=方法调用监测已关闭,数据将不会更新,需要开启请到配置面板
tab.summary.interface-metric.total-num=接口数
tab.summary.interface-metric.delay-num=延迟响应数
tab.summary.interface-metric.normal-num=正常响应数
tab.summary.response-metric.avg-num=平均响应ms
tab.summary.response-metric.max-num=最大响应ms
tab.summary.response-metric.min-num=最小响应ms
tab.summary.sysusage-metric.cpu-usage=CPU使用率
tab.summary.sysusage-metric.heap-memory=堆内存
tab.summary.sysusage-metric.physical-memory=物理内存
tab.summary.sysusage-metric.cpu-usage.user-usage=用户使用率
tab.summary.sysusage-metric.cpu-usage.sys-usage=系统使用率
tab.summary.sysusage-metric.cpu-usage.io-waiting=IO 等待率
tab.summary.sysusage-metric.heap-memory.init=初始值
tab.summary.sysusage-metric.heap-memory.max=最大值
tab.summary.sysusage-metric.heap-memory.used=已使用
tab.summary.sysusage-metric.physical-memory.total=总物理内存
tab.summary.sysusage-metric.physical-memory.used=已使用内存
tab.summary.sysusage-metric.physical-memory.current-used=此程序占用
tab.interface.search-tip=搜索方法名或者类名...
tab.interface.interface-list.avg-tip=平均响应
tab.interface.interface-list.show-metric.type=类型
tab.interface.interface-list.show-metric.avg=平均耗时
tab.interface.interface-list.show-metric.max=最大耗时
tab.interface.interface-list.show-metric.min=最小耗时
tab.interface.interface-list.show-metric.exception-num=异常数目
tab.interface.interface-list.show-metric.exception-unit=
tab.interface.interface-list.show-metric.param-analyse=入参组合分析
tab.exception.exception-list.show-metric.class=异常类
tab.exception.exception-list.show-metric.method=异常方法
tab.exception.exception-list.show-metric.line=异常行
tab.exception.exception-list.show-metric.message=异常消息
tab.thread.thread-metric=线程统计
tab.thread.thread-list=线程列表
tab.thread.thread-list.cpu-usage=CPU使用率
tab.thread.thread-metric.all=ALL
tab.thread.thread-metric.runnable=RUNNABLE
tab.thread.thread-metric.blocked=BLOCKED
tab.thread.thread-metric.waiting=WAITING
tab.thread.thread-metric.time-waiting=TIME_WAITING
tab.hotupdate.class-file-input-tip=更新的类文件:编译过的.class文件
tab.hotupdate.class-file-null-tip=类文件不能为空
tab.hotupdate.class-name-input-tip=更新的类全名com.xx.xx.TestService
tab.hotupdate.class-name-null-tip=类名不能为空
tab.hotupdate.confirm-name=更新
tab.hotupdate.change-ok-tip=更新成功
tab.hotupdate.change-fail-tip=更新失败
tab.configuration.kotime-config=KoTime配置
tab.configuration.dynamic-config=dynamic.properties配置
tab.configuration.kotime-config.enable-kotime-tip=开启KoTime
tab.configuration.kotime-config.enable-exception-tip=开启异常检测
tab.configuration.kotime-config.enable-console-tip=开启控制台日志
tab.configuration.kotime-config.enable-email-tip=开启邮件通知
tab.configuration.kotime-config.select-language-tip=语言选择
tab.configuration.kotime-config.select-language-chinese=中文
tab.configuration.kotime-config.select-language-english=英文
tab.configuration.kotime-config.threshold-tip=方法运行时间阈值
tab.configuration.kotime-config.threshold-confirm=确认
tab.configuration.kotime-config.clear-data-tip=清空链路数据
tab.configuration.kotime-config.clear-data-confirm=确认
tab.configuration.kotime-config.change-ok-tip=设置成功
tab.configuration.kotime-config.change-fail-tip=更新失败
tab.configuration.bottom-tip=变更配置以后请重新刷新页面
tab.configuration.dynamic-config.confirm-name=更新
tab.configuration.dynamic-config.change-ok-tip=更新成功
tab.configuration.dynamic-config.change-fail-tip=更新失败,请正确编写配置!
tab.support.version-tip=点击查看版本发布信息
tab.support.support-tip=技术支持
tab.support.pro-tip=升级专业版
tab.support.plugin-tip=本地化插件

View File

@ -0,0 +1,103 @@
kotime-title=KoTime
kotime-confirm=OK
kotime-refresh=refresh
tab.summary=Summary
tab.interface=Interfaces
tab.exception=Exceptions
tab.thread=Threads
tab.hotupdate=Hot Update
tab.configuration=Configurations
tab.support=Tech Support
tab.summary.interface-metric=Number of Interface
tab.summary.response-metric=Response Time
tab.summary.sysusage-metric=System Usage
tab.summary.bottom-normal-tip=Please call apis before visiting this page!
tab.summary.bottom-close-tip=KoTime switch was closed!
tab.summary.interface-metric.total-num=Total
tab.summary.interface-metric.delay-num=Delayed
tab.summary.interface-metric.normal-num=Normal
tab.summary.response-metric.avg-num=Avgms
tab.summary.response-metric.max-num=Maxms
tab.summary.response-metric.min-num=Minms
tab.summary.sysusage-metric.cpu-usage=CPU Usage
tab.summary.sysusage-metric.heap-memory=Heap Memory
tab.summary.sysusage-metric.physical-memory=Physical Memory
tab.summary.sysusage-metric.cpu-usage.user-usage=User Usage
tab.summary.sysusage-metric.cpu-usage.sys-usage=System Usage
tab.summary.sysusage-metric.cpu-usage.io-waiting=IO Wait Rate
tab.summary.sysusage-metric.heap-memory.init=Init
tab.summary.sysusage-metric.heap-memory.max=Max
tab.summary.sysusage-metric.heap-memory.used=Used
tab.summary.sysusage-metric.physical-memory.total=Total
tab.summary.sysusage-metric.physical-memory.used=Used
tab.summary.sysusage-metric.physical-memory.current-used=ThisUsed
tab.interface.search-tip=search method name or class name...
tab.interface.interface-list.avg-tip=avg
tab.interface.interface-list.show-metric.type=type
tab.interface.interface-list.show-metric.avg=avg time
tab.interface.interface-list.show-metric.max=max time
tab.interface.interface-list.show-metric.min=min time
tab.interface.interface-list.show-metric.exception-num=number of exception
tab.interface.interface-list.show-metric.exception-unit=
tab.interface.interface-list.show-metric.param-analyse=Combination of parameters
tab.exception.exception-list.show-metric.class=Class
tab.exception.exception-list.show-metric.method=Method
tab.exception.exception-list.show-metric.line=Line
tab.exception.exception-list.show-metric.message=exception message
tab.thread.thread-metric=Number of Thread
tab.thread.thread-list=Thread List
tab.thread.thread-list.cpu-usage=CPU Usage
tab.thread.thread-metric.all=ALL
tab.thread.thread-metric.runnable=RUNNABLE
tab.thread.thread-metric.blocked=BLOCKED
tab.thread.thread-metric.waiting=WAITING
tab.thread.thread-metric.time-waiting=TIME_WAITING
tab.hotupdate.class-file-input-tip=class file needed to updatecompiled class file
tab.hotupdate.class-file-null-tip=Null file
tab.hotupdate.class-name-input-tip=class name needed to update com.xx.xx.TestService
tab.hotupdate.class-name-null-tip=Null class name
tab.hotupdate.confirm-name=Update
tab.hotupdate.change-ok-tip=OK
tab.hotupdate.change-fail-tip=FAIL
tab.configuration.kotime-config=KoTime Configure
tab.configuration.dynamic-config=dynamic.properties Configure
tab.configuration.kotime-config.enable-kotime-tip=KoTime switch
tab.configuration.kotime-config.enable-exception-tip=exception switch
tab.configuration.kotime-config.enable-console-tip=console log switch
tab.configuration.kotime-config.enable-email-tip=email switch
tab.configuration.kotime-config.select-language-tip=language switch
tab.configuration.kotime-config.select-language-chinese=Chinese
tab.configuration.kotime-config.select-language-english=English
tab.configuration.kotime-config.threshold-tip=time threshold
tab.configuration.kotime-config.threshold-confirm=OK
tab.configuration.kotime-config.clear-data-tip=clear data
tab.configuration.kotime-config.clear-data-confirm=OK
tab.configuration.kotime-config.change-ok-tip=OK
tab.configuration.kotime-config.change-fail-tip=FAIL
tab.configuration.bottom-tip=Please refresh this page after updating configurations
tab.configuration.dynamic-config.confirm-name=Update
tab.configuration.dynamic-config.change-ok-tip=OK
tab.configuration.dynamic-config.change-fail-tip=FAIL
tab.support.version-tip=show versions
tab.support.support-tip=Tech Support
tab.support.pro-tip=KoTime Pro
tab.support.plugin-tip=Local Plugin

View File

@ -0,0 +1,64 @@
function getSize(size) {
let sizes = [' Bytes', ' KB', ' MB', ' GB',
' TB', ' PB', ' EB', ' ZB', ' YB'];
for (let i = 1; i < sizes.length; i++) {
if (size < Math.pow(1024, i))
return (Math.round((size / Math.pow(1024, i - 1)) * 100) / 100) + sizes[i - 1];
}
return size;
}
function getDom(id){
return document.getElementById(id)
}
function post(url,data,successfun,errorFun) {
fetch(url, {
method: 'post',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
}).then(response => response.json())
.then(json => {
successfun(json);
}).catch(e => {
if (errorFun) {
errorFun(e);
}
});
}
function postFormData(url,data,successfun,errorFun) {
fetch(url, {
method: 'post',
body: data
}).then(response => response.json())
.then(json => {
successfun(json);
}).catch(e => {
if (errorFun) {
errorFun(e);
}
});
}
function get(url,fun) {
fetch(url).then(response => response.json())
.then(json => {
fun(json)
}).catch(e => {
console.error(e)
})
}
function noticeSuccess(message){
UIkit.notification.closeAll();
UIkit.notification("<font color='green'>"+message+"</font>", {});
}
function noticeError(message){
UIkit.notification.closeAll();
UIkit.notification("<font color='red'>"+message+"</font>", {});
}

View File

@ -1,992 +0,0 @@
<head>
<meta charset="UTF-8">
<title>KoTime</title>
<!-- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.2.2/dist/css/uikit.min.css"/>-->
<!-- UIkit JS -->
<!-- <script src="https://cdn.jsdelivr.net/npm/uikit@3.2.2/dist/js/uikit.min.js"></script>-->
<!-- <script src="https://cdn.jsdelivr.net/npm/uikit@3.2.2/dist/js/uikit-icons.min.js"></script>-->
<style>
UIKitCss
</style>
<script>
UIKitJs;
uiKitIconsJs;
MetricFlowJs;
jQueryJs;
var graph;
var d = 180;
var globalThreshold = globalThresholdValue;
var globalNeedLogin = globalNeedLoginValue;
var staticTokenVisit = staticTokenVisitValue;
var staticToken = staticTokenValue;
var globalToken = staticTokenVisit?staticToken:sessionStorage.getItem("kotimeToken");
var globalToken = sessionStorage.getItem("kotimeToken");
let globalIsLogin = false;
function concatToken(url) {
if (globalNeedLogin) {
if (url.indexOf('?')>-1) {
url += '&kotoken='+globalToken;
}else {
url += '?kotoken='+globalToken;
}
}
return url
}
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(concatToken('contextPath/koTime/getParamGraph'+"?methodId="+clickNodeId.replace('node','')), 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(concatToken('contextPath/koTime/getTree?methodName=' + name), 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(concatToken('contextPath/koTime/getMethodsByExceptionId?exceptionId=' + id+'&message='+message), 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'>Error username or password</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'>Logined</font>",{});
UIkit.notification.closeAll()
sessionStorage.setItem("kotimeToken", re["token"]);
location.reload();
}else {
UIkit.notification("<font color='red'>Error username or password</font>",{});
}
},
error:function (re) {
console.log(re)
}
});
}
function searchTip(e){
let question = $('#searchText').val()
$.get(concatToken('contextPath/koTime/getApiTips?question='+question), function (data) {
$("#condidates").html("")
for (let i = 0; i < data.length; i++) {
let name = data[i];
$("#condidates").append('<option value="'+name+'"/>');
};
});
}
function searchApis(e) {
if (e.keyCode == 13) {
let question = $('#searchText').val()
$.get(concatToken('contextPath/koTime/getApis?question='+question), function (data) {
let element = document.getElementById('apiList');
html = '';
for (let i = 0; i < data.length; i++) {
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('"+apiId+"')\" style='color: #333;font-weight: 400;font-size: 14px;' id=\""+apiId+"-list\">"+ className+"#<span style='font-size: 16px;font-weight: 500;'>"+methodName+"</span>&nbsp(<span style='font-size: 14px;font-weight: 430;color:#032b11'>"+routeName+"</span>)&nbsp &nbsp<span style='font-size: 10px;text-transform: lowercase' class=\"uk-label uk-label-"+color+"\">avg "+avgRunTime+" ms</span></li>";
}else{
html += "<li onclick=\"showMethods('"+apiId+"')\" style='color: #333;font-weight: 400;font-size: 14px;' id=\""+apiId+"-list\">"+ className+"#<span style='font-size: 16px;font-weight: 500;'>"+methodName+"</span>&nbsp &nbsp<span style='font-size: 10px;text-transform: lowercase' class=\"uk-label uk-label-"+color+"\">avg "+avgRunTime+" ms</span></li>";
}
};
element.innerHTML = html;
});
$('#searchText').val('');
}
}
function updateClass(){
// document.querySelector("#classForm").submit();
var formData = new FormData();
var file = document.querySelector('#classFile').files[0];
if (file==null || file==undefined) {
UIkit.notification("<font color='red'>Null file</font>",{});
return;
}
var className = document.querySelector("#className").value
if (className==null || className==undefined || className.length<2) {
UIkit.notification("<font color='red'>Null class name</font>",{});
return;
}
formData.append('classFile', file);
formData.append('className', className );
$.ajax({
url: concatToken('contextPath/koTime/updateClass'),
type: 'POST',
cache: false,
data: formData,
processData: false,
contentType: false,
dataType: "json",
success: function (res) {
if (res['state']==1) {
UIkit.notification.closeAll();
UIkit.notification("<font color='green'>Success</font>",{});
}else {
UIkit.notification.closeAll();
UIkit.notification("<font color='red'>"+res['message']+"</font>",{});
}
},
error: function (XmlHttpRequest, textStatus, errorThrown) {
UIkit.notification.closeAll();
UIkit.notification("<font color='red'>Fail</font>",{});
location.reload();
},
complete: function () {}
})
}
function updateDynamicProperties(){
let propertiesDom = document.querySelector("#dynamicText");
let propertiesText = propertiesDom.value;
if (propertiesText && propertiesText.indexOf("=")>0) {
$.ajax({
type:'POST',
url:concatToken('contextPath/koTime/updateDynamicProperties'),
data:JSON.stringify({
text:propertiesText
}),
dataType:'json',
headers: {
'Content-Type': 'application/json'
},
success:function (re) {
UIkit.notification.closeAll();
UIkit.notification("<font color='green'>更新成功</font>",{});
}
});
}else {
UIkit.notification.closeAll();
UIkit.notification("<font color='red'>更新失败,请正确编写配置!</font>",{});
}
}
function loadDynamicProperties() {
$.get(concatToken('contextPath/koTime/getDynamicProperties'), function (data) {
let text = data['data'];
document.querySelector("#dynamicText").value = text;
});
}
function loadLatestVersion(){
/*get the latest version so that you can update kotime immediately*/
$.ajax({
url: 'http://www.kotime.cn/common/latestVersion?version=2.3.7',
type: 'GET',
cache: false,
dataType: "json",
async: true,
success: function (res) {
if (res['state']==1) {
document.querySelector("#version-notice").innerHTML=res['content']['versionNo']
}
},
error: function (XmlHttpRequest, textStatus, errorThrown) {
},
complete: function () {}
})
}
function loadCpuInfo() {
$.get(concatToken('contextPath/koTime/getCpuInfo'), function (data) {
let systemLoad = data['systemLoad']*100;
let userRate = data['userRate']*100;
let sysRate = data['sysRate']*100;
let logicalNum = data['logicalNum'];
let waitRate = data['waitRate']*100;
var systemLoadDom = document.querySelector("#systemLoad");
if (systemLoad>50) {
systemLoadDom.style.color='#cc0c0c';
}else {
systemLoadDom.style.color='#29da93';
};
systemLoadDom.innerHTML = `${systemLoad.toFixed(2)}%`;
document.querySelector("#cpuSysRate").innerHTML = `${sysRate.toFixed(2)}%`;
document.querySelector("#cpuUserRate").innerHTML = `${userRate.toFixed(2)}%`;
document.querySelector("#cpuWaitRate").innerHTML = `${waitRate.toFixed(2)}%`;
document.querySelector("#cpuLogicalAmount").innerHTML = `CPU Usage(${logicalNum})`;
});
}
function loadHeapMemoryInfo() {
$.get(concatToken('contextPath/koTime/getHeapMemoryInfo'), function (data) {
let initValue = data['initValue']/1024/1024;
let maxValue = data['maxValue']/1024/1024;
let usedValue = data['usedValue']/1024/1024;
let usedRate = data['usedRate']*100;
var heapUsedRateDom = document.querySelector("#heapUsedRate");
if (usedRate>50) {
heapUsedRateDom.style.color='#cc0c0c';
}else {
heapUsedRateDom.style.color='#29da93';
};
document.querySelector("#heapInit").innerHTML = `${initValue.toFixed()}M`;
document.querySelector("#heapMax").innerHTML = `${maxValue.toFixed()}M`;
document.querySelector("#heapUsed").innerHTML = `${usedValue.toFixed()}M`;
heapUsedRateDom.innerHTML = `${usedRate.toFixed(2)}%`;
});
}
function loadPhysicalMemoryInfo() {
$.get(concatToken('contextPath/koTime/getPhysicalMemoryInfo'), function (data) {
let initValue = data['initValue']/1024/1024;
let thisUsedValue = data['thisUsedValue']/1024/1024;
let usedValue = data['usedValue']/1024/1024;
let usedRate = data['usedRate']*100;
var physicalUsedRateDom = document.querySelector("#physicalUsedRate");
if (usedRate>50) {
physicalUsedRateDom.style.color='#cc0c0c';
}else {
physicalUsedRateDom.style.color='#29da93';
};
physicalUsedRateDom.innerHTML = `${usedRate.toFixed(2)}%`;
document.querySelector("#physicalAmount").innerHTML = `${initValue.toFixed()}M`;
document.querySelector("#physicalUsed").innerHTML = `${usedValue.toFixed()}M`;
document.querySelector("#thisUsed").innerHTML = `${thisUsedValue.toFixed()}M`;
});
}
function loadConfig() {
$.get(concatToken('contextPath/koTime/getConfig'), function (data) {
let versionNoticeEnable = data['versionNotice'];
if (versionNoticeEnable) {
loadLatestVersion();
}
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?"We can see interfaces after invoking methods!":"KoTime switch was closed!";
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 mailEnable = data['mailEnable'];
let mailEnableDom = document.getElementById('mailEnable');
mailEnableDom.checked = mailEnable;
let language = data['language'];
$("#languageSwitch").val(language)
});
}
function addConfigEvent() {
document.getElementById('kotimeEnable').onclick = function(){
$.ajax({type:'POST',url:concatToken('contextPath/koTime/updateConfig'),data:JSON.stringify({enable:document.getElementById('kotimeEnable').checked}),dataType:'json', headers: {'Content-Type': 'application/json' }});
UIkit.notification("<font color='green'>OK</font>",{});
};
document.getElementById('exceptionEnable').onclick = function(){
$.ajax({type:'POST',url:concatToken('contextPath/koTime/updateConfig'),data:JSON.stringify({exceptionEnable:document.getElementById('exceptionEnable').checked}),dataType:'json', headers: {'Content-Type': 'application/json' }});
UIkit.notification("<font color='green'>OK</font>",{});
};
document.getElementById('logEnable').onclick = function(){
$.ajax({type:'POST',url:concatToken('contextPath/koTime/updateConfig'),data:JSON.stringify({logEnable:document.getElementById('logEnable').checked}),dataType:'json', headers: {'Content-Type': 'application/json' }});
UIkit.notification("<font color='green'>OK</font>",{});
};
document.getElementById('mailEnable').onclick = function(){
$.ajax({type:'POST',url:concatToken('contextPath/koTime/updateConfig'),data:JSON.stringify({mailEnable:document.getElementById('mailEnable').checked}),dataType:'json', headers: {'Content-Type': 'application/json' }});
UIkit.notification("<font color='green'>OK</font>",{});
};
document.getElementById('languageSwitch').onchange = function(){
let selectedObj = document.getElementById('languageSwitch');
$.ajax({type:'POST',url:concatToken('contextPath/koTime/updateConfig'),data:JSON.stringify({language:selectedObj.options[selectedObj.selectedIndex].value}),dataType:'json', headers: {'Content-Type': 'application/json' }});
UIkit.notification("<font color='green'>OK</font>",{});
};
document.getElementById("timeThresholdYes").onclick = function(){
$.ajax({type:'POST',url:concatToken('contextPath/koTime/updateConfig'),data:JSON.stringify({threshold:document.getElementById('timeThreshold').value}),dataType:'json', headers: {'Content-Type': 'application/json' }});
UIkit.notification("<font color='green'>OK</font>",{});
};
document.getElementById("clearDataYes").onclick = function(){
$.ajax({type:'POST',url:'contextPath/koTime/clearData?kotoken='+globalToken,dataType:'json', headers: {'Content-Type': 'application/json' }});
UIkit.notification("<font color='green'>OK</font>",{});
};
}
function loadStatistic() {
$.get(concatToken('contextPath/koTime/getStatistic'), 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;
let avgRunTime = data['avgRunTime'];
let systemAvgRunTime = document.getElementById("systemAvgRunTime");
systemAvgRunTime.innerHTML=avgRunTime;
if (avgRunTime>globalThreshold) {
document.getElementById("systemAvgRunTime").style.color='#cc0c0c';
}else {
document.getElementById("systemAvgRunTime").style.color='#29da93';
};
let maxRunTime = data['maxRunTime'];
let systemMaxRunTime = document.getElementById("systemMaxRunTime");
systemMaxRunTime.innerHTML=maxRunTime;
if (maxRunTime>globalThreshold) {
document.getElementById("systemMaxRunTime").style.color='#cc0c0c';
}else {
document.getElementById("systemMaxRunTime").style.color='#29da93';
};
let minRunTime = data['minRunTime'];
let systemMinRunTime = document.getElementById("systemMinRunTime");
systemMinRunTime.innerHTML=minRunTime;
if (minRunTime>globalThreshold) {
document.getElementById("systemMinRunTime").style.color='#cc0c0c';
}else {
document.getElementById("systemMinRunTime").style.color='#29da93';
};
});
}
function loadApis() {
let searchText = $("#searchText").val();
$.get(concatToken('contextPath/koTime/getApis?question='+searchText), function (data) {
let element = document.getElementById('apiList');
html = '';
for (let i = 0; i < data.length; i++) {
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('"+apiId+"')\" style='color: #333;font-weight: 400;font-size: 14px;' id=\""+apiId+"-list\">"+ className+"#<span style='font-size: 16px;font-weight: 500;'>"+methodName+"</span>&nbsp(<span style='font-size: 14px;font-weight: 430;color:#032b11'>"+routeName+"</span>)&nbsp &nbsp<span style='font-size: 10px;text-transform: lowercase' class=\"uk-label uk-label-"+color+"\">avg "+avgRunTime+" ms</span></li>";
}else{
html += "<li onclick=\"showMethods('"+apiId+"')\" style='color: #333;font-weight: 400;font-size: 14px;' id=\""+apiId+"-list\">"+ className+"#<span style='font-size: 16px;font-weight: 500;'>"+methodName+"</span>&nbsp &nbsp<span style='font-size: 10px;text-transform: lowercase' class=\"uk-label uk-label-"+color+"\">avg "+avgRunTime+" ms</span></li>";
}
};
element.innerHTML = html;
});
}
function loadExceptions() {
$.get(concatToken('contextPath/koTime/getExceptions'), 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>&nbsp &nbsp<span style='font-size: 10px;' class=\"uk-label uk-label-danger\">"+message+"</span></li>";
};
element.innerHTML = html;
});
}
function refreshData() {
$.get(concatToken('contextPath/koTime/isLogin'), function (data) {
globalIsLogin = data['isLogin']==1?true:false;
if (globalNeedLogin==true && globalIsLogin == false) {
UIkit.modal(document.getElementById("modal-login")).show();
return;
}else {
loadStatistic();
loadConfig();
addConfigEvent();
loadApis();
loadExceptions();
loadCpuInfo();
loadHeapMemoryInfo();
loadPhysicalMemoryInfo();
loadThreadsInfo();
loadDynamicProperties();
}
});
}
const cpuUsageColorMap = {
'RED': '#cc0c0c',
'YELLOW': '#f0ad4e',
'LIGHT_BLUE': '#5bc0de'
};
function getCpuUsageColor(usage) {
if (usage > 50) {
return cpuUsageColorMap['RED'];
} else if (usage >= 20 && usage <= 50) {
return cpuUsageColorMap['YELLOW'];
} else {
return cpuUsageColorMap['LIGHT_BLUE'];
}
}
let threadMap = new Map();
function loadThreadsInfo(queryState) {
queryState = queryState || '';
$.get(concatToken('contextPath/koTime/getThreadsInfo?state='+queryState), function (data) {
let statistics = data['statistics'];
let all = statistics['all'];
let RUNNABLE = statistics['RUNNABLE'] || 0;
let BLOCKED = statistics['BLOCKED'] || 0;
let WAITING = statistics['WAITING'] || 0;
let TIMED_WAITING = statistics['TIMED_WAITING'] || 0;
document.querySelector("#threadNum").innerHTML = all;
document.querySelector("#runnableNum").innerHTML = RUNNABLE;
document.querySelector("#blockedNum").innerHTML = BLOCKED;
document.querySelector("#waitingNum").innerHTML = WAITING;
document.querySelector("#timedWaitingNum").innerHTML = TIMED_WAITING;
let element = document.getElementById('threadList');
let html = '';
let threads = data['threads'];
let colors = {
'RUNNABLE':'#32d296',
'BLOCKED':'#cc0c0c',
'WAITING':'#ad7070',
'TIMED_WAITING':'#ad7070'
}
for (let i = 0; i < threads.length; i++) {
let thread = threads[i];
let id = thread['id'];
let name = thread['name'];
let classType = thread['classType'];
let state = thread['state'];
let stacks = thread['stacks'];
let cpuUsage = thread['cpuUsage'];
let cpuUsageColor = getCpuUsageColor(cpuUsage);
threadMap[id+''] = stacks;
html+=`<li onclick="showThreadInfo('${id}')" style='color: #333;font-weight: 400;font-size: 14px;'>id=<span style="font-size: 16px;font-weight: 500;">${id}</span>&nbsp; &nbsp;name=${name}&nbsp; &nbsp;class=${classType}&nbsp; &nbsp;<span style="font-size: 10px;background-color: ${cpuUsageColor};" class="uk-label uk-label-success">CPU-UsagePercent:${cpuUsage}%</span>&nbsp; &nbsp;<span style='font-size: 10px;background-color: ${colors[state]};' class="uk-label uk-label-success">${state}</span></li>`;
}
element.innerHTML = html;
});
}
function showThreadInfo(id) {
let stacks = threadMap[id];
let html = '';
for (let i = 0; i < stacks.length; i++) {
let stack = stacks[i];
let className = stack['className']
let methodName = stack['methodName']
let fileName = stack['fileName']
let lineNumber = stack['lineNumber']
html+=`<li style='color: #333;font-weight: 400;font-size: 14px;'>${className}.${methodName}&nbsp; &nbsp;<span style='font-size: 10px;background-color: darkslategray;text-transform: unset' class="uk-label uk-label-success">${fileName}${lineNumber}</span></li>`;
}
let threadDetailDom = document.getElementById('thread-detail');
threadDetailDom.innerHTML = html;
UIkit.notification.closeAll();
UIkit.modal(document.getElementById("modal-thread")).show();
}
$(document).ready(function () {
refreshData();
});
</script>
</head>
<!--endreplace-->
<body style="background-color: #f2f3f2" >
<nav class="uk-navbar-container" style="background-color: #404b67;height: 85px" uk-navbar>
<div class="uk-navbar-center">
<div class="uk-grid-small" uk-grid>
<div onclick="refreshData()" style="margin-top: 20px;font-size: 24px;color: white;cursor: pointer" class="uk-width-expand" >KoTime</div>
</div>
</div>
</nav>
<ul class="uk-flex-center" uk-tab style="background-color: #404b67;margin-top: 0px;">
<li id="zl" class="uk-active"><a href="#" style="color: #edeef1;font-size: 14px;text-transform: capitalize">Summary</a></li>
<li id="jklb"><a href="#" style="color: #edeef1;font-size: 14px;text-transform: capitalize">Interfaces</a></li>
<li><a href="#" style="color: #edeef1;font-size: 14px;text-transform: capitalize">Exceptions</a></li>
<li><a href="#" style="color: #edeef1;font-size: 14px;text-transform: capitalize">Threads</a></li>
<li><a href="#" style="color: #edeef1;font-size: 14px;text-transform: capitalize">Hot update</a></li>
<li><a href="#" style="color: #edeef1;font-size: 14px;text-transform: capitalize">Configurations</a></li>
<li><a href="#" style="color: #edeef1;font-size: 14px;text-transform: capitalize">Contact me</a><span title="Latest release" style="position: absolute;top:-10px;left: 90%;border-radius: 5px;text-transform: unset" class="uk-label" id="version-notice" onclick="window.location.href='http://www.kotime.cn/docs/kaiyuan#/v220/introduce'"></span></li>
</ul>
<ul class="uk-switcher uk-margin">
<li style="margin-left: 30%;margin-right: 30%;">
<ul class="uk-flex-left" uk-tab>
<li class="uk-active"><a href="#" style="text-transform: capitalize" >Number of Interface</a></li>
</ul>
<div style="margin-top: 20px;" class="uk-grid-small uk-child-width-expand@s uk-text-center" uk-grid>
<div>
<div id="systemTotalNum-div" style="border-radius: 10px;background-color: #fefffe;padding: 20px"
className="uk-card uk-card-default uk-card-body uk-label-success">
<span style="font-size: 10px;color: #3b3f4f">All</span><br>
<span style="font-size: 30px;color: #020718;font-weight: bold" id="systemTotalNum">0</span>
</div>
</div>
<div>
<div id="systemDelayNum-div" style="border-radius: 10px;background-color: #fefffe;padding: 20px"
className="uk-card uk-card-default uk-card-body uk-label-success">
<span style="font-size: 10px;color: #3b3f4f">Delayed</span>
<br>
<span style="font-size: 30px;color: #cc0c0c;font-weight: bold" id="systemDelayNum">0</span></div>
</div>
<div>
<div id="systemNormalNum-div" style="border-radius: 10px;background-color: #fefffe;padding: 20px"
className="uk-card uk-card-default uk-card-body uk-label-success">
<span style="font-size: 10px;color: #3b3f4f">Normal</span>
<br>
<span style="font-size: 30px;color: #29da93;font-weight: bold" id="systemNormalNum">0</span></div>
</div>
</div>
<ul style="margin-top: 10px;" class="uk-flex-left" uk-tab>
<li class="uk-active"><a href="#" style="text-transform: capitalize">Response Time</a></li>
</ul>
<div style="margin-top: 10px;" class="uk-grid-small uk-child-width-expand@s uk-text-center" uk-grid>
<div>
<div id="systemAvgRunTime-div" style="border-radius: 10px;background-color: #fefffe;padding: 20px"
className="uk-card uk-card-default uk-card-body uk-label-success">
<span style="font-size: 10px;color: #3b3f4f">Avgms</span>
<br>
<span style="font-size: 30px;color: #020718;font-weight: bold" id="systemAvgRunTime">0</span></div>
</div>
<div>
<div id="systemMaxRunTime-div" style="border-radius: 10px;background-color: #fefffe;padding: 20px"
className="uk-card uk-card-default uk-card-body uk-label-success">
<span style="font-size: 10px;color: #3b3f4f">Maxms</span>
<br>
<span style="font-size: 30px;color: #020718;font-weight: bold" id="systemMaxRunTime">0</span></div>
</div>
<div>
<div id="systemMinRunTime-div" style="border-radius: 10px;background-color: #fefffe;padding: 20px"
className="uk-card uk-card-default uk-card-body uk-label-success">
<span style="font-size: 10px;color: #3b3f4f">Minms</span>
<br>
<span style="font-size: 30px;color: #020718;font-weight: bold" id="systemMinRunTime">0</span></div>
</div>
</div>
<ul class="uk-flex-left" uk-tab>
<li class="uk-active"><a href="#" style="text-transform: capitalize">System Usage</a></li>
</ul>
<div style="margin-top: 20px;" class="uk-grid-small uk-child-width-expand@s uk-text-center" uk-grid>
<div>
<div id="cpuInfo-div" style="border-radius: 10px;background-color: #fefffe;padding: 20px" class="uk-card uk-card-default uk-card-body uk-label-success">
<span style="font-size: 12px;color: #3b3f4f;justify-content: space-around;text-transform: unset" id="cpuLogicalAmount">CPU Usage</span><span style="font-size: 15px;color: #020718;font-weight: bold" id="systemLoad" >0</span>
<hr style="margin-top: 7px">
<ul class="uk-list-bullet" style="text-align: left;margin-top: -13px">
<li style="margin-top: -2px;"><span style="font-size: 8px;color: #3b3f4f;text-transform: unset">User Usage</span><span style="font-size: 12px;color: #020718;font-weight: bold" id="cpuUserRate" >0</span></li>
<li style="margin-top: -2px;"><span style="font-size: 8px;color: #3b3f4f;text-transform: unset">System Usage</span><span style="font-size: 12px;color: #020718;font-weight: bold" id="cpuSysRate" >0</span></li>
<li style="margin-top: -2px;"><span style="font-size: 8px;color: #3b3f4f;text-transform: unset">IO Wait Rate</span><span style="font-size: 12px;color: #020718;font-weight: bold" id="cpuWaitRate" >0</span></li>
</ul>
</div>
</div>
<div>
<div id="heapMemory-div" style="border-radius: 10px;background-color: #fefffe;padding: 20px" class="uk-card uk-card-default uk-card-body uk-label-success">
<span style="font-size: 12px;color: #3b3f4f;justify-content: space-around;text-transform: unset">Heap Memory</span><span style="font-size: 15px;color: #020718;font-weight: bold" id="heapUsedRate" >0</span>
<hr style="margin-top: 7px">
<ul class="uk-list-bullet" style="text-align: left;margin-top: -13px">
<li style="margin-top: -2px;"><span style="font-size: 8px;color: #3b3f4f;text-transform: unset">Init</span><span style="font-size: 12px;color: #020718;font-weight: bold" id="heapInit" >0</span></li>
<li style="margin-top: -2px;"><span style="font-size: 8px;color: #3b3f4f;text-transform: unset">Max</span><span style="font-size: 12px;color: #020718;font-weight: bold" id="heapMax" >0</span></li>
<li style="margin-top: -2px;"><span style="font-size: 8px;color: #3b3f4f;text-transform: unset">Used</span><span style="font-size: 12px;color: #020718;font-weight: bold" id="heapUsed" >0</span></li>
</ul>
</div>
</div>
<div>
<div id="physicalMemory-div" style="border-radius: 10px;background-color: #fefffe;padding: 20px" class="uk-card uk-card-default uk-card-body uk-label-success">
<span style="font-size: 12px;color: #3b3f4f;justify-content: space-around;text-transform: unset">Physical Memory</span><span style="font-size: 15px;color: #020718;font-weight: bold" id="physicalUsedRate" >0</span>
<hr style="margin-top: 7px">
<ul class="uk-list-bullet" style="text-align: left;margin-top: -13px">
<li style="margin-top: -2px;"><span style="font-size: 8px;color: #3b3f4f;text-transform: unset">All</span><span style="font-size: 12px;color: #020718;font-weight: bold" id="physicalAmount" >0</span></li>
<li style="margin-top: -2px;"><span style="font-size: 8px;color: #3b3f4f;text-transform: unset">Used</span><span style="font-size: 12px;color: #020718;font-weight: bold" id="physicalUsed" >0</span></li>
<li style="margin-top: -2px;"><span style="font-size: 8px;color: #3b3f4f;text-transform: unset">ThisUsed</span><span style="font-size: 12px;color: #020718;font-weight: bold" id="thisUsed" >0</span></li>
</ul>
</div>
</div>
</div>
<div class="uk-alert-success" uk-alert>
<a class="uk-alert-close" uk-close></a>
<p id="apiTip">Please call apis before visiting this page!</p>
</div>
</li>
<li style="margin-left: 20%;margin-right: 20%;">
<div style="left: 35%;width: 350px;" class="uk-search uk-search-default">
<span uk-search-icon></span>
<input list="condidates" id="searchText" style="border-top: none;border-right: none;border-left: none;border-bottom: 1px solid lightgreen;color:#213121" class="uk-search-input" type="search" placeholder="search method name or class name..." oninput="searchTip(event);" onkeydown="searchApis(event);">
<datalist id="condidates" onkeydown="searchApis(event);">
</datalist>
</div>
<ul id="apiList" style="background-color: rgba(245,242,242,0.96);padding: 10px;overflow-y: auto;max-height: 70%" class="uk-list uk-list-divider">
<li>method 1 1&nbsp<span class="uk-label uk-label-success">0</span></li>
</ul>
</li>
<li style="margin-left: 20%;margin-right: 20%;">
<ul id="exceptionList" style="background-color: rgba(245,242,242,0.96);padding: 10px;overflow-y: auto;max-height: 73%" class="uk-list uk-list-divider">
<li>exception 1 1&nbsp<span class="uk-label uk-label-danger">closed</span></li>
</ul>
</li>
<li style="margin-left: 30%;margin-right: 30%;">
<ul class="uk-flex-left" uk-tab>
<li class="uk-active"><a href="#" style="text-transform: capitalize">Number of thread</a></li>
</ul>
<div style="margin-top: 20px;" class="uk-grid-small uk-child-width-expand@s uk-text-center" uk-grid>
<div>
<div onclick="loadThreadsInfo('')" id="threadNum-div" style="cursor:pointer;border-radius: 10px;background-color: #fefffe;padding: 20px" class="uk-card uk-card-default uk-card-body uk-label-success">
<span style="font-size: 10px;color: #3b3f4f">ALL</span><br>
<span style="font-size: 30px;color: #020718;font-weight: bold" id="threadNum" >0</span>
</div>
</div>
<div>
<div onclick="loadThreadsInfo('RUNNABLE')" id="runnableNum-div" style="cursor:pointer;border-radius: 10px;background-color: #fefffe;padding: 20px" class="uk-card uk-card-default uk-card-body uk-label-success">
<span style="font-size: 10px;color: #3b3f4f">RUNNABLE</span>
<br>
<span style="font-size: 30px;color: #29da93;font-weight: bold" id="runnableNum">0</span>
</div>
</div>
<div>
<div onclick="loadThreadsInfo('BLOCKED')" id="blockedNum-div" style="cursor:pointer;border-radius: 10px;background-color: #fefffe;padding: 20px" class="uk-card uk-card-default uk-card-body uk-label-success">
<span style="font-size: 10px;color: #3b3f4f">BLOCKED</span>
<br>
<span style="font-size: 30px;color: #cc0c0c;font-weight: bold" id="blockedNum">0</span></div>
</div>
<div>
<div onclick="loadThreadsInfo('WAITING')" id="waitingNum-div" style="cursor:pointer;border-radius: 10px;background-color: #fefffe;padding: 20px" class="uk-card uk-card-default uk-card-body uk-label-success">
<span style="font-size: 10px;color: #3b3f4f">WAITING</span>
<br>
<span style="font-size: 30px;color: #ad7070;font-weight: bold" id="waitingNum">0</span></div>
</div>
<div>
<div onclick="loadThreadsInfo('TIMED_WAITING')" id="timedWaitingNum-div" style="cursor:pointer;border-radius: 10px;background-color: #fefffe;padding: 20px" class="uk-card uk-card-default uk-card-body uk-label-success">
<span style="font-size: 10px;color: #3b3f4f">TIMED_WAITING</span>
<br>
<span style="font-size: 30px;color: #ad7070;font-weight: bold" id="timedWaitingNum">0</span></div>
</div>
</div>
<ul class="uk-flex-left" uk-tab>
<li class="uk-active"><a href="#" style="text-transform: capitalize">Threads</a></li>
</ul>
<ul id="threadList" style="background-color: rgba(245,242,242,0.96);padding: 10px;overflow-y: auto;max-height: 65%" class="uk-list uk-list-divider">
<li>thread 1 1&nbsp<span class="uk-label uk-label-success">0</span></li>
</ul>
</li>
<li style="margin-left: 35%;margin-right: 35%;">
<div class="uk-card uk-card-default uk-card-body">
<div id="classForm" >
<div uk-form-custom="target: true" class="uk-form-controls">
<input id="classFile" name="classFile" type="file" >
<input id="form-file" style="width: 500px;border-radius: 5px" class="uk-input" type="text" placeholder="class file needed to updatecompiled class file" >
</div>
<br>
<br>
<input id="className" name="className" style="width: 500px;border-radius: 5px" class="uk-input" id="" type="text" placeholder="class name needed to update com.xx.xx.TestService" >
<br>
<br>
<button type="button" onclick="updateClass();" style="width: 500px;background-color: #19985d;border-radius: 5px" class="uk-button uk-button-primary uk-width-1-1 uk-margin-small-bottom">OK</button>
</div>
</div>
</li>
<li style="margin-left: 30%;margin-right: 30%;">
<ul class="uk-flex-left" uk-tab>
<li class="uk-active"><a href="#" style="text-transform: unset">KoTime Configuration</a></li>
<li class=""><a href="#" style="text-transform: unset">dynamic.properties Configuration</a></li>
</ul>
<ul class="uk-switcher uk-margin">
<li>
<div style="margin-top: 20px;" class="uk-grid-small uk-child-width-expand@s uk-text-left uk-card uk-card-default uk-card-body" style="border-radius: 5px" uk-grid>
<div class="layui-tab-item">
<label >KoTime switch</label> <input id='kotimeEnable' type="checkbox" checked>
<br>
<label >exception switch</label> <input id='exceptionEnable' type="checkbox">
<br>
<label >console log switch</label> <input id='logEnable' type="checkbox">
<br>
<label >email switch</label> <input id='mailEnable' type="checkbox">
<br>
<label>language switch</label>
<select id="languageSwitch" >
<option value="chinese">Chinese</option>
<option value="english">English</option>
</select>
<br>
<label >time threshold</label> <input id='timeThreshold' type="input"><button style="background-color: #177ce1;border: 1px solid #177ce1;cursor: pointer;color: white" id="timeThresholdYes">OK</button>
<br>
<label >clear data</label><button style="background-color: #177ce1;border: 1px solid #177ce1;cursor: pointer;color: white" id="clearDataYes">OK</button>
<br>
<br>
<br>
<div class="uk-alert-success" uk-alert>
<a class="uk-alert-close" uk-close></a>
<p>Please refresh this page after updating configurations</p>
</div>
</div>
</div>
</li>
<li>
<div class="uk-card uk-card-default uk-card-body" style="border-radius: 5px">
<textarea id="dynamicText" class="uk-textarea" placeholder="" wrap="off" style="overflow-y: auto;height: 65%;resize: none;overflow-x: auto;"></textarea>
<br>
<br>
<button type="button" onclick="updateDynamicProperties();" style="width: 100%;background-color: #19985d;border-radius: 5px" class="uk-button uk-button-primary uk-width-1-1 uk-margin-small-bottom">OK</button>
</div>
</li>
</ul>
</li>
<li style="margin-left: 30%;margin-right: 30%;">
<script src='https://gitee.com/huoyo/ko-time/widget_preview' async defer></script>
<div id="osc-gitee-widget-tag"></div>
<style>
.osc_pro_color {color: #ffffff !important;}
.osc_panel_color {background-color: #1e252b !important;}
.osc_background_color {background-color: #323d47 !important;}
.osc_border_color {border-color: #455059 !important;}
.osc_desc_color {color: #d7deea !important;}
.osc_link_color * {color: #99a0ae !important;}
</style>
<br>
<div class="uk-alert-success" uk-alert>
<a class="uk-alert-close" uk-close></a>
<a href="http://www.kotime.cn/#doc?version=v2.3.7">Technical support</a><br>
<a href="http://www.kotime.cn/#products?version=v2.3.7">KoTime Pro</a><br>
<a href="http://www.kotime.cn/person?version=v2.3.7">Local plugin</a></div>
</li>
</ul>
<div id="modal-thread" uk-modal>
<div class="uk-modal-dialog" style="width: 75%">
<button class="uk-modal-close-default" type="button" uk-close></button>
<div class="uk-modal-body uk-margin-auto-vertical" uk-overflow-auto>
<ul id="thread-detail" style="background-color: rgba(245,242,242,0.96);padding: 10px;overflow-y: auto;max-height: 70%" class="uk-list uk-list-divider">
</ul>
</div>
<div class="uk-modal-footer uk-text-right">
<button class="uk-button uk-button-primary uk-modal-close" type="button">OK</button>
</div>
</div>
</div>
<div id="modal-exception" uk-modal>
<div class="uk-modal-dialog">
<button class="uk-modal-close-default" type="button" uk-close></button>
<div id="exception-detail" class="uk-modal-body uk-margin-auto-vertical" uk-overflow-auto>
</div>
<div class="uk-modal-footer uk-text-right">
<button class="uk-button uk-button-primary uk-modal-close" type="button">OK</button>
</div>
</div>
</div>
<div id="modal-method" class="uk-modal-full" uk-modal>
<div class="uk-modal-dialog">
<button class="uk-modal-close-full uk-close-large" type="button" uk-close></button>
<div class="uk-grid-collapse uk-child-width-1-1@s uk-flex-middle" uk-grid>
<div uk-height-viewport>
<div id="layerDemo" width="1200px" height="900px">
</div>
</div>
</div>
</div>
</div>
<div id="modal-login" class="uk-modal-full" uk-modal>
<div class="uk-modal-dialog" style="background-color: rgb(242, 243, 242)">
<div class="uk-grid-collapse uk-child-width-1-1@s uk-flex-middle" uk-grid>
<div uk-height-viewport>
<div class="uk-text-center" uk-grid>
<div class="uk-width-1-3@m">
</div>
<div class="uk-width-1-3@m" style="margin-top: 100px;">
<form class="uk-card uk-card-default uk-card-body" style="border-radius: 5px">
<div class="uk-margin">
<div class="uk-inline">
<div style="font-size: 35px;" class="uk-width-expand" >KoTime</div>
</div>
</div>
<br>
<div class="uk-margin">
<div class="uk-inline">
<span class="uk-form-icon" uk-icon="icon: user"></span>
<input id="userName" class="uk-input" type="text">
</div>
</div>
<div class="uk-margin">
<div class="uk-inline">
<span class="uk-form-icon uk-form-icon-flip" uk-icon="icon: lock"></span>
<input id="userPassword" type="password" class="uk-input" >
</div>
</div>
<div class="uk-margin">
<div class="uk-inline">
<a class="uk-button uk-button-default uk-label-success" style="border-radius: 5px" onclick="login();" >OK</a>
</div>
</div>
</form>
</div>
<div class="uk-width-1-3@m">
</div>
</div>
</div>
</div>
</div>
</div>
<!--<div class="uk-margin-medium-bottom" style="position:absolute;top:95%;left:45%;text-align:center;">-->
<!-- <ul class="uk-flex-center" uk-tab>-->
<!-- <li class=""><a style="font-size: 7px;text-transform:capitalize" href="#">@2021 Huoyo</a></li>-->
<!-- </ul>-->
<!--</div>-->
</body>

File diff suppressed because it is too large Load Diff