diff --git a/collector/pom.xml b/collector/pom.xml
index 70deccc..92b9b41 100644
--- a/collector/pom.xml
+++ b/collector/pom.xml
@@ -103,6 +103,12 @@
sshd-core
2.8.0
+
+
+ com.microsoft.sqlserver
+ mssql-jdbc
+ 10.2.0.jre8
+
\ No newline at end of file
diff --git a/collector/src/main/java/com/usthe/collector/collect/database/JdbcCommonCollect.java b/collector/src/main/java/com/usthe/collector/collect/database/JdbcCommonCollect.java
index c4c74f5..0e852f4 100644
--- a/collector/src/main/java/com/usthe/collector/collect/database/JdbcCommonCollect.java
+++ b/collector/src/main/java/com/usthe/collector/collect/database/JdbcCommonCollect.java
@@ -56,7 +56,9 @@ public class JdbcCommonCollect extends AbstractCollect {
int timeout = 3000;
try {
// 获取查询语句超时时间
- timeout = Integer.parseInt(jdbcProtocol.getTimeout());
+ if (jdbcProtocol.getTimeout() != null) {
+ timeout = Integer.parseInt(jdbcProtocol.getTimeout());
+ }
} catch (Exception e) {
log.warn(e.getMessage());
}
@@ -140,7 +142,9 @@ public class JdbcCommonCollect extends AbstractCollect {
Connection connection = DriverManager.getConnection(url, username, password);
statement = connection.createStatement();
// 设置查询超时时间10秒
- statement.setQueryTimeout(timeout);
+ int timeoutSecond = timeout / 1000;
+ timeoutSecond = timeoutSecond <= 0 ? 1 : timeoutSecond;
+ statement.setQueryTimeout(timeoutSecond);
// 设置查询最大行数1000行
statement.setMaxRows(1000);
JdbcConnect jdbcConnect = new JdbcConnect(connection);
@@ -200,7 +204,7 @@ public class JdbcCommonCollect extends AbstractCollect {
HashMap values = new HashMap<>(columns.size());
while (resultSet.next()) {
if (resultSet.getString(1) != null) {
- values.put(resultSet.getString(1).toLowerCase(), resultSet.getString(2));
+ values.put(resultSet.getString(1).toLowerCase().trim(), resultSet.getString(2));
}
}
CollectRep.ValueRow.Builder valueRowBuilder = CollectRep.ValueRow.newBuilder();
@@ -277,6 +281,10 @@ public class JdbcCommonCollect extends AbstractCollect {
url = "jdbc:postgresql://" + jdbcProtocol.getHost() + ":" + jdbcProtocol.getPort()
+ "/" + (jdbcProtocol.getDatabase() == null ? "" : jdbcProtocol.getDatabase());
break;
+ case "sqlserver":
+ url = "jdbc:sqlserver://" + jdbcProtocol.getHost() + ":" + jdbcProtocol.getPort()
+ + ";" + (jdbcProtocol.getDatabase() == null ? "" : "DatabaseName=" + jdbcProtocol.getDatabase());
+ break;
default:
throw new IllegalArgumentException("Not support database platform: " + jdbcProtocol.getPlatform());
diff --git a/collector/src/main/java/com/usthe/collector/dispatch/MetricsCollect.java b/collector/src/main/java/com/usthe/collector/dispatch/MetricsCollect.java
index 54c1a31..93ad92f 100644
--- a/collector/src/main/java/com/usthe/collector/dispatch/MetricsCollect.java
+++ b/collector/src/main/java/com/usthe/collector/dispatch/MetricsCollect.java
@@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.stream.Collectors;
/**
@@ -172,14 +173,23 @@ public class MetricsCollect implements Runnable, Comparable {
if (metrics.getCalculates() == null) {
metrics.setCalculates(Collections.emptyList());
}
+ // eg: database_pages=Database pages 非常规映射
+ Map fieldAliasMap = new HashMap<>(8);
Map fieldExpressionMap = metrics.getCalculates()
.stream()
.map(cal -> {
int splitIndex = cal.indexOf("=");
String field = cal.substring(0, splitIndex);
String expressionStr = cal.substring(splitIndex + 1);
- Expression expression = AviatorEvaluator.compile(expressionStr, true);
+ Expression expression = null;
+ try {
+ expression = AviatorEvaluator.compile(expressionStr, true);
+ } catch (Exception e) {
+ fieldAliasMap.put(field, expressionStr);
+ return null;
+ }
return new Object[]{field, expression}; })
+ .filter(Objects::nonNull)
.collect(Collectors.toMap(arr -> (String)arr[0], arr -> (Expression) arr[1]));
List fields = metrics.getFields();
@@ -226,7 +236,12 @@ public class MetricsCollect implements Runnable, Comparable {
}
} else {
// 不存在 则映射别名值
- value = aliasFieldValueMap.get(realField);
+ String aliasField = fieldAliasMap.get(realField);
+ if (aliasField != null) {
+ value = aliasFieldValueMap.get(aliasField);
+ } else {
+ value = aliasFieldValueMap.get(realField);
+ }
}
if (value == null) {
value = CommonConstants.NULL_VALUE;
diff --git a/manager/src/main/resources/define/app/sqlserver.yml b/manager/src/main/resources/define/app/sqlserver.yml
new file mode 100644
index 0000000..f4eacc9
--- /dev/null
+++ b/manager/src/main/resources/define/app/sqlserver.yml
@@ -0,0 +1,136 @@
+category: db
+app: sqlserver
+name:
+ zh-CN: SqlServer数据库
+ en-US: SqlServer DB
+# 参数映射map. type是参数类型: 0-number数字, 1-string明文字符串, 2-secret加密字符串
+# 强制固定必须参数 - host
+configmap:
+ - key: host
+ type: 1
+ - key: port
+ type: 0
+ - key: username
+ type: 1
+ - key: password
+ type: 2
+ - key: database
+ type: 1
+ - key: timeout
+ type: 0
+ - key: url
+ type: 1
+# 指标组列表
+metrics:
+ - name: basic
+ # 指标组调度优先级(0-127)越小优先级越高,优先级低的指标组会等优先级高的指标组采集完成后才会被调度,相同优先级的指标组会并行调度采集
+ # 优先级为0的指标组为可用性指标组,即它会被首先调度,采集成功才会继续调度其它指标组,采集失败则中断调度
+ priority: 0
+ # 指标组中的具体监控指标
+ fields:
+ # 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
+ - field: machine_name
+ type: 1
+ instance: true
+ - field: server_name
+ type: 1
+ - field: version
+ type: 1
+ - field: edition
+ type: 1
+ - field: start_time
+ type: 1
+ protocol: jdbc
+ jdbc:
+ # 主机host: ipv4 ipv6 域名
+ host: ^_^host^_^
+ # 端口
+ port: ^_^port^_^
+ platform: sqlserver
+ username: ^_^username^_^
+ password: ^_^password^_^
+ database: ^_^database^_^
+ timeout: ^_^timeout^_^
+ # SQL查询方式: oneRow, multiRow, columns
+ queryType: oneRow
+ # sql
+ sql: SELECT SERVERPROPERTY('MachineName') AS machine_name, SERVERPROPERTY('ServerName') AS server_name, SERVERPROPERTY('ProductVersion') AS version, SERVERPROPERTY('Edition') AS edition, sqlserver_start_time AS start_time FROM sys.dm_os_sys_info;
+ url: ^_^url^_^
+
+ - name: performance_counters
+ priority: 1
+ fields:
+ # 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
+ - field: database_pages
+ type: 0
+ - field: target_pages
+ type: 0
+ - field: page_life_expectancy
+ type: 0
+ - field: buffer_cache_hit_ratio
+ type: 0
+ - field: checkpoint_pages_sec
+ type: 0
+ - field: page_reads_sec
+ type: 0
+ - field: page_writes_sec
+ type: 0
+ # (非必须)监控指标别名,与上面的指标名映射。用于采集接口数据字段不直接是最终指标名称,需要此别名做映射转换
+ aliasFields:
+ - Database pages
+ - Target pages
+ - Page life expectancy
+ - Buffer cache hit ratio
+ - Checkpoint pages/sec
+ - Page reads/sec
+ - Page writes/sec
+ # (非必须)指标计算表达式,与上面的别名一起作用,计算出最终需要的指标值
+ # eg: cores=core1+core2, usage=usage, waitTime=allTime-runningTime
+ calculates:
+ - database_pages=Database pages
+ - target_pages=Target pages
+ - page_life_expectancy=Page life expectancy
+ - buffer_cache_hit_ratio=Buffer cache hit ratio
+ - checkpoint_pages_sec=Checkpoint pages/sec
+ - page_reads_sec=Page reads/sec
+ - page_writes_sec=Page writes/sec
+ protocol: jdbc
+ jdbc:
+ # 主机host: ipv4 ipv6 域名
+ host: ^_^host^_^
+ # 端口
+ port: ^_^port^_^
+ platform: sqlserver
+ username: ^_^username^_^
+ password: ^_^password^_^
+ database: ^_^database^_^
+ timeout: ^_^timeout^_^
+ # SQL查询方式: oneRow, multiRow, columns
+ queryType: columns
+ # sql
+ sql: select counter_name, cntr_value from sys.dm_os_performance_counters where object_name = 'SQLServer:Buffer Manager';
+ url: ^_^url^_^
+
+ - name: connection
+ priority: 1
+ fields:
+ # 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
+ - field: connection
+ type: 0
+ unit: 连接数
+ protocol: jdbc
+ jdbc:
+ # 主机host: ipv4 ipv6 域名
+ host: ^_^host^_^
+ # 端口
+ port: ^_^port^_^
+ platform: sqlserver
+ username: ^_^username^_^
+ password: ^_^password^_^
+ database: ^_^database^_^
+ timeout: ^_^timeout^_^
+ # SQL查询方式: oneRow, multiRow, columns
+ queryType: oneRow
+ # sql
+ sql: SELECT cntr_value as connection FROM sys.dm_os_performance_counters WHERE object_name = 'SQLServer:General Statistics' AND counter_name = 'User Connections';
+ url: ^_^url^_^
\ No newline at end of file
diff --git a/manager/src/main/resources/define/param/mariadb.yml b/manager/src/main/resources/define/param/mariadb.yml
index 6c436d5..9443d1c 100644
--- a/manager/src/main/resources/define/param/mariadb.yml
+++ b/manager/src/main/resources/define/param/mariadb.yml
@@ -9,7 +9,7 @@ param:
type: number
range: '[0,65535]'
required: true
- defaultValue: 80
+ defaultValue: 3306
placeholder: '请输入端口'
- field: timeout
name: 查询超时时间
diff --git a/manager/src/main/resources/define/param/mysql.yml b/manager/src/main/resources/define/param/mysql.yml
index 791188c..3cd86f2 100644
--- a/manager/src/main/resources/define/param/mysql.yml
+++ b/manager/src/main/resources/define/param/mysql.yml
@@ -9,7 +9,7 @@ param:
type: number
range: '[0,65535]'
required: true
- defaultValue: 80
+ defaultValue: 3306
placeholder: '请输入端口'
- field: timeout
name: 查询超时时间
diff --git a/manager/src/main/resources/define/param/sqlserver.yml b/manager/src/main/resources/define/param/sqlserver.yml
new file mode 100644
index 0000000..d69707f
--- /dev/null
+++ b/manager/src/main/resources/define/param/sqlserver.yml
@@ -0,0 +1,36 @@
+app: sqlserver
+param:
+ - field: host
+ name: 主机Host
+ type: host
+ required: true
+ - field: port
+ name: 端口
+ type: number
+ range: '[0,65535]'
+ required: true
+ defaultValue: 1433
+ placeholder: '请输入端口'
+ - field: timeout
+ name: 查询超时时间
+ type: number
+ required: false
+ defaultValue: 3000
+ placeholder: '查询超时时间'
+ - field: database
+ name: 数据库名称
+ type: text
+ required: false
+ - field: username
+ name: 用户名
+ type: text
+ limit: 20
+ required: false
+ - field: password
+ name: 密码
+ type: password
+ required: false
+ - field: url
+ name: URL
+ type: text
+ required: false
\ No newline at end of file
diff --git a/warehouse/src/main/java/com/usthe/warehouse/store/TdEngineDataStorage.java b/warehouse/src/main/java/com/usthe/warehouse/store/TdEngineDataStorage.java
index db54e86..dc9ad56 100644
--- a/warehouse/src/main/java/com/usthe/warehouse/store/TdEngineDataStorage.java
+++ b/warehouse/src/main/java/com/usthe/warehouse/store/TdEngineDataStorage.java
@@ -23,6 +23,7 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.regex.Pattern;
/**
* influxdb存储采集数据
@@ -39,6 +40,7 @@ public class TdEngineDataStorage implements DisposableBean {
private HikariDataSource hikariDataSource;
private WarehouseWorkerPool workerPool;
private MetricsDataExporter dataExporter;
+ private static final Pattern SQL_SPECIAL_STRING_PATTERN = Pattern.compile("(\\\\)|(')");
private static final String INSERT_TABLE_DATA_SQL = "INSERT INTO %s USING %s TAGS (%s) VALUES %s";
private static final String CREATE_SUPER_TABLE_SQL = "CREATE STABLE IF NOT EXISTS %s %s TAGS (monitor BIGINT)";
private static final String NO_SUPER_TABLE_ERROR = "Table does not exist";
@@ -200,8 +202,9 @@ public class TdEngineDataStorage implements DisposableBean {
}
private String formatStringValue(String value){
- return value.replaceAll("(\\\\)|(')","\\\\$0");
+ return SQL_SPECIAL_STRING_PATTERN.matcher(value).replaceAll("\\\\$0");
}
+
@Override
public void destroy() throws Exception {
if (hikariDataSource != null) {