Browse Source

!37 V_1.0.9
Merge pull request !37 from AE86/V_1.0.0

AE86 3 years ago
parent
commit
a44220e379
81 changed files with 1783 additions and 835 deletions
  1. 20 22
      README.md
  2. 1 1
      dbsyncer-biz/pom.xml
  3. 17 7
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/MonitorService.java
  4. 2 1
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/checker/impl/mapping/MappingChecker.java
  5. 77 58
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/MonitorServiceImpl.java
  6. 17 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/AbstractMetricDetailFormatter.java
  7. 9 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/MetricDetailFormatter.java
  8. 16 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/impl/CpuMetricDetailFormatter.java
  9. 25 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/impl/DiskMetricDetailFormatter.java
  10. 16 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/impl/DoubleRoundMetricDetailFormatter.java
  11. 20 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/impl/GCMetricDetailFormatter.java
  12. 19 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/impl/MemoryMetricDetailFormatter.java
  13. 15 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/impl/ValueMetricDetailFormatter.java
  14. 38 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/vo/AppReportMetricVo.java
  15. 32 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/vo/HistoryStackVo.java
  16. 16 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/vo/MetricResponseVo.java
  17. 1 1
      dbsyncer-cache/pom.xml
  18. 1 1
      dbsyncer-cluster/pom.xml
  19. 1 1
      dbsyncer-common/pom.xml
  20. 3 14
      dbsyncer-common/src/main/java/org/dbsyncer/common/event/Event.java
  21. 3 3
      dbsyncer-common/src/main/java/org/dbsyncer/common/model/Paging.java
  22. 4 5
      dbsyncer-common/src/main/java/org/dbsyncer/common/util/DateFormatUtil.java
  23. 1 1
      dbsyncer-connector/pom.xml
  24. 1 1
      dbsyncer-listener/pom.xml
  25. 4 14
      dbsyncer-listener/src/main/java/org/dbsyncer/listener/AbstractExtractor.java
  26. 3 10
      dbsyncer-listener/src/main/java/org/dbsyncer/listener/Extractor.java
  27. 1 1
      dbsyncer-listener/src/main/java/org/dbsyncer/listener/oracle/OracleExtractor.java
  28. 1 9
      dbsyncer-listener/src/main/java/org/dbsyncer/listener/oracle/dcn/DBChangeNotification.java
  29. 3 3
      dbsyncer-listener/src/main/java/org/dbsyncer/listener/quartz/QuartzExtractor.java
  30. 3 3
      dbsyncer-listener/src/main/java/org/dbsyncer/listener/sqlserver/SqlServerExtractor.java
  31. 1 1
      dbsyncer-manager/pom.xml
  32. 5 5
      dbsyncer-manager/src/main/java/org/dbsyncer/manager/puller/impl/IncrementPuller.java
  33. 1 1
      dbsyncer-manager/src/main/java/org/dbsyncer/manager/template/impl/PreloadTemplate.java
  34. 1 1
      dbsyncer-monitor/pom.xml
  35. 29 2
      dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/Monitor.java
  36. 27 0
      dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/MonitorException.java
  37. 182 13
      dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/MonitorFactory.java
  38. 48 0
      dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/enums/DiskMetricEnum.java
  39. 82 0
      dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/enums/MetricEnum.java
  40. 55 0
      dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/enums/StatisticEnum.java
  41. 54 0
      dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/enums/ThreadPoolMetricEnum.java
  42. 95 0
      dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/model/AppReportMetric.java
  43. 56 0
      dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/model/MetricResponse.java
  44. 29 0
      dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/model/Sample.java
  45. 1 1
      dbsyncer-parser/pom.xml
  46. 35 56
      dbsyncer-parser/src/main/java/org/dbsyncer/parser/ParserFactory.java
  47. 1 1
      dbsyncer-parser/src/main/java/org/dbsyncer/parser/model/Config.java
  48. 2 14
      dbsyncer-parser/src/main/java/org/dbsyncer/parser/model/Mapping.java
  49. 2 2
      dbsyncer-parser/src/main/resources/Mapping.json
  50. 1 1
      dbsyncer-plugin/pom.xml
  51. 1 1
      dbsyncer-storage/pom.xml
  52. 0 5
      dbsyncer-storage/src/main/java/org/dbsyncer/storage/query/Param.java
  53. 5 5
      dbsyncer-storage/src/main/java/org/dbsyncer/storage/query/Query.java
  54. 1 7
      dbsyncer-web/pom.xml
  55. 7 10
      dbsyncer-web/src/main/java/org/dbsyncer/web/config/CacheConfiguration.java
  56. 62 63
      dbsyncer-web/src/main/java/org/dbsyncer/web/config/ThreadPoolConfig.java
  57. 9 17
      dbsyncer-web/src/main/java/org/dbsyncer/web/config/WebAppConfig.java
  58. 0 25
      dbsyncer-web/src/main/java/org/dbsyncer/web/config/WebSocketConfig.java
  59. 3 2
      dbsyncer-web/src/main/java/org/dbsyncer/web/controller/TestController.java
  60. 0 49
      dbsyncer-web/src/main/java/org/dbsyncer/web/controller/databus/DataBusController.java
  61. 7 0
      dbsyncer-web/src/main/java/org/dbsyncer/web/controller/monitor/HistoryStackValueFormatter.java
  62. 130 3
      dbsyncer-web/src/main/java/org/dbsyncer/web/controller/monitor/MonitorController.java
  63. 17 0
      dbsyncer-web/src/main/java/org/dbsyncer/web/controller/monitor/impl/CpuHistoryStackValueFormatterImpl.java
  64. 22 0
      dbsyncer-web/src/main/java/org/dbsyncer/web/controller/monitor/impl/MemoryHistoryStackValueFormatterImpl.java
  65. 3 1
      dbsyncer-web/src/main/resources/application.properties
  66. 4 4
      dbsyncer-web/src/main/resources/public/connector/add.html
  67. 5 5
      dbsyncer-web/src/main/resources/public/connector/edit.html
  68. 0 56
      dbsyncer-web/src/main/resources/public/databus/databus.html
  69. 11 11
      dbsyncer-web/src/main/resources/public/index/index.html
  70. 3 8
      dbsyncer-web/src/main/resources/public/mapping/editFull.html
  71. 1 1
      dbsyncer-web/src/main/resources/public/mapping/editIncrementDQL.html
  72. 181 128
      dbsyncer-web/src/main/resources/public/monitor/monitor.html
  73. 2 0
      dbsyncer-web/src/main/resources/static/js/common.js
  74. 6 6
      dbsyncer-web/src/main/resources/static/js/connector/add.js
  75. 1 1
      dbsyncer-web/src/main/resources/static/js/connector/edit.js
  76. 1 0
      dbsyncer-web/src/main/resources/static/js/index.js
  77. 3 3
      dbsyncer-web/src/main/resources/static/js/index/index.js
  78. 216 168
      dbsyncer-web/src/main/resources/static/js/monitor/index.js
  79. 3 0
      dbsyncer-web/src/main/resources/static/plugins/js/echarts/echarts.min.js
  80. 1 1
      pom.xml
  81. 1 1
      version.cmd

+ 20 - 22
README.md

@@ -1,6 +1,6 @@
 <div>
     <h3>介绍</h3>
-    <p>DBSyncer是一款开源的数据同步软件,提供Mysql、Oracle、SqlServer、SQL结果集等场景,支持自定义同步转换业务。</p>
+    <p>DBSyncer是一款开源的数据同步中间件,提供Mysql、Oracle、SqlServer、SQL结果集等同步场景。支持上传插件自定义同步转换业务,提供监控全量和增量数据统计图、应用性能预警等。</p>
     <p>特点</p>
     <ol>
         <li>组合驱动,自定义库同步到库组合,关系型数据库与非关系型之间组合,任意搭配表同步映射关系</li>
@@ -24,10 +24,10 @@
             <tr>
                 <td>Mysql</td>
                 <td>Oracle</td>
-                <td>SQLServer</td>
+                <td>SqlServer</td>
                 <td>Mysql</td>
                 <td>Oracle</td>
-                <td>SQLServer</td>
+                <td>SqlServer</td>
             </tr>
             <tr>
                 <td rowspan="6">数据源</td>
@@ -49,7 +49,7 @@
                 <td>√</td>
             </tr>
             <tr>
-                <td>SQLServer</td>
+                <td>SqlServer</td>
                 <td>√</td>
                 <td>√</td>
                 <td>√</td>
@@ -76,7 +76,7 @@
                 <td>√</td>
             </tr>
             <tr>
-                <td>DQLSQLServer</td>
+                <td>DQLSqlServer</td>
                 <td>√</td>
                 <td>√</td>
                 <td>√</td>
@@ -94,7 +94,7 @@
                 <td colspan="7">10g以上(Oracle-9i未测试)</td>
             </tr>
             <tr>
-                <td>SQLServer</td>
+                <td>SqlServer</td>
                 <td colspan="7">2008以上</td>
             </tr>
             <tr>
@@ -127,10 +127,10 @@
             </tr>
             <tr>
                 <td>
-                    <p>Mysql</p>
-                    <p>开启Binlog功能,my.ini配置:</p>
+                    <h5>Mysql</h5>
                 </td>
                 <td>
+                    <p>修改my.ini文件配置:</p>
                     <p># 服务唯一ID</p>
                     <p>server_id=1</p>
                     <p>log-bin=mysql_bin</p>
@@ -145,10 +145,10 @@
             </tr>
             <tr>
                 <td>
-                    <p>Oracle</p>
-                    <p>授予账号监听权限:</p>
+                    <h5>Oracle</h5>
                 </td>
                 <td>
+                    <p>授予账号监听权限:</p>
                     <p>grant change notification to AE86</p>
                     <p>要求目标源表必须定义一个长度为18的varchar字段,用于接收rowid值,来实现增删改操作</p>
                 </td>
@@ -156,10 +156,10 @@
             </tr>
             <tr>
                 <td>
-                    <p>SQLServer</p>
-                    <p>开启CDC:</p>
+                    <h5>SqlServer</h5>
                 </td>
                 <td>
+                    <p>开启CDC:</p>
                     <p>要求2008版本以上, 启动代理服务(Agent服务), 连接账号具有 sysadmin 固定服务器角色或 db_owner 固定数据库角色的成员身份。对于所有其他用户,具有源表SELECT 权限;如果已定义捕获实例的访问控制角色,则还要求具有该数据库角色的成员身份。</p>
                 </td>
                 <td>SQL Server 2008提供了内建的方法变更数据捕获(Change Data Capture 即CDC)以实现异步跟踪用户表的数据修改</td>
@@ -185,23 +185,21 @@
     <p align="center">
         <img src="https://images.gitee.com/uploads/images/2020/0519/000443_b52b4a8c_376718.png" />
     </p>
+    <p>驱动关系配置</p>
     <p align="center">
-        <img src="https://images.gitee.com/uploads/images/2020/0602/221008_64dbb479_376718.png" />
-    </p>
-    <p align="center">
-        <img src="https://images.gitee.com/uploads/images/2020/0602/221018_20d0ef67_376718.png" />
-    </p>
-    <p align="center">
-        <img src="https://images.gitee.com/uploads/images/2020/0602/221029_c4f5d804_376718.png" />
+        <img src="https://images.gitee.com/uploads/images/2021/0728/000933_477eb06d_376718.png" />
     </p>
+    <p>驱动表关系配置</p>
     <p align="center">
-        <img src="https://images.gitee.com/uploads/images/2021/0518/004836_3b4b9e49_376718.png" />
+        <img src="https://images.gitee.com/uploads/images/2021/0727/235329_54f0fbc6_376718.png" />
     </p>
+    <p>监控</p>
     <p align="center">
-        <img src="https://images.gitee.com/uploads/images/2021/0518/004947_6883e6c8_376718.png" />
+        <img src="https://images.gitee.com/uploads/images/2021/0728/000645_35a544b3_376718.png" />
     </p>
+    <p>上传插件</p>
     <p align="center">
-        <img src="https://images.gitee.com/uploads/images/2021/0518/005017_31e6697b_376718.png" />
+        <img src="https://images.gitee.com/uploads/images/2021/0727/235455_1ebda1f0_376718.png" />
     </p>
     <h3>流程图</h3>
     <p align="center">

+ 1 - 1
dbsyncer-biz/pom.xml

@@ -5,7 +5,7 @@
 	<parent>
 		<artifactId>dbsyncer</artifactId>
 		<groupId>org.ghi</groupId>
-		<version>1.0.8-Alpha</version>
+		<version>1.0.9-Alpha</version>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
 

+ 17 - 7
dbsyncer-biz/src/main/java/org/dbsyncer/biz/MonitorService.java

@@ -1,7 +1,10 @@
 package org.dbsyncer.biz;
 
+import org.dbsyncer.biz.vo.AppReportMetricVo;
 import org.dbsyncer.biz.vo.MetaVo;
 import org.dbsyncer.common.model.Paging;
+import org.dbsyncer.monitor.enums.MetricEnum;
+import org.dbsyncer.monitor.model.MetricResponse;
 import org.dbsyncer.storage.enums.StorageDataStatusEnum;
 
 import java.util.List;
@@ -14,13 +17,6 @@ import java.util.Map;
  */
 public interface MonitorService {
 
-    /**
-     * 获取线程信息
-     *
-     * @return
-     */
-    Map getThreadInfo();
-
     /**
      * 获取驱动元信息列表
      *
@@ -72,4 +68,18 @@ public interface MonitorService {
      * @return
      */
     List<StorageDataStatusEnum> getStorageDataStatusEnumAll();
+
+    /**
+     * 获取监控系统指标
+     *
+     * @return
+     */
+    List<MetricEnum> getMetricEnumAll();
+
+    /**
+     * 获取应用报告
+     *
+     * @return
+     */
+    AppReportMetricVo queryAppReportMetric(List<MetricResponse> metrics);
 }

+ 2 - 1
dbsyncer-biz/src/main/java/org/dbsyncer/biz/checker/impl/mapping/MappingChecker.java

@@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.util.Assert;
 
+import java.time.Instant;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -90,7 +91,6 @@ public class MappingChecker extends AbstractChecker {
 
         // 全量配置
         mapping.setReadNum(NumberUtils.toInt(params.get("readNum"), mapping.getReadNum()));
-        mapping.setThreadNum(NumberUtils.toInt(params.get("threadNum"), mapping.getThreadNum()));
         mapping.setBatchNum(NumberUtils.toInt(params.get("batchNum"), mapping.getBatchNum()));
 
         // 增量配置(日志/定时)
@@ -124,6 +124,7 @@ public class MappingChecker extends AbstractChecker {
 
         getMetaTotal(meta, mapping.getModel());
 
+        meta.setUpdateTime(Instant.now().toEpochMilli());
         manager.editMeta(meta);
     }
 

+ 77 - 58
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/MonitorServiceImpl.java

@@ -3,30 +3,30 @@ package org.dbsyncer.biz.impl;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.math.NumberUtils;
 import org.dbsyncer.biz.MonitorService;
-import org.dbsyncer.biz.vo.DataVo;
-import org.dbsyncer.biz.vo.LogVo;
-import org.dbsyncer.biz.vo.MetaVo;
+import org.dbsyncer.biz.metric.MetricDetailFormatter;
+import org.dbsyncer.biz.metric.impl.*;
+import org.dbsyncer.biz.vo.*;
 import org.dbsyncer.common.model.Paging;
 import org.dbsyncer.common.util.CollectionUtils;
 import org.dbsyncer.common.util.JsonUtil;
-import org.dbsyncer.manager.Manager;
 import org.dbsyncer.monitor.Monitor;
+import org.dbsyncer.monitor.enums.DiskMetricEnum;
+import org.dbsyncer.monitor.enums.MetricEnum;
+import org.dbsyncer.monitor.enums.ThreadPoolMetricEnum;
+import org.dbsyncer.monitor.model.AppReportMetric;
+import org.dbsyncer.monitor.model.MetricResponse;
 import org.dbsyncer.parser.enums.ModelEnum;
 import org.dbsyncer.parser.model.Mapping;
 import org.dbsyncer.parser.model.Meta;
 import org.dbsyncer.storage.constant.ConfigConstant;
 import org.dbsyncer.storage.enums.StorageDataStatusEnum;
-import org.dbsyncer.storage.query.Query;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.util.Assert;
 
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
+import javax.annotation.PostConstruct;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -37,22 +37,33 @@ import java.util.stream.Collectors;
 @Service
 public class MonitorServiceImpl implements MonitorService {
 
-    private final Logger logger = LoggerFactory.getLogger(getClass());
-
     @Autowired
     private Monitor monitor;
 
-    @Autowired
-    private Manager manager;
-
-    @Override
-    public Map getThreadInfo() {
-        return monitor.getThreadInfo();
+    private Map<String, MetricDetailFormatter> metricDetailFormatterMap = new LinkedHashMap<>();
+
+    @PostConstruct
+    private void init() {
+        metricDetailFormatterMap.putIfAbsent(ThreadPoolMetricEnum.TASK_SUBMITTED.getCode(), new ValueMetricDetailFormatter());
+        metricDetailFormatterMap.putIfAbsent(ThreadPoolMetricEnum.QUEUE_UP.getCode(), new ValueMetricDetailFormatter());
+        metricDetailFormatterMap.putIfAbsent(ThreadPoolMetricEnum.ACTIVE.getCode(), new ValueMetricDetailFormatter());
+        metricDetailFormatterMap.putIfAbsent(ThreadPoolMetricEnum.COMPLETED.getCode(), new ValueMetricDetailFormatter());
+        metricDetailFormatterMap.putIfAbsent(ThreadPoolMetricEnum.REMAINING_CAPACITY.getCode(), new ValueMetricDetailFormatter());
+        metricDetailFormatterMap.putIfAbsent(MetricEnum.THREADS_LIVE.getCode(), new DoubleRoundMetricDetailFormatter());
+        metricDetailFormatterMap.putIfAbsent(MetricEnum.THREADS_PEAK.getCode(), new DoubleRoundMetricDetailFormatter());
+        metricDetailFormatterMap.putIfAbsent(MetricEnum.MEMORY_USED.getCode(), new MemoryMetricDetailFormatter());
+        metricDetailFormatterMap.putIfAbsent(MetricEnum.MEMORY_COMMITTED.getCode(), new MemoryMetricDetailFormatter());
+        metricDetailFormatterMap.putIfAbsent(MetricEnum.MEMORY_MAX.getCode(), new MemoryMetricDetailFormatter());
+        metricDetailFormatterMap.putIfAbsent(MetricEnum.CPU_USAGE.getCode(), new CpuMetricDetailFormatter());
+        metricDetailFormatterMap.putIfAbsent(MetricEnum.GC_PAUSE.getCode(), new GCMetricDetailFormatter());
+        metricDetailFormatterMap.putIfAbsent(DiskMetricEnum.THRESHOLD.getCode(), new DiskMetricDetailFormatter());
+        metricDetailFormatterMap.putIfAbsent(DiskMetricEnum.FREE.getCode(), new DiskMetricDetailFormatter());
+        metricDetailFormatterMap.putIfAbsent(DiskMetricEnum.TOTAL.getCode(), new DiskMetricDetailFormatter());
     }
 
     @Override
     public List<MetaVo> getMetaAll() {
-        List<MetaVo> list = manager.getMetaAll()
+        List<MetaVo> list = monitor.getMetaAll()
                 .stream()
                 .map(m -> convertMeta2Vo(m))
                 .sorted(Comparator.comparing(MetaVo::getUpdateTime).reversed())
@@ -63,38 +74,18 @@ public class MonitorServiceImpl implements MonitorService {
     @Override
     public String getDefaultMetaId(Map<String, String> params) {
         String id = params.get(ConfigConstant.CONFIG_MODEL_ID);
-        if (StringUtils.isNotBlank(id)) {
-            return id;
-        }
-        return getDefaultMetaId();
+        return getDefaultMetaId(id);
     }
 
     @Override
     public Paging queryData(Map<String, String> params) {
         String id = params.get(ConfigConstant.CONFIG_MODEL_ID);
-        // 获取默认驱动元信息
-        if (StringUtils.isBlank(id)) {
-            id = getDefaultMetaId();
-        }
-
         int pageNum = NumberUtils.toInt(params.get("pageNum"), 1);
         int pageSize = NumberUtils.toInt(params.get("pageSize"), 10);
-        // 没有驱动
-        if (StringUtils.isBlank(id)) {
-            return new Paging(pageNum, pageSize);
-        }
-
-        Query query = new Query(pageNum, pageSize);
-        // 查询异常信息
         String error = params.get(ConfigConstant.DATA_ERROR);
-        if (StringUtils.isNotBlank(error)) {
-            query.put(ConfigConstant.DATA_ERROR, error, true);
-        }
-        // 查询是否成功, 默认查询失败
         String success = params.get(ConfigConstant.DATA_SUCCESS);
-        query.put(ConfigConstant.DATA_SUCCESS, StringUtils.isNotBlank(success) ? success : StorageDataStatusEnum.FAIL.getCode(), false, true);
 
-        Paging paging = manager.queryData(query, id);
+        Paging paging = monitor.queryData(getDefaultMetaId(id), pageNum, pageSize, error, success);
         List<Map> data = (List<Map>) paging.getData();
         paging.setData(data.stream()
                 .map(m -> convert2Vo(m, DataVo.class))
@@ -105,7 +96,7 @@ public class MonitorServiceImpl implements MonitorService {
     @Override
     public String clearData(String id) {
         Assert.hasText(id, "驱动不存在.");
-        manager.clearData(id);
+        monitor.clearData(id);
         return "清空同步数据成功";
     }
 
@@ -113,13 +104,8 @@ public class MonitorServiceImpl implements MonitorService {
     public Paging queryLog(Map<String, String> params) {
         int pageNum = NumberUtils.toInt(params.get("pageNum"), 1);
         int pageSize = NumberUtils.toInt(params.get("pageSize"), 10);
-        Query query = new Query(pageNum, pageSize);
-        // 查询日志内容
         String json = params.get(ConfigConstant.CONFIG_MODEL_JSON);
-        if (StringUtils.isNotBlank(json)) {
-            query.put(ConfigConstant.CONFIG_MODEL_JSON, json, true);
-        }
-        Paging paging = manager.queryLog(query);
+        Paging paging = monitor.queryLog(pageNum, pageSize, json);
         List<Map> data = (List<Map>) paging.getData();
         paging.setData(data.stream()
                 .map(m -> convert2Vo(m, LogVo.class))
@@ -129,17 +115,31 @@ public class MonitorServiceImpl implements MonitorService {
 
     @Override
     public String clearLog() {
-        manager.clearLog();
+        monitor.clearLog();
         return "清空日志成功";
     }
 
     @Override
     public List<StorageDataStatusEnum> getStorageDataStatusEnumAll() {
-        return manager.getStorageDataStatusEnumAll();
+        return monitor.getStorageDataStatusEnumAll();
+    }
+
+    @Override
+    public List<MetricEnum> getMetricEnumAll() {
+        return monitor.getMetricEnumAll();
+    }
+
+    @Override
+    public AppReportMetricVo queryAppReportMetric(List<MetricResponse> metrics) {
+        AppReportMetric appReportMetric = monitor.getAppReportMetric();
+        AppReportMetricVo vo = new AppReportMetricVo();
+        BeanUtils.copyProperties(appReportMetric, vo);
+        vo.setMetrics(getMetrics(metrics));
+        return vo;
     }
 
     private MetaVo convertMeta2Vo(Meta meta) {
-        Mapping mapping = manager.getMapping(meta.getMappingId());
+        Mapping mapping = monitor.getMapping(meta.getMappingId());
         Assert.notNull(mapping, "驱动不存在.");
         ModelEnum modelEnum = ModelEnum.getModelEnum(mapping.getModel());
         MetaVo metaVo = new MetaVo(modelEnum.getName(), mapping.getName());
@@ -149,15 +149,34 @@ public class MonitorServiceImpl implements MonitorService {
     }
 
     private <T> T convert2Vo(Map map, Class<T> clazz) {
-        String json = JsonUtil.objToJson(map);
-        return JsonUtil.jsonToObj(json, clazz);
+        return JsonUtil.jsonToObj(JsonUtil.objToJson(map), clazz);
     }
 
-    private String getDefaultMetaId() {
-        List<MetaVo> list = getMetaAll();
-        if (!CollectionUtils.isEmpty(list)) {
-            return list.get(0).getId();
+    private String getDefaultMetaId(String id) {
+        if (StringUtils.isBlank(id)) {
+            List<MetaVo> list = getMetaAll();
+            if (!CollectionUtils.isEmpty(list)) {
+                return list.get(0).getId();
+            }
         }
-        return "";
+        return id;
+    }
+
+    private List<MetricResponseVo> getMetrics(List<MetricResponse> metrics) {
+        // 线程池状态
+        List<MetricResponse> metricList = monitor.getThreadPoolInfo();
+        // 系统指标
+        metricList.addAll(metrics);
+
+        // 转换显示
+        return metricList.stream().map(metric -> {
+            MetricResponseVo vo = new MetricResponseVo();
+            BeanUtils.copyProperties(metric, vo);
+            MetricDetailFormatter detailFormatter = metricDetailFormatterMap.get(vo.getCode());
+            if (null != detailFormatter) {
+                detailFormatter.format(vo);
+            }
+            return vo;
+        }).collect(Collectors.toList());
     }
 }

+ 17 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/AbstractMetricDetailFormatter.java

@@ -0,0 +1,17 @@
+package org.dbsyncer.biz.metric;
+
+import org.dbsyncer.biz.vo.MetricResponseVo;
+import org.dbsyncer.common.util.CollectionUtils;
+
+public abstract class AbstractMetricDetailFormatter implements MetricDetailFormatter{
+
+    protected abstract void apply(MetricResponseVo vo);
+
+    @Override
+    public void format(MetricResponseVo vo) {
+        if(CollectionUtils.isEmpty(vo.getMeasurements())){
+            return;
+        }
+        apply(vo);
+    }
+}

+ 9 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/MetricDetailFormatter.java

@@ -0,0 +1,9 @@
+package org.dbsyncer.biz.metric;
+
+import org.dbsyncer.biz.vo.MetricResponseVo;
+
+public interface MetricDetailFormatter {
+
+    void format(MetricResponseVo vo);
+
+}

+ 16 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/impl/CpuMetricDetailFormatter.java

@@ -0,0 +1,16 @@
+package org.dbsyncer.biz.metric.impl;
+
+import org.dbsyncer.biz.metric.AbstractMetricDetailFormatter;
+import org.dbsyncer.biz.vo.MetricResponseVo;
+import org.dbsyncer.monitor.model.Sample;
+
+public final class CpuMetricDetailFormatter extends AbstractMetricDetailFormatter {
+
+    @Override
+    public void apply(MetricResponseVo vo) {
+        Sample sample = vo.getMeasurements().get(0);
+        Double value = (Double) sample.getValue();
+        vo.setDetail(String.format("%.2f", (value * 100)) + "%");
+    }
+
+}

+ 25 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/impl/DiskMetricDetailFormatter.java

@@ -0,0 +1,25 @@
+package org.dbsyncer.biz.metric.impl;
+
+import org.dbsyncer.biz.metric.AbstractMetricDetailFormatter;
+import org.dbsyncer.biz.vo.MetricResponseVo;
+import org.dbsyncer.monitor.model.Sample;
+
+import java.math.BigDecimal;
+
+public class DiskMetricDetailFormatter extends AbstractMetricDetailFormatter {
+
+    @Override
+    public void apply(MetricResponseVo vo) {
+        Sample sample = vo.getMeasurements().get(0);
+        BigDecimal decimal = new BigDecimal(String.valueOf(sample.getValue()));
+        BigDecimal bt = divide(decimal,0);
+        BigDecimal mb = divide(bt,0);
+        BigDecimal gb = divide(mb,2);
+        vo.setDetail(gb + "GB");
+    }
+
+    private BigDecimal divide(BigDecimal d1, int scale) {
+        return d1.divide(new BigDecimal("1024"), scale, BigDecimal.ROUND_HALF_UP);
+    }
+
+}

+ 16 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/impl/DoubleRoundMetricDetailFormatter.java

@@ -0,0 +1,16 @@
+package org.dbsyncer.biz.metric.impl;
+
+import org.dbsyncer.biz.metric.AbstractMetricDetailFormatter;
+import org.dbsyncer.biz.vo.MetricResponseVo;
+import org.dbsyncer.monitor.model.Sample;
+
+public final class DoubleRoundMetricDetailFormatter extends AbstractMetricDetailFormatter {
+
+    @Override
+    public void apply(MetricResponseVo vo) {
+        Sample sample = vo.getMeasurements().get(0);
+        long round = Math.round((Double) sample.getValue());
+        vo.setDetail(String.valueOf(round));
+    }
+
+}

+ 20 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/impl/GCMetricDetailFormatter.java

@@ -0,0 +1,20 @@
+package org.dbsyncer.biz.metric.impl;
+
+import org.dbsyncer.biz.metric.AbstractMetricDetailFormatter;
+import org.dbsyncer.biz.vo.MetricResponseVo;
+import org.dbsyncer.monitor.model.Sample;
+
+import java.util.List;
+
+public final class GCMetricDetailFormatter extends AbstractMetricDetailFormatter {
+
+    @Override
+    public void apply(MetricResponseVo vo) {
+        List<Sample> list = vo.getMeasurements();
+        long count = Math.round((Double) list.get(0).getValue());
+        String total = String.format("%.2f", ((Double) list.get(1).getValue()));
+        long max = Math.round((Double) list.get(2).getValue());
+        vo.setDetail(String.format("%s次,耗时:%s秒,最长:%s秒", count, total, max));
+    }
+
+}

+ 19 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/impl/MemoryMetricDetailFormatter.java

@@ -0,0 +1,19 @@
+package org.dbsyncer.biz.metric.impl;
+
+import org.dbsyncer.biz.metric.AbstractMetricDetailFormatter;
+import org.dbsyncer.biz.vo.MetricResponseVo;
+import org.dbsyncer.common.util.CollectionUtils;
+import org.dbsyncer.monitor.model.Sample;
+
+import java.text.DecimalFormat;
+
+public class MemoryMetricDetailFormatter extends AbstractMetricDetailFormatter {
+
+    @Override
+    public void apply(MetricResponseVo vo) {
+        Sample sample = vo.getMeasurements().get(0);
+        Double value = (Double) sample.getValue();
+        vo.setDetail(String.format("%.2fMB", (value / 1024 / 1024)));
+    }
+
+}

+ 15 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/metric/impl/ValueMetricDetailFormatter.java

@@ -0,0 +1,15 @@
+package org.dbsyncer.biz.metric.impl;
+
+import org.dbsyncer.biz.metric.AbstractMetricDetailFormatter;
+import org.dbsyncer.biz.vo.MetricResponseVo;
+import org.dbsyncer.monitor.model.Sample;
+
+public final class ValueMetricDetailFormatter extends AbstractMetricDetailFormatter {
+
+    @Override
+    public void apply(MetricResponseVo vo) {
+        Sample sample = vo.getMeasurements().get(0);
+        vo.setDetail(String.valueOf(sample.getValue()));
+    }
+
+}

+ 38 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/vo/AppReportMetricVo.java

@@ -0,0 +1,38 @@
+package org.dbsyncer.biz.vo;
+
+import org.dbsyncer.monitor.model.AppReportMetric;
+
+import java.util.List;
+
+public class AppReportMetricVo extends AppReportMetric {
+
+    private List<MetricResponseVo> metrics;
+
+    private HistoryStackVo cpu;
+
+    private HistoryStackVo memory;
+
+    public List<MetricResponseVo> getMetrics() {
+        return metrics;
+    }
+
+    public void setMetrics(List<MetricResponseVo> metrics) {
+        this.metrics = metrics;
+    }
+
+    public HistoryStackVo getCpu() {
+        return cpu;
+    }
+
+    public void setCpu(HistoryStackVo cpu) {
+        this.cpu = cpu;
+    }
+
+    public HistoryStackVo getMemory() {
+        return memory;
+    }
+
+    public void setMemory(HistoryStackVo memory) {
+        this.memory = memory;
+    }
+}

+ 32 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/vo/HistoryStackVo.java

@@ -0,0 +1,32 @@
+package org.dbsyncer.biz.vo;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class HistoryStackVo {
+
+    private List<Object> name;
+
+    private List<Object> value;
+
+    public HistoryStackVo() {
+        this.name = new LinkedList<>();
+        this.value = new LinkedList<>();
+    }
+
+    public List<Object> getName() {
+        return name;
+    }
+
+    public void setName(List<Object> name) {
+        this.name = name;
+    }
+
+    public List<Object> getValue() {
+        return value;
+    }
+
+    public void setValue(List<Object> value) {
+        this.value = value;
+    }
+}

+ 16 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/vo/MetricResponseVo.java

@@ -0,0 +1,16 @@
+package org.dbsyncer.biz.vo;
+
+import org.dbsyncer.monitor.model.MetricResponse;
+
+public class MetricResponseVo extends MetricResponse {
+
+    private String detail;
+
+    public String getDetail() {
+        return detail;
+    }
+
+    public void setDetail(String detail) {
+        this.detail = detail;
+    }
+}

+ 1 - 1
dbsyncer-cache/pom.xml

@@ -4,7 +4,7 @@
 	<parent>
 		<artifactId>dbsyncer</artifactId>
 		<groupId>org.ghi</groupId>
-		<version>1.0.8-Alpha</version>
+		<version>1.0.9-Alpha</version>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
dbsyncer-cluster/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>dbsyncer</artifactId>
         <groupId>org.ghi</groupId>
-		<version>1.0.8-Alpha</version>
+		<version>1.0.9-Alpha</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
dbsyncer-common/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>dbsyncer</artifactId>
         <groupId>org.ghi</groupId>
-		<version>1.0.8-Alpha</version>
+		<version>1.0.9-Alpha</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>dbsyncer-common</artifactId>

+ 3 - 14
dbsyncer-common/src/main/java/org/dbsyncer/common/event/Event.java

@@ -10,22 +10,11 @@ import java.util.Map;
 public interface Event {
 
     /**
-     * 日志数据变更事件
+     * 数据变更事件
      *
-     * @param rowChangedEvent
+     * @param event
      */
-    default void changedLogEvent(RowChangedEvent rowChangedEvent) {
-        // nothing to do
-    }
-
-    /**
-     * 定时数据变更事件
-     *
-     * @param rowChangedEvent
-     */
-    default void changedQuartzEvent(RowChangedEvent rowChangedEvent){
-        // nothing to do
-    }
+    void changedEvent(RowChangedEvent event);
 
     /**
      * 写入增量点事件

+ 3 - 3
dbsyncer-common/src/main/java/org/dbsyncer/common/model/Paging.java

@@ -5,9 +5,9 @@ import java.util.Collections;
 
 public class Paging {
 
-    private long          total;
-    private int           pageNum;
-    private int           pageSize;
+    private long total;
+    private int pageNum;
+    private int pageSize;
     private Collection data;
 
     public Paging(int pageNum, int pageSize) {

+ 4 - 5
dbsyncer-common/src/main/java/org/dbsyncer/common/util/DateFormatUtil.java

@@ -9,20 +9,19 @@ import java.util.Date;
 
 public abstract class DateFormatUtil {
 
-    private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
     private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+    private static final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
     private static ZoneId zoneId = ZoneId.systemDefault();
 
     public DateFormatUtil() {
     }
 
-    public static String getCurrentDateTime() {
-        return LocalDateTime.now().format(dateTimeFormatter);
+    public static String getCurrentTime() {
+        return LocalDateTime.now().format(timeFormatter);
     }
 
     public static String dateToString(Date date){
-        String format = date.toInstant().atZone(zoneId).toLocalDate().format(dateFormatter);
-        return format;
+        return date.toInstant().atZone(zoneId).toLocalDate().format(dateFormatter);
     }
 
     public static Date stringToDate(String s){

+ 1 - 1
dbsyncer-connector/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>dbsyncer</artifactId>
         <groupId>org.ghi</groupId>
-		<version>1.0.8-Alpha</version>
+		<version>1.0.9-Alpha</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
dbsyncer-listener/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>dbsyncer</artifactId>
         <groupId>org.ghi</groupId>
-		<version>1.0.8-Alpha</version>
+		<version>1.0.9-Alpha</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 4 - 14
dbsyncer-listener/src/main/java/org/dbsyncer/listener/AbstractExtractor.java

@@ -13,10 +13,8 @@ import org.slf4j.LoggerFactory;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Executor;
-import java.util.concurrent.LinkedBlockingQueue;
 
 /**
  * @version 1.0.0
@@ -26,7 +24,6 @@ import java.util.concurrent.LinkedBlockingQueue;
 public abstract class AbstractExtractor implements Extractor {
 
     private final Logger logger = LoggerFactory.getLogger(getClass());
-    protected BlockingQueue queue = new LinkedBlockingQueue<>(100);
     protected Executor taskExecutor;
     protected ConnectorFactory connectorFactory;
     protected ScheduledTaskService scheduledTaskService;
@@ -55,16 +52,9 @@ public abstract class AbstractExtractor implements Extractor {
     }
 
     @Override
-    public void changedQuartzEvent(RowChangedEvent rowChangedEvent) {
+    public void changedEvent(RowChangedEvent event) {
         if (!CollectionUtils.isEmpty(watcher)) {
-            watcher.forEach(w -> w.changedQuartzEvent(rowChangedEvent));
-        }
-    }
-
-    @Override
-    public void changedLogEvent(RowChangedEvent rowChangedEvent) {
-        if (!CollectionUtils.isEmpty(watcher)) {
-            watcher.forEach(w -> w.changedLogEvent(rowChangedEvent));
+            watcher.forEach(w -> w.changedEvent(event));
         }
     }
 
@@ -97,8 +87,8 @@ public abstract class AbstractExtractor implements Extractor {
         }
     }
 
-    protected void asynSendRowChangedEvent(RowChangedEvent rowChangedEvent) {
-        taskExecutor.execute(() -> changedLogEvent(rowChangedEvent));
+    protected void asynSendRowChangedEvent(RowChangedEvent event) {
+        taskExecutor.execute(() -> changedEvent(event));
     }
 
     public void setTaskExecutor(Executor taskExecutor) {

+ 3 - 10
dbsyncer-listener/src/main/java/org/dbsyncer/listener/Extractor.java

@@ -28,18 +28,11 @@ public interface Extractor {
     void clearAllListener();
 
     /**
-     * 定时模式: 监听增量事件
+     * 数据变更事件
      *
-     * @param rowChangedEvent
-     */
-    void changedQuartzEvent(RowChangedEvent rowChangedEvent);
-
-    /**
-     * 日志模式: 监听增量事件
-     *
-     * @param rowChangedEvent
+     * @param event
      */
-    void changedLogEvent(RowChangedEvent rowChangedEvent);
+    void changedEvent(RowChangedEvent event);
 
     /**
      * 刷新增量点事件

+ 1 - 1
dbsyncer-listener/src/main/java/org/dbsyncer/listener/oracle/OracleExtractor.java

@@ -25,7 +25,7 @@ public class OracleExtractor extends AbstractExtractor {
             String username = config.getUsername();
             String password = config.getPassword();
             String url = config.getUrl();
-            client = new DBChangeNotification(username, password, url, queue);
+            client = new DBChangeNotification(username, password, url);
             client.setFilterTable(filterTable);
             client.addRowEventListener((e) -> asynSendRowChangedEvent(e));
             client.start();

+ 1 - 9
dbsyncer-listener/src/main/java/org/dbsyncer/listener/oracle/dcn/DBChangeNotification.java

@@ -48,23 +48,15 @@ public class DBChangeNotification {
     private OracleStatement            statement;
     private DatabaseChangeRegistration dcr;
     private Map<Integer, String>       tables;
-    private BlockingQueue<DCNEvent>    queue;
     private Worker                     worker;
     private Set<String>                filterTable;
     private List<RowEventListener>     listeners = new ArrayList<>();
+    private BlockingQueue<DCNEvent>    queue = new LinkedBlockingQueue<> (100);
 
     public DBChangeNotification(String username, String password, String url) {
         this.username = username;
         this.password = password;
         this.url = url;
-        this.queue = new LinkedBlockingQueue<> (100);
-    }
-
-    public DBChangeNotification(String username, String password, String url, BlockingQueue queue) {
-        this.username = username;
-        this.password = password;
-        this.url = url;
-        this.queue = queue;
     }
 
     public void addRowEventListener(RowEventListener rowEventListener) {

+ 3 - 3
dbsyncer-listener/src/main/java/org/dbsyncer/listener/quartz/QuartzExtractor.java

@@ -90,15 +90,15 @@ public class QuartzExtractor extends AbstractExtractor implements ScheduledTaskJ
             for (Map<String, Object> row : data) {
                 event = row.get(eventFieldName);
                 if (update.contains(event)) {
-                    changedQuartzEvent(new RowChangedEvent(index, ConnectorConstant.OPERTION_UPDATE, Collections.EMPTY_MAP, row));
+                    changedEvent(new RowChangedEvent(index, ConnectorConstant.OPERTION_UPDATE, Collections.EMPTY_MAP, row));
                     continue;
                 }
                 if (insert.contains(event)) {
-                    changedQuartzEvent(new RowChangedEvent(index, ConnectorConstant.OPERTION_INSERT, Collections.EMPTY_MAP, row));
+                    changedEvent(new RowChangedEvent(index, ConnectorConstant.OPERTION_INSERT, Collections.EMPTY_MAP, row));
                     continue;
                 }
                 if (delete.contains(event)) {
-                    changedQuartzEvent(new RowChangedEvent(index, ConnectorConstant.OPERTION_DELETE, row, Collections.EMPTY_MAP));
+                    changedEvent(new RowChangedEvent(index, ConnectorConstant.OPERTION_DELETE, row, Collections.EMPTY_MAP));
                     continue;
                 }
 

+ 3 - 3
dbsyncer-listener/src/main/java/org/dbsyncer/listener/sqlserver/SqlServerExtractor.java

@@ -257,17 +257,17 @@ public class SqlServerExtractor extends AbstractExtractor {
         for (CDCEvent event : list) {
             int code = event.getCode();
             if (TableOperationEnum.isUpdateAfter(code)) {
-                changedLogEvent(new RowChangedEvent(event.getTableName(), ConnectorConstant.OPERTION_UPDATE, Collections.EMPTY_LIST, event.getRow()));
+                changedEvent(new RowChangedEvent(event.getTableName(), ConnectorConstant.OPERTION_UPDATE, Collections.EMPTY_LIST, event.getRow()));
                 continue;
             }
 
             if (TableOperationEnum.isInsert(code)) {
-                changedLogEvent(new RowChangedEvent(event.getTableName(), ConnectorConstant.OPERTION_INSERT, Collections.EMPTY_LIST, event.getRow()));
+                changedEvent(new RowChangedEvent(event.getTableName(), ConnectorConstant.OPERTION_INSERT, Collections.EMPTY_LIST, event.getRow()));
                 continue;
             }
 
             if (TableOperationEnum.isDelete(code)) {
-                changedLogEvent(new RowChangedEvent(event.getTableName(), ConnectorConstant.OPERTION_DELETE, event.getRow(), Collections.EMPTY_LIST));
+                changedEvent(new RowChangedEvent(event.getTableName(), ConnectorConstant.OPERTION_DELETE, event.getRow(), Collections.EMPTY_LIST));
             }
         }
     }

+ 1 - 1
dbsyncer-manager/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>dbsyncer</artifactId>
         <groupId>org.ghi</groupId>
-		<version>1.0.8-Alpha</version>
+		<version>1.0.9-Alpha</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 5 - 5
dbsyncer-manager/src/main/java/org/dbsyncer/manager/puller/impl/IncrementPuller.java

@@ -187,9 +187,9 @@ public class IncrementPuller extends AbstractPuller implements ScheduledTaskJob,
     }
 
     abstract class AbstractListener implements Event {
-        protected Mapping                   mapping;
-        protected String                    metaId;
-        protected AtomicBoolean             changed = new AtomicBoolean();
+        protected Mapping mapping;
+        protected String metaId;
+        protected AtomicBoolean changed = new AtomicBoolean();
 
         @Override
         public void flushEvent(Map<String, String> map) {
@@ -252,7 +252,7 @@ public class IncrementPuller extends AbstractPuller implements ScheduledTaskJob,
         }
 
         @Override
-        public void changedQuartzEvent(RowChangedEvent rowChangedEvent) {
+        public void changedEvent(RowChangedEvent rowChangedEvent) {
             final FieldPicker picker = tablePicker.get(rowChangedEvent.getTableGroupIndex());
             logger.info("监听数据=> tableName:{}, event:{}, before:{}, after:{}", picker.getTableGroup().getSourceTable().getName(),
                     rowChangedEvent.getEvent(),
@@ -311,7 +311,7 @@ public class IncrementPuller extends AbstractPuller implements ScheduledTaskJob,
         }
 
         @Override
-        public void changedLogEvent(RowChangedEvent rowChangedEvent) {
+        public void changedEvent(RowChangedEvent rowChangedEvent) {
             // 处理过程有异常向上抛
             List<FieldPicker> pickers = tablePicker.get(rowChangedEvent.getTableName());
             if (!CollectionUtils.isEmpty(pickers)) {

+ 1 - 1
dbsyncer-manager/src/main/java/org/dbsyncer/manager/template/impl/PreloadTemplate.java

@@ -57,7 +57,7 @@ public final class PreloadTemplate extends AbstractTemplate implements Applicati
         Query query = new Query();
         query.setType(StorageEnum.CONFIG);
         String filterType = config.getFilterType();
-        query.put(ConfigConstant.CONFIG_MODEL_TYPE, filterType);
+        query.addFilter(ConfigConstant.CONFIG_MODEL_TYPE, filterType);
 
         int pageNum = 1;
         int pageSize = 20;

+ 1 - 1
dbsyncer-monitor/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>dbsyncer</artifactId>
         <groupId>org.ghi</groupId>
-		<version>1.0.8-Alpha</version>
+		<version>1.0.9-Alpha</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 29 - 2
dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/Monitor.java

@@ -1,6 +1,14 @@
 package org.dbsyncer.monitor;
 
-import java.util.Map;
+import org.dbsyncer.common.model.Paging;
+import org.dbsyncer.monitor.enums.MetricEnum;
+import org.dbsyncer.monitor.model.AppReportMetric;
+import org.dbsyncer.monitor.model.MetricResponse;
+import org.dbsyncer.parser.model.Mapping;
+import org.dbsyncer.parser.model.Meta;
+import org.dbsyncer.storage.enums.StorageDataStatusEnum;
+
+import java.util.List;
 
 /**
  * @author AE86
@@ -11,5 +19,24 @@ public interface Monitor {
 
     boolean isAlive(String id);
 
-    Map getThreadInfo();
+    Mapping getMapping(String mappingId);
+
+    List<Meta> getMetaAll();
+
+    Paging queryData(String id, int pageNum, int pageSize, String error, String success);
+
+    void clearData(String collectionId);
+
+    Paging queryLog(int pageNum, int pageSize, String json);
+
+    void clearLog();
+
+    List<StorageDataStatusEnum> getStorageDataStatusEnumAll();
+
+    List<MetricEnum> getMetricEnumAll();
+
+    List<MetricResponse> getThreadPoolInfo();
+
+    AppReportMetric getAppReportMetric();
+
 }

+ 27 - 0
dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/MonitorException.java

@@ -0,0 +1,27 @@
+package org.dbsyncer.monitor;
+
+/**
+ * @author AE86
+ * @version 1.0.0
+ * @date 2021/7/23 22:39
+ */
+public class MonitorException extends RuntimeException {
+
+	private static final long serialVersionUID = 1L;
+
+	public MonitorException(String message) {
+        super(message);
+    }
+
+    public MonitorException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public MonitorException(Throwable cause) {
+        super(cause);
+    }
+
+    protected MonitorException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}

+ 182 - 13
dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/MonitorFactory.java

@@ -1,18 +1,37 @@
 package org.dbsyncer.monitor;
 
+import org.apache.commons.lang.StringUtils;
+import org.dbsyncer.common.model.Paging;
+import org.dbsyncer.common.util.CollectionUtils;
+import org.dbsyncer.connector.constant.ConnectorConstant;
 import org.dbsyncer.manager.Manager;
+import org.dbsyncer.monitor.enums.MetricEnum;
+import org.dbsyncer.monitor.enums.StatisticEnum;
+import org.dbsyncer.monitor.enums.ThreadPoolMetricEnum;
+import org.dbsyncer.monitor.model.AppReportMetric;
+import org.dbsyncer.monitor.model.MetricResponse;
+import org.dbsyncer.monitor.model.Sample;
 import org.dbsyncer.parser.model.Connector;
+import org.dbsyncer.parser.model.Mapping;
+import org.dbsyncer.parser.model.Meta;
+import org.dbsyncer.storage.constant.ConfigConstant;
+import org.dbsyncer.storage.enums.StorageDataStatusEnum;
+import org.dbsyncer.storage.query.Query;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Component;
 
-import java.util.HashMap;
-import java.util.Map;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * @author AE86
@@ -30,6 +49,12 @@ public class MonitorFactory implements Monitor {
     @Autowired
     private Executor taskExecutor;
 
+    /**
+     * 工作线程池队列容量
+     */
+    @Value(value = "${dbsyncer.web.thread.pool.queue.capacity}")
+    private int queueCapacity;
+
     @Override
     @Cacheable(value = "connector", keyGenerator = "cacheKeyGenerator")
     public boolean isAlive(String id) {
@@ -38,19 +63,163 @@ public class MonitorFactory implements Monitor {
     }
 
     @Override
-    public Map getThreadInfo() {
-        Map map = new HashMap();
-        if (taskExecutor instanceof ThreadPoolTaskExecutor) {
-            ThreadPoolTaskExecutor threadTask = (ThreadPoolTaskExecutor) taskExecutor;
-            ThreadPoolExecutor threadPoolExecutor = threadTask.getThreadPoolExecutor();
+    public Mapping getMapping(String mappingId) {
+        return manager.getMapping(mappingId);
+    }
 
-            map.put("已提交", threadPoolExecutor.getTaskCount());
-            map.put("已完成", threadPoolExecutor.getCompletedTaskCount());
-            map.put("处理中", threadPoolExecutor.getActiveCount());
-            map.put("排队中", threadPoolExecutor.getQueue().size());
-            map.put("队列长度", threadPoolExecutor.getQueue().remainingCapacity());
+    @Override
+    public List<Meta> getMetaAll() {
+        return manager.getMetaAll();
+    }
+
+    @Override
+    public Paging queryData(String id, int pageNum, int pageSize, String error, String success) {
+        // 没有驱动
+        if (StringUtils.isBlank(id)) {
+            return new Paging(pageNum, pageSize);
         }
-        return map;
+
+        // 查询异常信息
+        Query query = new Query(pageNum, pageSize);
+        if (StringUtils.isNotBlank(error)) {
+            query.addFilter(ConfigConstant.DATA_ERROR, error, true);
+        }
+        // 查询是否成功, 默认查询失败
+        query.addFilter(ConfigConstant.DATA_SUCCESS, StringUtils.isNotBlank(success) ? success : StorageDataStatusEnum.FAIL.getCode(), false, true);
+        return manager.queryData(query, id);
+    }
+
+    @Override
+    public void clearData(String collectionId) {
+        manager.clearData(collectionId);
+    }
+
+    @Override
+    public Paging queryLog(int pageNum, int pageSize, String json) {
+        Query query = new Query(pageNum, pageSize);
+        if (StringUtils.isNotBlank(json)) {
+            query.addFilter(ConfigConstant.CONFIG_MODEL_JSON, json, true);
+        }
+        return manager.queryLog(query);
+    }
+
+    @Override
+    public void clearLog() {
+        manager.clearLog();
+    }
+
+    @Override
+    public List<StorageDataStatusEnum> getStorageDataStatusEnumAll() {
+        return manager.getStorageDataStatusEnumAll();
+    }
+
+    @Override
+    public List<MetricEnum> getMetricEnumAll() {
+        return Arrays.asList(MetricEnum.values());
+    }
+
+    @Override
+    public List<MetricResponse> getThreadPoolInfo() {
+        ThreadPoolTaskExecutor threadTask = (ThreadPoolTaskExecutor) taskExecutor;
+        ThreadPoolExecutor pool = threadTask.getThreadPoolExecutor();
+
+        List<MetricResponse> list = new ArrayList<>();
+        list.add(createMetricResponse(ThreadPoolMetricEnum.TASK_SUBMITTED, pool.getTaskCount()));
+        list.add(createMetricResponse(ThreadPoolMetricEnum.QUEUE_UP, pool.getQueue().size()));
+        list.add(createMetricResponse(ThreadPoolMetricEnum.ACTIVE, pool.getActiveCount()));
+        list.add(createMetricResponse(ThreadPoolMetricEnum.COMPLETED, pool.getCompletedTaskCount()));
+        list.add(createMetricResponse(ThreadPoolMetricEnum.REMAINING_CAPACITY, pool.getQueue().remainingCapacity()));
+        return list;
+    }
+
+    @Override
+    public AppReportMetric getAppReportMetric() {
+        final List<Meta> metaAll = manager.getMetaAll();
+        AppReportMetric report = new AppReportMetric();
+        report.setSuccess(getMappingSuccess(metaAll));
+        report.setFail(getMappingFail(metaAll));
+        report.setInsert(getMappingInsert(metaAll));
+        report.setUpdate(getMappingUpdate(metaAll));
+        report.setDelete(getMappingDelete(metaAll));
+
+        // 线程池使用情况
+        ThreadPoolTaskExecutor threadTask = (ThreadPoolTaskExecutor) taskExecutor;
+        ThreadPoolExecutor pool = threadTask.getThreadPoolExecutor();
+        BlockingQueue<Runnable> queue = pool.getQueue();
+        report.setQueueUp(queue.size());
+        report.setQueueCapacity(queueCapacity);
+        return report;
+    }
+
+    /**
+     * 获取所有驱动成功数
+     *
+     * @param metaAll
+     * @return
+     */
+    private long getMappingSuccess(List<Meta> metaAll) {
+        return queryMappingMetricCount(metaAll, (query) -> query.addFilter(ConfigConstant.DATA_SUCCESS, StorageDataStatusEnum.SUCCESS.getCode(), false, true));
+    }
+
+    /**
+     * 获取所有驱动失败数
+     *
+     * @param metaAll
+     * @return
+     */
+    private long getMappingFail(List<Meta> metaAll) {
+        return queryMappingMetricCount(metaAll, (query) -> query.addFilter(ConfigConstant.DATA_SUCCESS, StorageDataStatusEnum.FAIL.getCode(), false, true));
+    }
+
+    /**
+     * 获取所有驱动事件插入数
+     *
+     * @param metaAll
+     * @return
+     */
+    private long getMappingInsert(List<Meta> metaAll) {
+        return queryMappingMetricCount(metaAll, (query) -> query.addFilter(ConfigConstant.DATA_EVENT, ConnectorConstant.OPERTION_INSERT));
+    }
+
+    /**
+     * 获取所有驱动事件更新数
+     *
+     * @param metaAll
+     * @return
+     */
+    private long getMappingUpdate(List<Meta> metaAll) {
+        return queryMappingMetricCount(metaAll, (query) -> query.addFilter(ConfigConstant.DATA_EVENT, ConnectorConstant.OPERTION_UPDATE));
+    }
+
+    /**
+     * 获取所有驱动事件删除数
+     *
+     * @param metaAll
+     * @return
+     */
+    private long getMappingDelete(List<Meta> metaAll) {
+        return queryMappingMetricCount(metaAll, (query) -> query.addFilter(ConfigConstant.DATA_EVENT, ConnectorConstant.OPERTION_DELETE));
+    }
+
+    private MetricResponse createMetricResponse(ThreadPoolMetricEnum metricEnum, Object value) {
+        return new MetricResponse(metricEnum.getCode(), metricEnum.getGroup(), metricEnum.getMetricName(), Arrays.asList(new Sample(StatisticEnum.COUNT.getTagValueRepresentation(), value)));
+    }
+
+    private long queryMappingMetricCount(List<Meta> metaAll, QueryMappingOperation operation) {
+        AtomicLong total = new AtomicLong(0);
+        if (!CollectionUtils.isEmpty(metaAll)) {
+            Query query = new Query(1, 1);
+            operation.apply(query);
+            metaAll.forEach(meta -> {
+                Paging paging = manager.queryData(query, meta.getId());
+                total.getAndAdd(paging.getTotal());
+            });
+        }
+        return total.get();
+    }
+
+    private interface QueryMappingOperation {
+        void apply(Query query);
     }
 
 }

+ 48 - 0
dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/enums/DiskMetricEnum.java

@@ -0,0 +1,48 @@
+package org.dbsyncer.monitor.enums;
+
+/**
+ * 硬盘指标
+ *
+ * @author AE86
+ * @version 1.0.0
+ * @date 2021/07/23 0:19
+ */
+public enum DiskMetricEnum {
+
+    /**
+     * 已用
+     */
+    THRESHOLD("disk.space.threshold", "硬盘", "已用"),
+
+    /**
+     * 空闲
+     */
+    FREE("disk.space.free", "硬盘", "空闲"),
+    
+    /**
+     * 总共
+     */
+    TOTAL("disk.space.total", "硬盘", "总共"),;
+
+    private String code;
+    private String group;
+    private String metricName;
+
+    DiskMetricEnum(String code, String group, String metricName) {
+        this.code = code;
+        this.group = group;
+        this.metricName = metricName;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getGroup() {
+        return group;
+    }
+
+    public String getMetricName() {
+        return metricName;
+    }
+}

+ 82 - 0
dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/enums/MetricEnum.java

@@ -0,0 +1,82 @@
+package org.dbsyncer.monitor.enums;
+
+import org.apache.commons.lang.StringUtils;
+import org.dbsyncer.connector.ConnectorException;
+import org.dbsyncer.monitor.MonitorException;
+
+/**
+ * 系统指标
+ *
+ * @author AE86
+ * @version 1.0.0
+ * @date 2021/07/22 19:19
+ */
+public enum MetricEnum {
+
+    /**
+     * 线程活跃数
+     */
+    THREADS_LIVE("jvm.threads.live", "应用线程", "活跃数"),
+
+    /**
+     * 线程峰值
+     */
+    THREADS_PEAK("jvm.threads.peak", "应用线程", "峰值数"),
+
+    /**
+     * 内存已用
+     */
+    MEMORY_USED("jvm.memory.used", "内存", "已用"),
+
+    /**
+     * 内存空闲
+     */
+    MEMORY_COMMITTED("jvm.memory.committed", "内存", "空闲"),
+
+    /**
+     * 内存总共
+     */
+    MEMORY_MAX("jvm.memory.max", "内存", "总共"),
+
+    /**
+     * GC
+     */
+    GC_PAUSE("jvm.gc.pause", "GC", "已用"),
+
+    /**
+     * CPU已用
+     */
+    CPU_USAGE("system.cpu.usage", "CPU", "已用");
+
+    private String code;
+    private String group;
+    private String metricName;
+
+    MetricEnum(String code, String group, String metricName) {
+        this.code = code;
+        this.group = group;
+        this.metricName = metricName;
+    }
+
+    public static MetricEnum getMetric(String code) throws ConnectorException {
+        for (MetricEnum e : MetricEnum.values()) {
+            if (StringUtils.equals(code, e.getCode())) {
+                return e;
+            }
+        }
+        throw new MonitorException(String.format("Metric code \"%s\" does not exist.", code));
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getGroup() {
+        return group;
+    }
+
+    public String getMetricName() {
+        return metricName;
+    }
+
+}

+ 55 - 0
dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/enums/StatisticEnum.java

@@ -0,0 +1,55 @@
+package org.dbsyncer.monitor.enums;
+
+public enum StatisticEnum {
+
+    /**
+     * The sum of the amounts recorded.
+     */
+    TOTAL("total"),
+
+    /**
+     * The sum of the times recorded. Reported in the monitoring system's base unit of time
+     */
+    TOTAL_TIME("total"),
+
+    /**
+     * Rate per second for calls.
+     */
+    COUNT("count"),
+
+    /**
+     * The maximum amount recorded. When this represents a time, it is reported in the monitoring system's base unit of time.
+     */
+    MAX("max"),
+
+    /**
+     * Instantaneous value, such as those reported by gauges.
+     */
+    VALUE("value"),
+
+    /**
+     * Undetermined.
+     */
+    UNKNOWN("unknown"),
+
+    /**
+     * Number of currently active tasks for a long task timer.
+     */
+    ACTIVE_TASKS("active"),
+
+    /**
+     * Duration of a running task in a long task timer. Always reported in the monitoring system's base unit of time.
+     */
+    DURATION("duration");
+
+    private String tagValueRepresentation;
+
+    StatisticEnum(String tagValueRepresentation) {
+        this.tagValueRepresentation = tagValueRepresentation;
+    }
+
+    public String getTagValueRepresentation() {
+        return tagValueRepresentation;
+    }
+
+}

+ 54 - 0
dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/enums/ThreadPoolMetricEnum.java

@@ -0,0 +1,54 @@
+package org.dbsyncer.monitor.enums;
+
+/**
+ * 线程池指标
+ *
+ * @author AE86
+ * @version 1.0.0
+ * @date 2021/07/23 0:19
+ */
+public enum ThreadPoolMetricEnum {
+
+    /**
+     * 已提交
+     */
+    TASK_SUBMITTED("thread.pool.task.submitted", "线程池", "已提交"),
+    /**
+     * 排队中
+     */
+    QUEUE_UP("thread.pool.queue.up", "线程池", "排队中"),
+    /**
+     * 处理中
+     */
+    ACTIVE("thread.pool.active", "线程池", "处理中"),
+    /**
+     * 已完成
+     */
+    COMPLETED("thread.pool.completed", "线程池", "已完成"),
+    /**
+     * 空闲队列
+     */
+    REMAINING_CAPACITY("thread.pool.remaining.capacity", "线程池", "空闲队列");
+
+    private String code;
+    private String group;
+    private String metricName;
+
+    ThreadPoolMetricEnum(String code, String group, String metricName) {
+        this.code = code;
+        this.group = group;
+        this.metricName = metricName;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getGroup() {
+        return group;
+    }
+
+    public String getMetricName() {
+        return metricName;
+    }
+}

+ 95 - 0
dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/model/AppReportMetric.java

@@ -0,0 +1,95 @@
+package org.dbsyncer.monitor.model;
+
+public class AppReportMetric {
+
+    /**
+     * 已处理成功数
+     */
+    private long success;
+
+    /**
+     * 已处理失败数
+     */
+    private long fail;
+
+    /**
+     * 插入事件
+     */
+    private long insert;
+
+    /**
+     * 更新事件
+     */
+    private long update;
+
+    /**
+     * 删除事件
+     */
+    private long delete;
+
+    /**
+     * 待处理数
+     */
+    private long queueUp;
+
+    /**
+     * 队列长度
+     */
+    private long queueCapacity;
+
+    public long getSuccess() {
+        return success;
+    }
+
+    public void setSuccess(long success) {
+        this.success = success;
+    }
+
+    public long getFail() {
+        return fail;
+    }
+
+    public void setFail(long fail) {
+        this.fail = fail;
+    }
+
+    public long getInsert() {
+        return insert;
+    }
+
+    public void setInsert(long insert) {
+        this.insert = insert;
+    }
+
+    public long getUpdate() {
+        return update;
+    }
+
+    public void setUpdate(long update) {
+        this.update = update;
+    }
+
+    public long getDelete() {
+        return delete;
+    }
+
+    public void setDelete(long delete) {
+        this.delete = delete;
+    }
+
+    public long getQueueUp() {
+        return queueUp;
+    }
+
+    public void setQueueUp(long queueUp) {
+        this.queueUp = queueUp;
+    }
+
+    public long getQueueCapacity() {
+        return queueCapacity;
+    }
+
+    public void setQueueCapacity(long queueCapacity) {
+        this.queueCapacity = queueCapacity;
+    }
+}

+ 56 - 0
dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/model/MetricResponse.java

@@ -0,0 +1,56 @@
+package org.dbsyncer.monitor.model;
+
+import java.util.List;
+
+public class MetricResponse {
+
+    private String code;
+
+    private String group;
+
+    private String metricName;
+
+    private List<Sample> measurements;
+
+    public MetricResponse() {
+    }
+
+    public MetricResponse(String code, String group, String metricName, List<Sample> measurements) {
+        this.code = code;
+        this.group = group;
+        this.metricName = metricName;
+        this.measurements = measurements;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getGroup() {
+        return group;
+    }
+
+    public void setGroup(String group) {
+        this.group = group;
+    }
+
+    public String getMetricName() {
+        return metricName;
+    }
+
+    public void setMetricName(String metricName) {
+        this.metricName = metricName;
+    }
+
+    public List<Sample> getMeasurements() {
+        return measurements;
+    }
+
+    public void setMeasurements(List<Sample> measurements) {
+        this.measurements = measurements;
+    }
+}

+ 29 - 0
dbsyncer-monitor/src/main/java/org/dbsyncer/monitor/model/Sample.java

@@ -0,0 +1,29 @@
+package org.dbsyncer.monitor.model;
+
+public final class Sample {
+
+    private String statistic;
+
+    private Object value;
+
+    public Sample(String statistic, Object value) {
+        this.statistic = statistic;
+        this.value = value;
+    }
+
+    public String getStatistic() {
+        return statistic;
+    }
+
+    public void setStatistic(String statistic) {
+        this.statistic = statistic;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+
+    public void setValue(Object value) {
+        this.value = value;
+    }
+}

+ 1 - 1
dbsyncer-parser/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>dbsyncer</artifactId>
         <groupId>org.ghi</groupId>
-		<version>1.0.8-Alpha</version>
+		<version>1.0.9-Alpha</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 35 - 56
dbsyncer-parser/src/main/java/org/dbsyncer/parser/ParserFactory.java

@@ -19,6 +19,7 @@ import org.dbsyncer.listener.enums.QuartzFilterEnum;
 import org.dbsyncer.parser.enums.ConvertEnum;
 import org.dbsyncer.parser.enums.ParserEnum;
 import org.dbsyncer.parser.flush.FlushService;
+import org.dbsyncer.parser.logger.LogType;
 import org.dbsyncer.parser.model.*;
 import org.dbsyncer.parser.util.ConvertUtil;
 import org.dbsyncer.parser.util.PickerUtil;
@@ -31,7 +32,6 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationContext;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Component;
 import org.springframework.util.Assert;
 
@@ -39,7 +39,7 @@ import java.time.Instant;
 import java.util.*;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.Executor;
 
 /**
  * @author AE86
@@ -63,6 +63,9 @@ public class ParserFactory implements Parser {
     @Autowired
     private FlushService flushService;
 
+    @Autowired
+    private Executor taskExecutor;
+
     @Autowired
     private ApplicationContext applicationContext;
 
@@ -78,7 +81,13 @@ public class ParserFactory implements Parser {
 
     @Override
     public boolean isAliveConnectorConfig(ConnectorConfig config) {
-        return connectorFactory.isAlive(config);
+        try {
+            return connectorFactory.isAlive(config);
+        } catch (Exception e) {
+            LogType.ConnectorLog logType = LogType.ConnectorLog.FAILED;
+            flushService.asyncWrite(logType.getType(), String.format("%s%s", logType.getName(), e.getMessage()));
+        }
+        return false;
     }
 
     @Override
@@ -210,7 +219,6 @@ public class ParserFactory implements Parser {
         Map<String, String> params = getMeta(metaId).getMap();
         params.putIfAbsent(ParserEnum.PAGE_INDEX.getCode(), ParserEnum.PAGE_INDEX.getDefaultValue());
         int pageSize = mapping.getReadNum();
-        int threadSize = mapping.getThreadNum();
         int batchSize = mapping.getBatchNum();
         ConnectorMapper sConnectionMapper = connectorFactory.connect(sConfig);
         ConnectorMapper tConnectionMapper = connectorFactory.connect(tConfig);
@@ -241,7 +249,7 @@ public class ParserFactory implements Parser {
             pluginFactory.convert(group.getPlugin(), data, target);
 
             // 5、写入目标源
-            Result writer = writeBatch(tConnectionMapper, command, picker.getTargetFields(), target, threadSize, batchSize);
+            Result writer = writeBatch(tConnectionMapper, command, picker.getTargetFields(), target, batchSize);
 
             // 6、更新结果
             flush(task, writer, target);
@@ -346,12 +354,10 @@ public class ParserFactory implements Parser {
      * @param command
      * @param fields
      * @param target
-     * @param threadSize
      * @param batchSize
      * @return
      */
-    private Result writeBatch(ConnectorMapper connectorMapper, Map<String, String> command, List<Field> fields, List<Map> target,
-                              int threadSize, int batchSize) {
+    private Result writeBatch(ConnectorMapper connectorMapper, Map<String, String> command, List<Field> fields, List<Map> target, int batchSize) {
         // 总数
         int total = target.size();
         // 单次任务
@@ -361,45 +367,32 @@ public class ParserFactory implements Parser {
 
         // 批量任务, 拆分
         int taskSize = total % batchSize == 0 ? total / batchSize : total / batchSize + 1;
-        threadSize = taskSize <= threadSize ? taskSize : threadSize;
 
-        // 转换为消息队列,根据batchSize获取数据,并发写入
+        // 转换为消息队列,并发写入
         Queue<Map> queue = new ConcurrentLinkedQueue<>(target);
 
-        // 创建线程池
-        final ThreadPoolTaskExecutor executor = getThreadPoolTaskExecutor(threadSize, taskSize - threadSize);
         final Result result = new Result();
-        for (; ; ) {
-            if (taskSize <= 0) {
-                break;
-            }
-            // TODO 优化 CountDownLatch
-            final CountDownLatch latch = new CountDownLatch(threadSize);
-            for (int i = 0; i < threadSize; i++) {
-                executor.execute(() -> {
-                    try {
-                        Result w = parallelTask(batchSize, queue, connectorMapper, command, fields);
-                        // CAS
-                        result.getFailData().addAll(w.getFailData());
-                        result.getFail().getAndAdd(w.getFail().get());
-                        result.getError().append(w.getError());
-                    } catch (Exception e) {
-                        result.getError().append(e.getMessage()).append(System.lineSeparator());
-                    } finally {
-                        latch.countDown();
-                    }
-                });
-            }
-            try {
-                latch.await();
-            } catch (InterruptedException e) {
-                logger.error(e.getMessage());
-            }
-
-            taskSize -= threadSize;
+        final CountDownLatch latch = new CountDownLatch(taskSize);
+        for (int i = 0; i < taskSize; i++) {
+            taskExecutor.execute(() -> {
+                try {
+                    Result w = parallelTask(batchSize, queue, connectorMapper, command, fields);
+                    // CAS
+                    result.getFailData().addAll(w.getFailData());
+                    result.getFail().getAndAdd(w.getFail().get());
+                    result.getError().append(w.getError());
+                } catch (Exception e) {
+                    result.getError().append(e.getMessage()).append(System.lineSeparator());
+                } finally {
+                    latch.countDown();
+                }
+            });
+        }
+        try {
+            latch.await();
+        } catch (InterruptedException e) {
+            logger.error(e.getMessage());
         }
-
-        executor.shutdown();
         return result;
     }
 
@@ -416,18 +409,4 @@ public class ParserFactory implements Parser {
         return connectorFactory.writer(new WriterBatchConfig(connectorMapper, command, fields, data));
     }
 
-    private ThreadPoolTaskExecutor getThreadPoolTaskExecutor(int threadSize, int queueCapacity) {
-        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
-        executor.setCorePoolSize(threadSize);
-        executor.setMaxPoolSize(threadSize);
-        executor.setQueueCapacity(queueCapacity);
-        executor.setKeepAliveSeconds(30);
-        executor.setAwaitTerminationSeconds(30);
-        executor.setThreadNamePrefix("ParserExecutor");
-        executor.setWaitForTasksToCompleteOnShutdown(true);
-        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
-        executor.initialize();
-        return executor;
-    }
-
 }

+ 1 - 1
dbsyncer-parser/src/main/java/org/dbsyncer/parser/model/Config.java

@@ -9,7 +9,7 @@ public class Config extends ConfigModel {
 
     private String password;
 
-    private int refreshInterval = 10;
+    private int refreshInterval = 5;
 
     public String getPassword() {
         return password;

+ 2 - 14
dbsyncer-parser/src/main/java/org/dbsyncer/parser/model/Mapping.java

@@ -40,15 +40,12 @@ public class Mapping extends AbstractConfigModel {
     // 元信息ID
     private String metaId;
 
-    // 每次读取数
+    // 批量读取
     private int readNum = 10000;
 
-    // 每次写入数
+    // 单次写入
     private int batchNum = 200;
 
-    // 线程数
-    private int threadNum = 5;
-
     public String getSourceConnectorId() {
         return sourceConnectorId;
     }
@@ -126,13 +123,4 @@ public class Mapping extends AbstractConfigModel {
         return this;
     }
 
-    public int getThreadNum() {
-        return threadNum;
-    }
-
-    public Mapping setThreadNum(int threadNum) {
-        this.threadNum = threadNum;
-        return this;
-    }
-
 }

+ 2 - 2
dbsyncer-parser/src/main/resources/Mapping.json

@@ -68,6 +68,6 @@
     ]
   },
   "metaId":"1",
-  "batchNum": 200,
-  "threadNum": 5
+  "readNum": 10000,
+  "batchNum": 200
 }

+ 1 - 1
dbsyncer-plugin/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>dbsyncer</artifactId>
         <groupId>org.ghi</groupId>
-		<version>1.0.8-Alpha</version>
+		<version>1.0.9-Alpha</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
dbsyncer-storage/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>dbsyncer</artifactId>
         <groupId>org.ghi</groupId>
-		<version>1.0.8-Alpha</version>
+		<version>1.0.9-Alpha</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 0 - 5
dbsyncer-storage/src/main/java/org/dbsyncer/storage/query/Param.java

@@ -11,11 +11,6 @@ public class Param {
     private boolean highlighter;
     private boolean number;
 
-    public Param(String key, String value) {
-        this.key = key;
-        this.value = value;
-    }
-
     public Param(String key, String value, boolean highlighter, boolean number) {
         this.key = key;
         this.value = value;

+ 5 - 5
dbsyncer-storage/src/main/java/org/dbsyncer/storage/query/Query.java

@@ -37,15 +37,15 @@ public class Query {
         this.params = new ArrayList<>();
     }
 
-    public void put(String key, String value) {
-        put(key, value, false, false);
+    public void addFilter(String key, String value) {
+        addFilter(key, value, false, false);
     }
 
-    public void put(String key, String value, boolean highlighter) {
-        put(key, value, highlighter, false);
+    public void addFilter(String key, String value, boolean highlighter) {
+        addFilter(key, value, highlighter, false);
     }
 
-    public void put(String key, String value, boolean highlighter, boolean number) {
+    public void addFilter(String key, String value, boolean highlighter, boolean number) {
         params.add(new Param(key, value, highlighter, number));
         if (highlighter) {
             enableHighLightSearch = highlighter;

+ 1 - 7
dbsyncer-web/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>dbsyncer</artifactId>
         <groupId>org.ghi</groupId>
-		<version>1.0.8-Alpha</version>
+		<version>1.0.9-Alpha</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -59,12 +59,6 @@
             <artifactId>spring-boot-starter-security</artifactId>
         </dependency>
 
-        <!-- Websocket -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-websocket</artifactId>
-        </dependency>
-
     </dependencies>
 
     <build>

+ 7 - 10
dbsyncer-web/src/main/java/org/dbsyncer/web/config/CacheConfiguration.java

@@ -35,16 +35,13 @@ public class CacheConfiguration {
 
     @Bean
     public KeyGenerator cacheKeyGenerator() {
-        return new KeyGenerator() {
-            @Override
-            public Object generate(Object target, Method method, Object... params) {
-                String className = method.getDeclaringClass().getSimpleName();
-                String methodName = method.getName();
-                String paramHash = String.valueOf(Arrays.toString(params).hashCode());
-                String cacheKey = new StringJoiner("_").add(className).add(methodName).add(paramHash).toString();
-                logger.debug("generate cache key : {}", cacheKey);
-                return cacheKey;
-            }
+        return (target, method, params) -> {
+            String className = method.getDeclaringClass().getSimpleName();
+            String methodName = method.getName();
+            String paramHash = String.valueOf(Arrays.toString(params).hashCode());
+            String cacheKey = new StringJoiner("_").add(className).add(methodName).add(paramHash).toString();
+            logger.debug("generate cache key : {}", cacheKey);
+            return cacheKey;
         };
     }
 

+ 62 - 63
dbsyncer-web/src/main/java/org/dbsyncer/web/config/TaskPoolConfig.java → dbsyncer-web/src/main/java/org/dbsyncer/web/config/ThreadPoolConfig.java

@@ -1,64 +1,63 @@
-package org.dbsyncer.web.config;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.scheduling.TaskScheduler;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
-
-import java.util.concurrent.Executor;
-import java.util.concurrent.ThreadPoolExecutor;
-
-/**
- * @version 1.0.0
- * @author AE86
- * @date 2020-04-26 23:40
- */
-@Configuration
-public class TaskPoolConfig {
-
-    @Bean("taskExecutor")
-    public Executor taskExecutor() {
-        //注意这一行日志:2. do submit,taskCount [101], completedTaskCount [87], activeCount [5], queueSize [9]
-        //这说明提交任务到线程池的时候,调用的是submit(Callable task)这个方法,当前已经提交了101个任务,完成了87个,当前有5个线程在处理任务,还剩9个任务在队列中等待,线程池的基本情况一路了然;
-        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
-        //核心线程数10:线程池创建时候初始化的线程数
-        executor.setCorePoolSize(10);
-        //最大线程数128:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
-        //maxPoolSize 当系统负载大道最大值时,核心线程数已无法按时处理完所有任务,这是就需要增加线程.每秒200个任务需要20个线程,那么当每秒1000个任务时,则需要(1000-queueCapacity)*(20/200),即60个线程,可将maxPoolSize设置为60;
-        executor.setMaxPoolSize(128);
-        //缓冲队列360:用来缓冲执行任务的队列
-        executor.setQueueCapacity(360);
-        //允许线程的空闲时间30秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
-        executor.setKeepAliveSeconds(30);
-        //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
-        executor.setThreadNamePrefix("taskExecutor");
-        //理线程池对拒绝任务的处策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
-        /*CallerRunsPolicy:线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
-        这个策略显然不想放弃执行任务。但是由于池中已经没有任何资源了,那么就直接使用调用该execute的线程本身来执行。(开始我总不想丢弃任务的执行,但是对某些应用场景来讲,很有可能造成当前线程也被阻塞。如果所有线程都是不能执行的,很可能导致程序没法继续跑了。需要视业务情景而定吧。)
-        AbortPolicy:处理程序遭到拒绝将抛出运行时 RejectedExecutionException
-        这种策略直接抛出异常,丢弃任务。(jdk默认策略,队列满并线程满时直接拒绝添加新任务,并抛出异常,所以说有时候放弃也是一种勇气,为了保证后续任务的正常进行,丢弃一些也是可以接收的,记得做好记录)
-        DiscardPolicy:不能执行的任务将被删除
-        这种策略和AbortPolicy几乎一样,也是丢弃任务,只不过他不抛出异常。
-        DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)
-        该策略就稍微复杂一些,在pool没有关闭的前提下首先丢掉缓存在队列中的最早的任务,然后重新尝试运行该任务。这个策略需要适当小心*/
-        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
-        executor.setWaitForTasksToCompleteOnShutdown(true);
-        executor.setAwaitTerminationSeconds(30);
-        executor.initialize();
-        return executor;
-    }
-
-    @Bean
-    public TaskScheduler taskScheduler() {
-        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
-        taskScheduler.setPoolSize(5);
-        taskScheduler.setRemoveOnCancelPolicy(true);
-        taskScheduler.setThreadNamePrefix("taskScheduler");
-        taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
-        taskScheduler.setAwaitTerminationSeconds(60);
-        return taskScheduler;
-    }
-
-
+package org.dbsyncer.web.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * @author AE86
+ * @version 1.0.0
+ * @date 2020-04-26 23:40
+ */
+@Configuration
+public class ThreadPoolConfig {
+
+    /**
+     * 工作线程池队列容量
+     */
+    @Value(value = "${dbsyncer.web.thread.pool.queue.capacity}")
+    private int queueCapacity;
+
+    /**
+     * 工作线程数
+     */
+    @Value(value = "${dbsyncer.web.thread.pool.core.size}")
+    private int coreSize;
+
+    @Bean("taskExecutor")
+    public Executor taskExecutor() {
+        //注意这一行日志:2. do submit,taskCount [101], completedTaskCount [87], activeCount [5], queueSize [9]
+        //这说明提交任务到线程池的时候,调用的是submit(Callable task)这个方法,当前已经提交了101个任务,完成了87个,当前有5个线程在处理任务,还剩9个任务在队列中等待,线程池的基本情况一路了然;
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        //核心线程数10:线程池创建时候初始化的线程数
+        executor.setCorePoolSize(coreSize);
+        //最大线程数128:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
+        //maxPoolSize 当系统负载大道最大值时,核心线程数已无法按时处理完所有任务,这是就需要增加线程.每秒200个任务需要20个线程,那么当每秒1000个任务时,则需要(1000-queueCapacity)*(20/200),即60个线程,可将maxPoolSize设置为60;
+        executor.setMaxPoolSize(128);
+        //缓冲队列:用来缓冲执行任务的队列
+        executor.setQueueCapacity(queueCapacity);
+        //允许线程的空闲时间30秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
+        executor.setKeepAliveSeconds(30);
+        //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
+        executor.setThreadNamePrefix("taskExecutor");
+        //理线程池对拒绝任务的处策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
+        /*CallerRunsPolicy:线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
+        这个策略显然不想放弃执行任务。但是由于池中已经没有任何资源了,那么就直接使用调用该execute的线程本身来执行。(开始我总不想丢弃任务的执行,但是对某些应用场景来讲,很有可能造成当前线程也被阻塞。如果所有线程都是不能执行的,很可能导致程序没法继续跑了。需要视业务情景而定吧。)
+        AbortPolicy:处理程序遭到拒绝将抛出运行时 RejectedExecutionException
+        这种策略直接抛出异常,丢弃任务。(jdk默认策略,队列满并线程满时直接拒绝添加新任务,并抛出异常,所以说有时候放弃也是一种勇气,为了保证后续任务的正常进行,丢弃一些也是可以接收的,记得做好记录)
+        DiscardPolicy:不能执行的任务将被删除
+        这种策略和AbortPolicy几乎一样,也是丢弃任务,只不过他不抛出异常。
+        DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)
+        该策略就稍微复杂一些,在pool没有关闭的前提下首先丢掉缓存在队列中的最早的任务,然后重新尝试运行该任务。这个策略需要适当小心*/
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
+        executor.setWaitForTasksToCompleteOnShutdown(true);
+        executor.setAwaitTerminationSeconds(30);
+        executor.initialize();
+        return executor;
+    }
+
 }

+ 9 - 17
dbsyncer-web/src/main/java/org/dbsyncer/web/config/WebAppConfig.java

@@ -70,12 +70,7 @@ public class WebAppConfig extends WebSecurityConfigurerAdapter implements Authen
      */
     @Bean
     public AuthenticationFailureHandler loginFailHandler() {
-        return new AuthenticationFailureHandler() {
-            @Override
-            public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) {
-                write(response, RestResult.restFail(e.getMessage(), 401));
-            }
-        };
+        return (request, response, e) -> write(response, RestResult.restFail(e.getMessage(), 401));
     }
 
     /**
@@ -97,17 +92,14 @@ public class WebAppConfig extends WebSecurityConfigurerAdapter implements Authen
 
     @Bean
     public LogoutSuccessHandler logoutHandler() {
-        return new LogoutSuccessHandler() {
-            @Override
-            public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
-                try {
-                    Object principal = authentication.getPrincipal();
-                    logger.info("USER : {} LOGOUT SUCCESS ! ", principal);
-                    write(response, RestResult.restSuccess("注销成功!"));
-                } catch (Exception e) {
-                    logger.info("LOGOUT EXCEPTION , e : {}", e.getMessage());
-                    write(response, RestResult.restFail(e.getMessage(), 403));
-                }
+        return (request, response, authentication) -> {
+            try {
+                Object principal = authentication.getPrincipal();
+                logger.info("USER : {} LOGOUT SUCCESS ! ", principal);
+                write(response, RestResult.restSuccess("注销成功!"));
+            } catch (Exception e) {
+                logger.info("LOGOUT EXCEPTION , e : {}", e.getMessage());
+                write(response, RestResult.restFail(e.getMessage(), 403));
             }
         };
     }

+ 0 - 25
dbsyncer-web/src/main/java/org/dbsyncer/web/config/WebSocketConfig.java

@@ -1,25 +0,0 @@
-package org.dbsyncer.web.config;
-
-import org.springframework.context.annotation.Configuration;
-import org.springframework.messaging.simp.config.MessageBrokerRegistry;
-import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
-import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
-import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
-
-@Configuration
-@EnableWebSocketMessageBroker
-public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
-
-    @Override
-    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
-        // 解决跨域问题
-        stompEndpointRegistry.addEndpoint("/simple")
-                .setAllowedOrigins("*")
-                .withSockJS();
-    }
-
-    @Override
-    public void configureMessageBroker(MessageBrokerRegistry registry) {
-        registry.enableSimpleBroker("/topic");
-    }
-}

+ 3 - 2
dbsyncer-web/src/main/java/org/dbsyncer/web/controller/TestController.java

@@ -46,9 +46,10 @@ public class TestController implements InitializingBean {
 
     @ResponseBody
     @RequestMapping("/demo")
-    public void demo(ModelMap modelMap, Long id, String version) {
+    public String demo(ModelMap modelMap, Long id, String version) {
         logger.info("id:{},version:{}", id, version);
         modelMap.put("data", RandomUtils.nextInt(100));
+        return id + version;
     }
 
     @ResponseBody
@@ -78,7 +79,7 @@ public class TestController implements InitializingBean {
             Object invoke = invocableMethod.invokeForRequest(webRequest, mavContainer, providedArgs.toArray());
             return invoke;
         } catch (Exception e) {
-            e.printStackTrace();
+            logger.error(e.getMessage());
         }
         return null;
     }

+ 0 - 49
dbsyncer-web/src/main/java/org/dbsyncer/web/controller/databus/DataBusController.java

@@ -1,49 +0,0 @@
-package org.dbsyncer.web.controller.databus;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.messaging.simp.SimpMessagingTemplate;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-
-@Controller
-@RequestMapping("/dataBus")
-public class DataBusController {
-
-    @Autowired
-    private SimpMessagingTemplate messagingTemplate;
-
-    @RequestMapping("")
-    public String getView(Model model) {
-        return "databus/databus.html";
-    }
-
-    /**
-     * 定时推送消息
-     */
-    @Scheduled(fixedRate = 1000)
-    public void callback() {
-        String format = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-        messagingTemplate.convertAndSend("/topic/callback", "定时推送消息时间: " + format);
-    }
-
-    /**
-     * 第一位,表示秒,取值0-59
-     * 第二位,表示分,取值0-59
-     * 第三位,表示小时,取值0-23
-     * 第四位,日期天/日,取值1-31
-     * 第五位,日期月份,取值1-12
-     * 第六位,星期,取值1-7
-     * [秒 分 时 日 月 星期]
-     */
-    @Scheduled(cron = "0 0 */1 * * ?")
-    public void testCron() {
-        String format = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-        System.out.println("定时任务:" + format);
-    }
-
-}

+ 7 - 0
dbsyncer-web/src/main/java/org/dbsyncer/web/controller/monitor/HistoryStackValueFormatter.java

@@ -0,0 +1,7 @@
+package org.dbsyncer.web.controller.monitor;
+
+public interface HistoryStackValueFormatter {
+
+    Object formatValue(Object value);
+
+}

+ 130 - 3
dbsyncer-web/src/main/java/org/dbsyncer/web/controller/monitor/MonitorController.java

@@ -1,17 +1,35 @@
 package org.dbsyncer.web.controller.monitor;
 
+import org.dbsyncer.biz.ConfigService;
 import org.dbsyncer.biz.MonitorService;
+import org.dbsyncer.biz.vo.AppReportMetricVo;
+import org.dbsyncer.biz.vo.ConfigVo;
+import org.dbsyncer.biz.vo.HistoryStackVo;
 import org.dbsyncer.biz.vo.RestResult;
+import org.dbsyncer.common.util.CollectionUtils;
+import org.dbsyncer.common.util.DateFormatUtil;
+import org.dbsyncer.monitor.enums.DiskMetricEnum;
+import org.dbsyncer.monitor.enums.MetricEnum;
+import org.dbsyncer.monitor.enums.StatisticEnum;
+import org.dbsyncer.monitor.model.MetricResponse;
+import org.dbsyncer.monitor.model.Sample;
 import org.dbsyncer.web.controller.BaseController;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.boot.actuate.health.HealthEndpoint;
+import org.springframework.boot.actuate.metrics.MetricsEndpoint;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.ModelMap;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
 
 import javax.servlet.http.HttpServletRequest;
-import java.util.Map;
+import java.util.*;
 
 @Controller
 @RequestMapping("/monitor")
@@ -19,13 +37,31 @@ public class MonitorController extends BaseController {
 
     private final Logger logger = LoggerFactory.getLogger(getClass());
 
+    private final static int COUNT = 24;
+    private HistoryStackVo cpu = new HistoryStackVo();
+    private HistoryStackVo memory = new HistoryStackVo();
+
     @Autowired
     private MonitorService monitorService;
 
+    @Autowired
+    private ConfigService configService;
+
+    @Autowired
+    private MetricsEndpoint metricsEndpoint;
+
+    @Autowired
+    private HealthEndpoint healthEndpoint;
+
+    @Autowired
+    private HistoryStackValueFormatter cpuHistoryStackValueFormatterImpl;
+
+    @Autowired
+    private HistoryStackValueFormatter memoryHistoryStackValueFormatterImpl;
+
     @RequestMapping("")
     public String index(HttpServletRequest request, ModelMap model) {
         Map<String, String> params = getParams(request);
-        model.put("threadInfo", monitorService.getThreadInfo());
         model.put("metaId", monitorService.getDefaultMetaId(params));
         model.put("meta", monitorService.getMetaAll());
         model.put("storageDataStatus", monitorService.getStorageDataStatusEnumAll());
@@ -34,6 +70,12 @@ public class MonitorController extends BaseController {
         return "monitor/monitor.html";
     }
 
+    @Scheduled(fixedRate = 5000)
+    public void recordHistoryStackMetric() {
+        recordHistoryStackMetric(MetricEnum.CPU_USAGE, cpu, cpuHistoryStackValueFormatterImpl);
+        recordHistoryStackMetric(MetricEnum.MEMORY_USED, memory, memoryHistoryStackValueFormatterImpl);
+    }
+
     @GetMapping("/queryData")
     @ResponseBody
     public RestResult queryData(HttpServletRequest request) {
@@ -80,4 +122,89 @@ public class MonitorController extends BaseController {
         }
     }
 
+    @ResponseBody
+    @GetMapping("/queryAppReportMetric")
+    public RestResult queryAppReportMetric() {
+        try {
+            List<MetricResponse> list = new ArrayList<>();
+            List<MetricEnum> metricEnumList = monitorService.getMetricEnumAll();
+            if (!CollectionUtils.isEmpty(metricEnumList)) {
+                metricEnumList.forEach(m -> list.add(getMetricResponse(m.getCode())));
+            }
+            list.addAll(getDiskHealth());
+            AppReportMetricVo reportMetric = monitorService.queryAppReportMetric(list);
+            reportMetric.setCpu(cpu);
+            reportMetric.setMemory(memory);
+            return RestResult.restSuccess(reportMetric);
+        } catch (Exception e) {
+            logger.error(e.getLocalizedMessage(), e.getClass());
+            return RestResult.restFail(e.getMessage());
+        }
+    }
+
+    @ResponseBody
+    @GetMapping("/getRefreshInterval")
+    public RestResult getRefreshInterval() {
+        try {
+            ConfigVo config = configService.getConfig();
+            return RestResult.restSuccess(config.getRefreshInterval());
+        } catch (Exception e) {
+            logger.error(e.getLocalizedMessage(), e.getClass());
+            return RestResult.restFail(e.getMessage());
+        }
+    }
+
+    /**
+     * 硬盘状态
+     *
+     * @return
+     */
+    private List<MetricResponse> getDiskHealth() {
+        List<MetricResponse> list = new ArrayList<>();
+        Health health = healthEndpoint.health();
+        Map<String, Object> details = health.getDetails();
+        Health diskSpace = (Health) details.get("diskSpace");
+        Map<String, Object> diskSpaceDetails = diskSpace.getDetails();
+        list.add(createDiskMetricResponse(DiskMetricEnum.THRESHOLD, diskSpaceDetails.get("threshold")));
+        list.add(createDiskMetricResponse(DiskMetricEnum.FREE, diskSpaceDetails.get("free")));
+        list.add(createDiskMetricResponse(DiskMetricEnum.TOTAL, diskSpaceDetails.get("total")));
+        return list;
+    }
+
+    private MetricResponse createDiskMetricResponse(DiskMetricEnum metricEnum, Object value) {
+        return new MetricResponse(metricEnum.getCode(), metricEnum.getGroup(), metricEnum.getMetricName(),
+                Arrays.asList(new Sample(StatisticEnum.COUNT.getTagValueRepresentation(), value)));
+    }
+
+    private MetricResponse getMetricResponse(String code) {
+        MetricsEndpoint.MetricResponse metric = metricsEndpoint.metric(code, null);
+        MetricResponse metricResponse = new MetricResponse();
+        MetricEnum metricEnum = MetricEnum.getMetric(metric.getName());
+        metricResponse.setCode(metricEnum.getCode());
+        metricResponse.setGroup(metricEnum.getGroup());
+        metricResponse.setMetricName(metricEnum.getMetricName());
+        if (!CollectionUtils.isEmpty(metric.getMeasurements())) {
+            List<Sample> measurements = new ArrayList<>();
+            metric.getMeasurements().forEach(s -> measurements.add(new Sample(s.getStatistic().getTagValueRepresentation(), s.getValue())));
+            metricResponse.setMeasurements(measurements);
+        }
+        return metricResponse;
+    }
+
+    private void recordHistoryStackMetric(MetricEnum metricEnum, HistoryStackVo stackVo, HistoryStackValueFormatter formatter) {
+        MetricResponse metricResponse = getMetricResponse(metricEnum.getCode());
+        List<Sample> measurements = metricResponse.getMeasurements();
+        if (!CollectionUtils.isEmpty(measurements)) {
+            addHistoryStack(stackVo.getValue(), formatter.formatValue(measurements.get(0).getValue()));
+            addHistoryStack(stackVo.getName(), DateFormatUtil.getCurrentTime());
+        }
+    }
+
+    private void addHistoryStack(List<Object> stack, Object value) {
+        if (stack.size() >= COUNT) {
+            stack.remove(0);
+        }
+        stack.add(value);
+    }
+
 }

+ 17 - 0
dbsyncer-web/src/main/java/org/dbsyncer/web/controller/monitor/impl/CpuHistoryStackValueFormatterImpl.java

@@ -0,0 +1,17 @@
+package org.dbsyncer.web.controller.monitor.impl;
+
+import org.dbsyncer.web.controller.monitor.HistoryStackValueFormatter;
+import org.springframework.stereotype.Service;
+
+@Service
+public class CpuHistoryStackValueFormatterImpl implements HistoryStackValueFormatter {
+
+    @Override
+    public Object formatValue(Object value) {
+        Double val = (Double) value;
+        val *= 100;
+        String percent = String.format("%.2f", val);
+        return percent;
+    }
+
+}

+ 22 - 0
dbsyncer-web/src/main/java/org/dbsyncer/web/controller/monitor/impl/MemoryHistoryStackValueFormatterImpl.java

@@ -0,0 +1,22 @@
+package org.dbsyncer.web.controller.monitor.impl;
+
+import org.dbsyncer.web.controller.monitor.HistoryStackValueFormatter;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+
+@Service
+public class MemoryHistoryStackValueFormatterImpl implements HistoryStackValueFormatter {
+
+    @Override
+    public Object formatValue(Object value) {
+        BigDecimal decimal = new BigDecimal(String.valueOf(value));
+        BigDecimal bt = divide(decimal,0);
+        BigDecimal mb = divide(bt,2);
+        return mb;
+    }
+
+    private BigDecimal divide(BigDecimal d1, int scale) {
+        return d1.divide(new BigDecimal("1024"), scale, BigDecimal.ROUND_HALF_UP);
+    }
+}

+ 3 - 1
dbsyncer-web/src/main/resources/application.properties

@@ -5,6 +5,8 @@ server.port=18686
 dbsyncer.web.login.username=admin
 dbsyncer.web.login.password=0DPiKuNIrrVmD8IUCuw1hQxNqZc=
 dbsyncer.web.cache.connector.timeout=5
+dbsyncer.web.thread.pool.core.size=10
+dbsyncer.web.thread.pool.queue.capacity=1000
 server.servlet.session.timeout=1800
 server.servlet.context-path=/
 
@@ -21,7 +23,7 @@ management.endpoints.web.base-path=/app
 management.endpoints.web.exposure.include=*
 management.endpoint.health.show-details=always
 info.app.name=DBSyncer
-info.app.version=1.0.7-Alpha
+info.app.version=1.0.9-Alpha
 info.app.copyright=&copy;2021 ${info.app.name}(${info.app.version})<br />Designed By <a href='https://gitee.com/ghi/dbsyncer' target='_blank' >AE86</a>
 
 #All < Trace < Debug < Info < Warn < Error < Fatal < OFF

+ 4 - 4
dbsyncer-web/src/main/resources/public/connector/add.html

@@ -8,7 +8,7 @@
             <!-- 标题 -->
             <div class="row text-center">
                 <div class="page-header">
-                    <h3>添加连接</h3>
+                    <h3>添加连接</h3>
                 </div>
             </div>
 
@@ -30,11 +30,11 @@
                 <div class="col-md-12">
                     <div class="panel panel-info">
                         <div class="panel-heading">
-                            <h3 class="panel-title">连接配置</h3>
+                            <h3 class="panel-title">连接配置</h3>
                         </div>
 
                         <div class="panel-body">
-                            <!-- 连接类型 -->
+                            <!-- 连接类型 -->
                             <div class="form-group">
                                 <label class="col-sm-2 control-label">类型</label>
                                 <div class="col-sm-10">
@@ -53,7 +53,7 @@
                                 </div>
                             </div>
 
-                            <!-- 连接配置 -->
+                            <!-- 连接配置 -->
                             <div class="connectorConfig"></div>
 
                         </div>

+ 5 - 5
dbsyncer-web/src/main/resources/public/connector/edit.html

@@ -8,7 +8,7 @@
             <!-- 标题 -->
             <div class="row text-center">
                 <div class="page-header">
-                    <h3>修改连接</h3>
+                    <h3>修改连接</h3>
                 </div>
             </div>
 
@@ -30,11 +30,11 @@
                 <div class="col-md-12">
                     <div class="panel panel-info">
                         <div class="panel-heading">
-                            <h3 class="panel-title">连接配置</h3>
+                            <h3 class="panel-title">连接配置</h3>
                         </div>
 
                         <div class="panel-body">
-                            <!-- 连接ID -->
+                            <!-- 连接ID -->
                             <div class="form-group hidden">
                                 <label class="col-sm-2 control-label">ID</label>
                                 <div class="col-sm-10">
@@ -42,7 +42,7 @@
                                 </div>
                             </div>
 
-                            <!-- 连接类型 -->
+                            <!-- 连接类型 -->
                             <div class="form-group">
                                 <label class="col-sm-2 control-label">类型</label>
                                 <div class="col-sm-10">
@@ -58,7 +58,7 @@
                                 </div>
                             </div>
 
-                            <!-- 连接配置 -->
+                            <!-- 连接配置 -->
                             <div class="connectorConfig">
                                 <div th:replace="'connector/add'+${connector?.config?.connectorType} :: content"></div>
                             </div>

+ 0 - 56
dbsyncer-web/src/main/resources/public/databus/databus.html

@@ -1,56 +0,0 @@
-<html>
-<head>
-    <meta charset="UTF-8"/>
-    <title>广播式WebSocket</title>
-    <script src="https://cdn.bootcss.com/sockjs-client/1.4.0/sockjs.min.js"></script>
-    <script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
-    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
-</head>
-<body onload="disconnect()">
-<noscript><h2 style="color: #e80b0a;">Sorry,浏览器不支持WebSocket</h2></noscript>
-<div>
-    <div>
-        <button id="connect" onclick="connect();">连接</button>
-        <button id="disconnect" disabled="disabled" onclick="disconnect();">断开连接</button>
-    </div>
-
-    <div id="conversationDiv">
-        <label>服务端响应:</label>
-        <p id="callback"></p>
-    </div>
-</div>
-<script type="text/javascript">
-    var stompClient = null;
-
-    function setConnected(connected) {
-        document.getElementById("connect").disabled = connected;
-        document.getElementById("disconnect").disabled = !connected;
-        document.getElementById("conversationDiv").style.visibility = connected ? 'visible' : 'hidden';
-        $("#response").html();
-        $("#callback").html();
-    }
-
-    function connect() {
-        var socket = new SockJS('/simple');
-        stompClient = Stomp.over(socket);
-        stompClient.connect({}, function (frame) {
-            setConnected(true);
-            console.log('Connected:' + frame);
-
-            stompClient.subscribe('/topic/callback', function (response) {
-                $("#callback").html(response.body);
-            });
-        });
-    }
-
-    function disconnect() {
-        if (stompClient != null) {
-            stompClient.disconnect();
-        }
-        setConnected(false);
-        console.log('Disconnected');
-    }
-
-</script>
-</body>
-</html>

+ 11 - 11
dbsyncer-web/src/main/resources/public/index/index.html

@@ -7,9 +7,9 @@
     <div class="row">
         <form class="form-horizontal" role="form" method="post">
 
-            <!-- 连接管理 -->
+            <!-- 连接管理 -->
             <div class="col-md-12">
-                <!-- 连接开始位置 -->
+                <!-- 连接开始位置 -->
                 <div class="form-group">
                     <div class="col-md-12">
                         <button type="button" class="btn btn-primary" id="indexAddConnectorBtn">
@@ -17,14 +17,14 @@
                         </button>
                     </div>
                 </div>
-                <!-- 显示连接列表 -->
+                <!-- 显示连接列表 -->
                 <div class="row" th:if="${connectors?.size() gt 0}">
                     <div class="col-md-12">
                         <div class="panel panel-default">
-                            <!-- 连接 -->
+                            <!-- 连接 -->
                             <div class="panel-body text-center">
                                 <div class="row connectorList">
-                                    <!-- 连接__开始 -->
+                                    <!-- 连接__开始 -->
                                     <div class="col-md-1" th:each="c,state : ${connectors}">
                                         <div th:id="${c?.id}" class="jumbotron dbsyncer_block">
                                             <div class="row">
@@ -42,7 +42,7 @@
                                             </ul>
                                         </div>
                                     </div>
-                                    <!-- 连接__结束 -->
+                                    <!-- 连接__结束 -->
 
                                 </div>
                             </div>
@@ -50,7 +50,7 @@
                         </div>
                     </div>
                 </div>
-                <!-- 连接开结束位置 -->
+                <!-- 连接开结束位置 -->
             </div>
 
             <!-- 驱动管理 -->
@@ -88,8 +88,8 @@
                                                         </div>
                                                         <div class="col-md-1"></div>
                                                     </div>
-                                                    <span th:if="${m?.sourceConnector?.running}" th:title="连接正常" class="well-sign-left"><i class="fa fa-2x fa-circle well-sign-green"></i></span>
-                                                    <span th:unless="${m?.sourceConnector?.running}" th:title="连接异常" class="well-sign-left"><i class="fa fa-2x fa-times-circle-o well-sign-red"></i></span>
+                                                    <span th:if="${m?.sourceConnector?.running}" th:title="连接正常" class="well-sign-left"><i class="fa fa-2x fa-circle well-sign-green"></i></span>
+                                                    <span th:unless="${m?.sourceConnector?.running}" th:title="连接异常" class="well-sign-left"><i class="fa fa-2x fa-times-circle-o well-sign-red"></i></span>
                                                 </div>
 
                                                 <!--中间图标 -->
@@ -112,8 +112,8 @@
                                                             <span th:text="${m?.targetConnector?.name}" th:title="${m?.targetConnector?.name}"></span>
                                                         </div>
                                                         <div class="col-md-1"></div>
-                                                        <span th:if="${m?.targetConnector?.running}" th:title="连接正常" class="well-sign-right"><i class="fa fa-2x fa-circle well-sign-green"></i></span>
-                                                        <span th:unless="${m?.targetConnector?.running}" th:title="连接异常" class="well-sign-right"><i class="fa fa-2x fa-times-circle-o well-sign-red"></i></span>
+                                                        <span th:if="${m?.targetConnector?.running}" th:title="连接正常" class="well-sign-right"><i class="fa fa-2x fa-circle well-sign-green"></i></span>
+                                                        <span th:unless="${m?.targetConnector?.running}" th:title="连接异常" class="well-sign-right"><i class="fa fa-2x fa-times-circle-o well-sign-red"></i></span>
                                                     </div>
                                                 </div>
                                             </div>

+ 3 - 8
dbsyncer-web/src/main/resources/public/mapping/editFull.html

@@ -8,23 +8,18 @@
     <div class="form-group">
         <div class="row">
             <div class="col-md-4">
-                <label class="col-sm-3 control-label text-right">读取<strong class="driverVerifcateRequired">*</strong></label>
+                <label class="col-sm-3 control-label text-right">批量读取<strong class="driverVerifcateRequired">*</strong></label>
                 <div class="col-sm-9">
                     <input type="number" name="readNum" class="form-control" min="1" dbsyncer-valid="require" th:value="${mapping?.readNum}">
                 </div>
             </div>
             <div class="col-md-4">
-                <label class="col-sm-3 control-label text-right">线程<strong class="driverVerifcateRequired">*</strong></label>
-                <div class="col-sm-9">
-                    <input type="number" name="threadNum" class="form-control" min="1" dbsyncer-valid="require" th:value="${mapping?.threadNum}">
-                </div>
-            </div>
-            <div class="col-md-4">
-                <label class="col-sm-3 control-label text-right">写入<strong class="driverVerifcateRequired">*</strong></label>
+                <label class="col-sm-3 control-label text-right">单次写入<strong class="driverVerifcateRequired">*</strong></label>
                 <div class="col-sm-9">
                     <input type="number" name="batchNum" class="form-control" min="1" dbsyncer-valid="require" th:value="${mapping?.batchNum}">
                 </div>
             </div>
+            <div class="col-md-4"></div>
         </div>
     </div>
 </div>

+ 1 - 1
dbsyncer-web/src/main/resources/public/mapping/editIncrementDQL.html

@@ -3,7 +3,7 @@
       xmlns:th="http://www.thymeleaf.org" lang="zh-CN">
 
 <div th:fragment="content">
-    <!-- 针对DQL的连接配置 -->
+    <!-- 针对DQL的连接配置 -->
     <div class="form-group" th:if="${#strings.startsWith(mapping?.sourceConnector?.config?.connectorType,'Dql')}">
         <div class="row">
             <div class="col-md-4">

+ 181 - 128
dbsyncer-web/src/main/resources/public/monitor/monitor.html

@@ -6,150 +6,203 @@
 <div class="container-fluid">
     <div class="row">
         <form class="form-horizontal" role="form" method="post">
-
-            <!-- 数据 -->
+            <!-- 应用性能 -->
             <div class="col-md-12">
-                <div class="form-group">
-                    <div class="col-md-3">
-                        <!-- 驱动下拉 -->
-                        <select id="searchMetaData" class="form-control select-control">
-                            <option th:each="m,s:${meta}" th:value="${m?.id}" th:text="${m?.mappingName} +' (' + ${m?.model} +')'" th:selected="${m?.id eq metaId}"/>
-                        </select>
-                    </div>
-                    <div class="col-md-1">
-                        <!-- 是否包含成功 -->
-                        <select id="searchDataSuccess" class="form-control select-control">
-                            <option th:value="${c?.value}" th:text="${c?.message}" th:each="c,state : ${storageDataStatus}"/>
-                        </select>
-                    </div>
-                    <div class="col-sm-4">
-                        <input id="searchDataKeyword" class="form-control" type="text" maxlength="32" placeholder="请输入异常关键字(最多32个字)." />
-                    </div>
-                    <div class="col-md-1">
-                        <button id="queryDataBtn" type="button" class="btn btn-primary">查询数据</button>
-                    </div>
-                    <div class="col-md-3 text-right">
-                        <button th:id="${metaId}" type="button" class="btn btn-default clearDataBtn">清空数据</button>
-                    </div>
-                </div>
+                <div class="panel-group">
+                    <div class="panel panel-success">
+                        <div class="panel-heading">
+                            <h4 class="panel-title">
+                                <u data-toggle="collapse" class="dbsyncer_pointer" href="#systemMetrics">应用性能</u>
+                            </h4>
+                        </div>
+                        <div id="systemMetrics" class="panel-body panel-collapse collapse in">
+                            <div class="col-md-7">
+                                <div class="row">
+                                    <div class="col-md-4">
+                                        <h3><small>总共</small>&nbsp;<span class="label label-info" id="totalSpan">0</span></h3>
+                                    </div>
+                                    <div class="col-md-4">
+                                        <h3><small>成功</small>&nbsp;<span class="label label-success" id="successSpan">0</span></h3>
+                                    </div>
+                                    <div class="col-md-4">
+                                        <h3><small>失败</small>&nbsp;<span class="label label-warning" id="failSpan">0</span></h3>
+                                    </div>
+                                </div>
+                                <div class="row">
+                                    <div class="col-md-4">
+                                        <h3><small>新增</small>&nbsp;<span class="label label-default" id="insertSpan">0</span></h3>
+                                    </div>
+                                    <div class="col-md-4">
+                                        <h3><small>修改</small>&nbsp;<span class="label label-default" id="updateSpan">0</span></h3>
+                                    </div>
+                                    <div class="col-md-4">
+                                        <h3><small>删除</small>&nbsp;<span class="label label-default" id="deleteSpan">0</span></h3>
+                                    </div>
+                                </div>
+                                <hr>
+                                <div class="row">
+                                    <div class="col-md-4">
+                                        <div id="totalChart" style="height: 260px;"></div>
+                                    </div>
 
-                <table class="table table-hover metaDataList">
-                    <thead>
-                    <tr>
-                        <th style="width:3%;"></th>
-                        <th style="width:5%;">事件</th>
-                        <th style="width:5%;">结果</th>
-                        <th style="width:60%;">异常</th>
-                        <th style="width:17%;">时间</th>
-                        <th style="width:10%;">详情</th>
-                    </tr>
-                    </thead>
-                    <tbody id="dataList">
-                        <tr th:each="d,s : ${pagingData?.data}">
-                            <td th:text="${s.index}+1"></td>
-                            <td th:text="${d?.event}"></td>
-                            <td>
-                                <span th:if="${d?.success == 1}" class="label label-success">成功</span>
-                                <span th:if="${d?.success == 0}" class="label label-warning">失败</span>
-                            </td>
-                            <td style="max-width:100px;" class="dbsyncer_over_hidden"><a href="javascript:;" class="dbsyncer_pointer queryError">[[${d?.error}]]</a></td>
-                            <td th:text="${#dates.format(d?.createTime, 'yyyy-MM-dd HH:mm:ss')}"></td>
-                            <td><a th:json="${d?.json}" href="javascript:;" class="label label-info queryData">查看数据</a><div class="hidden" th:text="${d?.json}"></div></td>
-                        </tr>
-                    </tbody>
-                </table>
-
-                <div class="form-group">
-                    <div class="col-md-5">共计: <span id="dataTotal">[[${pagingData?.total}]]</span>条</div>
-                    <div class="col-md-7">
-                        <a href="javascript:void(0);" id="queryDataMore" num="1">显示更多<i class="fa fa-angle-double-down" aria-hidden="true"></i></a>
-                    </div>
-                </div>
+                                    <div class="col-md-4">
+                                        <div id="eventChart" style="height: 260px;"></div>
+                                    </div>
 
-            </div>
+                                    <div class="col-md-4">
+                                        <div id="queueChart" style="height: 260px;"></div>
+                                    </div>
+                                </div>
+                                <div class="row">
+                                    <div class="col-md-6">
+                                        <div id="cpuChart" style="height: 260px; "></div>
+                                    </div>
 
-            <!-- 性能指标 -->
-            <div class="col-md-12">
-                <div class="col-md-6">
-                    <table class="table table-hover">
-                        <caption>系统性能</caption>
-                        <thead>
-                        <tr>
-                            <th style="width:10%;">类型</th>
-                            <th style="width:10%;">状态</th>
-                            <th style="width:80%;">指标</th>
-                        </tr>
-                        </thead>
-                        <tbody id="systemList"></tbody>
-                    </table>
-                </div>
+                                    <div class="col-md-6">
+                                        <div id="memoryChart" style="height: 260px;"></div>
+                                    </div>
+                                </div>
+                            </div>
 
-                <div class="col-md-3">
-                    <div id="cpuChart" style="height: 260px; max-width: 260px; margin: 0px auto;"></div>
-                </div>
+                            <div class="col-md-5">
+                                <div class="row">
+                                    <div class="col-md-12">
+                                        <table id="metricTable" class="table table-hover">
+                                            <tr th:each="m,s : ${metrics}">
+                                                <td style="width:5%;" th:text="${s.index}+1"></td>
+                                                <td th:text="${'['+ m?.group + '] ' + m?.metricName}"></td>
+                                                <td th:text="${m?.detail}"></td>
+                                            </tr>
+                                        </table>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
 
-                <div class="col-md-3">
-                    <div id="memChart" style="height: 260px; max-width: 260px; margin: 0px auto;"></div>
+                    </div>
                 </div>
             </div>
 
-            <!-- 线程任务 -->
+            <!-- 数据 -->
             <div class="col-md-12">
-                <div class="col-md-6">
-                    <table class="table table-hover">
-                        <caption>线程任务</caption>
-                        <thead>
-                        <tr>
-                            <th style="width:3%;"></th>
-                            <th style="width:70%;">类型</th>
-                            <th style="width:27%;">指标</th>
-                        </tr>
-                        </thead>
-                        <tr th:each="item,userStat:${threadInfo}">
-                            <td th:text="${userStat.index}+1"></td>
-                            <td th:text="${userStat.current.key}"></td><!-- key-->
-                            <td th:text="${userStat.current.value}"></td><!-- value-->
-                        </tr>
-                    </table>
+                <div class="panel-group">
+                    <div class="panel panel-default">
+                        <div class="panel-heading">
+                            <h4 class="panel-title">
+                                <u data-toggle="collapse" class="dbsyncer_pointer" href="#queryDataPanel">查询数据</u>
+                            </h4>
+                        </div>
+                        <div id="queryDataPanel" class="panel-body panel-collapse collapse in">
+                            <div class="form-group">
+                                <div class="col-md-3">
+                                    <!-- 驱动下拉 -->
+                                    <select id="searchMetaData" class="form-control select-control">
+                                        <option th:each="m,s:${meta}" th:value="${m?.id}" th:text="${m?.mappingName} +' (' + ${m?.model} +')'" th:selected="${m?.id eq metaId}"/>
+                                    </select>
+                                </div>
+                                <div class="col-md-1">
+                                    <!-- 是否包含成功 -->
+                                    <select id="searchDataSuccess" class="form-control select-control">
+                                        <option th:value="${c?.value}" th:text="${c?.message}" th:each="c,state : ${storageDataStatus}"/>
+                                    </select>
+                                </div>
+                                <div class="col-sm-4">
+                                    <input id="searchDataKeyword" class="form-control" type="text" maxlength="32" placeholder="请输入异常关键字(最多32个字)." />
+                                </div>
+                                <div class="col-md-1">
+                                    <button id="queryDataBtn" type="button" class="btn btn-primary">查询数据</button>
+                                </div>
+                                <div class="col-md-3 text-right">
+                                    <button th:id="${metaId}" type="button" class="btn btn-default clearDataBtn">清空数据</button>
+                                </div>
+                            </div>
+
+                            <table class="table table-hover metaDataList">
+                                <thead>
+                                <tr>
+                                    <th style="width:3%;"></th>
+                                    <th style="width:5%;">事件</th>
+                                    <th style="width:5%;">结果</th>
+                                    <th style="width:60%;">异常</th>
+                                    <th style="width:17%;">时间</th>
+                                    <th style="width:10%;">详情</th>
+                                </tr>
+                                </thead>
+                                <tbody id="dataList">
+                                <tr th:each="d,s : ${pagingData?.data}">
+                                    <td th:text="${s.index}+1"></td>
+                                    <td th:text="${d?.event}"></td>
+                                    <td>
+                                        <span th:if="${d?.success == 1}" class="label label-success">成功</span>
+                                        <span th:if="${d?.success == 0}" class="label label-warning">失败</span>
+                                    </td>
+                                    <td style="max-width:100px;" class="dbsyncer_over_hidden"><a href="javascript:;" class="dbsyncer_pointer queryError">[[${d?.error}]]</a></td>
+                                    <td th:text="${#dates.format(d?.createTime, 'yyyy-MM-dd HH:mm:ss')}"></td>
+                                    <td><a th:json="${d?.json}" href="javascript:;" class="label label-info queryData">查看数据</a><div class="hidden" th:text="${d?.json}"></div></td>
+                                </tr>
+                                </tbody>
+                            </table>
+
+                            <div class="form-group">
+                                <div class="col-md-5">共计: <span id="dataTotal">[[${pagingData?.total}]]</span>条</div>
+                                <div class="col-md-7">
+                                    <a href="javascript:void(0);" id="queryDataMore" num="1">显示更多<i class="fa fa-angle-double-down" aria-hidden="true"></i></a>
+                                </div>
+                            </div>
+                        </div>
+
+                    </div>
                 </div>
             </div>
 
             <!-- 日志 -->
             <div class="col-md-12">
-                <div class="form-group">
-                    <div class="col-sm-4">
-                        <input id="searchLogKeyword" class="form-control" type="text" maxlength="32" placeholder="请输入内容关键字(最多32个字)." />
-                    </div>
-                    <div class="col-md-1">
-                        <button id="queryLogBtn" type="button" class="btn btn-primary">查询日志</button>
-                    </div>
-                    <div class="col-md-4"></div>
-                    <div class="col-md-3 text-right">
-                        <button th:id="${metaId}" type="button" class="btn btn-default clearLogBtn">清空日志</button>
-                    </div>
-                </div>
+                <div class="panel-group">
+                    <div class="panel panel-default">
+                        <div class="panel-heading">
+                            <h4 class="panel-title">
+                                <u data-toggle="collapse" class="dbsyncer_pointer" href="#queryLogPanel">查询日志</u>
+                            </h4>
+                        </div>
+                        <div id="queryLogPanel" class="panel-body panel-collapse collapse">
+                            <div class="form-group">
+                                <div class="col-sm-4">
+                                    <input id="searchLogKeyword" class="form-control" type="text" maxlength="32" placeholder="请输入内容关键字(最多32个字)." />
+                                </div>
+                                <div class="col-md-1">
+                                    <button id="queryLogBtn" type="button" class="btn btn-primary">查询日志</button>
+                                </div>
+                                <div class="col-md-4"></div>
+                                <div class="col-md-3 text-right">
+                                    <button th:id="${metaId}" type="button" class="btn btn-default clearLogBtn">清空日志</button>
+                                </div>
+                            </div>
+
+                            <table class="table table-hover">
+                                <thead>
+                                <tr>
+                                    <th style="width:3%;"></th>
+                                    <th style="width:70%;">内容</th>
+                                    <th style="width:27%;">时间</th>
+                                </tr>
+                                </thead>
+                                <tbody id="logList">
+                                <tr th:each="l,s : ${pagingLog?.data}">
+                                    <td th:text="${s.index}+1"></td>
+                                    <td th:text="${l?.json}"></td>
+                                    <td th:text="${#dates.format(l?.createTime, 'yyyy-MM-dd HH:mm:ss')}"></td>
+                                </tr>
+                                </tbody>
+                            </table>
+
+                            <div class="form-group">
+                                <div class="col-md-5">共计: <span id="logTotal">[[${pagingLog?.total}]]</span>条</div>
+                                <div class="col-md-7">
+                                    <a href="javascript:void(0);" id="queryLogMore" num="1">显示更多<i class="fa fa-angle-double-down" aria-hidden="true"></i></a>
+                                </div>
+                            </div>
+                        </div>
 
-                <table class="table table-hover">
-                    <thead>
-                    <tr>
-                        <th style="width:3%;"></th>
-                        <th style="width:70%;">内容</th>
-                        <th style="width:27%;">时间</th>
-                    </tr>
-                    </thead>
-                    <tbody id="logList">
-                    <tr th:each="l,s : ${pagingLog?.data}">
-                        <td th:text="${s.index}+1"></td>
-                        <td th:text="${l?.json}"></td>
-                        <td th:text="${#dates.format(l?.createTime, 'yyyy-MM-dd HH:mm:ss')}"></td>
-                    </tr>
-                    </tbody>
-                </table>
-
-                <div class="form-group">
-                    <div class="col-md-5">共计: <span id="logTotal">[[${pagingLog?.total}]]</span>条</div>
-                    <div class="col-md-7">
-                        <a href="javascript:void(0);" id="queryLogMore" num="1">显示更多<i class="fa fa-angle-double-down" aria-hidden="true"></i></a>
                     </div>
                 </div>
             </div>

+ 2 - 0
dbsyncer-web/src/main/resources/static/js/common.js

@@ -4,6 +4,8 @@ var $path = document.location.pathname;
 var $basePath = $location[0] + '//' + $location[2] + $path.substr(0, $path.substr(1).indexOf("/")+1);
 // 全局内容区域
 var $initContainer = $("#initContainer");
+// 监控定时器
+var timer;
 
 // ******************* 插件封装 ***************************
 // 全局提示框

+ 6 - 6
dbsyncer-web/src/main/resources/static/js/connector/add.js

@@ -1,7 +1,7 @@
 function submit(data) {
     doPoster("/connector/add", data, function (data) {
         if (data.success == true) {
-            bootGrowl("新增连接成功!", "success");
+            bootGrowl("新增连接成功!", "success");
             backIndexPage();
         } else {
             bootGrowl(data.resultValue, "danger");
@@ -17,11 +17,11 @@ var check = function () {
     }
 };
 
-//切换连接
+//切换连接
 function changeConnectorType($this) {
-    //连接类型
+    //连接类型
     var connType = $this.val();
-    //获取连接配置元素
+    //获取连接配置元素
     var connectorConfig = $this.parent().parent().parent().find(".connectorConfig");
     //清空配置
     connectorConfig.html("");
@@ -39,10 +39,10 @@ $(function () {
         width: "100%",
         theme: "classic"
     });
-    // 默认渲染连接页面
+    // 默认渲染连接页面
     changeConnectorType($connectorTypeSelect);
 
-    //连接类型切换事件
+    //连接类型切换事件
     $("select[name='connectorType']").change(function () {
         changeConnectorType($(this));
     });

+ 1 - 1
dbsyncer-web/src/main/resources/static/js/connector/edit.js

@@ -1,7 +1,7 @@
 function submit(data) {
     doPoster("/connector/edit", data, function (data) {
         if (data.success == true) {
-            bootGrowl("修改连接成功!", "success");
+            bootGrowl("修改连接成功!", "success");
             backIndexPage();
         } else {
             bootGrowl(data.resultValue, "danger");

+ 1 - 0
dbsyncer-web/src/main/resources/static/js/index.js

@@ -39,6 +39,7 @@ $(function () {
 
     // 绑定所有的菜单链接点击事件,根据不同的URL加载页面
     $("#menu li a[url]").click(function () {
+        clearInterval(timer);
         // 加载页面
         doLoader($(this).attr("url"));
     });

+ 3 - 3
dbsyncer-web/src/main/resources/static/js/index/index.js

@@ -1,12 +1,12 @@
-// 添加连接
+// 添加连接
 function bindAddConnector() {
-    // 绑定添加连接按钮点击事件
+    // 绑定添加连接按钮点击事件
     $("#indexAddConnectorBtn").click(function () {
         doLoader('/connector/page/add');
     });
 }
 
-// 编辑连接
+// 编辑连接
 function bindEditConnector() {
     $(".connectorList .dbsyncer_block").click(function () {
         var $id = $(this).attr("id");

+ 216 - 168
dbsyncer-web/src/main/resources/static/js/monitor/index.js

@@ -211,176 +211,227 @@ function showLog($logList, arr, append){
     return html;
 }
 
-// 查看系统指标
-function showSystemInfo(){
-    doGetWithoutLoading("/app/health",{}, function (data) {
-        var details = data.details;
-        var html = showPoint("硬盘", details.diskSpace);
-
-        doGetWithoutLoading("/app/metrics/jvm.threads.live",{}, function (data) {
-            html += showSystemItem("线程活跃", data.measurements[0].value);
-            doGetWithoutLoading("/app/metrics/jvm.threads.peak",{}, function (data) {
-                html += showSystemItem("线程峰值", data.measurements[0].value);
-                doGetWithoutLoading("/app/metrics/jvm.gc.pause",{}, function (data) {
-                    var count =  data.measurements[0].value;
-                    var time =  data.measurements[1].value;
-                    time = time.toFixed(2);
-                    var text = count+"次";
-                    text += ",耗时:"+time + "秒";
-                    html += showSystemItem("GC", text);
-                    $("#systemList").html(html);
-                });
-            });
-        });
-    });
-
+// 堆积数据
+function showQueueChart(queueUp, queueCapacity){
+    var option={
+        title:{
+            text:"堆积数据",
+            x:'center',
+            y: 'top'
+        },
+        tooltip : {
+            formatter: "{a}: {c}",
+            position: 'top'
+        },
+        series: [
+            {
+                name: "待处理",
+                animation: true,
+                type: 'gauge',
+                min: 0,
+                max: queueCapacity,
+                splitNumber: 5,
+                axisLine: {            // 坐标轴线
+                    lineStyle: {       // 属性lineStyle控制线条样式
+                        color: [[0.1, '#5cb85c'], [0.3, '#5bc0de'],[0.8, '#f0ad4e'],[1, '#d9534f']],
+                        width: 10
+                    }
+                },
+                axisTick: {            // 坐标轴小标记
+                    length: 15,        // 属性length控制线长
+                    lineStyle: {       // 属性lineStyle控制线条样式
+                        color: 'auto'
+                    }
+                },
+                splitLine: {           // 分隔线
+                    length: 20,         // 属性length控制线长
+                    lineStyle: {       // 属性lineStyle(详见lineStyle)控制线条样式
+                        color: 'auto'
+                    }
+                },
+                detail: {fontSize:12, offsetCenter:[0,'65%']},
+                data: [{value: queueUp, name: ''}]
+            }
+        ]
+    };
+    echarts.init(document.getElementById('queueChart')).setOption(option);
 }
-
-// CPU
-function showCpu(){
-    doGetWithoutLoading("/app/metrics/system.cpu.usage",{}, function (data) {
-        var value = data.measurements[0].value * 100;
-        value = value.toFixed(2);
-        var option={
-            title:{
-                text:"CPU",
-                x:'center',
-                y: 'top'
-            },
-            tooltip : {
-                formatter: "{a}: {c}%",
-                position: 'top'
-            },
-            series: [
-                {
-                    name: "已用",
-                    animation: true,
-                    type: 'gauge',
-                    min: 0,
-                    max: 100,
-                    splitNumber: 4,
-                    axisLine: {            // 坐标轴线
-                        lineStyle: {       // 属性lineStyle控制线条样式
-                            color: [[0.1, '#d9534f'], [0.3, '#f0ad4e'],[0.8, '#5bc0de'],[1, '#5cb85c']],
-                            width: 10
-                        }
-                    },
-                    axisTick: {            // 坐标轴小标记
-                        length: 15,        // 属性length控制线长
-                        lineStyle: {       // 属性lineStyle控制线条样式
-                            color: 'auto'
-                        }
-                    },
-                    splitLine: {           // 分隔线
-                        length: 20,         // 属性length控制线长
-                        lineStyle: {       // 属性lineStyle(详见lineStyle)控制线条样式
-                            color: 'auto'
-                        }
-                    },
-                    detail: {formatter:'{value}%', fontSize:12, offsetCenter:[0,'65%']},
-                    data: [{value: value, name: ''}]
+// 事件分类
+function showEventChart(ins, upd, del){
+    var option = {
+        title: {
+            text: '事件分类',
+            left: 'center'
+        },
+        tooltip: {
+            trigger: 'item'
+        },
+        legend: {
+            orient: 'vertical',
+            left: 'left',
+        },
+        series: [
+            {
+                name: '事件',
+                type: 'pie',
+                radius: '50%',
+                data: [
+                    {value:upd, name:'更新'},
+                    {value:ins, name:'插入'},
+                    {value:del, name:'删除'}
+                ],
+                emphasis: {
+                    itemStyle: {
+                        shadowBlur: 10,
+                        shadowOffsetX: 0,
+                        shadowColor: 'rgba(0, 0, 0, 0.5)'
+                    }
                 }
-            ]
-        };
-        echarts.init(document.getElementById('cpuChart')).setOption(option);
+            }
+        ]
+    };
+    echarts.init(document.getElementById('eventChart')).setOption(option);
 
-    });
+    $("#insertSpan").html(ins);
+    $("#updateSpan").html(upd);
+    $("#deleteSpan").html(del);
 }
+// 统计成功失败
+function showTotalChart(success, fail){
+    var option = {
+        title: {
+            text: '已完成数据',
+            left: 'center'
+        },
+        tooltip: {
+            trigger: 'item'
+        },
+        legend: {
+            orient: 'vertical',
+            left: 'left',
+        },
+        series: [
+            {
+                name: '已完成',
+                type: 'pie',
+                radius: '50%',
+                data: [
+                    {value:success, name:'成功'},
+                    {value:fail, name:'失败'}
+                ],
+                emphasis: {
+                    itemStyle: {
+                        shadowBlur: 10,
+                        shadowOffsetX: 0,
+                        shadowColor: 'rgba(0, 0, 0, 0.5)'
+                    }
+                }
+            }
+        ]
+    };
+    echarts.init(document.getElementById('totalChart')).setOption(option);
 
-// 内存
-function showMem(){
-    doGetWithoutLoading("/app/metrics/jvm.memory.max",{}, function (data) {
-        var max = data.measurements[0].value;
-        max = (max / 1024 / 1024 / 1024).toFixed(2);
-        doGetWithoutLoading("/app/metrics/jvm.memory.used",{}, function (data) {
-            var used = data.measurements[0].value;
-            used = (used / 1024 / 1024 / 1024).toFixed(2);
-            doGetWithoutLoading("/app/metrics/jvm.memory.committed",{}, function (data) {
-                var committed = data.measurements[0].value;
-                committed = (committed / 1024 / 1024 / 1024).toFixed(2);
-
-                var option = {
-                    title : {
-                        show:true,
-                        text: '内存'+ max +'GB',
-                        x:'center',
-                        y: 'top'
-                    },
-                    tooltip : {
-                        trigger: 'item',
-                        formatter: "{b} : {c} GB"
-                    },
-                    series : [
-                        {
-                            name:'内存',
-                            type:'pie',
-                            color: function(params) {
-                                // build a color map as your need.
-                                var colorList = [
-                                    '#60C0DD','#F0805A','#89DFAA'
-                                ];
-                                return colorList[params.dataIndex]
-                            },
-                            label:{
-                                normal:{
-                                    show:true,
-                                    position:'inner',
-                                    formatter:'{d}%'
-                                }
-                            },
-                            data:[
-                                {value:max,name:'总共'},
-                                {value:used,name:'已用'},
-                                {value:committed,name:'空闲'}
-                            ]
-                        }
-                    ]
-                };
-                echarts.init(document.getElementById('memChart')).setOption(option);
-
-            });
-        });
+    $("#totalSpan").html(success + fail);
+    $("#successSpan").html(success);
+    $("#failSpan").html(fail);
+}
+// CPU历史
+function showCpuChart(cpu){
+    var option = {
+        title : {
+            show:true,
+            text: 'CPU(%)',
+            x:'center',
+            y: 'bottom'
+        },
+        tooltip : {
+            trigger: 'item',
+            formatter: "{b} : {c}%"
+        },
+        xAxis: {
+            type: 'category',
+            data: cpu.name
+        },
+        yAxis: {
+            type: 'value'
+        },
+        series: [{
+            data: cpu.value,
+            type: 'line'
+        }]
+    };
+    echarts.init(document.getElementById('cpuChart')).setOption(option);
+}
+// 内存历史
+function showMemoryChart(memory){
+    var option = {
+        title : {
+            show:true,
+            text: '内存(MB)',
+            x:'center',
+            y: 'bottom'
+        },
+        tooltip : {
+            trigger: 'item',
+            formatter: "{b} : {c}MB"
+        },
+        xAxis: {
+            type: 'category',
+            boundaryGap: false,
+            data: memory.name
+        },
+        yAxis: {
+            type: 'value'
+        },
+        series: [{
+            data: memory.value,
+            type: 'line',
+            areaStyle: {}
+        }]
+    };
+    echarts.init(document.getElementById('memoryChart')).setOption(option);
+}
+// 指标列表
+function showMetricTable(metrics){
+    var html = '';
+    $.each(metrics, function(i) {
+        html += '<tr>';
+        html += '   <td style="width:5%;">'+ (i + 1) +'</td>';
+        html += '   <td>'+ metrics[i].metricName +'</td>';
+        html += '   <td>'+ metrics[i].detail +'</td>';
+        html += '</tr>';
     });
-
+    $("#metricTable").html(html);
 }
-
-function showPoint(title, point){
-    var status = point.status;
-    var d = point.details;
-    var total = (d.total / 1024 / 1024 / 1024).toFixed(2);
-    var threshold = (d.threshold / 1024 / 1024 / 1024).toFixed(2);
-    var free = (d.free / 1024 / 1024 / 1024).toFixed(2);
-
-    // UP/DOWN success/danger
-    var statusColor = status == 'UP' ? 'success' : 'danger';
-
-    // more than 63%/78% waring/danger
-    var precent = (threshold / total).toFixed(2);
-    var barColor = precent >= 63 ? 'waring' : 'success';
-    barColor = precent >= 78 ? 'danger' : barColor;
-
-    var html = "";
-    html += "<tr>";
-    html += "   <td>" + title + "</td>";
-    html += "   <td><span class='label label-" + statusColor + "'>" + status + "</span></td>";
-    html += "   <td>";
-    html += "       <div class='progress' title='总共" + total + "GB,已用" + threshold + "GB,空闲" + free + "GB'>";
-    html += "           <div class='progress-bar progress-bar-" + barColor + " progress-bar-striped active' style='width: " + precent + "%'>" + threshold + "GB</div>";
-    html += "           <div class='progress-bar' style='width: " + (100 - precent) + "%'>" + free + "GB</div>";
-    html += "       </div>";
-    html += "   </td>";
-    html += "</tr>";
-    return html;
+// 显示图表信息
+function showChartTable(){
+    doGetWithoutLoading("/monitor/queryAppReportMetric",{}, function (data) {
+        if (data.success == true) {
+            var report = data.resultValue;
+            showTotalChart(report.success, report.fail);
+            showEventChart(report.insert, report.update, report.delete);
+            showQueueChart(report.queueUp, report.queueCapacity);
+            showCpuChart(report.cpu);
+            showMemoryChart(report.memory);
+            showMetricTable(report.metrics);
+        } else {
+            bootGrowl(data.resultValue, "danger");
+        }
+    });
 }
-
-function showSystemItem(title, value){
-    var html = "";
-    html += "<tr>";
-    html += "   <td>" + title + "</td>";
-    html += "   <td><span class='label label-success'>UP</span></td>";
-    html += "   <td>"+value+"</td>";
-    html += "</tr>";
-    return html;
+// 创建定时器
+function createTimer(){
+    clearInterval(timer);
+    showChartTable();
+    doGetWithoutLoading("/monitor/getRefreshInterval",{}, function (data) {
+        if (data.success == true) {
+            timer = setInterval(function(){
+                showChartTable();
+            }, data.resultValue * 1000);
+        } else {
+            bootGrowl(data.resultValue, "danger");
+        }
+    });
 }
 
 $(function () {
@@ -390,10 +441,9 @@ $(function () {
         theme: "classic"
     });
 
-    // 连接类型切换事件
+    // 连接类型切换事件
     $("#searchMetaData").change(function () {
-        var $id = $(this).val();
-        doLoader('/monitor?id=' + $id);
+        $("#queryDataBtn").click();
     });
     // 数据状态切换事件
     $("#searchDataSuccess").change(function () {
@@ -409,9 +459,7 @@ $(function () {
     bindClearEvent($(".clearDataBtn"), "确认清空数据?", "清空数据成功!", "/monitor/clearData");
     bindClearEvent($(".clearLogBtn"), "确认清空日志?", "清空日志成功!", "/monitor/clearLog");
 
-    showCpu();
-    showMem();
-    showSystemInfo();
+    createTimer();
 
     // 绑定回车事件
     $("#searchDataKeyword").keydown(function (e) {

File diff suppressed because it is too large
+ 3 - 0
dbsyncer-web/src/main/resources/static/plugins/js/echarts/echarts.min.js


+ 1 - 1
pom.xml

@@ -6,7 +6,7 @@
 
     <groupId>org.ghi</groupId>
     <artifactId>dbsyncer</artifactId>
-	<version>1.0.8-Alpha</version>
+	<version>1.0.9-Alpha</version>
     <packaging>pom</packaging>
     <name>dbsyncer</name>
     <url>https://gitee.com/ghi/dbsyncer</url>

+ 1 - 1
version.cmd

@@ -1,6 +1,6 @@
 @echo off
 
-set APP_VERSION=1.0.8-Alpha
+set APP_VERSION=1.0.9-Alpha
 
 echo "Clean Project ..."
 call mvn clean -f pom.xml

Some files were not shown because too many files changed in this diff