package cn.langpy.kotime.data; import cn.langpy.kotime.constant.KoSqlConstant; import cn.langpy.kotime.model.*; import cn.langpy.kotime.service.GraphService; import cn.langpy.kotime.util.Common; import cn.langpy.kotime.util.Context; import cn.langpy.kotime.util.DataBaseUtil; import cn.langpy.kotime.util.MethodType; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import java.lang.reflect.Parameter; import java.math.BigDecimal; import java.sql.Connection; import java.sql.SQLException; import java.util.*; import java.util.logging.Logger; import java.util.stream.Collectors; import static java.util.stream.Collectors.toList; /** * zhangchang */ @Component("database") @Lazy public class DataBase implements GraphService { public static Logger log = Logger.getLogger(DataBase.class.toString()); private Connection readConnection; private Connection writeConnection; public DataBase() { Runtime.getRuntime().addShutdownHook( new Thread(() -> { try { if (null!=readConnection) { readConnection.close(); } if (null!=writeConnection) { writeConnection.close(); } } catch (SQLException throwables) { throwables.printStackTrace(); }finally { log.info("kotime=>closed database connections..."); } }) ); } public Connection getReadConnection() { try { if (null == readConnection || readConnection.isClosed()) { readConnection = Context.getDataSource().getConnection(); } } catch (SQLException throwables) { throwables.printStackTrace(); } return readConnection; } public Connection getWriteConnection() { try { if (null == writeConnection || writeConnection.isClosed()) { writeConnection = Context.getDataSource().getConnection(); } } catch (SQLException throwables) { throwables.printStackTrace(); } return writeConnection; } @Override public void addMethodNode(MethodNode methodNode) { if (null == methodNode) { return; } // List> query = DataBaseUtil.query(getWriteConnection(),KoSqlConstant.queryMethod, new Object[]{methodNode.getId()}); boolean existsById = DataBaseUtil.existsById(getWriteConnection(),KoSqlConstant.queryMethod, methodNode.getId()); if (!existsById) { Object[] params = new Object[]{ methodNode.getId(), methodNode.getName(), methodNode.getClassName(), methodNode.getMethodName(), methodNode.getRouteName(), methodNode.getMethodType().name() }; DataBaseUtil.insert(getWriteConnection(),KoSqlConstant.addMethod, params); } else { if (methodNode.getMethodType() == MethodType.Controller && !StringUtils.isEmpty(methodNode.getRouteName())) { Object[] params = new Object[]{ methodNode.getName(), methodNode.getClassName(), methodNode.getMethodName(), methodNode.getRouteName(), methodNode.getMethodType().name(), methodNode.getId(), }; DataBaseUtil.update(getWriteConnection(),KoSqlConstant.updateMethod, params); } } } @Override public synchronized void addExceptionNode(ExceptionNode exceptionNode) { // List> query = DataBaseUtil.query(getWriteConnection(),KoSqlConstant.queryException, new Object[]{exceptionNode.getId()}); boolean existsById = DataBaseUtil.existsById(getWriteConnection(),KoSqlConstant.queryException, exceptionNode.getId()); if (!existsById) { Object[] params = new Object[]{ exceptionNode.getId(), exceptionNode.getName(), exceptionNode.getClassName(), exceptionNode.getMessage() }; DataBaseUtil.insert(getWriteConnection(),KoSqlConstant.addException, params); } } @Override public synchronized MethodRelation addMethodRelation(MethodNode sourceMethodNode, MethodNode targetMethodNode) { if (null == sourceMethodNode || null == targetMethodNode) { return null; } if (sourceMethodNode.getId().equals(targetMethodNode.getId())) { return null; } try { List> query = DataBaseUtil.query(getWriteConnection(),KoSqlConstant.queryMethodRe, new Object[]{sourceMethodNode.getId() + targetMethodNode.getId()}); if (query.size() > 0) { Map old = query.get(0); double oldAvg = Double.valueOf(old.get("avg_run_time") + ""); double oldMax = Double.valueOf(old.get("max_run_time") + ""); double oldMin = Double.valueOf(old.get("min_run_time") + ""); BigDecimal bg = BigDecimal.valueOf((targetMethodNode.getValue() + oldAvg) / 2.0); double avg = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); double max = targetMethodNode.getValue() > oldMax ? targetMethodNode.getValue() : oldMax; double min = targetMethodNode.getValue() < oldMin ? targetMethodNode.getValue() : oldMin; Object[] params = new Object[]{ sourceMethodNode.getId(), targetMethodNode.getId(), avg, max, min, sourceMethodNode.getId() + targetMethodNode.getId() }; DataBaseUtil.update(getWriteConnection(),KoSqlConstant.updateMethodRe, params); return null; } else { Object[] params = new Object[]{ sourceMethodNode.getId() + targetMethodNode.getId(), sourceMethodNode.getId(), targetMethodNode.getId(), targetMethodNode.getValue(), targetMethodNode.getValue(), targetMethodNode.getValue() }; DataBaseUtil.insert(getWriteConnection(),KoSqlConstant.addMethodRe, params); } } catch (Exception e) { e.printStackTrace(); } return null; } @Override public synchronized ExceptionRelation addExceptionRelation(MethodNode sourceMethodNode, ExceptionNode exceptionNode) { // List> query = DataBaseUtil.query(getWriteConnection(),KoSqlConstant.queryExceptionRe, new Object[]{sourceMethodNode.getId() + exceptionNode.getId()}); boolean existsById = DataBaseUtil.existsById(getWriteConnection(),KoSqlConstant.queryExceptionRe, sourceMethodNode.getId() + exceptionNode.getId()); if (!existsById) { Object[] params = new Object[]{ sourceMethodNode.getId() + exceptionNode.getId(), sourceMethodNode.getId(), exceptionNode.getId(), exceptionNode.getValue() }; DataBaseUtil.insert(getWriteConnection(),KoSqlConstant.addExceptionRe, params); } return null; } @Override public synchronized void addParamAnalyse(String methodId, Parameter[] names, Object[] values, double v) { String paramsKey = Common.getPramsStr(names, values); List> query = DataBaseUtil.query(getWriteConnection(),KoSqlConstant.queryParamsAna, new Object[]{methodId, paramsKey}); if (query.size() == 0) { Object[] params = new Object[]{ methodId, paramsKey, v, v, v }; DataBaseUtil.insert(getWriteConnection(),KoSqlConstant.addParamsAna, params); } else { Map old = query.get(0); double oldAvg = Double.valueOf(old.get("avg_run_time") + ""); double oldMax = Double.valueOf(old.get("max_run_time") + ""); double oldMin = Double.valueOf(old.get("min_run_time") + ""); BigDecimal bg = BigDecimal.valueOf((v + oldAvg) / 2.0); double avg = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); double max = v > oldMax ? v : oldMax; double min = v < oldMin ? v : oldMin; Object[] params = new Object[]{ avg, max, min, methodId, paramsKey }; DataBaseUtil.update(getWriteConnection(),KoSqlConstant.updateParamsAna, params); } } @Override public MethodInfo getTree(String methodId) { MethodInfo rootInfo = new MethodInfo(); List methodNodes = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryMethod, new Object[]{methodId}, MethodNode.class); if (methodNodes.size() == 0) { return rootInfo; } MethodNode methodNode = methodNodes.get(0); rootInfo.setId(methodNode.getId()); rootInfo.setName(methodNode.getName()); rootInfo.setClassName(methodNode.getClassName()); rootInfo.setMethodName(methodNode.getMethodName()); rootInfo.setMethodType(methodNode.getMethodType()); rootInfo.setRouteName(methodNode.getRouteName()); List relations = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryMethodReByTarget, new Object[]{methodId}, MethodRelation.class); if (relations.size() == 0) { return rootInfo; } MethodRelation methodRelation = relations.get(0); rootInfo.setValue(methodRelation.getAvgRunTime()); rootInfo.setAvgRunTime(methodRelation.getAvgRunTime()); rootInfo.setMaxRunTime(methodRelation.getMaxRunTime()); rootInfo.setMinRunTime(methodRelation.getMinRunTime()); List exceptionInfos = getExceptions(methodId); rootInfo.setExceptionNum(exceptionInfos.size()); rootInfo.setExceptions(exceptionInfos); List methodInfos = new ArrayList<>(); recursionMethod(rootInfo, methodInfos); methodInfos.clear(); return rootInfo; } public void recursionMethod(MethodInfo rootInfo, List methodInfos) { List children = getChildren(rootInfo.getId()); if (children != null && children.size() > 0) { if (!methodInfos.contains(rootInfo.getId())) { methodInfos.add(rootInfo.getId()); rootInfo.setChildren(children); for (MethodInfo child : children) { recursionMethod(child, methodInfos); } } } } @Override public Map getMethodParamGraph(String methodId) { Map paramMetricMap = new HashMap<>(); List paramAnas = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryParamsAnaBySource, new Object[]{methodId}, ParamAna.class); if (paramAnas.size() == 0) { return paramMetricMap; } for (ParamAna paramAna : paramAnas) { if (!paramMetricMap.containsKey(paramAna.getSourceId())) { ParamMetric paramMetric = new ParamMetric(); paramMetric.setAvgRunTime(paramAna.getAvgRunTime()); paramMetric.setMaxRunTime(paramAna.getMaxRunTime()); paramMetric.setMinRunTime(paramAna.getMinRunTime()); paramMetricMap.put(paramAna.getParams(), paramMetric); } } return paramMetricMap; } @Override public SystemStatistic getRunStatistic() { SystemStatistic systemStatistic = new SystemStatistic(); List controllerApis = getControllers(); if (null == controllerApis || controllerApis.size() == 0) { return systemStatistic; } int delayNum = (int) controllerApis.stream().filter(controllerApi -> controllerApi.getAvgRunTime() >= Context.getConfig().getThreshold()).count(); systemStatistic.setDelayNum(delayNum); int normalNum = (int) controllerApis.stream().filter(controllerApi -> controllerApi.getAvgRunTime() < Context.getConfig().getThreshold()).count(); systemStatistic.setNormalNum(normalNum); int totalNum = (int) controllerApis.stream().count(); systemStatistic.setTotalNum(totalNum); Double max = controllerApis.stream().map(api -> api.getAvgRunTime()).max(Double::compareTo).get(); Double min = controllerApis.stream().map(api -> api.getAvgRunTime()).min(Double::compareTo).get(); Double avg = controllerApis.stream().map(api -> api.getAvgRunTime()).collect(Collectors.averagingDouble(Double::doubleValue)); BigDecimal bg = BigDecimal.valueOf(avg); avg = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); systemStatistic.setMaxRunTime(max); systemStatistic.setMinRunTime(min); systemStatistic.setAvgRunTime(avg); return systemStatistic; } @Override public List getControllers() { List methodInfos = new ArrayList<>(); List controllers = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryController, new Object[]{MethodType.Controller.name()}, MethodInfo.class); for (MethodInfo methodNode : controllers) { String id = methodNode.getId(); List relations = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryMethodReByTarget, new Object[]{id}, MethodRelation.class); if (relations.size() == 0) { continue; } MethodRelation relation = relations.get(0); MethodInfo methodInfo = new MethodInfo(); methodInfo.setId(methodNode.getId()); methodInfo.setName(methodNode.getName()); methodInfo.setClassName(methodNode.getClassName()); methodInfo.setMethodName(methodNode.getMethodName()); methodInfo.setMethodType(methodNode.getMethodType()); methodInfo.setRouteName(methodNode.getRouteName()); methodInfo.setValue(relation.getAvgRunTime()); methodInfo.setAvgRunTime(relation.getAvgRunTime()); methodInfo.setMaxRunTime(relation.getMaxRunTime()); methodInfo.setMinRunTime(relation.getMinRunTime()); if (!methodInfos.contains(methodInfo)) { methodInfos.add(methodInfo); } } return methodInfos; } @Override public List getCondidates(String question) { List methodNodes = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryMethodLikeName, new Object[]{"%" + question + "%"}, MethodNode.class); List methodInfos = new ArrayList<>(); if (methodNodes.size() > 0) { methodInfos = methodNodes.stream().map(MethodNode::getName).collect(toList()); } return methodInfos; } @Override public List searchMethods(String question) { List methodInfos = new ArrayList<>(); List methodNodes = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryMethodLikeName, new Object[]{"%" + question + "%"}, MethodNode.class); for (MethodNode methodNode : methodNodes) { String id = methodNode.getId(); List relations = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryMethodReByTarget, new Object[]{id}, MethodRelation.class); if (relations.size() == 0) { continue; } MethodRelation relation = relations.get(0); MethodInfo methodInfo = new MethodInfo(); methodInfo.setId(methodNode.getId()); methodInfo.setName(methodNode.getName()); methodInfo.setClassName(methodNode.getClassName()); methodInfo.setMethodName(methodNode.getMethodName()); methodInfo.setMethodType(methodNode.getMethodType()); methodInfo.setRouteName(methodNode.getRouteName()); methodInfo.setValue(relation.getAvgRunTime()); methodInfo.setAvgRunTime(relation.getAvgRunTime()); methodInfo.setMaxRunTime(relation.getMaxRunTime()); methodInfo.setMinRunTime(relation.getMinRunTime()); if (!methodInfos.contains(methodInfo)) { methodInfos.add(methodInfo); } } return methodInfos; } @Override public List getChildren(String methodId) { List relations = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryMethodReBySource, new Object[]{methodId}, MethodRelation.class); List methodInfos = new ArrayList<>(); for (MethodRelation methodRelation : relations) { List methodNodes = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryMethod, new Object[]{methodRelation.getTargetId()}, MethodNode.class); if (methodNodes.size() == 0) { continue; } MethodNode methodNode = methodNodes.get(0); MethodInfo methodInfo = new MethodInfo(); methodInfo.setId(methodNode.getId()); methodInfo.setName(methodNode.getName()); methodInfo.setClassName(methodNode.getClassName()); methodInfo.setMethodName(methodNode.getMethodName()); methodInfo.setRouteName(methodNode.getRouteName()); methodInfo.setMethodType(methodNode.getMethodType()); methodInfo.setValue(methodRelation.getAvgRunTime()); methodInfo.setAvgRunTime(methodRelation.getAvgRunTime()); methodInfo.setMaxRunTime(methodRelation.getMaxRunTime()); methodInfo.setMinRunTime(methodRelation.getMinRunTime()); List exceptionInfos = getExceptions(methodNode.getId()); methodInfo.setExceptionNum(exceptionInfos.size()); methodInfo.setExceptions(exceptionInfos); if (!methodInfos.contains(methodInfo)) { methodInfos.add(methodInfo); } } return methodInfos; } @Override public List getExceptionInfos(String exceptionId) { List relations = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryExceptionReByTarget, new Object[]{exceptionId}, ExceptionRelation.class); List exceptionInfos = new ArrayList<>(); for (ExceptionRelation relation : relations) { String sourceMethodId = relation.getSourceId(); List methodNodes = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryMethod, new Object[]{sourceMethodId}, MethodNode.class); if (methodNodes.size() == 0) { continue; } MethodNode methodNode = methodNodes.get(0); List exceptions = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryMethod, new Object[]{exceptionId}, ExceptionNode.class); if (methodNodes.size() == 0) { continue; } ExceptionNode exceptionNode = exceptions.get(0); ExceptionInfo exceptionInfo = new ExceptionInfo(); exceptionInfo.setId(exceptionNode.getId()); exceptionInfo.setName(exceptionNode.getName()); exceptionInfo.setClassName(exceptionNode.getClassName()); exceptionInfo.setLocation(relation.getLocation()); exceptionInfo.setMessage(exceptionNode.getMessage()); exceptionInfo.setMethodName(methodNode.getMethodName()); exceptionInfo.setOccurClassName(methodNode.getClassName()); if (!exceptionInfos.contains(exceptionInfo)) { exceptionInfos.add(exceptionInfo); } } return exceptionInfos; } @Override public List getExceptions(String methodId) { List exceptionInfos = new ArrayList<>(); List relations = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryExceptionReByTarget, new Object[]{methodId}, ExceptionRelation.class); for (ExceptionRelation relation : relations) { String exceptionId = relation.getTargetId(); List exceptionNodes = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryException, new Object[]{exceptionId}, ExceptionNode.class); if (exceptionNodes.size() == 0) { continue; } ExceptionNode exceptionNode = exceptionNodes.get(0); ExceptionInfo exceptionInfo = new ExceptionInfo(); exceptionInfo.setId(exceptionNode.getId()); exceptionInfo.setName(exceptionNode.getName()); exceptionInfo.setClassName(exceptionNode.getClassName()); exceptionInfo.setMessage(exceptionNode.getMessage()); exceptionInfo.setLocation(relation.getLocation()); if (!exceptionInfos.contains(exceptionInfo)) { exceptionInfos.add(exceptionInfo); } } return exceptionInfos; } @Override public List getExceptions() { List exceptionNodes = DataBaseUtil.query(getReadConnection(),KoSqlConstant.queryExceptions, null, ExceptionNode.class); return exceptionNodes; } }