add dynamic properties

This commit is contained in:
huoyo 2023-05-06 18:28:14 +08:00
parent 1d81178589
commit ed2c9977b4
9 changed files with 354 additions and 91 deletions

View File

@ -6,7 +6,7 @@
<groupId>cn.langpy</groupId>
<artifactId>ko-time</artifactId>
<version>2.4.0</version>
<version>2.4.1</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

@ -45,6 +45,15 @@ public class DefaultConfig {
private String mailReceivers;
private Integer mailThreshold;
private String mailScope;
private String propertyFile;
public String getPropertyFile() {
return propertyFile;
}
public void setPropertyFile(String propertyFile) {
this.propertyFile = propertyFile;
}
public Boolean getMailEnable() {
return mailEnable;

View File

@ -3,7 +3,6 @@ package cn.langpy.kotime.config;
import cn.langpy.kotime.annotation.KoListener;
import cn.langpy.kotime.handler.RunTimeHandler;
import cn.langpy.kotime.handler.InvokedHandler;
import cn.langpy.kotime.service.EmailSendService;
import cn.langpy.kotime.service.GraphService;
import cn.langpy.kotime.service.InvokedQueue;
import cn.langpy.kotime.util.Common;
@ -17,7 +16,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
@ -25,6 +24,7 @@ import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.io.*;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@ -68,35 +68,7 @@ public class LoadConfig {
@PostConstruct
public void initConfig() {
DefaultConfig config = new DefaultConfig();
config.setLogEnable(defaultConfig.getLogEnable() == null ? logEnable : defaultConfig.getLogEnable());
config.setLogLanguage(defaultConfig.getLogLanguage() == null ? logLanguage : defaultConfig.getLogLanguage());
config.setThreshold(defaultConfig.getThreshold() == null ? timeThreshold : defaultConfig.getThreshold());
config.setExceptionEnable(defaultConfig.getExceptionEnable() == null ? exceptionEnable : defaultConfig.getExceptionEnable());
config.setSaver(defaultConfig.getSaver() == null ? saveSaver : defaultConfig.getSaver());
config.setEnable(defaultConfig.getEnable() == null ? kotimeEnable : defaultConfig.getEnable());
config.setDataPrefix(defaultConfig.getDataPrefix() == null ? (StringUtils.hasText(serverContext)?serverContext.substring(1):"KOTIME") : defaultConfig.getDataPrefix());
config.setContextPath(defaultConfig.getContextPath());
config.setLanguage(defaultConfig.getLanguage() == null ? "chinese" : defaultConfig.getLanguage());
config.setThreadNum(defaultConfig.getThreadNum() == null ? 2 : defaultConfig.getThreadNum());
config.setDiscardRate(defaultConfig.getDiscardRate() == null ? 0.3 : defaultConfig.getDiscardRate());
config.setAuthExpire(defaultConfig.getAuthExpire() == null ? (12*60*60l) : defaultConfig.getAuthExpire());
config.setAuthEnable(defaultConfig.getAuthEnable() == null ? false : defaultConfig.getAuthEnable());
config.setParamAnalyse(defaultConfig.getParamAnalyse() == null ? true : defaultConfig.getParamAnalyse());
config.setDataReset(defaultConfig.getDataReset() == null ? false : defaultConfig.getDataReset());
config.setVersionNotice(defaultConfig.getVersionNotice() == null ? true : defaultConfig.getVersionNotice());
config.setStaticToken(defaultConfig.getStaticToken());
config.setMailEnable(defaultConfig.getMailEnable());
config.setMailProtocol(defaultConfig.getMailProtocol() == null ? "smtp" : defaultConfig.getMailProtocol());
config.setMailHost(defaultConfig.getMailHost() == null ? "smtp.qq.com" : defaultConfig.getMailHost());
config.setMailPort(defaultConfig.getMailPort() == null ? 587 : defaultConfig.getMailPort());
config.setMailEncoding(defaultConfig.getMailEncoding() == null ? "UTF-8" : defaultConfig.getMailEncoding());
config.setMailThreshold(defaultConfig.getMailThreshold() == null ? 4: defaultConfig.getMailThreshold());
config.setMailScope(defaultConfig.getMailScope() == null ? "Controller": defaultConfig.getMailScope());
config.setMailUser(defaultConfig.getMailUser());
config.setMailCode(defaultConfig.getMailCode());
config.setMailReceivers(defaultConfig.getMailReceivers());
DefaultConfig config = improveConfig();
configDataSource(config);
configRedisTemplate(config);
@ -123,8 +95,71 @@ public class LoadConfig {
log.info("kotime=>view:http://localhost:" + serverPort + serverContext + "/koTime");
}
initMethodHandlers();
loadPropertyFile();
}
public DefaultConfig improveConfig() {
DefaultConfig config = new DefaultConfig();
config.setLogEnable(defaultConfig.getLogEnable() == null ? logEnable : defaultConfig.getLogEnable());
config.setLogLanguage(defaultConfig.getLogLanguage() == null ? logLanguage : defaultConfig.getLogLanguage());
config.setThreshold(defaultConfig.getThreshold() == null ? timeThreshold : defaultConfig.getThreshold());
config.setExceptionEnable(defaultConfig.getExceptionEnable() == null ? exceptionEnable : defaultConfig.getExceptionEnable());
config.setSaver(defaultConfig.getSaver() == null ? saveSaver : defaultConfig.getSaver());
config.setEnable(defaultConfig.getEnable() == null ? kotimeEnable : defaultConfig.getEnable());
config.setDataPrefix(defaultConfig.getDataPrefix() == null ? (StringUtils.hasText(serverContext) ? serverContext.substring(1) : "KOTIME") : defaultConfig.getDataPrefix());
config.setContextPath(defaultConfig.getContextPath());
config.setLanguage(defaultConfig.getLanguage() == null ? "chinese" : defaultConfig.getLanguage());
config.setThreadNum(defaultConfig.getThreadNum() == null ? 2 : defaultConfig.getThreadNum());
config.setDiscardRate(defaultConfig.getDiscardRate() == null ? 0.3 : defaultConfig.getDiscardRate());
config.setAuthExpire(defaultConfig.getAuthExpire() == null ? (12 * 60 * 60l) : defaultConfig.getAuthExpire());
config.setAuthEnable(defaultConfig.getAuthEnable() == null ? false : defaultConfig.getAuthEnable());
config.setParamAnalyse(defaultConfig.getParamAnalyse() == null ? true : defaultConfig.getParamAnalyse());
config.setDataReset(defaultConfig.getDataReset() == null ? false : defaultConfig.getDataReset());
config.setVersionNotice(defaultConfig.getVersionNotice() == null ? true : defaultConfig.getVersionNotice());
config.setStaticToken(defaultConfig.getStaticToken());
config.setMailEnable(defaultConfig.getMailEnable());
config.setMailProtocol(defaultConfig.getMailProtocol() == null ? "smtp" : defaultConfig.getMailProtocol());
config.setMailHost(defaultConfig.getMailHost() == null ? "smtp.qq.com" : defaultConfig.getMailHost());
config.setMailPort(defaultConfig.getMailPort() == null ? 587 : defaultConfig.getMailPort());
config.setMailEncoding(defaultConfig.getMailEncoding() == null ? "UTF-8" : defaultConfig.getMailEncoding());
config.setMailThreshold(defaultConfig.getMailThreshold() == null ? 4 : defaultConfig.getMailThreshold());
config.setMailScope(defaultConfig.getMailScope() == null ? "Controller" : defaultConfig.getMailScope());
config.setMailUser(defaultConfig.getMailUser());
config.setMailCode(defaultConfig.getMailCode());
config.setMailReceivers(defaultConfig.getMailReceivers());
config.setPropertyFile(defaultConfig.getPropertyFile() == null ? "dynamic.properties" : defaultConfig.getPropertyFile());
return config;
}
public void loadPropertyFile() {
ClassPathResource classPathResource = new ClassPathResource(Context.getConfig().getPropertyFile());
try (
InputStream inputStream = classPathResource.getInputStream();
InputStreamReader streamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader reader = new BufferedReader(streamReader)) {
String line = "";
Map<String, String> dynamicProperties = Context.getDynamicProperties();
while ((line = reader.readLine()) != null) {
line = line.trim();
int i = line.indexOf("=");
if (i<1) {
continue;
}
String propertyStr = line.substring(0, i).trim();
String valueStr = line.substring(i+1).trim();
dynamicProperties.put(propertyStr,valueStr);
}
} catch (UnsupportedEncodingException e) {
log.severe("kotime=>dynamic.properties requires utf-8");
e.printStackTrace();
} catch (FileNotFoundException e){
log.warning("kotime=>No dynamic.properties found so that you can not use dynamic properties to set.");
}catch (IOException e) {
e.printStackTrace();
}
}
public void configDataSource(DefaultConfig config) {

View File

@ -385,4 +385,47 @@ public class KoTimeController {
map.put("threads", threads);
return map;
}
@PostMapping("/updateDynamicProperties")
@ResponseBody
@Auth
public boolean updateDynamicProperties(@RequestBody TextParam textParam) {
if (!StringUtils.hasText(textParam.getText())) {
return false;
}
String[] textSplit = textParam.getText().trim().split("\n");
Map<String, String> dynamicProperties = Context.getDynamicProperties();
for (String line : textSplit) {
line = line.trim();
int i = line.indexOf("=");
if (i<1) {
continue;
}
String propertyStr = line.substring(0, i).trim();
String valueStr = line.substring(i+1).trim();
log.info("updated property: "+propertyStr+"=("+dynamicProperties.get(propertyStr)+"->"+valueStr+")");
dynamicProperties.put(propertyStr,valueStr);
}
return true;
}
@GetMapping("/getDynamicProperties")
@ResponseBody
@Auth
public Map getDynamicProperties() {
Map map = new HashMap();
map.put("state", 0);
map.put("message", "文件不能为空");
Map<String, String> dynamicProperties = Context.getDynamicProperties();
StringBuilder stringBuilder = new StringBuilder();
for (String key : dynamicProperties.keySet()) {
String value = dynamicProperties.get(key);
if (value!=null) {
stringBuilder.append(key+"="+value+"\n");
}
}
map.put("data", stringBuilder.toString());
return map;
}
}

View File

@ -0,0 +1,13 @@
package cn.langpy.kotime.model;
public class TextParam {
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}

View File

@ -9,6 +9,8 @@ import javax.sql.DataSource;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* zhangchang
@ -20,6 +22,7 @@ public class Context {
private static DataSource dataSource;
private static StringRedisTemplate stringRedisTemplate;
private static GraphService saver;
private static Map<String,String> dynamicProperties;
static {
config = new DefaultConfig();
@ -27,6 +30,7 @@ public class Context {
config.setEnable(true);
config.setLogLanguage("chinese");
invokedHandlers = new ArrayList<>();
dynamicProperties = new ConcurrentHashMap<>();
}
@ -77,4 +81,12 @@ public class Context {
public static void setSaver(GraphService saver) {
Context.saver = saver;
}
public static Map<String, String> getDynamicProperties() {
return dynamicProperties;
}
public static void setDynamicProperties(Map<String, String> dynamicProperties) {
Context.dynamicProperties = dynamicProperties;
}
}

View File

@ -10,13 +10,14 @@ import org.springframework.data.redis.core.StringRedisTemplate;
import javax.sql.DataSource;
import java.util.*;
import java.util.stream.Collectors;
public class KoUtil {
private final static String koTimeSecret = UUID.randomUUID().toString().replace("-", "");
private final static List<Integer> choices = randomSecretIndexs();
private static Map<String,Object> caches = new HashMap<>();
private static Map<String, Object> caches = new HashMap<>();
/**
* nothing to introduce for this, that everyone knows!
@ -50,11 +51,11 @@ public class KoUtil {
* note: this Datasource will not affect project's datasource
*/
public static void setDataSource(DataSource dataSource) {
caches.put("dataSource",dataSource);
caches.put("dataSource", dataSource);
}
public static DataSource getDataSource() {
return (DataSource)caches.get("dataSource");
return (DataSource) caches.get("dataSource");
}
/**
@ -62,11 +63,11 @@ public class KoUtil {
* note: you can choose one between setRedisTemplate and setJedisPool to save data
*/
public static void setStringRedisTemplate(RedisTemplate redisTemplate) {
caches.put("redisTemplate",redisTemplate);
caches.put("redisTemplate", redisTemplate);
}
public static StringRedisTemplate getStringRedisTemplate() {
return (StringRedisTemplate)caches.get("redisTemplate");
return (StringRedisTemplate) caches.get("redisTemplate");
}
@ -86,9 +87,9 @@ public class KoUtil {
ExceptionNode exception = new ExceptionNode();
exception.setName(e.getClass().getSimpleName());
exception.setClassName(e.getClass().getName());
exception.setMessage(e.getMessage()+"");
exception.setId(exception.getClassName() +"."+ exception.getName());
MethodNode current = getCurrentMethodInfo();
exception.setMessage(e.getMessage() + "");
exception.setId(exception.getClassName() + "." + exception.getName());
MethodNode current = getCurrentMethodInfo();
for (StackTraceElement stackTraceElement : e.getStackTrace()) {
if (stackTraceElement.getClassName().equals(current.getClassName())) {
exception.setValue(stackTraceElement.getLineNumber());
@ -104,6 +105,7 @@ public class KoUtil {
/**
* get the current method
*
* @return
*/
public static MethodNode getCurrentMethodInfo() {
@ -172,4 +174,46 @@ public class KoUtil {
return decodeStr;
}
public static void setProperty(String propertyName, String propertyValue) {
Context.getDynamicProperties().put(propertyName, propertyValue);
}
public static String getProperty(String propertyName) {
String value = Context.getDynamicProperties().get(propertyName);
return value;
}
public static int getPropertyAsInteger(String propertyName) {
String value = getProperty(propertyName);
return Integer.valueOf(value);
}
public static double getPropertyAsDouble(String propertyName) {
String value = getProperty(propertyName);
return Double.valueOf(value);
}
public static double getPropertyAsFloat(String propertyName) {
String value = getProperty(propertyName);
return Float.valueOf(value);
}
public static boolean getPropertyAsBoolean(String propertyName) {
String value = getProperty(propertyName);
if ("true".equals(value) || "false".equals(value)) {
return Boolean.valueOf(value);
}
throw new RuntimeException("can not convert null value to boolean value.");
}
public static List<String> getPropertyAsList(String propertyName, String split) {
String value = getProperty(propertyName);
if (value == null) {
throw new RuntimeException("can not convert null value to list values.");
}
String[] split1 = value.split(split);
return Arrays.stream(split1).collect(Collectors.toList());
}
}

View File

@ -260,6 +260,40 @@
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({
@ -515,6 +549,7 @@
loadHeapMemoryInfo();
loadPhysicalMemoryInfo();
loadThreadsInfo();
loadDynamicProperties();
}
});
}
@ -778,32 +813,51 @@
</div>
</li>
<li style="margin-left: 30%;margin-right: 30%;">
<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>
<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="" style="overflow-y: auto;height: 65%;resize: none"></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>

View File

@ -50,6 +50,7 @@
loadHeapMemoryInfo();
loadPhysicalMemoryInfo();
loadThreadsInfo();
loadDynamicProperties();
}
});
@ -438,6 +439,39 @@
})
}
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(){
$.ajax({
url: 'http://www.kotime.cn/common/latestVersion?version=2.3.8',
@ -771,31 +805,50 @@
</div>
</li>
<li style="margin-left: 30%;margin-right: 30%;">
<div class="layui-tab-item">
<label >开启koTime</label> <input id='kotimeEnable' type="checkbox" checked>
<br>
<label >开启异常监测:</label> <input id='exceptionEnable' type="checkbox">
<br>
<label >开启控制台日志:</label> <input id='logEnable' type="checkbox">
<br>
<label >开启邮件通知:</label> <input id='mailEnable' type="checkbox">
<br>
<label>语言选择:</label>
<select id="languageSwitch" >
<option value="chinese">中文</option>
<option value="english">英文</option>
</select>
<br>
<label >方法运行时间阈值:</label> <input id='timeThreshold' type="input"><button style="background-color: #177ce1;border: 1px solid #177ce1;cursor: pointer;color: white" id="timeThresholdYes">确认</button>
<br>
<label >清空链路数据:</label><button style="background-color: #177ce1;border: 1px solid #177ce1;cursor: pointer;color: white" id="clearDataYes">确认</button>
<br>
<br>
<div class="uk-alert-success" uk-alert>
<a class="uk-alert-close" uk-close></a>
<p>变更配置以后请重新刷新页面</p>
</div>
</div>
<ul class="uk-flex-left" uk-tab>
<li class="uk-active"><a href="#" style="text-transform: unset">KoTime配置</a></li>
<li class=""><a href="#" style="text-transform: unset">dynamic.properties配置</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</label> <input id='kotimeEnable' type="checkbox" checked>
<br>
<label >开启异常监测:</label> <input id='exceptionEnable' type="checkbox">
<br>
<label >开启控制台日志:</label> <input id='logEnable' type="checkbox">
<br>
<label >开启邮件通知:</label> <input id='mailEnable' type="checkbox">
<br>
<label>语言选择:</label>
<select id="languageSwitch" >
<option value="chinese">中文</option>
<option value="english">英文</option>
</select>
<br>
<label >方法运行时间阈值:</label> <input id='timeThreshold' type="input"><button style="background-color: #177ce1;border: 1px solid #177ce1;cursor: pointer;color: white" id="timeThresholdYes">确认</button>
<br>
<label >清空链路数据:</label><button style="background-color: #177ce1;border: 1px solid #177ce1;cursor: pointer;color: white" id="clearDataYes">确认</button>
<br>
<br>
<div class="uk-alert-success" uk-alert>
<a class="uk-alert-close" uk-close></a>
<p>变更配置以后请重新刷新页面</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="" style="overflow-y: auto;height: 65%;resize: none"></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">更新</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>