Compare commits
19 Commits
feature#mu
...
fix#search
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad1b1b48db | ||
|
|
9eb3b9842d | ||
|
|
790bcc6f16 | ||
|
|
4ce0698834 | ||
|
|
6c69da92f6 | ||
|
|
84c1f6b348 | ||
|
|
4ebf408349 | ||
|
|
5b33ac687e | ||
|
|
0f5a0c0cfc | ||
|
|
4404d2347b | ||
|
|
49660ff03f | ||
|
|
b2558d641d | ||
|
|
a6038d1feb | ||
|
|
eca634bd55 | ||
|
|
c99cfaf2b7 | ||
|
|
daa505ce20 | ||
|
|
c2e60bebdd | ||
|
|
8b97d0a2ca | ||
|
|
7c12eda30e |
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
custom: ['https://hertzbeat.com/docs/others/sponsor']
|
||||
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Used Version**
|
||||
the version , tag or branch used
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Community Support
|
||||
url: https://github.com/dromara/hertzbeat/discussions
|
||||
about: Please ask and answer questions here.
|
||||
- name: Security Bug Bounty
|
||||
url: https://github.com/dromara/hertzbeat/issues
|
||||
about: Please report security vulnerabilities here.
|
||||
10
.github/ISSUE_TEMPLATE/custom.md
vendored
Normal file
10
.github/ISSUE_TEMPLATE/custom.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Custom issue template
|
||||
about: Describe this issue template's purpose here.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
67
.github/workflows/codeql-analysis.yml
vendored
Normal file
67
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '21 13 * * 4'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'java' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
12
.github/workflows/issues-translator.yml
vendored
Normal file
12
.github/workflows/issues-translator.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
name: 'issues-translator'
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: tomsun28/issues-translate-action@v2.6
|
||||
24
.github/workflows/maven-build.yml
vendored
Normal file
24
.github/workflows/maven-build.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# This workflow will build a Java project with Maven
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
|
||||
|
||||
name: Java CI with Maven
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
- name: Build with Maven
|
||||
run: mvn -B package --file pom.xml
|
||||
62
CONTRIBUTING.md
Normal file
62
CONTRIBUTING.md
Normal file
@@ -0,0 +1,62 @@
|
||||
参与贡献
|
||||
=======================================
|
||||
|
||||
非常欢迎参与项目贡献,我们致力于维护一个互相帮助的快乐社区。
|
||||
|
||||
### 模块
|
||||
|
||||
- **[manager](https://github.com/dromara/hertzbeat/tree/master/manager)** 提供监控管理,系统管理基础服务
|
||||
> 提供对监控的管理,监控应用配置的管理,系统用户租户后台管理等。
|
||||
- **[collector](https://github.com/dromara/hertzbeat/tree/master/collector)** 提供监控数据采集服务
|
||||
> 使用通用协议远程采集获取对端指标数据。
|
||||
- **[scheduler](https://github.com/dromara/hertzbeat/tree/master/scheduler)** 提供监控任务调度服务
|
||||
> 采集任务管理,一次性任务和周期性任务的调度分发。
|
||||
- **[warehouse](https://github.com/dromara/hertzbeat/tree/master/warehouse)** 提供监控数据仓储服务
|
||||
> 采集指标结果数据管理,数据落盘,查询,计算统计。
|
||||
- **[alerter](https://github.com/dromara/hertzbeat/tree/master/alerter)** 提供告警服务
|
||||
> 告警计算触发,监控状态联动,告警配置,告警通知。
|
||||
- **[web-app](https://github.com/dromara/hertzbeat/tree/master/web-app)** 提供可视化控制台页面
|
||||
> 监控告警系统可视化控制台前端
|
||||
|
||||

|
||||
|
||||
## 如何贡献?
|
||||
|
||||
我们不仅仅接收代码的贡献提交,您也可以通过提交文档的更新或者BUG的报告来参与社区贡献。
|
||||
|
||||
如果是新的贡献者,请首先了解参考仓库提交Issues,提交Pull Requests如何工作。
|
||||
|
||||
https://github.com/dromara/hertzbeat/issues
|
||||
https://github.com/dromara/hertzbeat/pulls
|
||||
https://gitee.com/dromara/hertzbeat/issues
|
||||
https://gitee.com/dromara/hertzbeat/pulls
|
||||
|
||||
## 本地代码工程启动
|
||||
|
||||
此为前后端分离项目,本地代码启动需将后端[manager](manager)和前端[web-app](web-app)分别启动生效。
|
||||
|
||||
### 后端启动
|
||||
|
||||
1. 部署启动依赖服务`MYSQL`和`TDengine`数据库
|
||||
2. 需要`maven3+`和`java8+`环境
|
||||
3. 修改配置文件的依赖服务地址等信息-`manager/src/main/resources/application.yml`
|
||||
4. 启动`manager`服务 `manager/src/main/java/com/usthe/manager/Manager.java`
|
||||
|
||||
### 前端启动
|
||||
|
||||
1. 需要nodejs npm环境
|
||||
下载地址:https://nodejs.org/en/download
|
||||
2. 安装yarn `npm install -g yarn`
|
||||
3. 在前端工程目录web-app下执行 `yarn install`
|
||||
4. 全局安装angular-cli `npm install -g @angular/cli@12 --registry=https://registry.npm.taobao.org`
|
||||
5. 待本地后端启动后,在web-app目录下启动本地前端 `ng serve --open`
|
||||
6. 浏览器访问 localhost:4200 即可开始
|
||||
|
||||
## 加入交流
|
||||
|
||||
[Github Discussion](https://github.com/dromara/hertzbeat/discussions)
|
||||
加微信号 tan-cloud 拉您进微信交流群
|
||||
加QQ群号 718618151 进QQ交流群, 验证信息: tancloud
|
||||
微信公众号:tancloudtech
|
||||
[Dromara社区网站](https://dromara.org/)
|
||||
[HertzBeat用户网站](https://support.qq.com/products/379369)
|
||||
@@ -95,6 +95,14 @@
|
||||
|
||||
详细步骤参考 [通过安装包安装HertzBeat](https://hertzbeat.com/docs/start/package-deploy)
|
||||
|
||||
##### 本地代码启动
|
||||
1. 此为前后端分离项目,本地代码调试需要分别启动后端工程manager和前端工程web-app
|
||||
2. 后端:需要`maven3+`和`java8+`环境,修改YML配置信息并启动manager服务
|
||||
3. 前端:需要`nodejs npm angular-cli`环境,待本地后端启动后,在web-app目录下启动 `ng serve --open`
|
||||
4. 浏览器访问 localhost:4200 即可开始
|
||||
|
||||
详细步骤参考 [参与贡献之本地代码启动](CONTRIBUTING.md)
|
||||
|
||||
**HAVE FUN**
|
||||
|
||||
## 💬 社区交流
|
||||
|
||||
@@ -138,32 +138,24 @@ public class CalculateAlarm {
|
||||
}
|
||||
List<CollectRep.Field> fields = metricsData.getFieldsList();
|
||||
Map<String, Object> fieldValueMap = new HashMap<>(16);
|
||||
fieldValueMap.put("app", app);
|
||||
fieldValueMap.put("metrics", metrics);
|
||||
for (CollectRep.ValueRow valueRow : metricsData.getValuesList()) {
|
||||
if (!valueRow.getColumnsList().isEmpty()) {
|
||||
fieldValueMap.clear();
|
||||
String instance = valueRow.getInstance();
|
||||
if (!"".equals(instance)) {
|
||||
fieldValueMap.put("instance", instance);
|
||||
} else {
|
||||
fieldValueMap.remove("instance");
|
||||
}
|
||||
for (int index = 0; index < valueRow.getColumnsList().size(); index++) {
|
||||
String valueStr = valueRow.getColumns(index);
|
||||
CollectRep.Field field = fields.get(index);
|
||||
fieldValueMap.put("metric", field.getName());
|
||||
if (field.getType() == CommonConstants.TYPE_NUMBER) {
|
||||
Double doubleValue = CommonUtil.parseDoubleStr(valueStr);
|
||||
if (doubleValue != null) {
|
||||
fieldValueMap.put(field.getName(), doubleValue);
|
||||
} else {
|
||||
fieldValueMap.remove(field.getName());
|
||||
}
|
||||
} else {
|
||||
if (!"".equals(valueStr)) {
|
||||
fieldValueMap.put(field.getName(), valueStr);
|
||||
} else {
|
||||
fieldValueMap.remove(field.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,6 +179,9 @@ public class CalculateAlarm {
|
||||
}
|
||||
} else {
|
||||
int times = 1;
|
||||
fieldValueMap.put("app", app);
|
||||
fieldValueMap.put("metrics", metrics);
|
||||
fieldValueMap.put("metric", define.getField());
|
||||
Alert alert = Alert.builder()
|
||||
.monitorId(monitorId)
|
||||
.alertDefineId(define.getId())
|
||||
|
||||
@@ -91,6 +91,18 @@
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.27</version>
|
||||
</dependency>
|
||||
<!-- postgresql -->
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>42.3.3</version>
|
||||
</dependency>
|
||||
<!-- linux ssh -->
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-core</artifactId>
|
||||
<version>2.8.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -2,6 +2,7 @@ package com.usthe.collector.collect.common.cache;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 缓存key唯一标识符
|
||||
@@ -10,6 +11,7 @@ import lombok.Data;
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@ToString
|
||||
public class CacheIdentifier {
|
||||
|
||||
private String ip;
|
||||
|
||||
@@ -21,9 +21,9 @@ import java.util.concurrent.TimeUnit;
|
||||
public class CommonCache {
|
||||
|
||||
/**
|
||||
* 默认缓存时间 30minute
|
||||
* 默认缓存时间 800s
|
||||
*/
|
||||
private static final long DEFAULT_CACHE_TIMEOUT = 30 * 60 * 1000L;
|
||||
private static final long DEFAULT_CACHE_TIMEOUT = 800 * 1000L;
|
||||
|
||||
/**
|
||||
* 默认最大缓存数量
|
||||
@@ -121,15 +121,17 @@ public class CommonCache {
|
||||
timeoutMap.put(key, new Long[]{currentTime, DEFAULT_CACHE_TIMEOUT});
|
||||
} else if (cacheTime[0] + cacheTime[1] < currentTime) {
|
||||
// 过期了 discard 关闭这个cache的资源
|
||||
log.warn("[cache] clean the timeout cache, key {}", key);
|
||||
timeoutMap.remove(key);
|
||||
cacheMap.remove(key);
|
||||
if (value instanceof CacheCloseable) {
|
||||
log.warn("[cache] close the timeout cache, key {}", key);
|
||||
((CacheCloseable)value).close();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("clean timeout cache error: {}.", e.getMessage(), e);
|
||||
log.error("[cache] clean timeout cache error: {}.", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +157,15 @@ public class CommonCache {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增或更新cache
|
||||
* @param key 存储对象key
|
||||
* @param value 存储对象
|
||||
*/
|
||||
public void addCache(Object key, Object value) {
|
||||
addCache(key, value, DEFAULT_CACHE_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据缓存key获取缓存对象
|
||||
* @param key key
|
||||
@@ -164,15 +175,18 @@ public class CommonCache {
|
||||
public Optional<Object> getCache(Object key, boolean refreshCache) {
|
||||
Long[] cacheTime = timeoutMap.get(key);
|
||||
if (cacheTime == null || cacheTime.length != CACHE_TIME_LENGTH) {
|
||||
log.warn("[cache] not hit the cache, key {}.", key);
|
||||
return Optional.empty();
|
||||
}
|
||||
if (cacheTime[0] + cacheTime[1] < System.currentTimeMillis()) {
|
||||
log.warn("[cache] is timeout, remove it, key {}.", key);
|
||||
timeoutMap.remove(key);
|
||||
cacheMap.remove(key);
|
||||
return Optional.empty();
|
||||
}
|
||||
Object value = cacheMap.get(key);
|
||||
if (value == null) {
|
||||
log.error("[cache] value is null, remove it, key {}.", key);
|
||||
cacheMap.remove(key);
|
||||
timeoutMap.remove(key);
|
||||
} else if (refreshCache) {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.usthe.collector.collect.common.ssh;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.sshd.client.SshClient;
|
||||
|
||||
/**
|
||||
* ssh公共client
|
||||
* @author tom
|
||||
* @date 2022/3/11 15:58
|
||||
*/
|
||||
@Slf4j
|
||||
public class CommonSshClient {
|
||||
|
||||
private static SshClient sshClient;
|
||||
|
||||
|
||||
static {
|
||||
sshClient = SshClient.setUpDefaultClient();
|
||||
sshClient.start();
|
||||
}
|
||||
|
||||
public static SshClient getSshClient() {
|
||||
return sshClient;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import com.usthe.common.entity.job.protocol.JdbcProtocol;
|
||||
import com.usthe.common.entity.message.CollectRep;
|
||||
import com.usthe.common.util.CommonConstants;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.postgresql.util.PSQLException;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
@@ -72,7 +73,16 @@ public class JdbcCommonCollect extends AbstractCollect {
|
||||
} catch (CommunicationsException communicationsException) {
|
||||
log.warn("Jdbc sql error: {}, code: {}.", communicationsException.getMessage(), communicationsException.getErrorCode());
|
||||
builder.setCode(CollectRep.Code.UN_REACHABLE);
|
||||
builder.setMsg("Query Error: " + communicationsException.getMessage() + " Code: " + communicationsException.getErrorCode());
|
||||
builder.setMsg("Error: " + communicationsException.getMessage() + " Code: " + communicationsException.getErrorCode());
|
||||
} catch (PSQLException psqlException) {
|
||||
// for PostgreSQL 08001
|
||||
if (CollectorConstants.POSTGRESQL_UN_REACHABLE_CODE.equals(psqlException.getSQLState())) {
|
||||
// 对端链接失败 不可达
|
||||
builder.setCode(CollectRep.Code.UN_REACHABLE);
|
||||
} else {
|
||||
builder.setCode(CollectRep.Code.FAIL);
|
||||
}
|
||||
builder.setMsg("Error: " + psqlException.getMessage() + " Code: " + psqlException.getSQLState());
|
||||
} catch (SQLException sqlException) {
|
||||
log.warn("Jdbc sql error: {}, code: {}.", sqlException.getMessage(), sqlException.getErrorCode());
|
||||
builder.setCode(CollectRep.Code.FAIL);
|
||||
@@ -124,7 +134,7 @@ public class JdbcCommonCollect extends AbstractCollect {
|
||||
// 设置查询最大行数1000行
|
||||
statement.setMaxRows(1000);
|
||||
JdbcConnect jdbcConnect = new JdbcConnect(connection);
|
||||
CommonCache.getInstance().addCache(identifier, jdbcConnect, 10000L);
|
||||
CommonCache.getInstance().addCache(identifier, jdbcConnect);
|
||||
return statement;
|
||||
}
|
||||
|
||||
@@ -253,6 +263,10 @@ public class JdbcCommonCollect extends AbstractCollect {
|
||||
+ "/" + (jdbcProtocol.getDatabase() == null ? "" : jdbcProtocol.getDatabase())
|
||||
+ "?useUnicode=true&characterEncoding=utf-8&useSSL=false";
|
||||
break;
|
||||
case "postgresql":
|
||||
url = "jdbc:postgresql://" + jdbcProtocol.getHost() + ":" + jdbcProtocol.getPort()
|
||||
+ "/" + (jdbcProtocol.getDatabase() == null ? "" : jdbcProtocol.getDatabase());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Not support database platform: " + jdbcProtocol.getPlatform());
|
||||
|
||||
|
||||
@@ -406,7 +406,11 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
}
|
||||
}
|
||||
}
|
||||
// headers
|
||||
// The default request header can be overridden if customized
|
||||
// keep-alive
|
||||
requestBuilder.addHeader(HttpHeaders.CONNECTION, "keep-alive");
|
||||
requestBuilder.addHeader(HttpHeaders.USER_AGENT,"Mozilla/5.0 (Windows NT 6.1; WOW64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36");
|
||||
// headers The custom request header is overwritten here
|
||||
Map<String, String> headers = httpProtocol.getHeaders();
|
||||
if (headers != null && !headers.isEmpty()) {
|
||||
for (Map.Entry<String, String> header : headers.entrySet()) {
|
||||
@@ -415,8 +419,6 @@ public class HttpCollectImpl extends AbstractCollect {
|
||||
}
|
||||
}
|
||||
}
|
||||
// keep-alive
|
||||
requestBuilder.addHeader(HttpHeaders.CONNECTION, "keep-alive");
|
||||
// add accept
|
||||
if (DispatchConstants.PARSE_DEFAULT.equals(httpProtocol.getParseType())
|
||||
|| DispatchConstants.PARSE_JSON_PATH.equals(httpProtocol.getParseType())) {
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
package com.usthe.collector.collect.ssh;
|
||||
|
||||
import com.usthe.collector.collect.AbstractCollect;
|
||||
import com.usthe.collector.collect.common.cache.CacheIdentifier;
|
||||
import com.usthe.collector.collect.common.cache.CommonCache;
|
||||
import com.usthe.collector.collect.common.ssh.CommonSshClient;
|
||||
import com.usthe.collector.util.CollectorConstants;
|
||||
import com.usthe.common.entity.job.Metrics;
|
||||
import com.usthe.common.entity.job.protocol.SshProtocol;
|
||||
import com.usthe.common.entity.message.CollectRep;
|
||||
import com.usthe.common.util.CommonConstants;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.sshd.client.SshClient;
|
||||
import org.apache.sshd.client.channel.ClientChannel;
|
||||
import org.apache.sshd.client.channel.ClientChannelEvent;
|
||||
import org.apache.sshd.client.session.ClientSession;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* ssh协议采集实现
|
||||
* @author tom
|
||||
* @date 2022/03/11 15:10
|
||||
*/
|
||||
@Slf4j
|
||||
public class SshCollectImpl extends AbstractCollect {
|
||||
|
||||
private static final String PARSE_TYPE_ONE_ROW = "oneRow";
|
||||
private static final String PARSE_TYPE_MULTI_ROW = "multiRow";
|
||||
|
||||
private SshCollectImpl(){}
|
||||
|
||||
public static SshCollectImpl getInstance() {
|
||||
return SshCollectImpl.Singleton.INSTANCE;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void collect(CollectRep.MetricsData.Builder builder, long appId, String app, Metrics metrics) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
// 校验参数
|
||||
try {
|
||||
validateParams(metrics);
|
||||
} catch (Exception e) {
|
||||
builder.setCode(CollectRep.Code.FAIL);
|
||||
builder.setMsg(e.getMessage());
|
||||
return;
|
||||
}
|
||||
SshProtocol sshProtocol = metrics.getSsh();
|
||||
// 超时时间默认300毫秒
|
||||
int timeout = 3000;
|
||||
try {
|
||||
timeout = Integer.parseInt(sshProtocol.getTimeout());
|
||||
} catch (Exception e) {
|
||||
log.warn(e.getMessage());
|
||||
}
|
||||
try {
|
||||
ClientSession clientSession = getConnectSession(sshProtocol, timeout);
|
||||
ClientChannel channel = clientSession.createExecChannel(sshProtocol.getScript());
|
||||
ByteArrayOutputStream response = new ByteArrayOutputStream();
|
||||
channel.setOut(response);
|
||||
if (!channel.open().verify(timeout).isOpened()) {
|
||||
throw new Exception("open failed");
|
||||
}
|
||||
List<ClientChannelEvent> list = new ArrayList<>();
|
||||
list.add(ClientChannelEvent.CLOSED);
|
||||
channel.waitFor(list, timeout);
|
||||
Long responseTime = System.currentTimeMillis() - startTime;
|
||||
channel.close();
|
||||
String result = response.toString();
|
||||
if (!StringUtils.hasText(result)) {
|
||||
builder.setCode(CollectRep.Code.FAIL);
|
||||
builder.setMsg("采集数据失败");
|
||||
}
|
||||
switch (sshProtocol.getParseType()) {
|
||||
case PARSE_TYPE_ONE_ROW:
|
||||
parseResponseDataByOne(result, metrics.getAliasFields(), builder, responseTime);
|
||||
break;
|
||||
default: parseResponseDataByMulti(result, metrics.getAliasFields(), builder, responseTime);
|
||||
break;
|
||||
}
|
||||
} catch (ConnectException connectException) {
|
||||
log.debug(connectException.getMessage());
|
||||
builder.setCode(CollectRep.Code.UN_CONNECTABLE);
|
||||
builder.setMsg("对端拒绝连接:服务未启动端口监听或防火墙");
|
||||
} catch (IOException ioException) {
|
||||
log.debug(ioException.getMessage());
|
||||
builder.setCode(CollectRep.Code.UN_CONNECTABLE);
|
||||
builder.setMsg("对端连接失败 " + ioException.getMessage());
|
||||
} catch (Exception exception) {
|
||||
log.debug(exception.getMessage());
|
||||
builder.setCode(CollectRep.Code.FAIL);
|
||||
builder.setMsg(exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseResponseDataByOne(String result, List<String> aliasFields, CollectRep.MetricsData.Builder builder, Long responseTime) {
|
||||
String[] lines = result.split("\n");
|
||||
if (lines.length + 1 < aliasFields.size()) {
|
||||
log.error("ssh response data not enough: {}", result);
|
||||
}
|
||||
CollectRep.ValueRow.Builder valueRowBuilder = CollectRep.ValueRow.newBuilder();
|
||||
int aliasIndex = 0;
|
||||
int lineIndex = 0;
|
||||
while (aliasIndex < aliasFields.size()) {
|
||||
if (CollectorConstants.RESPONSE_TIME.equalsIgnoreCase(aliasFields.get(aliasIndex))) {
|
||||
valueRowBuilder.addColumns(responseTime.toString());
|
||||
} else {
|
||||
valueRowBuilder.addColumns(lines[lineIndex].trim());
|
||||
lineIndex++;
|
||||
}
|
||||
aliasIndex++;
|
||||
}
|
||||
builder.addValues(valueRowBuilder.build());
|
||||
}
|
||||
|
||||
private void parseResponseDataByMulti(String result, List<String> aliasFields,
|
||||
CollectRep.MetricsData.Builder builder, Long responseTime) {
|
||||
String[] lines = result.split("\n");
|
||||
if (lines.length <= 1) {
|
||||
log.error("ssh response data only has header: {}", result);
|
||||
}
|
||||
String[] fields = lines[0].split(" ");
|
||||
Map<String, Integer> fieldMapping = new HashMap<>(fields.length);
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
fieldMapping.put(fields[i].trim().toLowerCase(), i);
|
||||
}
|
||||
for (int i = 1; i < lines.length; i++) {
|
||||
String[] values = lines[i].split(" ");
|
||||
CollectRep.ValueRow.Builder valueRowBuilder = CollectRep.ValueRow.newBuilder();
|
||||
for (String alias : aliasFields) {
|
||||
if (CollectorConstants.RESPONSE_TIME.equalsIgnoreCase(alias)) {
|
||||
valueRowBuilder.addColumns(responseTime.toString());
|
||||
} else {
|
||||
Integer index = fieldMapping.get(alias.toLowerCase());
|
||||
if (index != null && index < values.length) {
|
||||
valueRowBuilder.addColumns(values[index]);
|
||||
} else {
|
||||
valueRowBuilder.addColumns(CommonConstants.NULL_VALUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
builder.addValues(valueRowBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
private ClientSession getConnectSession(SshProtocol sshProtocol, int timeout) throws IOException {
|
||||
CacheIdentifier identifier = CacheIdentifier.builder()
|
||||
.ip(sshProtocol.getHost()).port(sshProtocol.getPort())
|
||||
.username(sshProtocol.getUsername()).password(sshProtocol.getPassword())
|
||||
.build();
|
||||
Optional<Object> cacheOption = CommonCache.getInstance().getCache(identifier, true);
|
||||
ClientSession clientSession = null;
|
||||
if (cacheOption.isPresent()) {
|
||||
clientSession = (ClientSession) cacheOption.get();
|
||||
try {
|
||||
if (clientSession.isClosed() || clientSession.isClosing()) {
|
||||
clientSession = null;
|
||||
CommonCache.getInstance().removeCache(identifier);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn(e.getMessage());
|
||||
clientSession = null;
|
||||
CommonCache.getInstance().removeCache(identifier);
|
||||
}
|
||||
}
|
||||
if (clientSession != null) {
|
||||
return clientSession;
|
||||
}
|
||||
SshClient sshClient = CommonSshClient.getSshClient();
|
||||
clientSession = sshClient.connect(sshProtocol.getUsername(), sshProtocol.getHost(), Integer.parseInt(sshProtocol.getPort()))
|
||||
.verify(timeout, TimeUnit.MILLISECONDS).getSession();
|
||||
if (StringUtils.hasText(sshProtocol.getPassword())) {
|
||||
clientSession.addPasswordIdentity(sshProtocol.getPassword());
|
||||
}
|
||||
// 进行认证
|
||||
if (!clientSession.auth().verify(timeout, TimeUnit.MILLISECONDS).isSuccess()) {
|
||||
throw new IllegalArgumentException("认证失败");
|
||||
}
|
||||
CommonCache.getInstance().addCache(identifier, clientSession);
|
||||
return clientSession;
|
||||
}
|
||||
|
||||
private void validateParams(Metrics metrics) throws Exception {
|
||||
if (metrics == null || metrics.getSsh() == null) {
|
||||
throw new Exception("Ssh collect must has ssh params");
|
||||
}
|
||||
}
|
||||
|
||||
private static class Singleton {
|
||||
private static final SshCollectImpl INSTANCE = new SshCollectImpl();
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
|
||||
/**
|
||||
* icmp协议采集实现 - ping
|
||||
* telnet协议采集实现
|
||||
* @author tom
|
||||
* @date 2021/12/4 12:32
|
||||
*/
|
||||
|
||||
@@ -24,6 +24,10 @@ public interface DispatchConstants {
|
||||
* 协议 jdbc
|
||||
*/
|
||||
String PROTOCOL_JDBC = "jdbc";
|
||||
/**
|
||||
* 协议 ssh
|
||||
*/
|
||||
String PROTOCOL_SSH = "ssh";
|
||||
// 协议类型相关 - end //
|
||||
|
||||
// http协议相关 - start 需尽可能先复用 HttpHeaders //
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.usthe.collector.collect.AbstractCollect;
|
||||
import com.usthe.collector.collect.database.JdbcCommonCollect;
|
||||
import com.usthe.collector.collect.http.HttpCollectImpl;
|
||||
import com.usthe.collector.collect.icmp.IcmpCollectImpl;
|
||||
import com.usthe.collector.collect.ssh.SshCollectImpl;
|
||||
import com.usthe.collector.collect.telnet.TelnetCollectImpl;
|
||||
import com.usthe.collector.dispatch.timer.Timeout;
|
||||
import com.usthe.collector.dispatch.timer.WheelTimerTask;
|
||||
@@ -111,6 +112,9 @@ public class MetricsCollect implements Runnable, Comparable<MetricsCollect> {
|
||||
case DispatchConstants.PROTOCOL_JDBC:
|
||||
abstractCollect = JdbcCommonCollect.getInstance();
|
||||
break;
|
||||
case DispatchConstants.PROTOCOL_SSH:
|
||||
abstractCollect = SshCollectImpl.getInstance();
|
||||
break;
|
||||
// todo
|
||||
default: break;
|
||||
}
|
||||
|
||||
@@ -14,4 +14,9 @@ public interface CollectorConstants {
|
||||
String ERROR_MSG = "errorMsg";
|
||||
|
||||
String URL = "url";
|
||||
|
||||
/**
|
||||
* POSTGRESQL状态码 不可达
|
||||
*/
|
||||
String POSTGRESQL_UN_REACHABLE_CODE = "08001";
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.usthe.common.entity.job;
|
||||
import com.usthe.common.entity.job.protocol.HttpProtocol;
|
||||
import com.usthe.common.entity.job.protocol.IcmpProtocol;
|
||||
import com.usthe.common.entity.job.protocol.JdbcProtocol;
|
||||
import com.usthe.common.entity.job.protocol.SshProtocol;
|
||||
import com.usthe.common.entity.job.protocol.TcpUdpProtocol;
|
||||
import com.usthe.common.entity.job.protocol.TelnetProtocol;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -73,6 +74,10 @@ public class Metrics {
|
||||
* 使用公共的jdbc规范实现的数据库配置信息
|
||||
*/
|
||||
private JdbcProtocol jdbc;
|
||||
/**
|
||||
* 使用公共的ssh协议的监控配置信息
|
||||
*/
|
||||
private SshProtocol ssh;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.usthe.common.entity.job.protocol;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* ssh 协议参数配置
|
||||
* @author tom
|
||||
* @date 2022/3/11 15:20
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class SshProtocol {
|
||||
|
||||
/**
|
||||
* 对端主机ip或域名
|
||||
*/
|
||||
private String host;
|
||||
|
||||
/**
|
||||
* 对端主机端口
|
||||
*/
|
||||
private String port;
|
||||
|
||||
/**
|
||||
* 超时时间
|
||||
*/
|
||||
private String timeout = "3000";
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码(可选)
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 公钥(可选)
|
||||
*/
|
||||
private String publicKey;
|
||||
|
||||
/**
|
||||
* SSH执行脚本
|
||||
*/
|
||||
private String script;
|
||||
|
||||
/**
|
||||
* 响应数据解析方式:oneRow, multiRow
|
||||
*/
|
||||
private String parseType;
|
||||
}
|
||||
42
hertzbeat-for-dockercompose/Readme.md
Normal file
42
hertzbeat-for-dockercompose/Readme.md
Normal file
@@ -0,0 +1,42 @@
|
||||
## docker-compose部署方案
|
||||
|
||||
- 如果您不想部署而是直接使用,我们提供SAAS监控云-[TanCloud探云](https://console.tancloud.cn),即刻 **[登录注册](https://console.tancloud.cn)** 免费使用。
|
||||
- 如果你想自己本地快速部署的话,可以参考下面进行操作。
|
||||
|
||||
###
|
||||
|
||||
##### 安装Docker&Docker-compose
|
||||
|
||||
1. docker &docker-compos 安装自行百度,如果这也不会,那这个部署方式可能不适合您。
|
||||
|
||||
##### 下载并解压部署包-hertzbeat-for-dockercompose
|
||||
|
||||
1.进入 hertzbeat-for-dockercompose目录
|
||||
|
||||
`docker-compose up -d`
|
||||
|
||||
2.创建tdengine数据库
|
||||
|
||||
`$ docker exec -it tdengine /bin/bash
|
||||
root@tdengine-server:~/TDengine-server-2.4.0.4#`
|
||||
|
||||
创建名称为hertzbeat的数据库 进入容器后,执行 taos shell 客户端程序。
|
||||
|
||||
`root@tdengine-server:~/TDengine-server-2.4.0.4# taos
|
||||
Welcome to the TDengine shell from Linux, Client Version:2.4.0.4
|
||||
Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.
|
||||
taos>`
|
||||
|
||||
执行创建数据库命令
|
||||
|
||||
`taos> show databases;`
|
||||
|
||||
`taos> CREATE DATABASE hertzbeat KEEP 90 DAYS 10 BLOCKS 6 UPDATE 1;`
|
||||
|
||||
##### 重启应用
|
||||
|
||||
`docker-compose restart hertzbeat`
|
||||
|
||||
|
||||
---
|
||||
怎么样是不是很简单,只要几分钟就可以部署完成,赶紧试试吧!
|
||||
70
hertzbeat-for-dockercompose/conf/application.yml
Normal file
70
hertzbeat-for-dockercompose/conf/application.yml
Normal file
@@ -0,0 +1,70 @@
|
||||
server:
|
||||
port: 1157
|
||||
spring:
|
||||
application:
|
||||
name: ${HOSTNAME:@hertzbeat@}${PID}
|
||||
profiles:
|
||||
active: prod
|
||||
mvc:
|
||||
static-path-pattern: /console/**
|
||||
resources:
|
||||
static-locations:
|
||||
- classpath:/dist/
|
||||
- classpath:../dist/
|
||||
jackson:
|
||||
default-property-inclusion: NON_EMPTY
|
||||
|
||||
sureness:
|
||||
auths:
|
||||
- digest
|
||||
- basic
|
||||
- jwt
|
||||
|
||||
---
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: prod
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
username: root
|
||||
password: 1234
|
||||
url: jdbc:mysql://mysql:3306/hertzbeat?useUnicode=true&characterEncoding=utf-8&useSSL=false
|
||||
platform: mysql
|
||||
hikari:
|
||||
max-lifetime: 120000
|
||||
jpa:
|
||||
database: mysql
|
||||
|
||||
mail:
|
||||
# 请注意邮件服务器地址:qq邮箱为 smtp.qq.com qq企业邮箱为 smtp.exmail.qq.com
|
||||
host: smtp.qq.com
|
||||
username: 936751812@qq.com
|
||||
# 请注意此非邮箱账户密码 此需填写邮箱授权码
|
||||
password: xxqzvuqbnqvbbdac
|
||||
port: 465
|
||||
default-encoding: UTF-8
|
||||
properties:
|
||||
mail:
|
||||
smtp:
|
||||
socketFactoryClass: javax.net.ssl.SSLSocketFactory
|
||||
ssl:
|
||||
enable: true
|
||||
|
||||
thymeleaf:
|
||||
prefix: classpath:/templates/
|
||||
check-template-location: true
|
||||
cache: true
|
||||
suffix: .html
|
||||
#encoding: UTF-8
|
||||
#content-type: text/html
|
||||
mode: LEGACYHTML5
|
||||
|
||||
warehouse:
|
||||
store:
|
||||
td-engine:
|
||||
enabled: true
|
||||
driver-class-name: com.taosdata.jdbc.rs.RestfulDriver
|
||||
url: jdbc:TAOS-RS://tdengine:6041/hertzbeat
|
||||
username: root
|
||||
password: taosdata
|
||||
167
hertzbeat-for-dockercompose/conf/sql/schema.sql
Normal file
167
hertzbeat-for-dockercompose/conf/sql/schema.sql
Normal file
@@ -0,0 +1,167 @@
|
||||
set names utf8mb4;
|
||||
drop database if exists hertzbeat;
|
||||
create database hertzbeat;
|
||||
use hertzbeat;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for monitor
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS monitor ;
|
||||
CREATE TABLE monitor
|
||||
(
|
||||
id bigint not null auto_increment comment '监控ID',
|
||||
job_id bigint not null comment '监控对应下发的任务ID',
|
||||
name varchar(100) not null comment '监控的名称',
|
||||
app varchar(100) not null comment '监控的类型:linux,mysql,jvm...',
|
||||
host varchar(100) not null comment '监控的对端host:ipv4,ipv6,域名',
|
||||
intervals int not null default 600 comment '监控的采集间隔时间,单位秒',
|
||||
status tinyint not null default 1 comment '监控状态 0:未监控,1:可用,2:不可用,3:不可达',
|
||||
description varchar(255) comment '描述备注信息',
|
||||
creator varchar(100) comment '创建者',
|
||||
modifier varchar(100) comment '最新修改者',
|
||||
gmt_create timestamp default current_timestamp comment 'create time',
|
||||
gmt_update datetime default current_timestamp on update current_timestamp comment 'update time',
|
||||
primary key (id),
|
||||
index query_index (app, host, name)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for param
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS param ;
|
||||
CREATE TABLE param
|
||||
(
|
||||
id bigint not null auto_increment comment '参数ID',
|
||||
monitor_id bigint not null comment '监控ID',
|
||||
field varchar(100) not null comment '参数标识符',
|
||||
value varchar(255) comment '参数值,最大字符长度255',
|
||||
type tinyint not null default 0 comment '参数类型 0:数字 1:字符串 2:加密串',
|
||||
gmt_create timestamp default current_timestamp comment 'create time',
|
||||
gmt_update datetime default current_timestamp on update current_timestamp comment 'update time',
|
||||
primary key (id),
|
||||
index monitor_id (monitor_id),
|
||||
unique key unique_param (monitor_id, field)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for param
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS param_define ;
|
||||
CREATE TABLE param_define
|
||||
(
|
||||
id bigint not null auto_increment comment '参数ID',
|
||||
app varchar(100) not null comment '监控的类型:linux,mysql,jvm...',
|
||||
name varchar(100) not null comment '参数字段对外显示名称',
|
||||
field varchar(100) not null comment '参数字段标识符',
|
||||
type varchar(20) not null default 'text' comment '字段类型,样式(大部分映射input标签type属性)',
|
||||
required boolean not null default false comment '是否是必输项 true-必填 false-可选',
|
||||
param_range varchar(100) not null comment '当type为number时,用range表示范围 eg: 0-233',
|
||||
param_limit tinyint unsigned not null comment '当type为text时,用limit表示字符串限制大小.最大255',
|
||||
param_option varchar(255) not null comment '当type为radio单选框,checkbox复选框时,option表示可选项值列表',
|
||||
creator varchar(100) comment '创建者',
|
||||
modifier varchar(100) comment '最新修改者',
|
||||
gmt_create timestamp default current_timestamp comment 'create time',
|
||||
gmt_update datetime default current_timestamp on update current_timestamp comment 'update time',
|
||||
primary key (id),
|
||||
unique key unique_param_define (app, field)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for alert_define
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS alert_define ;
|
||||
CREATE TABLE alert_define
|
||||
(
|
||||
id bigint not null auto_increment comment '告警定义ID',
|
||||
app varchar(100) not null comment '配置告警的监控类型:linux,mysql,jvm...',
|
||||
metric varchar(100) not null comment '配置告警的指标集合:cpu,memory,info...',
|
||||
field varchar(100) not null comment '配置告警的指标:usage,cores...',
|
||||
preset boolean not null default false comment '是否是全局默认告警,是则所有此类型监控默认关联此告警',
|
||||
expr varchar(255) not null comment '告警触发条件表达式',
|
||||
priority tinyint not null default 0 comment '告警级别 0:高-emergency-紧急告警-红色 1:中-critical-严重告警-橙色 2:低-warning-警告告警-黄色',
|
||||
times int not null default 1 comment '触发次数,即达到触发阈值次数要求后才算触发告警',
|
||||
enable boolean not null default true comment '告警阈值开关',
|
||||
template varchar(255) not null comment '告警通知模板内容',
|
||||
creator varchar(100) comment '创建者',
|
||||
modifier varchar(100) comment '最新修改者',
|
||||
gmt_create timestamp default current_timestamp comment 'create time',
|
||||
gmt_update datetime default current_timestamp on update current_timestamp comment 'update time',
|
||||
primary key (id)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for alert_define_monitor_bind
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS alert_define_monitor_bind ;
|
||||
CREATE TABLE alert_define_monitor_bind
|
||||
(
|
||||
id bigint not null auto_increment comment '告警定义与监控关联ID',
|
||||
alert_define_id bigint not null comment '告警定义ID',
|
||||
monitor_id bigint not null comment '监控ID',
|
||||
gmt_create timestamp default current_timestamp comment 'create time',
|
||||
gmt_update datetime default current_timestamp on update current_timestamp comment 'update time',
|
||||
primary key (id),
|
||||
index index_bind (alert_define_id, monitor_id)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for alert
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS alert ;
|
||||
CREATE TABLE alert
|
||||
(
|
||||
id bigint not null auto_increment comment '告警ID',
|
||||
target varchar(255) not null comment '告警目标对象: 监控可用性-available 指标-app.metrics.field',
|
||||
monitor_id bigint not null comment '告警对象关联的监控ID',
|
||||
monitor_name varchar(100) comment '告警对象关联的监控名称',
|
||||
alert_define_id bigint comment '告警关联的告警定义ID',
|
||||
priority tinyint not null default 0 comment '告警级别 0:高-emergency-紧急告警-红色 1:中-critical-严重告警-橙色 2:低-warning-警告告警-黄色',
|
||||
content varchar(255) not null comment '告警通知实际内容',
|
||||
status tinyint not null default 0 comment '告警状态: 0-正常告警(待处理) 1-阈值触发但未达到告警次数 2-恢复告警 3-已处理',
|
||||
times int not null comment '触发次数,即达到告警定义的触发阈值次数要求后才会发告警',
|
||||
gmt_create timestamp default current_timestamp comment 'create time',
|
||||
primary key (id)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for notice_rule
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS notice_rule ;
|
||||
CREATE TABLE notice_rule
|
||||
(
|
||||
id bigint not null auto_increment comment '通知策略主键索引ID',
|
||||
name varchar(100) not null comment '策略名称',
|
||||
receiver_id bigint not null comment '消息接收人ID',
|
||||
receiver_name varchar(100) not null comment '消息接收人标识',
|
||||
enable boolean not null default true comment '是否启用此策略',
|
||||
filter_all boolean not null default true comment '是否转发所有',
|
||||
creator varchar(100) comment '创建者',
|
||||
modifier varchar(100) comment '最新修改者',
|
||||
gmt_create timestamp default current_timestamp comment 'create time',
|
||||
gmt_update datetime default current_timestamp on update current_timestamp comment 'update time',
|
||||
primary key (id)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for notice_receiver
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS notice_receiver ;
|
||||
CREATE TABLE notice_receiver
|
||||
(
|
||||
id bigint not null auto_increment comment '消息接收人ID',
|
||||
name varchar(100) not null comment '消息接收人姓名',
|
||||
type tinyint not null comment '通知信息方式: 0-手机短信 1-邮箱 2-webhook 3-微信公众号 4-企业微信机器人 5-钉钉机器人',
|
||||
phone varchar(100) comment '手机号, 通知方式为手机短信时有效',
|
||||
email varchar(100) comment '邮箱账号, 通知方式为邮箱时有效',
|
||||
hook_url varchar(255) comment 'URL地址, 通知方式为webhook有效',
|
||||
wechat_id varchar(255) comment 'openId, 通知方式为微信公众号或企业微信机器人有效',
|
||||
access_token varchar(255) comment '访问token, 通知方式为钉钉机器人有效',
|
||||
creator varchar(100) comment '创建者',
|
||||
modifier varchar(100) comment '最新修改者',
|
||||
gmt_create timestamp default current_timestamp comment 'create time',
|
||||
gmt_update datetime default current_timestamp on update current_timestamp comment 'update time',
|
||||
primary key (id)
|
||||
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
COMMIT;
|
||||
49
hertzbeat-for-dockercompose/conf/sureness.yml
Normal file
49
hertzbeat-for-dockercompose/conf/sureness.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
## -- sureness.yml文本数据源 -- ##
|
||||
|
||||
# 加载到匹配字典的资源,也就是需要被保护的,设置了所支持角色访问的资源
|
||||
# 没有配置的资源也默认被认证保护,但不鉴权
|
||||
# eg: /api/v1/source1===get===[role2] 表示 /api/v2/host===post 这条资源支持 role2 这一种角色访问
|
||||
# eg: /api/v1/source2===get===[] 表示 /api/v1/source2===get 这条资源不支持任何角色访问
|
||||
resourceRole:
|
||||
- /account/auth/refresh===post===[role1,role2,role3,role4]
|
||||
|
||||
# 需要被过滤保护的资源,不认证鉴权直接访问
|
||||
# /api/v1/source3===get 表示 /api/v1/source3===get 可以被任何人访问 无需登录认证鉴权
|
||||
excludedResource:
|
||||
- /account/auth/**===*
|
||||
- /===get
|
||||
- /i18n/**===get
|
||||
# web ui 静态资源
|
||||
- /console/**===get
|
||||
- /**/*.html===get
|
||||
- /**/*.js===get
|
||||
- /**/*.css===get
|
||||
- /**/*.ico===get
|
||||
- /**/*.ttf===get
|
||||
- /**/*.png===get
|
||||
- /**/*.gif===get
|
||||
- /**/*.png===*
|
||||
# swagger ui 资源
|
||||
- /swagger-resources/**===get
|
||||
- /v2/api-docs===get
|
||||
- /v3/api-docs===get
|
||||
|
||||
# 用户账户信息
|
||||
# 下面有 admin tom lili 三个账户
|
||||
# eg: admin 拥有[role1,role2]角色,密码为admin
|
||||
# eg: tom 拥有[role1,role2,role3],密码为tom@123
|
||||
# eg: lili 拥有[role1,role2],明文密码为lili, 加盐密码为1A676730B0C7F54654B0E09184448289
|
||||
account:
|
||||
- appId: admin
|
||||
credential: admin@123.
|
||||
role: [role1,role2]
|
||||
- appId: tom
|
||||
credential: tom@123.
|
||||
role: [role1,role2,role3]
|
||||
- appId: lili
|
||||
# 注意 Digest认证不支持加盐加密的密码账户
|
||||
# 加盐加密的密码,通过 MD5(password+salt)计算
|
||||
# 此账户的原始密码为 lili
|
||||
credential: 1A676730B0C7F54654B0E09194448289
|
||||
salt: 123
|
||||
role: [role1,role2]
|
||||
2
hertzbeat-for-dockercompose/dbdata/mysqldata/.gitignore
vendored
Normal file
2
hertzbeat-for-dockercompose/dbdata/mysqldata/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
2
hertzbeat-for-dockercompose/dbdata/taosdata/.gitignore
vendored
Normal file
2
hertzbeat-for-dockercompose/dbdata/taosdata/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
50
hertzbeat-for-dockercompose/docker-compose.yaml
Normal file
50
hertzbeat-for-dockercompose/docker-compose.yaml
Normal file
@@ -0,0 +1,50 @@
|
||||
version: "3.7"
|
||||
|
||||
networks:
|
||||
heartzbeat:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: "mysql:5.7"
|
||||
container_name: mysql
|
||||
hostname: mysql
|
||||
restart: always
|
||||
ports:
|
||||
- "3306:3306"
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
MYSQL_ROOT_PASSWORD: 1234
|
||||
volumes:
|
||||
- ./dbdata/mysqldata:/var/lib/mysql/
|
||||
- ./conf/sql:/docker-entrypoint-initdb.d/
|
||||
networks:
|
||||
- heartzbeat
|
||||
|
||||
TDengine:
|
||||
image: "tdengine/tdengine:latest"
|
||||
container_name: tdengine
|
||||
hostname: tdengine
|
||||
restart: always
|
||||
ports:
|
||||
- "6030-6049:6030-6049"
|
||||
- "6030-6049:6030-6049/udp"
|
||||
volumes:
|
||||
- ./dbdata/taosdata:/var/lib/taos/
|
||||
networks:
|
||||
- heartzbeat
|
||||
|
||||
hertzbeat:
|
||||
image: "tancloud/hertzbeat:1.0-beta.5"
|
||||
container_name: hertzbeat
|
||||
hostname: hertzbeat
|
||||
restart: always
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
volumes:
|
||||
- ./conf/application.yml:/opt/hertzbeat/config/application.yml
|
||||
- ./conf/sureness.yml:/opt/hertzbeat/config/sureness.yml
|
||||
ports:
|
||||
- "1157:1157"
|
||||
networks:
|
||||
- heartzbeat
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: HertzBeat赫兹节拍 v1.0.beta.4 发布,易用友好的高性能监控告警系统
|
||||
title: HertzBeat赫兹节拍 v1.0.beta.4 发布,易用友好的监控告警系统
|
||||
author: tom
|
||||
author_title: tom
|
||||
author_url: https://github.com/tomsun28
|
||||
|
||||
71
home/blog/2022-03-10-hertzbeat-v1.0-beta.5.md
Normal file
71
home/blog/2022-03-10-hertzbeat-v1.0-beta.5.md
Normal file
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: HertzBeat赫兹节拍 v1.0.beta.5 发布,易用友好的监控告警系统
|
||||
author: tom
|
||||
author_title: tom
|
||||
author_url: https://github.com/tomsun28
|
||||
author_image_url: https://avatars.githubusercontent.com/u/24788200?s=400&v=4
|
||||
tags: [opensource]
|
||||
---
|
||||
|
||||
HertzBeat赫兹跳动是由Dromara孵化,TanCloud开源的一个支持网站,API,PING,端口,数据库,全站等监控类型,支持阈值告警,告警通知(邮箱,webhook,钉钉,企业微信,飞书机器人),拥有易用友好的可视化操作界面的开源监控告警项目。
|
||||
|
||||
官网:hertzbeat.com | tancloud.cn
|
||||
|
||||
此升级版本包含了dashboard仪表盘重新设计,阈值表达式支持多指标,丰富了数据库监控类型,新增mariaDB和postgreSQL数据库的监控,控制台页面新增帮助文档等,欢迎使用。
|
||||
|
||||
版本特性:
|
||||
|
||||
1. feature 支持mariadb监控类型 (#11)
|
||||
2. feature dashboard仪表盘重构 (#13)
|
||||
3. feature 告警配置支持多指标集合 !10 由 @pengliren 提出 thanks
|
||||
4. feature 支持postgresql数据库的监控 (#16)
|
||||
5. 新增监控默认开启探测.
|
||||
6. 新增mysql采集指标.
|
||||
7. 新增监控大类别,支持自定义监控页面菜单自动渲染
|
||||
8. 操作页面新增帮助链接,完善自定义和阈值帮助文档
|
||||
9. feat: 模拟浏览器设置为chrome浏览器 #Issues 14 由@learning-code 贡献 thanks
|
||||
|
||||
BUG修复
|
||||
1. 登陆改登录,傻傻分不清.
|
||||
2. 文档新增常见问题,采集器http参数优化校验.
|
||||
3. 采集器调度第0优先级失败则取消后续的优化.
|
||||
4. bugfix website monitor path Illegal character in path at index
|
||||
5. bugfix深色主题适配问题 (#10)
|
||||
6. fix国际化异常 放开hierarchy接口认证保护
|
||||
|
||||
欢迎在线试用 https://console.tancloud.cn
|
||||
|
||||
|
||||
-----------------------
|
||||
|
||||
> [HertzBeat赫兹跳动](https://github.com/dromara/hertzbeat) 是由[Dromara](https://dromara.org)孵化,[TanCloud](https://tancloud.cn)开源的一个支持网站,API,PING,端口,数据库等监控类型,拥有易用友好的可视化操作界面的开源监控告警项目。
|
||||
> 我们也提供了对应的 **[SAAS版本监控云](https://console.tancloud.cn)**,中小团队和个人无需再为了监控自己的网站资源,而去部署一套繁琐的监控系统,**[登录即可免费开始](https://console.tancloud.cn)**。
|
||||
> HertzBeat 支持[自定义监控](https://hertzbeat.com/docs/advanced/extend-point) ,只用通过配置YML文件我们就可以自定义需要的监控类型和指标,来满足常见的个性化需求。
|
||||
> HertzBeat 模块化,`manager, collector, scheduler, warehouse, alerter` 各个模块解耦合,方便理解与定制开发。
|
||||
> HertzBeat 支持更自由化的告警配置(计算表达式),支持告警通知,告警模版,邮件钉钉微信飞书等及时通知送达
|
||||
> 欢迎登录 HertzBeat 的 [云环境TanCloud](https://console.tancloud.cn) 试用发现更多。
|
||||
> 我们正在快速迭代中,欢迎参与加入一起共建项目开源生态。
|
||||
|
||||
> `HertzBeat`的多类型支持,易扩展,低耦合,希望能帮助开发者和中小团队快速搭建自有监控系统。
|
||||
|
||||
老铁们可以通过演示视频来直观了解功能: https://www.bilibili.com/video/BV1Vi4y1f7i8
|
||||
|
||||
##### 欢迎联系交流哦
|
||||
|
||||
**微信交流群**
|
||||
|
||||
加微信号 tan-cloud 或 扫描下面账号二维码拉进微信群。
|
||||
<img alt="tan-cloud" src="https://cdn.jsdelivr.net/gh/dromara/hertzbeat@gh-pages/img/docs/help/tan-cloud-wechat.jpg" width="200"/>
|
||||
|
||||
**QQ交流群**
|
||||
|
||||
加QQ群号 718618151 或 扫描下面的群二维码进群, 验证信息: tancloud
|
||||
|
||||
<img alt="tan-cloud" src="https://cdn.jsdelivr.net/gh/dromara/hertzbeat@gh-pages/img/docs/help/qq-qr.jpg" width="200"/>
|
||||
|
||||
**仓库地址**
|
||||
|
||||
[Github](https://github.com/dromara/hertzbeat) https://github.com/dromara/hertzbeat
|
||||
[Gitee](https://gitee.com/dromara/hertzbeat) https://gitee.com/dromara/hertzbeat
|
||||
|
||||
看到这里不妨给个Star哦,灰常感谢,弯腰!!
|
||||
@@ -1,15 +1,15 @@
|
||||
---
|
||||
id: extend-mysql
|
||||
title: MYSQL协议自定义监控
|
||||
sidebar_label: MYSQL协议自定义监控
|
||||
id: extend-jdbc
|
||||
title: JDBC协议自定义监控
|
||||
sidebar_label: JDBC协议自定义监控
|
||||
---
|
||||
> 从[自定义监控](extend-point)了解熟悉了怎么自定义类型,指标,协议等,这里我们来详细介绍下用MYSQL协议自定义指标监控。
|
||||
> mysql协议自定义监控可以让我们很方便的通过写SQL查询语句就能监控到我们想监控的指标
|
||||
> 从[自定义监控](extend-point)了解熟悉了怎么自定义类型,指标,协议等,这里我们来详细介绍下用JDBC(目前支持mysql,mariadb,postgresql)自定义指标监控。
|
||||
> JDBC协议自定义监控可以让我们很方便的通过写SQL查询语句就能监控到我们想监控的指标
|
||||
|
||||
### MYSQL协议采集流程
|
||||
### JDBC协议采集流程
|
||||
【**系统直连MYSQL**】->【**运行SQL查询语句**】->【**响应数据解析:oneRow, multiRow, columns**】->【**指标数据提取**】
|
||||
|
||||
由流程可见,我们自定义一个MYSQL协议的监控类型,需要配置MYSQL请求参数,配置获取哪些指标,配置查询SQL语句。
|
||||
由流程可见,我们自定义一个JDBC协议的监控类型,需要配置JDBC请求参数,配置获取哪些指标,配置查询SQL语句。
|
||||
|
||||
### 数据解析方式
|
||||
SQL查询回来的数据字段和我们需要的指标映射,就能获取对应的指标数据,目前映射解析方式有三种:oneRow, multiRow, columns
|
||||
@@ -4,7 +4,7 @@ title: 自定义监控
|
||||
sidebar_label: 自定义监控
|
||||
---
|
||||
> HertzBeat拥有自定义监控能力,您只需配置两个YML文件就能适配一款自定义的监控类型。
|
||||
> 目前自定义监控支持[HTTP协议](extend-http),MYSQL协议,后续会支持更多通用协议(ssh telnet wmi snmp)。
|
||||
> 目前自定义监控支持[HTTP协议](extend-http),[JDBC](extend-jdbc)(mysql,mariadb,postgresql..)协议,后续会支持更多通用协议(ssh telnet wmi snmp)。
|
||||
|
||||
### 自定义步骤
|
||||
|
||||
|
||||
@@ -18,7 +18,11 @@ sidebar_label: 帮助入门
|
||||
|
||||
### 数据库监控
|
||||
|
||||
[MYSQL数据库监控](mysql)      [MariaDB数据库监控](mariadb)
|
||||
[MYSQL数据库监控](mysql)      [MariaDB数据库监控](mariadb)      [PostgreSQL数据库监控](postgresql)
|
||||
|
||||
### 操作系统监控
|
||||
|
||||
[Linux操作系统监控](linux)     
|
||||
|
||||
## 💡 告警服务
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ sidebar_label: 常见问题
|
||||
> 如信息所示,输入的监控Host须是ipv4,ipv6或域名,不能携带协议头,例如协议头http
|
||||
|
||||
2. ** 网站API等监控反馈statusCode:403或401,但对端服务本身无需认证,浏览器直接访问是OK **
|
||||
> 请排查是否是被防火墙拦截,如宝塔等默认设置了对请求header中`User-Agent=Apache-HttpClient`的拦截,若被拦截请删除此拦截规则。
|
||||
> 请排查是否是被防火墙拦截,如宝塔等默认设置了对请求header中`User-Agent=Apache-HttpClient`的拦截,若被拦截请删除此拦截规则。(v1.0.beat5版本已将user-agent模拟成浏览器此问题不存在)
|
||||
|
||||
### Docker部署常见问题
|
||||
|
||||
|
||||
70
home/docs/help/linux.md
Normal file
70
home/docs/help/linux.md
Normal file
@@ -0,0 +1,70 @@
|
||||
---
|
||||
id: linux
|
||||
title: 监控:Linux操作系统监控
|
||||
sidebar_label: Linux操作系统
|
||||
---
|
||||
|
||||
> 对Linux操作系统的通用性能指标进行采集监控。
|
||||
|
||||
### 配置参数
|
||||
|
||||
| 参数名称 | 参数帮助描述 |
|
||||
| ----------- | ----------- |
|
||||
| 监控Host | 被监控的对端IPV4,IPV6或域名。注意⚠️不带协议头(eg: https://, http://)。 |
|
||||
| 监控名称 | 标识此监控的名称,名称需要保证唯一性。 |
|
||||
| 端口 | Linux SSH对外提供的端口,默认为22。 |
|
||||
| 用户名 | SSH连接用户名,可选 |
|
||||
| 密码 | SSH连接密码,可选 |
|
||||
| 采集间隔 | 监控周期性采集数据间隔时间,单位秒,可设置的最小间隔为10秒 |
|
||||
| 是否探测 | 新增监控前是否先探测检查监控可用性,探测成功才会继续新增修改操作 |
|
||||
| 描述备注 | 更多标识和描述此监控的备注信息,用户可以在这里备注信息 |
|
||||
|
||||
### 采集指标
|
||||
|
||||
#### 指标集合:basic
|
||||
|
||||
| 指标名称 | 指标单位 | 指标帮助描述 |
|
||||
| ----------- | ----------- | ----------- |
|
||||
| hostname | 无 | 主机名称 |
|
||||
| version | 无 | 操作系统版本 |
|
||||
| uptime | 无 | 系统运行时间 |
|
||||
|
||||
#### 指标集合:cpu
|
||||
|
||||
| 指标名称 | 指标单位 | 指标帮助描述 |
|
||||
| ----------- | ----------- | ----------- |
|
||||
| info | 无 | CPU型号 |
|
||||
| cores | 核数 | CPU内核数量 |
|
||||
| interrupt | 个数 | CPU中断数量 |
|
||||
| load | 无 | CPU最近1/5/15分钟的平均负载 |
|
||||
| context_switch | 个数 | 当前上下文切换数量 |
|
||||
|
||||
|
||||
#### 指标集合:memory
|
||||
|
||||
| 指标名称 | 指标单位 | 指标帮助描述 |
|
||||
| ----------- | ----------- | ----------- |
|
||||
| total | Mb | 总内存容量 |
|
||||
| used | Mb | 用户程序内存量 |
|
||||
| free | Mb | 空闲内存容量 |
|
||||
| buff_cache | Mb | 缓存占用内存 |
|
||||
| available | Mb | 剩余可用内存容 |
|
||||
|
||||
#### 指标集合:disk
|
||||
|
||||
| 指标名称 | 指标单位 | 指标帮助描述 |
|
||||
| ----------- | ----------- | ----------- |
|
||||
| disk_num | 块数 | 磁盘总数 |
|
||||
| partition_num | 分区数 | 分区总数 |
|
||||
| block_write | 块数 | 写入磁盘的总块数 |
|
||||
| block_read | 块数 | 从磁盘读出的块数 |
|
||||
| write_rate | iops | 每秒写磁盘块的速率 |
|
||||
|
||||
#### 指标集合:interface
|
||||
|
||||
| 指标名称 | 指标单位 | 指标帮助描述 |
|
||||
| ----------- | ----------- | ----------- |
|
||||
| interface_name | 无 | 网卡名称 |
|
||||
| receive_bytes | byte | 入站数据流量(bytes) |
|
||||
| transmit_bytes | byte | 出站数据流量(bytes) |
|
||||
|
||||
@@ -12,7 +12,7 @@ sidebar_label: MariaDB数据库
|
||||
| ----------- | ----------- |
|
||||
| 监控Host | 被监控的对端IPV4,IPV6或域名。注意⚠️不带协议头(eg: https://, http://)。 |
|
||||
| 监控名称 | 标识此监控的名称,名称需要保证唯一性。 |
|
||||
| 端口 | 网站对外提供的端口,http一般默认为80,https一般默认为443。 |
|
||||
| 端口 | 数据库对外提供的端口,默认为3306。 |
|
||||
| 数据库名称 | 数据库实例名称,可选。 |
|
||||
| 用户名 | 数据库连接用户名,可选 |
|
||||
| 密码 | 数据库连接密码,可选 |
|
||||
@@ -40,8 +40,6 @@ sidebar_label: MariaDB数据库
|
||||
| threads_connected | 无 | MariaDB已经连接的连接数 |
|
||||
| threads_cached | 无 | MariaDB当前缓存的连接数 |
|
||||
| threads_running | 无 | MariaDB当前活跃的连接数 |
|
||||
| qps | 无 | 每秒请求查询次数。`QPS = questions/uptimes` |
|
||||
| tps | 无 | 每秒事务数据 `TPS= (commit+rollback)/seconds`|
|
||||
|
||||
|
||||
#### 指标集合:innodb
|
||||
|
||||
@@ -12,7 +12,7 @@ sidebar_label: MYSQL数据库
|
||||
| ----------- | ----------- |
|
||||
| 监控Host | 被监控的对端IPV4,IPV6或域名。注意⚠️不带协议头(eg: https://, http://)。 |
|
||||
| 监控名称 | 标识此监控的名称,名称需要保证唯一性。 |
|
||||
| 端口 | 网站对外提供的端口,http一般默认为80,https一般默认为443。 |
|
||||
| 端口 | 数据库对外提供的端口,默认为3306。 |
|
||||
| 数据库名称 | 数据库实例名称,可选。 |
|
||||
| 用户名 | 数据库连接用户名,可选 |
|
||||
| 密码 | 数据库连接密码,可选 |
|
||||
@@ -40,8 +40,6 @@ sidebar_label: MYSQL数据库
|
||||
| threads_connected | 无 | MySql已经连接的连接数 |
|
||||
| threads_cached | 无 | MySql当前缓存的连接数 |
|
||||
| threads_running | 无 | MySql当前活跃的连接数 |
|
||||
| qps | 无 | 每秒请求查询次数。`QPS = questions/uptimes` |
|
||||
| tps | 无 | 每秒事务数据 `TPS= (commit+rollback)/seconds`|
|
||||
|
||||
|
||||
#### 指标集合:innodb
|
||||
|
||||
56
home/docs/help/postgresql.md
Normal file
56
home/docs/help/postgresql.md
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
id: postgresql
|
||||
title: 监控:PostgreSQL数据库监控
|
||||
sidebar_label: PostgreSQL数据库
|
||||
---
|
||||
|
||||
> 对PostgreSQL数据库的通用性能指标进行采集监控。支持PostgreSQL 10+。
|
||||
|
||||
### 配置参数
|
||||
|
||||
| 参数名称 | 参数帮助描述 |
|
||||
| ----------- | ----------- |
|
||||
| 监控Host | 被监控的对端IPV4,IPV6或域名。注意⚠️不带协议头(eg: https://, http://)。 |
|
||||
| 监控名称 | 标识此监控的名称,名称需要保证唯一性。 |
|
||||
| 端口 | 数据库对外提供的端口,默认为5432。 |
|
||||
| 数据库名称 | 数据库实例名称,可选。 |
|
||||
| 用户名 | 数据库连接用户名,可选 |
|
||||
| 密码 | 数据库连接密码,可选 |
|
||||
| URL | 数据库连接URL,可选,若配置,则URL里面的数据库名称,用户名密码等参数会覆盖上面配置的参数 |
|
||||
| 采集间隔 | 监控周期性采集数据间隔时间,单位秒,可设置的最小间隔为10秒 |
|
||||
| 是否探测 | 新增监控前是否先探测检查监控可用性,探测成功才会继续新增修改操作 |
|
||||
| 描述备注 | 更多标识和描述此监控的备注信息,用户可以在这里备注信息 |
|
||||
|
||||
### 采集指标
|
||||
|
||||
#### 指标集合:basic
|
||||
|
||||
| 指标名称 | 指标单位 | 指标帮助描述 |
|
||||
| ----------- | ----------- | ----------- |
|
||||
| server_version | 无 | 数据库服务器的版本号 |
|
||||
| port | 无 | 数据库服务器端暴露服务端口 |
|
||||
| server_encoding | 无 | 数据库服务器端的字符集编码 |
|
||||
| data_directory | 无 | 数据库存储数据盘地址 |
|
||||
| max_connections | 连接数 | 数据库最大连接数 |
|
||||
|
||||
#### 指标集合:state
|
||||
|
||||
| 指标名称 | 指标单位 | 指标帮助描述 |
|
||||
| ----------- | ----------- | ----------- |
|
||||
| name | 无 | 数据库名称,或share-object为共享对象。 |
|
||||
| conflicts | 次数 | 由于与恢复冲突而在这个数据库中被取消的查询的数目 |
|
||||
| deadlocks | 个数 | 在这个数据库中被检测到的死锁数 |
|
||||
| blks_read | 次数 | 在这个数据库中被读取的磁盘块的数量 |
|
||||
| blks_hit | 次数 | 磁盘块被发现已经在缓冲区中的次数,这样不需要一次读取(这只包括 PostgreSQL 缓冲区中的命中,而不包括在操作系统文件系统缓冲区中的命中) |
|
||||
| blk_read_time | ms | 在这个数据库中后端花费在读取数据文件块的时间 |
|
||||
| blk_write_time | ms | 在这个数据库中后端花费在写数据文件块的时间 |
|
||||
| stats_reset | 无 | 这些统计信息上次被重置的时间 |
|
||||
|
||||
|
||||
#### 指标集合:activity
|
||||
|
||||
| 指标名称 | 指标单位 | 指标帮助描述 |
|
||||
| ----------- | ----------- | ----------- |
|
||||
| running | 连接数 | 当前客户端连接数 |
|
||||
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "MYSQL协议",
|
||||
"label": "JDBC协议",
|
||||
"items": [
|
||||
"advanced/extend-mysql"
|
||||
"advanced/extend-jdbc"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -56,7 +56,15 @@
|
||||
"label": "数据库监控",
|
||||
"items": [
|
||||
"help/mysql",
|
||||
"help/mariadb"
|
||||
"help/mariadb",
|
||||
"help/postgresql"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "操作系统",
|
||||
"items": [
|
||||
"help/linux"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -79,9 +79,17 @@ public class MonitorsController {
|
||||
orList.add(predicateName);
|
||||
}
|
||||
Predicate[] orPredicates = new Predicate[orList.size()];
|
||||
Predicate orPredicate = criteriaBuilder.and(orList.toArray(orPredicates));
|
||||
Predicate orPredicate = criteriaBuilder.or(orList.toArray(orPredicates));
|
||||
|
||||
return query.where(andPredicate,orPredicate).getRestriction();
|
||||
if (andPredicate.getExpressions().isEmpty() && orPredicate.getExpressions().isEmpty()) {
|
||||
return query.where().getRestriction();
|
||||
} else if (andPredicate.getExpressions().isEmpty()) {
|
||||
return query.where(orPredicate).getRestriction();
|
||||
} else if (orPredicate.getExpressions().isEmpty()) {
|
||||
return query.where(andPredicate).getRestriction();
|
||||
} else {
|
||||
return query.where(andPredicate,orPredicate).getRestriction();
|
||||
}
|
||||
};
|
||||
// 分页是必须的
|
||||
Sort sortExp = Sort.by(new Sort.Order(Sort.Direction.fromString(order), sort));
|
||||
|
||||
168
manager/src/main/resources/define/app/linux.yml
Normal file
168
manager/src/main/resources/define/app/linux.yml
Normal file
@@ -0,0 +1,168 @@
|
||||
# 此监控类型所属类别:service-应用服务监控 db-数据库监控 custom-自定义监控 os-操作系统监控
|
||||
category: os
|
||||
# 监控应用类型(与文件名保持一致) eg: linux windows tomcat mysql aws...
|
||||
app: linux
|
||||
name:
|
||||
zh-CN: Linux操作系统
|
||||
en-US: OS Linux
|
||||
# 参数映射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
|
||||
# 指标组列表
|
||||
metrics:
|
||||
# 第一个监控指标组 basic
|
||||
# 注意:内置监控指标有 (responseTime - 响应时间)
|
||||
- name: basic
|
||||
# 指标组调度优先级(0-127)越小优先级越高,优先级低的指标组会等优先级高的指标组采集完成后才会被调度,相同优先级的指标组会并行调度采集
|
||||
# 优先级为0的指标组为可用性指标组,即它会被首先调度,采集成功才会继续调度其它指标组,采集失败则中断调度
|
||||
priority: 0
|
||||
# 指标组中的具体监控指标
|
||||
fields:
|
||||
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
|
||||
- field: hostname
|
||||
type: 1
|
||||
instance: true
|
||||
- field: version
|
||||
type: 1
|
||||
- field: uptime
|
||||
type: 1
|
||||
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: ssh
|
||||
# 当protocol为http协议时具体的采集配置
|
||||
ssh:
|
||||
# 主机host: ipv4 ipv6 域名
|
||||
host: ^_^host^_^
|
||||
# 端口
|
||||
port: ^_^port^_^
|
||||
username: ^_^username^_^
|
||||
password: ^_^password^_^
|
||||
script: (uname -r ; hostname ; uptime | awk -F "," '{print $1}' | sed "s/ //g") | sed ":a;N;s/\n/^/g;ta" | awk -F '^' 'BEGIN{print "version hostname uptime"} {print $1, $2, $3}'
|
||||
# 响应数据解析方式:oneRow, multiRow
|
||||
parseType: multiRow
|
||||
|
||||
- name: cpu
|
||||
priority: 1
|
||||
fields:
|
||||
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
|
||||
- field: info
|
||||
type: 1
|
||||
- field: cores
|
||||
type: 0
|
||||
unit: 核数
|
||||
- field: interrupt
|
||||
type: 0
|
||||
unit: 个数
|
||||
- field: load
|
||||
type: 1
|
||||
- field: context_switch
|
||||
type: 0
|
||||
unit: 个数
|
||||
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: ssh
|
||||
# 当protocol为http协议时具体的采集配置
|
||||
ssh:
|
||||
# 主机host: ipv4 ipv6 域名
|
||||
host: ^_^host^_^
|
||||
# 端口
|
||||
port: ^_^port^_^
|
||||
username: ^_^username^_^
|
||||
password: ^_^password^_^
|
||||
script: "LANG=C lscpu | awk -F: '/Model name/ {print $2}';awk '/processor/{core++} END{print core}' /proc/cpuinfo;uptime | sed 's/,/ /g' | awk '{for(i=NF-2;i<=NF;i++)print $i }' | xargs;vmstat 1 1 | awk 'NR==3{print $11}';vmstat 1 1 | awk 'NR==3{print $12}'"
|
||||
parseType: oneRow
|
||||
|
||||
- name: memory
|
||||
priority: 2
|
||||
fields:
|
||||
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
|
||||
- field: total
|
||||
type: 0
|
||||
unit: Mb
|
||||
- field: used
|
||||
type: 0
|
||||
unit: Mb
|
||||
- field: free
|
||||
type: 0
|
||||
unit: Mb
|
||||
- field: buff_cache
|
||||
type: 0
|
||||
unit: Mb
|
||||
- field: available
|
||||
type: 0
|
||||
unit: Mb
|
||||
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: ssh
|
||||
# 当protocol为http协议时具体的采集配置
|
||||
ssh:
|
||||
# 主机host: ipv4 ipv6 域名
|
||||
host: ^_^host^_^
|
||||
# 端口
|
||||
port: ^_^port^_^
|
||||
username: ^_^username^_^
|
||||
password: ^_^password^_^
|
||||
script: free -m | grep Mem | awk 'BEGIN{print "total used free buff_cache available"} {print $2,$3,$4,$6,$7}'
|
||||
parseType: multiRow
|
||||
|
||||
- name: disk
|
||||
priority: 3
|
||||
fields:
|
||||
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
|
||||
- field: disk_num
|
||||
type: 0
|
||||
unit: 块数
|
||||
- field: partition_num
|
||||
type: 0
|
||||
unit: 分区数
|
||||
- field: block_write
|
||||
type: 0
|
||||
unit: 块数
|
||||
- field: block_read
|
||||
type: 0
|
||||
unit: 块数
|
||||
- field: write_rate
|
||||
type: 0
|
||||
unit: iops
|
||||
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: ssh
|
||||
# 当protocol为http协议时具体的采集配置
|
||||
ssh:
|
||||
# 主机host: ipv4 ipv6 域名
|
||||
host: ^_^host^_^
|
||||
# 端口
|
||||
port: ^_^port^_^
|
||||
username: ^_^username^_^
|
||||
password: ^_^password^_^
|
||||
script: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk 'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk 'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}'
|
||||
parseType: oneRow
|
||||
|
||||
- name: interface
|
||||
priority: 4
|
||||
fields:
|
||||
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
|
||||
- field: interface_name
|
||||
type: 1
|
||||
- field: receive_bytes
|
||||
type: 0
|
||||
unit: byte
|
||||
- field: transmit_bytes
|
||||
type: 0
|
||||
unit: byte
|
||||
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
|
||||
protocol: ssh
|
||||
# 当protocol为http协议时具体的采集配置
|
||||
ssh:
|
||||
# 主机host: ipv4 ipv6 域名
|
||||
host: ^_^host^_^
|
||||
# 端口
|
||||
port: ^_^port^_^
|
||||
username: ^_^username^_^
|
||||
password: ^_^password^_^
|
||||
script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}'
|
||||
parseType: multiRow
|
||||
121
manager/src/main/resources/define/app/postgresql.yml
Normal file
121
manager/src/main/resources/define/app/postgresql.yml
Normal file
@@ -0,0 +1,121 @@
|
||||
category: db
|
||||
app: postgresql
|
||||
name:
|
||||
zh-CN: PostgreSQL数据库
|
||||
en-US: PostgreSQL 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: url
|
||||
type: 1
|
||||
# 指标组列表
|
||||
metrics:
|
||||
- name: basic
|
||||
# 指标组调度优先级(0-127)越小优先级越高,优先级低的指标组会等优先级高的指标组采集完成后才会被调度,相同优先级的指标组会并行调度采集
|
||||
# 优先级为0的指标组为可用性指标组,即它会被首先调度,采集成功才会继续调度其它指标组,采集失败则中断调度
|
||||
priority: 0
|
||||
# 指标组中的具体监控指标
|
||||
fields:
|
||||
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
|
||||
- field: server_version
|
||||
type: 1
|
||||
instance: true
|
||||
- field: port
|
||||
type: 1
|
||||
- field: server_encoding
|
||||
type: 1
|
||||
- field: data_directory
|
||||
type: 1
|
||||
- field: max_connections
|
||||
type: 0
|
||||
unit: 连接数
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
# 主机host: ipv4 ipv6 域名
|
||||
host: ^_^host^_^
|
||||
# 端口
|
||||
port: ^_^port^_^
|
||||
platform: postgresql
|
||||
username: ^_^username^_^
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
# SQL查询方式: oneRow, multiRow, columns
|
||||
queryType: columns
|
||||
# sql
|
||||
sql: select name, setting as value from pg_settings where name = 'max_connections' or name = 'server_version' or name = 'server_encoding' or name = 'port' or name = 'data_directory';
|
||||
url: ^_^url^_^
|
||||
|
||||
- name: state
|
||||
priority: 1
|
||||
fields:
|
||||
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
|
||||
- field: name
|
||||
type: 1
|
||||
- field: conflicts
|
||||
type: 0
|
||||
unit: 次数
|
||||
- field: deadlocks
|
||||
type: 0
|
||||
unit: 个数
|
||||
- field: blks_read
|
||||
type: 0
|
||||
unit: 次数
|
||||
- field: blks_hit
|
||||
type: 0
|
||||
unit: 次数
|
||||
- field: blk_read_time
|
||||
type: 0
|
||||
unit: ms
|
||||
- field: blk_write_time
|
||||
type: 0
|
||||
unit: ms
|
||||
- field: stats_reset
|
||||
type: 1
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
# 主机host: ipv4 ipv6 域名
|
||||
host: ^_^host^_^
|
||||
# 端口
|
||||
port: ^_^port^_^
|
||||
platform: postgresql
|
||||
username: ^_^username^_^
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
# SQL查询方式: oneRow, multiRow, columns
|
||||
queryType: multiRow
|
||||
# sql
|
||||
sql: SELECT COALESCE(datname,'shared-object') as name, conflicts, deadlocks, blks_read, blks_hit, blk_read_time, blk_write_time, stats_reset from pg_stat_database where (datname != 'template1' and datname != 'template0') or datname is null;
|
||||
url: ^_^url^_^
|
||||
|
||||
- name: activity
|
||||
priority: 2
|
||||
fields:
|
||||
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
|
||||
- field: running
|
||||
type: 0
|
||||
unit: 连接数
|
||||
protocol: jdbc
|
||||
jdbc:
|
||||
# 主机host: ipv4 ipv6 域名
|
||||
host: ^_^host^_^
|
||||
# 端口
|
||||
port: ^_^port^_^
|
||||
platform: postgresql
|
||||
username: ^_^username^_^
|
||||
password: ^_^password^_^
|
||||
database: ^_^database^_^
|
||||
# SQL查询方式: oneRow, multiRow, columns
|
||||
queryType: oneRow
|
||||
# sql
|
||||
sql: SELECT count(*) as running FROM pg_stat_activity WHERE NOT pid=pg_backend_pid();
|
||||
url: ^_^url^_^
|
||||
22
manager/src/main/resources/define/param/linux.yml
Normal file
22
manager/src/main/resources/define/param/linux.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
app: linux
|
||||
param:
|
||||
- field: host
|
||||
name: 主机Host
|
||||
type: host
|
||||
required: true
|
||||
- field: port
|
||||
name: 端口
|
||||
type: number
|
||||
range: '[0,65535]'
|
||||
required: true
|
||||
defaultValue: 22
|
||||
placeholder: '请输入端口'
|
||||
- field: username
|
||||
name: 用户名
|
||||
type: text
|
||||
limit: 20
|
||||
required: true
|
||||
- field: password
|
||||
name: 密码
|
||||
type: password
|
||||
required: true
|
||||
30
manager/src/main/resources/define/param/postgresql.yml
Normal file
30
manager/src/main/resources/define/param/postgresql.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
app: postgresql
|
||||
param:
|
||||
- field: host
|
||||
name: 主机Host
|
||||
type: host
|
||||
required: true
|
||||
- field: port
|
||||
name: 端口
|
||||
type: number
|
||||
range: '[0,65535]'
|
||||
required: true
|
||||
defaultValue: 5432
|
||||
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
|
||||
@@ -13,6 +13,7 @@ excludedResource:
|
||||
- /account/auth/**===*
|
||||
- /===get
|
||||
- /i18n/**===get
|
||||
- /apps/hierarchy===get
|
||||
# web ui 静态资源
|
||||
- /console/**===get
|
||||
- /**/*.html===get
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd
|
||||
http://maven.apache.org/ASSEMBLY/2.0.0 ">
|
||||
<!--必填,会追加到打包文件名称的末尾-->
|
||||
<id>1.0-beta.4</id>
|
||||
<id>1.0-beta.5</id>
|
||||
<!--打包类型,可以设置多种类型,打包的时候不同的类型都会打包打出来-->
|
||||
<formats>
|
||||
<format>tar</format>
|
||||
|
||||
@@ -2,7 +2,7 @@ FROM openjdk:8-alpine
|
||||
|
||||
MAINTAINER tomsun28 "tomsun28@outlook.com"
|
||||
|
||||
ADD hertzbeat-1.0-beta.4.tar /opt/
|
||||
ADD hertzbeat-1.0-beta.5.tar /opt/
|
||||
|
||||
EXPOSE 1157
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ excludedResource:
|
||||
- /account/auth/**===*
|
||||
- /===get
|
||||
- /i18n/**===get
|
||||
- /apps/hierarchy===get
|
||||
# web ui 静态资源
|
||||
- /console/**===get
|
||||
- /**/*.html===get
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<h1 align="center">HertzBeat</h1>
|
||||
|
||||
> 前端工程
|
||||
|
||||
**面向开发者,易用友好的高性能监控云服务**
|
||||
**面向开发者,易用友好的监控告警系统**
|
||||
|
||||
## 本地启动
|
||||
## 前端本地启动
|
||||
|
||||
### npm 方式
|
||||
1. 需要nodejs npm环境
|
||||
@@ -21,13 +19,13 @@
|
||||
4. 全局安装angular-cli `npm install -g @angular/cli@12 --registry=https://registry.npm.taobao.org`
|
||||
5. 待本地后端启动后,在web-app目录下启动本地前端 `ng serve --open`
|
||||
|
||||
## 编译打包
|
||||
## hertzbeat 编译打包
|
||||
|
||||
web-app目录下执行
|
||||
1. web-app目录下执行
|
||||
|
||||
```ng build --prod --base-href /console/```
|
||||
|
||||
manager目录下执行
|
||||
2. manager目录下执行
|
||||
|
||||
```mvn package```
|
||||
|
||||
|
||||
@@ -96,7 +96,11 @@ export class HeaderSearchComponent implements AfterViewInit, OnDestroy {
|
||||
searchMonitors$.unsubscribe();
|
||||
if (message.code === 0) {
|
||||
let page = message.data;
|
||||
this.options = page.content;
|
||||
if (page.content != undefined) {
|
||||
this.options = page.content;
|
||||
} else {
|
||||
this.options = [];
|
||||
}
|
||||
this.cdr.detectChanges();
|
||||
} else {
|
||||
console.warn(message.msg);
|
||||
@@ -118,7 +122,7 @@ export class HeaderSearchComponent implements AfterViewInit, OnDestroy {
|
||||
qBlur(): void {
|
||||
this.focus = false;
|
||||
this.searchToggled = false;
|
||||
this.options.length = 0;
|
||||
this.options = [];
|
||||
this.toggleChangeChange.emit(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -127,7 +127,14 @@
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="target" nzRequired="true">指标对象</nz-form-label>
|
||||
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
|
||||
<nz-cascader required name="target" id="target" [nzOptions]="appHierarchies" [(ngModel)]="cascadeValues"></nz-cascader>
|
||||
<nz-cascader
|
||||
required
|
||||
name="target"
|
||||
id="target"
|
||||
[nzOptions]="appHierarchies"
|
||||
[(ngModel)]="cascadeValues"
|
||||
(ngModelChange)="cascadeOnChange($event)"
|
||||
></nz-cascader>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
@@ -138,8 +145,11 @@
|
||||
<nz-list-item *ngIf="cascadeValues.length == 3">
|
||||
<code>{{ cascadeValues[2] }} : 选中的指标对象</code>
|
||||
</nz-list-item>
|
||||
<nz-list-item>
|
||||
<code>instance : 所属行实例值</code>
|
||||
<nz-list-item *ngFor="let item of otherMetrics">
|
||||
<code>{{ item }} : 所属行其它指标对象</code>
|
||||
</nz-list-item>
|
||||
<nz-list-item *ngIf="otherMetrics.length != 0">
|
||||
<code>instance : 所属行实例</code>
|
||||
</nz-list-item>
|
||||
<nz-list-item>
|
||||
<code>支持操作符函数 : equals(str1,str2), ==, <, <=, >, >=, !=, ( ), +, -, &&, ||</code>
|
||||
@@ -167,7 +177,7 @@
|
||||
nz-input
|
||||
name="expr"
|
||||
id="expr"
|
||||
placeholder='根据此表达式计算判断是否触发阈值. 示例: equals(instance,"cpu1") && usage>40'
|
||||
placeholder="根据此表达式计算判断是否触发阈值. 示例: responseTime>40"
|
||||
>
|
||||
</textarea>
|
||||
</nz-textarea-count>
|
||||
@@ -204,20 +214,23 @@
|
||||
<nz-collapse>
|
||||
<nz-collapse-panel [nzActive]="isManageModalAdd" nzHeader="支持的通知模版环境变量">
|
||||
<nz-list nzSize="small" nzSplit="false">
|
||||
<nz-list-item *ngIf="cascadeValues.length == 3">
|
||||
<code>${metric} : 选中的指标对象名称</code>
|
||||
<nz-list-item>
|
||||
<code>${app} : 监控类型名称</code>
|
||||
</nz-list-item>
|
||||
<nz-list-item>
|
||||
<code>${metrics} : 监控指标集合名称</code>
|
||||
</nz-list-item>
|
||||
<nz-list-item *ngIf="cascadeValues.length == 3">
|
||||
<code>${{ '{' + cascadeValues[2] + '}' }} : 选中的指标对象值</code>
|
||||
<code>${metric} : 监控指标名称</code>
|
||||
</nz-list-item>
|
||||
<nz-list-item *ngIf="cascadeValues.length == 3">
|
||||
<code>${{ '{' + cascadeValues[2] + '}' }} : 监控指标对象值</code>
|
||||
</nz-list-item>
|
||||
<nz-list-item *ngFor="let item of otherMetrics">
|
||||
<code>${{ '{' + item + '}' }} : 所属行其它指标值</code>
|
||||
</nz-list-item>
|
||||
<nz-list-item>
|
||||
<code>${instance} : 所在行实例值</code>
|
||||
</nz-list-item>
|
||||
<nz-list-item>
|
||||
<code>${app} : 所属监控类型名称</code>
|
||||
</nz-list-item>
|
||||
<nz-list-item>
|
||||
<code>${metrics} : 所属监控指标组名称</code>
|
||||
<code>${instance} : 所属行实例值</code>
|
||||
</nz-list-item>
|
||||
</nz-list>
|
||||
</nz-collapse-panel>
|
||||
|
||||
@@ -136,6 +136,7 @@ export class AlertSettingComponent implements OnInit {
|
||||
if (message.code === 0) {
|
||||
this.define = message.data;
|
||||
this.cascadeValues = [this.define.app, this.define.metric, this.define.field];
|
||||
this.cascadeOnChange(this.cascadeValues);
|
||||
} else {
|
||||
this.notifySvc.error('查询此监控定义详情失败!', message.msg);
|
||||
}
|
||||
@@ -234,6 +235,26 @@ export class AlertSettingComponent implements OnInit {
|
||||
isManageModalAdd = true;
|
||||
define!: AlertDefine;
|
||||
cascadeValues: string[] = [];
|
||||
otherMetrics: string[] = [];
|
||||
cascadeOnChange(values: string[]): void {
|
||||
if (values == null || values.length != 3) {
|
||||
return;
|
||||
}
|
||||
this.appHierarchies.forEach(hierarchy => {
|
||||
if (hierarchy.value == values[0]) {
|
||||
hierarchy.children.forEach((metrics: { value: string; children: any[]}) => {
|
||||
if (metrics.value == values[1]) {
|
||||
this.otherMetrics = [];
|
||||
metrics.children.forEach(item => {
|
||||
if (item.value != values[2]) {
|
||||
this.otherMetrics.push(item.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
onManageModalCancel() {
|
||||
this.isManageModalVisible = false;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
};
|
||||
this.alertsTheme = {
|
||||
title: {
|
||||
subtext: '告警等级分布',
|
||||
subtext: '告警分布',
|
||||
left: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
<nz-breadcrumb-item>
|
||||
<i nz-icon nzType="pie-chart"></i>
|
||||
<span>{{ 'monitor.app.' + app | i18n }} 监控详情</span>
|
||||
<a [href]="'https://tancloud.cn/docs/help/' + monitor.app" target="_blank" style="float: right; margin-right: 5%">
|
||||
<span>帮助 </span>
|
||||
<i nz-icon nzType="question-circle" nzTheme="outline"></i>
|
||||
</a>
|
||||
</nz-breadcrumb-item>
|
||||
</nz-breadcrumb>
|
||||
<nz-divider></nz-divider>
|
||||
|
||||
@@ -28,11 +28,11 @@
|
||||
</button>
|
||||
<button nz-button nzType="primary" (click)="onEnableManageMonitors()">
|
||||
<i nz-icon nzType="up-circle" nzTheme="outline"></i>
|
||||
启用纳管
|
||||
启用监控
|
||||
</button>
|
||||
<button nz-button nzType="primary" (click)="onCancelManageMonitors()">
|
||||
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
|
||||
取消纳管
|
||||
取消监控
|
||||
</button>
|
||||
<button nz-button nzType="primary" (click)="sync()" nz-tooltip nzTooltipTitle="刷新">
|
||||
<i nz-icon nzType="sync" nzTheme="outline"></i>
|
||||
@@ -109,10 +109,10 @@
|
||||
<button nz-button nzType="primary" (click)="onDeleteOneMonitor(data.id)" nz-tooltip nzTooltipTitle="删除监控">
|
||||
<i nz-icon nzType="delete" nzTheme="outline"></i>
|
||||
</button>
|
||||
<button nz-button nzType="primary" (click)="onEnableManageOneMonitor(data.id)" nz-tooltip nzTooltipTitle="启用纳管">
|
||||
<button nz-button nzType="primary" (click)="onEnableManageOneMonitor(data.id)" nz-tooltip nzTooltipTitle="启用监控">
|
||||
<i nz-icon nzType="up-circle" nzTheme="outline"></i>
|
||||
</button>
|
||||
<button nz-button nzType="primary" (click)="onCancelManageOneMonitor(data.id)" nz-tooltip nzTooltipTitle="取消纳管">
|
||||
<button nz-button nzType="primary" (click)="onCancelManageOneMonitor(data.id)" nz-tooltip nzTooltipTitle="取消监控">
|
||||
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
|
||||
</button>
|
||||
</td>
|
||||
|
||||
@@ -154,7 +154,7 @@ export class MonitorListComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
this.modal.confirm({
|
||||
nzTitle: '请确认是否批量取消纳管!',
|
||||
nzTitle: '请确认是否批量取消监控!',
|
||||
nzOkText: '确定',
|
||||
nzCancelText: '取消',
|
||||
nzOkDanger: true,
|
||||
@@ -167,7 +167,7 @@ export class MonitorListComponent implements OnInit {
|
||||
let monitors = new Set<number>();
|
||||
monitors.add(monitorId);
|
||||
this.modal.confirm({
|
||||
nzTitle: '请确认是否取消纳管!',
|
||||
nzTitle: '请确认是否取消监控!',
|
||||
nzOkText: '确定',
|
||||
nzCancelText: '取消',
|
||||
nzOkDanger: true,
|
||||
@@ -182,28 +182,28 @@ export class MonitorListComponent implements OnInit {
|
||||
message => {
|
||||
cancelManage$.unsubscribe();
|
||||
if (message.code === 0) {
|
||||
this.notifySvc.success('取消纳管成功!', '');
|
||||
this.notifySvc.success('取消监控成功!', '');
|
||||
this.loadMonitorTable();
|
||||
} else {
|
||||
this.tableLoading = false;
|
||||
this.notifySvc.error('取消纳管失败!', message.msg);
|
||||
this.notifySvc.error('取消监控失败!', message.msg);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
this.tableLoading = false;
|
||||
cancelManage$.unsubscribe();
|
||||
this.notifySvc.error('取消纳管失败!', error.msg);
|
||||
this.notifySvc.error('取消监控失败!', error.msg);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
onEnableManageMonitors() {
|
||||
if (this.checkedMonitorIds == null || this.checkedMonitorIds.size === 0) {
|
||||
this.notifySvc.warning('未选中任何待启用纳管项!', '');
|
||||
this.notifySvc.warning('未选中任何待启用监控项!', '');
|
||||
return;
|
||||
}
|
||||
this.modal.confirm({
|
||||
nzTitle: '请确认是否批量启用纳管!',
|
||||
nzTitle: '请确认是否批量启用监控!',
|
||||
nzOkText: '确定',
|
||||
nzCancelText: '取消',
|
||||
nzOkDanger: true,
|
||||
@@ -216,7 +216,7 @@ export class MonitorListComponent implements OnInit {
|
||||
let monitors = new Set<number>();
|
||||
monitors.add(monitorId);
|
||||
this.modal.confirm({
|
||||
nzTitle: '请确认是否启用纳管!',
|
||||
nzTitle: '请确认是否启用监控!',
|
||||
nzOkText: '确定',
|
||||
nzCancelText: '取消',
|
||||
nzOkDanger: true,
|
||||
@@ -231,17 +231,17 @@ export class MonitorListComponent implements OnInit {
|
||||
message => {
|
||||
enableManage$.unsubscribe();
|
||||
if (message.code === 0) {
|
||||
this.notifySvc.success('启用纳管成功!', '');
|
||||
this.notifySvc.success('启用监控成功!', '');
|
||||
this.loadMonitorTable();
|
||||
} else {
|
||||
this.tableLoading = false;
|
||||
this.notifySvc.error('启用纳管失败!', message.msg);
|
||||
this.notifySvc.error('启用监控失败!', message.msg);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
this.tableLoading = false;
|
||||
enableManage$.unsubscribe();
|
||||
this.notifySvc.error('启用纳管失败!', error.msg);
|
||||
this.notifySvc.error('启用监控失败!', error.msg);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user