Compare commits

..

4 Commits

Author SHA1 Message Date
huacheng
3d65fe3861 feat: Alarm and receiving Chinese and English support #huacheng 2022-04-10 18:22:05 +08:00
huacheng
f3bd9930f1 fix: 企业微信更正名称 #huacheng 2022-04-06 21:21:33 +08:00
huacheng
dc61dd066c fix: msgtype更正名称 #huacheng 2022-04-05 22:21:56 +08:00
huacheng
4ad7972956 fix: 代码名称优化 #huacheng 2022-04-05 22:11:24 +08:00
90 changed files with 1073 additions and 2144 deletions

6
.gitignore vendored
View File

@@ -37,10 +37,4 @@ nbdist/
### VS Code ###
.vscode/
# dependencies
node_modules
.docusaurus
yarn.lock
# debug env
application-dev.yml

View File

@@ -6,7 +6,7 @@
[comment]: <> (<img alt="sureness" src="https://cdn.jsdelivr.net/gh/dromara/hertzbeat/home/static/img/hertzbeat-brand.svg" width="300">)
## HertzBeat 赫兹跳动 | [English Documentation](README_EN.md)
## HertzBeat 赫兹跳动
> 易用友好的监控告警系统。
@@ -35,7 +35,7 @@
----
[![tancloud](tancloud.gif)](https://www.bilibili.com/video/BV1DY4y1i7ts)
[![tancloud](tancloud.gif)](https://www.bilibili.com/video/BV1Vi4y1f7i8)
----
@@ -76,7 +76,7 @@
##### 安装TDengine
1. docker安装TDengine
`docker run -d -p 6030-6049:6030-6049 -p 6030-6049:6030-6049/udp --name tdengine tdengine/tdengine:2.4.0.12`
`docker run -d -p 6030-6049:6030-6049 -p 6030-6049:6030-6049/tcp -p 6030-6049:6030-6049/udp --name tdengine tdengine/tdengine:2.4.0.12`
2. 创建名称为hertzbeat的数据库
详细步骤参考 [依赖服务TDengine安装初始化](https://hertzbeat.com/docs/start/tdengine-init)
@@ -93,7 +93,6 @@
1. 下载您系统环境对应的安装包 [GITEE Release](https://gitee.com/dromara/hertzbeat/releases) [GITHUB Release](https://github.com/dromara/hertzbeat/releases)
2. 配置HertzBeat的配置文件 hertzbeat/config/application.yml
3. 部署启动 `$ ./startup.sh `
4. 浏览器访问 localhost:1157 即可开始,默认账号密码 admin/admin
详细步骤参考 [通过安装包安装HertzBeat](https://hertzbeat.com/docs/start/package-deploy)

View File

@@ -1,148 +0,0 @@
<p align="center">
<a href="https://hertzbeat.com">
<img alt="hertzbeat" src="https://cdn.jsdelivr.net/gh/dromara/hertzbeat/home/static/img/hertzbeat-brand.svg" width="260">
</a>
</p>
[comment]: <> (<img alt="sureness" src="https://cdn.jsdelivr.net/gh/dromara/hertzbeat/home/static/img/hertzbeat-brand.svg" width="300">)
## HertzBeat | [中文文档](README.md)
> Friendly cloud monitoring system.
![tan-cloud](https://img.shields.io/badge/web-monitor-4EB1BA)
![tan-cloud](https://img.shields.io/badge/api-monitor-lightgrey)
![tan-cloud](https://img.shields.io/badge/ping-connect-brightgreen)
![tan-cloud](https://img.shields.io/badge/port-available-green)
![tan-cloud](https://img.shields.io/badge/database-monitor-yellowgreen)
![tan-cloud](https://img.shields.io/badge/os-monitor-yellow)
![tan-cloud](https://img.shields.io/badge/custom-monitor-orange)
![tan-cloud](https://img.shields.io/badge/threshold-red)
![tan-cloud](https://img.shields.io/badge/alert-bule)
**Home: [hertzbeat.com](https://hertzbeat.com) | [tancloud.cn](https://tancloud.cn)**
## 🎡 <font color="green">Introduction</font>
> [HertzBeat](https://github.com/dromara/hertzbeat) is an opensource monitoring and alarm project incubated by [Dromara](https://dromara.org) and open sourced by [TanCloud](https://tancloud.cn), which supports Website, API, PING, Port, Database, OS Monitor etc.
> We also provide **[Monitoring Cloud For Saas](https://console.tancloud.cn)**, people no longer need to deploy a cumbersome monitoring system in order to monitor their website resources. **[Sign in to get started for free](https://console.tancloud.cn)**.
> HertzBeat supports more liberal threshold alarm configuration (calculation expression), supports alarm notification, alarm template, email, DingDing, WeChat FeiShu and WebHook.
> Most important is HertzBeat supports [Custom Monitoring](https://hertzbeat.com/docs/advanced/extend-point), just by configuring the YML file, we can customize the monitoring types and metrics what we need.
> HertzBeat is modular, `manager, collector, scheduler, warehouse, alerter` modules are decoupled for easy understanding and custom development.
> Welcome to HertzBeat's [Cloud Environment TanCloud](https://console.tancloud.cn) to try and discover more.
> Welcome to join us to build hertzbeat together.
> `HertzBeat`'s multi-type support, easy expansion, low coupling, hope to help developers and micro teams to quickly build their own monitoring system.
----
[![tancloud](tancloud.gif)](https://www.bilibili.com/video/BV1DY4y1i7ts)
----
## 🥐 Architecture
- **[manager](https://github.com/dromara/hertzbeat/tree/master/manager)** Provide monitoring management, system management basic services.
> Provides monitoring management, monitoring configuration management, system user management, etc.
- **[collector](https://github.com/dromara/hertzbeat/tree/master/collector)** Provide metrics data collection services.
> Use common protocols to remotely collect and obtain peer-to-peer metrics data.
- **[scheduler](https://github.com/dromara/hertzbeat/tree/master/scheduler)** Provide monitoring task scheduling service.
> Collection task management, scheduling and distribution of one-time tasks and periodic tasks.
- **[warehouse](https://github.com/dromara/hertzbeat/tree/master/warehouse)** Provide monitoring data warehousing services.
> Metrics data management, data query, calculation and statistics.
- **[alerter](https://github.com/dromara/hertzbeat/tree/master/alerter)** Provide alert service.
> Alarm calculation trigger, monitoring status linkage, alarm configuration, and alarm notification.
- **[web-app](https://github.com/dromara/hertzbeat/tree/master/web-app)** Provide web ui.
> Angular Web UI.
![hertzBeat](home/static/img/docs/hertzbeat-stru-en.svg)
## 🐕 Quick Start
- If you dont want to deploy but use it directly, we provide [SAAS Monitoring Cloud-TanCloud](https://console.tancloud.cn), **[Log In And Register For Free](https://console.tancloud.cn) **.
- If you want to deploy HertzBeat local, please refer to the following [Deployment Documentation](https://hertzbeat.com/docs/start/quickstart) for operation.
### 🐵 Dependency Service Deployment
> HertzBeat depends at least on relational database [MYSQL5+](https://www.mysql.com/) and time series database [TDengine2+](https://www.taosdata.com/getting-started)
##### Install MYSQL
1. Install mysql with docker
`docker run -d --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7`
2. Create database names `hertzbeat`
3. Run the database sql script [schema.sql](https://gitee.com/dromara/hertzbeat/raw/master/script/sql/schema.sql) located in the project repository `/script/sql/` directory.
For detailed steps, refer to [MYSQL Installation And Initialization](https://hertzbeat.com/docs/start/mysql-init)
##### Install TDengine
1. Install TDengine with docker
`docker run -d -p 6030-6049:6030-6049 -p 6030-6049:6030-6049/udp --name tdengine tdengine/tdengine:2.4.0.12`
2. Create database names `hertzbeat`
For detailed steps, refer to [TDengine Installation And Initialization](https://hertzbeat.com/docs/start/tdengine-init).
### 🍞 Install HertzBeat
> HertzBeat supports installation through source code, docker or package.
##### 1Install quickly via docker
`docker run -d -p 1157:1157 -v /opt/application.yml:/opt/hertzbeat/config/application.yml --name hertzbeat tancloud/hertzbeat:[版本tag]`
Detailed steps refer to [Install HertzBeat via Docker](https://hertzbeat.com/docs/start/docker-deploy)
##### 2Install via package
1. Download the installation package [GITEE Release](https://gitee.com/dromara/hertzbeat/releases) [GITHUB Release](https://github.com/dromara/hertzbeat/releases)
2. Configure the HertzBeat configuration yml file `hertzbeat/config/application.yml`
3. Run shell `$ ./startup.sh `
4. Access `localhost:1157` to start, default account: `admin/admin`
Detailed steps refer to [Install HertzBeat via package](https://hertzbeat.com/docs/start/package-deploy)
##### 3Start via source code
1. Local source code debugging needs to start the back-end project manager and the front-end project web-app.
2. Backendneed `maven3+`, `java8+`, start the manager service.
3. Webneed `nodejs npm angular-cli` environment, Run `ng serve --open` in `web-app` directory after backend startup.
4. Access `localhost:4200` to start, default account: `admin/admin`
Detailed steps refer to [CONTRIBUTING](CONTRIBUTING.md)
##### 4Install All(mysql+tdengine+hertzbeat) via Docker-compose
Install and deploy the mysql database, tdengine database and hertzbeat at one time through [docker-compose deployment script](script/docker-compose).
Detailed steps refer to [docker-compose install](script/docker-compose/README.md)
**HAVE FUN**
## 💬 Join discussion
HertzBeat is an incubation project of [Dromara Open Source Community](https://dromara.org/).
##### WeChat Group
Add WeChat account `tan-cloud` or scan the QR code below to pull you into the WeChat group.
<img alt="tan-cloud" src="https://cdn.jsdelivr.net/gh/dromara/hertzbeat@gh-pages/img/docs/help/tan-cloud-wechat.jpg" width="200"/>
##### QQ Group
QQ group number `718618151` or scan the group QR code below, verify code: `tancloud`
<img alt="tan-cloud" src="https://cdn.jsdelivr.net/gh/dromara/hertzbeat@gh-pages/img/docs/help/qq-qr.jpg" width="200"/>
##### Github Discussion
Welcome to Discuss in [Github Discussion](https://github.com/dromara/hertzbeat/discussions)
##### Public WeChat
<img alt="tan-cloud" src="https://cdn.jsdelivr.net/gh/dromara/hertzbeat/home/static/img/wechat.png" width="400"/>
##### Sponsor
Thanks [吉实信息(构建全新的微波+光交易网络)](https://www.flarespeed.com) sponsored server node.
Thanks [天上云计算(全新智慧上云)](https://www.tsyvps.com/aff/BZBEGYLX) sponsored server node.
## 🛡️ License
[`Apache License, Version 2.0`](https://www.apache.org/licenses/LICENSE-2.0.html)

View File

@@ -110,7 +110,7 @@ public class CalculateAlarm {
} else {
// 其他异常
alertBuilder.target(CommonConstants.AVAILABLE)
.content("监控可用性告警: " + metricsData.getCode().name() + " : " + metricsData.getMsg());
.content("监控紧急可用性告警: " + metricsData.getCode().name());
triggeredMonitorStateAlertMap.put(monitorId, metricsData.getCode());
dataQueue.addAlertData(alertBuilder.build());
}

View File

@@ -30,11 +30,12 @@ import java.util.List;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
/**
* 告警管理API
* Alarm Management API 告警管理API
*
* @author tom
* @date 2021/12/9 10:32
*/
@Api(tags = "告警批量管理API")
@Api(tags = "en: Alarm batch management API, zh:告警批量管理API")
@RestController
@RequestMapping(path = "/alerts", produces = {APPLICATION_JSON_VALUE})
public class AlertsController {
@@ -43,23 +44,23 @@ public class AlertsController {
private AlertService alertService;
@GetMapping
@ApiOperation(value = "查询告警列表", notes = "根据查询过滤项获取告警信息列表")
@ApiOperation(value = "Get a list of alarm information based on query filter items", notes = "根据查询过滤项获取告警信息列表")
public ResponseEntity<Message<Page<Alert>>> getAlerts(
@ApiParam(value = "告警ID", example = "6565466456") @RequestParam(required = false) List<Long> ids,
@ApiParam(value = "告警监控对象ID", example = "6565463543") @RequestParam(required = false) Long monitorId,
@ApiParam(value = "告警级别", example = "6565463543") @RequestParam(required = false) Byte priority,
@ApiParam(value = "告警状态", example = "6565463543") @RequestParam(required = false) Byte status,
@ApiParam(value = "告警内容模糊查询", example = "linux") @RequestParam(required = false) String content,
@ApiParam(value = "排序字段默认id", example = "name") @RequestParam(defaultValue = "id") String sort,
@ApiParam(value = "排序方式asc:升序desc:降序", example = "desc") @RequestParam(defaultValue = "desc") String order,
@ApiParam(value = "列表当前分页", example = "0") @RequestParam(defaultValue = "0") int pageIndex,
@ApiParam(value = "列表分页数量", example = "8") @RequestParam(defaultValue = "8") int pageSize) {
@ApiParam(value = "en: Alarm ID List,zh: 告警IDS", example = "6565466456") @RequestParam(required = false) List<Long> ids,
@ApiParam(value = "en: Alarm monitor object ID,zh: 告警监控对象ID", example = "6565463543") @RequestParam(required = false) Long monitorId,
@ApiParam(value = "en: Alarm level,zh: 告警级别", example = "6565463543") @RequestParam(required = false) Byte priority,
@ApiParam(value = "en: Alarm Status,zh: 告警状态", example = "6565463543") @RequestParam(required = false) Byte status,
@ApiParam(value = "en: Alarm content fuzzy query,zh:告警内容模糊查询", example = "linux") @RequestParam(required = false) String content,
@ApiParam(value = "en: Sort field, default id,zh: 排序字段默认id", example = "name") @RequestParam(defaultValue = "id") String sort,
@ApiParam(value = "en: Sort Type,zh: 排序方式asc:升序desc:降序", example = "desc") @RequestParam(defaultValue = "desc") String order,
@ApiParam(value = "en: List current page,zh: 列表当前分页", example = "0") @RequestParam(defaultValue = "0") int pageIndex,
@ApiParam(value = "en: Number of list pagination,zh: 列表分页数量", example = "8") @RequestParam(defaultValue = "8") int pageSize) {
Specification<Alert> specification = (root, query, criteriaBuilder) -> {
List<Predicate> andList = new ArrayList<>();
if (ids != null && !ids.isEmpty()) {
CriteriaBuilder.In<Long> inPredicate= criteriaBuilder.in(root.get("id"));
CriteriaBuilder.In<Long> inPredicate = criteriaBuilder.in(root.get("id"));
for (long id : ids) {
inPredicate.value(id);
}
@@ -92,10 +93,9 @@ public class AlertsController {
}
@DeleteMapping
@ApiOperation(value = "批量删除告警", notes = "根据告警ID列表批量删除告警")
@ApiOperation(value = "Delete alarms in batches", notes = "根据告警ID列表批量删除告警")
public ResponseEntity<Message<Void>> deleteAlertDefines(
@ApiParam(value = "告警IDs", example = "6565463543") @RequestParam(required = false) List<Long> ids
) {
@ApiParam(value = "en:Alarm List ID,zh: 告警IDs", example = "6565463543") @RequestParam(required = false) List<Long> ids) {
if (ids != null && !ids.isEmpty()) {
alertService.deleteAlerts(new HashSet<>(ids));
}
@@ -104,10 +104,10 @@ public class AlertsController {
}
@PutMapping(path = "/status/{status}")
@ApiOperation(value = "批量修改告警状态", notes = "批量修改告警状态,设置已读未读")
@ApiOperation(value = "Batch modify alarm status, set read and unread", notes = "批量修改告警状态,设置已读未读")
public ResponseEntity<Message<Void>> applyAlertDefinesStatus(
@ApiParam(value = "告警状态值", example = "0") @PathVariable Byte status,
@ApiParam(value = "告警IDs", example = "6565463543") @RequestParam(required = false) List<Long> ids) {
@ApiParam(value = "en:Alarm status value,zh: 告警状态值", example = "0") @PathVariable Byte status,
@ApiParam(value = "en:Alarm List IDS,zh: 告警IDS", example = "6565463543") @RequestParam(required = false) List<Long> ids) {
if (ids != null && status != null && !ids.isEmpty()) {
alertService.editAlertStatus(status, ids);
}
@@ -116,7 +116,7 @@ public class AlertsController {
}
@GetMapping(path = "/summary")
@ApiOperation(value = "获取告警统计信息", notes = "获取告警统计信息")
@ApiOperation(value = "Get alarm statistics", notes = "获取告警统计信息")
public ResponseEntity<Message<AlertSummary>> getAlertsSummary() {
AlertSummary alertSummary = alertService.getAlertsSummary();
Message<AlertSummary> message = new Message<>(alertSummary);

View File

@@ -12,20 +12,23 @@ import java.util.List;
import java.util.Set;
/**
* Alert 数据库操作
* Alert Database Operations Alert数据库操作
*
* @author tom
* @date 2021/12/9 10:03
*/
public interface AlertDao extends JpaRepository<Alert, Long>, JpaSpecificationExecutor<Alert> {
/**
* 根据ID列表删除告警
* @param alertIds 告警ID列表
* Delete alerts based on ID list 根据ID列表删除告警
*
* @param alertIds Alert ID List 告警ID列表
*/
void deleteAlertsByIdIn(Set<Long> alertIds);
/**
* 根据告警ID-状态值 更新告警状态
*
* @param status 状态值
* @param ids 告警ID列表
*/
@@ -34,8 +37,10 @@ public interface AlertDao extends JpaRepository<Alert, Long>, JpaSpecificationEx
void updateAlertsStatus(@Param(value = "status") Byte status, @Param(value = "ids") List<Long> ids);
/**
* Query the number of unhandled alarms of each alarm severity
* 查询各个告警级别的未处理告警数量
* @return 告警数量
*
* @return Number of alerts 告警数量
*/
@Query("select new com.usthe.alert.dto.AlertPriorityNum(mo.priority, count(mo.id)) from Alert mo where mo.status = 0 group by mo.priority")
List<AlertPriorityNum> findAlertPriorityNum();

View File

@@ -4,7 +4,8 @@ import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 监控级别告警数量
* Number of monitoring level alarms 监控级别告警数量
*
* @author tom
* @date 2022/3/6 19:52
*/
@@ -12,7 +13,13 @@ import lombok.Data;
@AllArgsConstructor
public class AlertPriorityNum {
/**
* Alarm level 告警级别
*/
private byte priority;
/**
* count 数量
*/
private long num;
}

View File

@@ -9,31 +9,43 @@ import lombok.NoArgsConstructor;
import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_ONLY;
/**
* 告警统计信息
* Alarm Statistics Information 告警统计信息
*
* @author tom
* @date 2022/3/6 19:25
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "告警统计信息")
@ApiModel(description = "en:Alarm Statistics Information,zh: 告警统计信息")
public class AlertSummary {
@ApiModelProperty(value = "告警总数量(包括已处理未处理告警)", example = "134", accessMode = READ_ONLY, position = 0)
@ApiModelProperty(value = "Total number of alerts (including processed and unprocessed alerts)",
notes = "告警总数量(包括已处理未处理告警)",
example = "134", accessMode = READ_ONLY, position = 0)
private long total;
@ApiModelProperty(value = "已处理告警数量", example = "34", accessMode = READ_ONLY, position = 1)
@ApiModelProperty(value = "Number of alerts handled",
notes = "已处理告警数量",
example = "34", accessMode = READ_ONLY, position = 1)
private long dealNum;
@ApiModelProperty(value = "告警处理率", example = "39.34", accessMode = READ_ONLY, position = 2)
@ApiModelProperty(value = "Alarm handling rate",
notes = "告警处理率",
example = "39.34", accessMode = READ_ONLY, position = 2)
private float rate;
@ApiModelProperty(value = "告警级别为警告告警的告警数量(指未处理告警)", example = "43", accessMode = READ_ONLY, position = 3)
@ApiModelProperty(value = "Number of alarms whose alarm severity is warning alarms (referring to unhandled alarms)",
notes = "告警级别为警告告警的告警数量(指未处理告警)",
example = "43", accessMode = READ_ONLY, position = 3)
private long priorityWarningNum;
@ApiModelProperty(value = "告警级别为严重告警的告警数量(指未处理告警)", example = "56", accessMode = READ_ONLY, position = 4)
@ApiModelProperty(value = "Number of alarms whose alarm severity is critical alarms (referring to unhandled alarms)",
notes = "告警级别为严重告警的告警数量(指未处理告警)",
example = "56", accessMode = READ_ONLY, position = 4)
private long priorityCriticalNum;
@ApiModelProperty(value = "告警级别为紧急告警的告警数量(指未处理告警)", example = "23", accessMode = READ_ONLY, position = 5)
@ApiModelProperty(value = "Number of alarms whose alarm severity is urgent alarms (referring to unhandled alarms)",
notes = "告警级别为紧急告警的告警数量(指未处理告警)", example = "23", accessMode = READ_ONLY, position = 5)
private long priorityEmergencyNum;
}

View File

@@ -10,43 +10,54 @@ import java.util.HashSet;
import java.util.List;
/**
* Alarm information management interface
* 告警信息管理接口
*
* @author tom
* @date 2021/12/9 10:06
*/
public interface AlertService {
/**
* 新增告警
* @param alert 告警实体
* @throws RuntimeException 新增过程异常抛出
* Add alarm record
* 新增告警记录
*
* @param alert Alert entity 告警实体
* @throws RuntimeException Add process exception throw 新增过程异常抛出
*/
void addAlert(Alert alert) throws RuntimeException;
/**
* Dynamic conditional query
* 动态条件查询
* @param specification 查询条件
* @param pageRequest 分页参数
* @return 查询结果
*
* @param specification Query conditions 查询条件
* @param pageRequest pagination parameters 分页参数
* @return search result 查询结果
*/
Page<Alert> getAlerts(Specification<Alert> specification, PageRequest pageRequest);
/**
* Delete alarms in batches according to the alarm ID list
* 根据告警ID列表批量删除告警
* @param ids 告警IDs
*
* @param ids Alarm ID List 告警IDS
*/
void deleteAlerts(HashSet<Long> ids);
/**
* Update the alarm status according to the alarm ID-status value
* 根据告警ID-状态值 更新告警状态
* @param status 待修改为的告警状态
* @param ids 待修改的告警IDs
*
* @param status Alarm status to be modified 待修改的告警状态
* @param ids Alarm ID List to be modified 待修改的告警ID集合
*/
void editAlertStatus(Byte status, List<Long> ids);
/**
* 获取告警统计信息
* @return 告警统计
* Get alarm statistics information 获取告警统计信息
*
* @return Alarm statistics information 告警统计
*/
AlertSummary getAlertsSummary();

View File

@@ -20,7 +20,8 @@ import java.util.HashSet;
import java.util.List;
/**
* 告警信息服务实现
* Realization of Alarm Information Service 告警信息服务实现
*
* @author tom
* @date 2021/12/10 15:39
*/
@@ -55,18 +56,24 @@ public class AlertServiceImpl implements AlertService {
@Override
public AlertSummary getAlertsSummary() {
AlertSummary alertSummary = new AlertSummary();
//Statistics on the alarm information in the alarm state
//统计正在告警状态下的告警信息
List<AlertPriorityNum> priorityNums = alertDao.findAlertPriorityNum();
if (priorityNums != null) {
for (AlertPriorityNum priorityNum : priorityNums) {
switch (priorityNum.getPriority()) {
case CommonConstants
.ALERT_PRIORITY_CODE_WARNING:
alertSummary.setPriorityWarningNum(priorityNum.getNum());break;
alertSummary.setPriorityWarningNum(priorityNum.getNum());
break;
case CommonConstants.ALERT_PRIORITY_CODE_CRITICAL:
alertSummary.setPriorityCriticalNum(priorityNum.getNum());break;
alertSummary.setPriorityCriticalNum(priorityNum.getNum());
break;
case CommonConstants.ALERT_PRIORITY_CODE_EMERGENCY:
alertSummary.setPriorityEmergencyNum(priorityNum.getNum());break;
default: break;
alertSummary.setPriorityEmergencyNum(priorityNum.getNum());
break;
default:
break;
}
}
}

View File

@@ -108,8 +108,8 @@ public class CommonHttpClient {
.setConnectTimeout(CONNECT_TIMEOUT)
// 数据传输最大响应间隔时间
.setSocketTimeout(SOCKET_TIMEOUT)
// 遇到301 302自动重定向跳转
.setRedirectsEnabled(true)
// 遇到301 302自动重定向跳转
.setRedirectsEnabled(false)
.build();
// 连接池
connectionManager = new PoolingHttpClientConnectionManager(registry);

View File

@@ -7,7 +7,6 @@ import com.google.gson.JsonParser;
import com.usthe.collector.collect.AbstractCollect;
import com.usthe.collector.collect.common.http.CommonHttpClient;
import com.usthe.collector.dispatch.DispatchConstants;
import com.usthe.collector.util.CollectUtil;
import com.usthe.collector.util.CollectorConstants;
import com.usthe.collector.util.JsonPathParser;
import com.usthe.common.entity.job.Metrics;
@@ -101,7 +100,7 @@ public class HttpCollectImpl extends AbstractCollect {
String parseType = metrics.getHttp().getParseType();
try {
if (DispatchConstants.PARSE_DEFAULT.equals(parseType)) {
parseResponseByDefault(resp, metrics.getAliasFields(), metrics.getHttp(), builder, responseTime);
parseResponseByDefault(resp, metrics.getAliasFields(), builder, responseTime);
} else if (DispatchConstants.PARSE_JSON_PATH.equals(parseType)) {
parseResponseByJsonPath(resp, metrics.getAliasFields(), metrics.getHttp(), builder, responseTime);
} else if (DispatchConstants.PARSE_PROMETHEUS.equals(parseType)) {
@@ -109,11 +108,11 @@ public class HttpCollectImpl extends AbstractCollect {
} else if (DispatchConstants.PARSE_XML_PATH.equals(parseType)) {
parseResponseByXmlPath(resp, metrics.getAliasFields(), metrics.getHttp(), builder);
} else if (DispatchConstants.PARSE_WEBSITE.equals(parseType)){
parseResponseByWebsite(resp, metrics.getAliasFields(), metrics.getHttp(), builder, responseTime);
parseResponseByWebsite(resp, metrics.getAliasFields(), builder, responseTime);
} else if (DispatchConstants.PARSE_SITE_MAP.equals(parseType)) {
parseResponseBySiteMap(resp, metrics.getAliasFields(), builder);
} else {
parseResponseByDefault(resp, metrics.getAliasFields(), metrics.getHttp(), builder, responseTime);
parseResponseByDefault(resp, metrics.getAliasFields(), builder, responseTime);
}
} catch (Exception e) {
log.info("parse error: {}.", e.getMessage(), e);
@@ -170,16 +169,13 @@ public class HttpCollectImpl extends AbstractCollect {
}
}
private void parseResponseByWebsite(String resp, List<String> aliasFields, HttpProtocol http,
private void parseResponseByWebsite(String resp, List<String> aliasFields,
CollectRep.MetricsData.Builder builder, Long responseTime) {
CollectRep.ValueRow.Builder valueRowBuilder = CollectRep.ValueRow.newBuilder();
// 网站关键词数量监测
int keywordNum = CollectUtil.countMatchKeyword(resp, http.getKeyword());
// todo resp 网站关键监测
for (String alias : aliasFields) {
if (CollectorConstants.RESPONSE_TIME.equalsIgnoreCase(alias)) {
valueRowBuilder.addColumns(responseTime.toString());
} else if (CollectorConstants.KEYWORD.equalsIgnoreCase(alias)) {
valueRowBuilder.addColumns(Integer.toString(keywordNum));
} else {
valueRowBuilder.addColumns(CommonConstants.NULL_VALUE);
}
@@ -281,7 +277,6 @@ public class HttpCollectImpl extends AbstractCollect {
private void parseResponseByJsonPath(String resp, List<String> aliasFields, HttpProtocol http,
CollectRep.MetricsData.Builder builder, Long responseTime) {
List<Map<String, Object>> results = JsonPathParser.parseContentWithJsonPath(resp, http.getParseScript());
int keywordNum = CollectUtil.countMatchKeyword(resp, http.getKeyword());
for (Map<String, Object> stringMap : results) {
CollectRep.ValueRow.Builder valueRowBuilder = CollectRep.ValueRow.newBuilder();
for (String alias : aliasFields) {
@@ -291,8 +286,6 @@ public class HttpCollectImpl extends AbstractCollect {
} else {
if (CollectorConstants.RESPONSE_TIME.equalsIgnoreCase(alias)) {
valueRowBuilder.addColumns(responseTime.toString());
} else if (CollectorConstants.KEYWORD.equalsIgnoreCase(alias)) {
valueRowBuilder.addColumns(Integer.toString(keywordNum));
} else {
valueRowBuilder.addColumns(CommonConstants.NULL_VALUE);
}
@@ -307,10 +300,9 @@ public class HttpCollectImpl extends AbstractCollect {
}
private void parseResponseByDefault(String resp, List<String> aliasFields, HttpProtocol http,
private void parseResponseByDefault(String resp, List<String> aliasFields,
CollectRep.MetricsData.Builder builder, Long responseTime) {
JsonElement element = JsonParser.parseString(resp);
int keywordNum = CollectUtil.countMatchKeyword(resp, http.getKeyword());
if (element.isJsonArray()) {
JsonArray array = element.getAsJsonArray();
for (JsonElement jsonElement : array) {
@@ -325,8 +317,6 @@ public class HttpCollectImpl extends AbstractCollect {
} else {
if (CollectorConstants.RESPONSE_TIME.equalsIgnoreCase(alias)) {
valueRowBuilder.addColumns(responseTime.toString());
} else if (CollectorConstants.KEYWORD.equalsIgnoreCase(alias)) {
valueRowBuilder.addColumns(Integer.toString(keywordNum));
} else {
valueRowBuilder.addColumns(CommonConstants.NULL_VALUE);
}

View File

@@ -105,13 +105,9 @@ public class CommonDispatcher implements MetricsTaskDispatch, CollectDataDispatc
.setId(timerJob.getJob().getMonitorId())
.setApp(timerJob.getJob().getApp())
.setMetrics(metricsTime.getMetrics().getName())
.setPriority(metricsTime.getMetrics().getPriority())
.setTime(System.currentTimeMillis())
.setCode(CollectRep.Code.TIMEOUT).setMsg("collect timeout").build();
log.error("[Collect Timeout]: \n{}", metricsData);
if (metricsData.getPriority() == 0) {
dispatchCollectData(metricsTime.timeout, metricsTime.getMetrics(), metricsData);
}
metricsTimeoutMonitorMap.remove(entry.getKey());
}
}
@@ -169,8 +165,8 @@ public class CommonDispatcher implements MetricsTaskDispatch, CollectDataDispatc
metricsSet.forEach(metricItem -> {
MetricsCollect metricsCollect = new MetricsCollect(metricItem, timeout, this);
jobRequestQueue.addJob(metricsCollect);
metricsTimeoutMonitorMap.put(job.getId() + "-" + metricItem.getName(),
new MetricsTime(System.currentTimeMillis(), metricItem, timeout));
metricsTimeoutMonitorMap.put(job.getId() + "-" + metrics.getName(),
new MetricsTime(System.currentTimeMillis(), metrics, timeout));
});
} else {
// 当前执行级别的指标组列表未全执行完成,
@@ -189,8 +185,8 @@ public class CommonDispatcher implements MetricsTaskDispatch, CollectDataDispatc
metricsSet.forEach(metricItem -> {
MetricsCollect metricsCollect = new MetricsCollect(metricItem, timeout, this);
jobRequestQueue.addJob(metricsCollect);
metricsTimeoutMonitorMap.put(job.getId() + "-" + metricItem.getName(),
new MetricsTime(System.currentTimeMillis(), metricItem, timeout));
metricsTimeoutMonitorMap.put(job.getId() + "-" + metrics.getName(),
new MetricsTime(System.currentTimeMillis(), metrics, timeout));
});
} else {
// 当前执行级别的指标组列表未全执行完成,

View File

@@ -34,10 +34,6 @@ import java.util.stream.Collectors;
@Slf4j
@Data
public class MetricsCollect implements Runnable, Comparable<MetricsCollect> {
/**
* 调度告警阈值时间 100ms
*/
private static final long WARN_DISPATCH_TIME = 100;
/**
* 监控ID
*/
@@ -247,10 +243,6 @@ public class MetricsCollect implements Runnable, Comparable<MetricsCollect> {
value = aliasFieldValueMap.get(realField);
}
}
// 处理可能带单位的指标数值 比如 34%, 34Mb并将数值小数点限制到4位
if (CommonConstants.TYPE_NUMBER == field.getType()) {
value = CommonUtil.parseDoubleStr(value, field.getUnit());
}
if (value == null) {
value = CommonConstants.NULL_VALUE;
}
@@ -275,15 +267,11 @@ public class MetricsCollect implements Runnable, Comparable<MetricsCollect> {
private CollectRep.MetricsData validateResponse(CollectRep.MetricsData.Builder builder) {
long endTime = System.currentTimeMillis();
builder.setTime(endTime);
long runningTime = endTime - startTime;
long allTime = endTime - newTime;
if (startTime - newTime >= WARN_DISPATCH_TIME) {
log.warn("[Collector Dispatch Warn, Dispatch Use {}ms.", startTime - newTime);
}
log.debug("[Collect]: newTime: {}, startTime: {}, spendTime: {}.", newTime, startTime, endTime - startTime);
if (builder.getCode() != CollectRep.Code.SUCCESS) {
log.info("[Collect Failed, Run {}ms, All {}ms] Reason: {}", runningTime, allTime, builder.getMsg());
log.info("[Collect Fail] Reason: {}", builder.getMsg());
} else {
log.info("[Collect Success, Run {}ms, All {}ms].", runningTime, allTime);
log.info("[Collect Success].");
}
return builder.build();
}

View File

@@ -1,35 +0,0 @@
package com.usthe.collector.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 采集器工具类
* @author tom
* @date 2022/4/6 09:35
*/
public class CollectUtil {
/**
* 关键字匹配计数
* @param content 内容
* @param keyword 关键字
* @return 匹配次数
*/
public static int countMatchKeyword(String content, String keyword) {
if (content == null || "".equals(content) || keyword == null || "".equals(keyword.trim())) {
return 0;
}
try {
Pattern pattern = Pattern.compile(keyword);
Matcher matcher = pattern.matcher(content);
int count = 0;
while (matcher.find()) {
count++;
}
return count;
} catch (Exception e) {
return 0;
}
}
}

View File

@@ -9,8 +9,6 @@ public interface CollectorConstants {
String RESPONSE_TIME = "responseTime";
String KEYWORD = "keyword";
String STATUS_CODE = "statusCode";
String ERROR_MSG = "errorMsg";

View File

@@ -4,7 +4,6 @@ import org.apache.commons.net.telnet.TelnetClient;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.net.ConnectException;
import static org.junit.jupiter.api.Assertions.*;
@@ -21,7 +20,7 @@ class TelnetCollectImplTest {
telnetClient = new TelnetClient("vt200");
telnetClient.setConnectTimeout(5000);
TelnetClient finalTelnetClient = telnetClient;
assertThrows(ConnectException.class,() -> finalTelnetClient.connect("127.0.0.1",0));
assertDoesNotThrow(() -> finalTelnetClient.connect("baidu.com",80));
telnetClient.disconnect();
} catch (IOException e) {
e.printStackTrace();

View File

@@ -23,7 +23,8 @@ import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_ONLY;
import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_WRITE;
/**
* 告警记录
* Alarm record entity 告警记录实体
*
* @author tom
* @date 2021/12/9 15:37
*/
@@ -33,52 +34,68 @@ import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_WRITE;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "告警记录实体")
@ApiModel(description = "en: Alarm record entity zh: 告警记录实体")
public class Alert {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@ApiModelProperty(value = "告警记录实体主键索引ID", example = "87584674384", accessMode = READ_ONLY, position = 0)
@ApiModelProperty(value = "Alarm record entity primary key index ID",
notes = "告警记录实体主键索引ID",
example = "87584674384", accessMode = READ_ONLY, position = 0)
private Long id;
@ApiModelProperty(value = "告警目标对象: 监控可用性-available 指标-app.metrics.field",
@ApiModelProperty(value = "Alert target object: monitor availability-available metrics-app.metrics.field",
notes = "告警目标对象: 监控可用性-available 指标-app.metrics.field",
example = "1", accessMode = READ_WRITE, position = 1)
@Length(max = 255)
private String target;
@ApiModelProperty(value = "告警对象关联的监控ID", example = "87432674336", accessMode = READ_WRITE, position = 2)
@ApiModelProperty(value = "Monitoring ID associated with the alarm object",
notes = "告警对象关联的监控ID",
example = "87432674336", accessMode = READ_WRITE, position = 2)
private Long monitorId;
@ApiModelProperty(value = "告警对象关联的监控名称", example = "Linux_192.132.23.1",
accessMode = READ_WRITE, position = 3)
@ApiModelProperty(value = "Monitoring name associated with the alarm object",
notes = "告警对象关联的监控名称",
example = "Linux_192.132.23.1", accessMode = READ_WRITE, position = 3)
private String monitorName;
@ApiModelProperty(value = "告警关联的告警定义ID", example = "8743267443543", accessMode = READ_WRITE, position = 4)
@ApiModelProperty(value = "Alarm definition ID associated with the alarm",
notes = "告警关联的告警定义ID",
example = "8743267443543", accessMode = READ_WRITE, position = 4)
private Long alertDefineId;
@ApiModelProperty(value = "告警级别 0:高-emergency-紧急告警-红色 1:中-critical-严重告警-橙色 2:低-warning-警告告警-黄色",
@ApiModelProperty(value = "Alarm level 0: high-emergency-critical alarm-red 1: medium-critical-critical alarm-orange 2: low-warning-warning alarm-yellow",
notes = "告警级别 0:高-emergency-紧急告警-红色 1:中-critical-严重告警-橙色 2:低-warning-警告告警-黄色",
example = "1", accessMode = READ_WRITE, position = 5)
@Min(0)
@Max(2)
private byte priority;
@ApiModelProperty(value = "告警通知实际内容", example = "linux_192.134.32.1: 534543534 cpu usage high",
@ApiModelProperty(value = "The actual content of the alarm notification",
notes = "告警通知实际内容",
example = "linux_192.134.32.1: 534543534 cpu usage high",
accessMode = READ_WRITE, position = 6)
@Length(max = 1024)
private String content;
@ApiModelProperty(value = "告警状态: 0-正常告警(待处理) 1-阈值触发但未达到告警次数 2-恢复告警 3-已处理",
@ApiModelProperty(value = "Alarm status: 0-normal alarm (to be processed) 1-threshold triggered but not reached the number of alarms 2-recovered alarm 3-processed",
notes = "告警状态: 0-正常告警(待处理) 1-阈值触发但未达到告警次数 2-恢复告警 3-已处理",
example = "1", accessMode = READ_WRITE, position = 7)
@Min(0)
@Max(2)
private byte status;
@ApiModelProperty(value = "告警阈值触发次数", example = "3", accessMode = READ_WRITE, position = 8)
@ApiModelProperty(value = "Alarm threshold trigger times",
notes = "告警阈值触发次数",
example = "3", accessMode = READ_WRITE, position = 8)
@Min(0)
@Max(10)
private int times;
@ApiModelProperty(value = "告警触发时间(毫秒时间戳)", example = "1612198922000", accessMode = READ_ONLY, position = 9)
@ApiModelProperty(value = "Alarm trigger time (timestamp in milliseconds)",
notes = "告警触发时间(毫秒时间戳)",
example = "1612198922000", accessMode = READ_ONLY, position = 9)
@Column(insertable = false, updatable = false)
private LocalDateTime gmtCreate;

View File

@@ -49,6 +49,7 @@ public class HttpProtocol {
* http请求携带的请求体
*/
private String payload;
/**
* 认证信息
*/
@@ -65,10 +66,6 @@ public class HttpProtocol {
* 数据解析脚本 当解析方式为 jsonPath or xmlPath时存在
*/
private String parseScript;
/**
* 内容关键字
*/
private String keyword;
/**
* 认证信息

View File

@@ -23,7 +23,9 @@ import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_ONLY;
import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_WRITE;
/**
* Message notification recipient entity
* 消息通知接收人实体
*
* @author tomsun28
* @date 2021/11/13 22:19
*/
@@ -33,56 +35,80 @@ import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_WRITE;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "消息通知接收人实体")
@ApiModel(description = "en: Message notification recipient entity,zh:消息通知接收人实体")
public class NoticeReceiver {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@ApiModelProperty(value = "接收人实体主键索引ID", example = "87584674384", accessMode = READ_ONLY, position = 0)
@ApiModelProperty(value = "Recipient entity primary key index ID",
notes = "接收人实体主键索引ID",
example = "87584674384", accessMode = READ_ONLY, position = 0)
private Long id;
@ApiModelProperty(value = "接收人名称", example = "tom", accessMode = READ_WRITE, position = 1)
@ApiModelProperty(value = "Recipient name",
notes = "接收人名称",
example = "tom", accessMode = READ_WRITE, position = 1)
@Length(max = 100)
@NotNull
private String name;
@ApiModelProperty(value = "通知信息方式: 0-手机短信 1-邮箱 2-webhook 3-微信公众号 4-企业微信机器人 5-钉钉机器人 6-飞书机器人", accessMode = READ_WRITE, position = 2)
@ApiModelProperty(value = "Notification information method: 0-SMS 1-Email 2-webhook 3-WeChat Official Account 4-Enterprise WeChat Robot 5-DingTalk Robot 6-FeiShu Robot",
notes = "通知信息方式: 0-手机短信 1-邮箱 2-webhook 3-微信公众号 4-企业微信机器人 5-钉钉机器人 6-飞书机器人",
accessMode = READ_WRITE, position = 2)
@Min(0)
@Max(8)
@NotNull
private Byte type;
@ApiModelProperty(value = "手机号, 通知方式为手机短信时有效", example = "18923435643", accessMode = READ_WRITE, position = 3)
@ApiModelProperty(value = "Mobile number: Valid when the notification method is SMS",
notes = "手机号 : 通知方式为手机短信时有效",
example = "18923435643", accessMode = READ_WRITE, position = 3)
@Length(max = 100)
private String phone;
@ApiModelProperty(value = "邮箱账号, 通知方式为邮箱时有效", example = "tom@qq.com", accessMode = READ_WRITE, position = 4)
@ApiModelProperty(value = "Email account: Valid when the notification method is email",
notes = "邮箱账号 : 通知方式为邮箱时有效",
example = "tom@qq.com", accessMode = READ_WRITE, position = 4)
@Length(max = 100)
private String email;
@ApiModelProperty(value = "URL地址, 通知方式为webhook有效", example = "https://www.tancloud.cn", accessMode = READ_WRITE, position = 5)
@ApiModelProperty(value = "URL address: The notification method is valid for webhook",
notes = "URL地址 : 通知方式为webhook有效",
example = "https://www.tancloud.cn", accessMode = READ_WRITE, position = 5)
@Length(max = 300)
private String hookUrl;
@ApiModelProperty(value = "openId, 通知方式为微信公众号或企业微信机器人有效", example = "343432", accessMode = READ_WRITE, position = 6)
@ApiModelProperty(value = "openId : The notification method is valid for WeChat official account or enterprise WeChat robot",
notes = "openId : 通知方式为微信公众号或企业微信机器人有效",
example = "343432", accessMode = READ_WRITE, position = 6)
@Length(max = 300)
private String wechatId;
@ApiModelProperty(value = "访问token, 通知方式为钉钉机器人有效", example = "34823984635647", accessMode = READ_WRITE, position = 7)
@ApiModelProperty(value = "Access token : The notification method is valid for DingTalk robot",
notes = "访问token : 通知方式为钉钉机器人有效",
example = "34823984635647", accessMode = READ_WRITE, position = 7)
@Length(max = 300)
private String accessToken;
@ApiModelProperty(value = "此条记录创建者", example = "tom", accessMode = READ_ONLY, position = 7)
@ApiModelProperty(value = "The creator of this record",
notes = "此条记录创建者",
example = "tom", accessMode = READ_ONLY, position = 7)
private String creator;
@ApiModelProperty(value = "此条记录最新修改者", example = "tom", accessMode = READ_ONLY, position = 8)
@ApiModelProperty(value = "This record was last modified by",
notes = "此条记录最新修改者",
example = "tom", accessMode = READ_ONLY, position = 8)
private String modifier;
@ApiModelProperty(value = "记录创建时间(毫秒时间戳)", example = "1612198922000", accessMode = READ_ONLY, position = 9)
@ApiModelProperty(value = "Record creation time (millisecond timestamp)",
notes = "记录创建时间(毫秒时间戳)",
example = "1612198922000", accessMode = READ_ONLY, position = 9)
@Column(insertable = false, updatable = false)
private LocalDateTime gmtCreate;
@ApiModelProperty(value = "记录最新修改时间(毫秒时间戳)", example = "1612198444000", accessMode = READ_ONLY, position = 10)
@ApiModelProperty(value = "Record the latest modification time (timestamp in milliseconds)",
notes = "记录最新修改时间(毫秒时间戳)",
example = "1612198444000", accessMode = READ_ONLY, position = 10)
@Column(insertable = false, updatable = false)
private LocalDateTime gmtUpdate;

View File

@@ -21,7 +21,9 @@ import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_ONLY;
import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_WRITE;
/**
* Notification strategy entity
* 通知策略
*
* @author tomsun28
* @date 2021/11/13 22:19
*/
@@ -31,45 +33,65 @@ import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_WRITE;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "通知策略实体")
@ApiModel(description = "en: Notify Policy Entity,zh: 通知策略实体")
public class NoticeRule {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@ApiModelProperty(value = "通知策略实体主键索引ID", example = "87584674384", accessMode = READ_ONLY, position = 0)
@ApiModelProperty(value = "Notification Policy Entity Primary Key Index ID",
notes = "通知策略实体主键索引ID",
example = "87584674384", accessMode = READ_ONLY, position = 0)
private Long id;
@ApiModelProperty(value = "策略名称", example = "dispatch-1", accessMode = READ_WRITE, position = 1)
@ApiModelProperty(value = "Policy name",
notes = "策略名称",
example = "dispatch-1", accessMode = READ_WRITE, position = 1)
@Length(max = 100)
@NotNull
private String name;
@ApiModelProperty(value = "接收人ID", example = "4324324", accessMode = READ_WRITE, position = 2)
@ApiModelProperty(value = "Recipient ID",
notes = "接收人ID",
example = "4324324", accessMode = READ_WRITE, position = 2)
@NotNull
private Long receiverId;
@ApiModelProperty(value = "接收人标识", example = "tom", accessMode = READ_WRITE, position = 3)
@ApiModelProperty(value = "Recipient identification",
notes = "接收人标识",
example = "tom", accessMode = READ_WRITE, position = 3)
@Length(max = 100)
@NotNull
private String receiverName;
@ApiModelProperty(value = "是否启用此策略", example = "true", accessMode = READ_WRITE, position = 4)
@ApiModelProperty(value = "Whether to enable this policy",
notes = "是否启用此策略",
example = "true", accessMode = READ_WRITE, position = 4)
private boolean enable = true;
@ApiModelProperty(value = "是否转发所有", example = "false", accessMode = READ_WRITE, position = 5)
@ApiModelProperty(value = "Whether to forward all",
notes = "是否转发所有",
example = "false", accessMode = READ_WRITE, position = 5)
private boolean filterAll = true;
@ApiModelProperty(value = "此条记录创建者", example = "tom", accessMode = READ_ONLY, position = 7)
@ApiModelProperty(value = "The creator of this record",
notes = "此条记录创建者",
example = "tom", accessMode = READ_ONLY, position = 7)
private String creator;
@ApiModelProperty(value = "此条记录最新修改者", example = "tom", accessMode = READ_ONLY, position = 8)
@ApiModelProperty(value = "This record was last modified by",
notes = "此条记录最新修改者",
example = "tom", accessMode = READ_ONLY, position = 8)
private String modifier;
@ApiModelProperty(value = "记录创建时间(毫秒时间戳)", example = "1612198922000", accessMode = READ_ONLY, position = 9)
@ApiModelProperty(value = "This record creation time (millisecond timestamp)",
notes = "记录创建时间(毫秒时间戳)",
example = "1612198922000", accessMode = READ_ONLY, position = 9)
@Column(insertable = false, updatable = false)
private LocalDateTime gmtCreate;
@ApiModelProperty(value = "记录最新修改时间(毫秒时间戳)", example = "1612198444000", accessMode = READ_ONLY, position = 10)
@ApiModelProperty(value = "Record the latest modification time (timestamp in milliseconds)",
notes = "记录最新修改时间(毫秒时间戳)",
example = "1612198444000", accessMode = READ_ONLY, position = 10)
@Column(insertable = false, updatable = false)
private LocalDateTime gmtUpdate;

View File

@@ -122,12 +122,6 @@ public class ParamDefine {
@ApiModelProperty(value = "当type为key-value时有效,表示value的别名描述", example = "Value", accessMode = READ_WRITE, position = 10)
private String valueAlias;
/**
* 是否是高级隐藏参数 true-是 false-否
*/
@ApiModelProperty(value = "是否是高级隐藏参数 true-是 false-否", example = "true", accessMode = READ_WRITE, position = 11)
private boolean hide = false;
/**
* 此条记录创建者
*/

View File

@@ -2,8 +2,6 @@ package com.usthe.common.util;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -17,7 +15,7 @@ public class CommonUtil {
private static final Pattern EMAIL_PATTERN = Pattern.compile("\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*");
private static final Pattern PHONE_PATTERN = Pattern.compile("^(((13[0-9])|(14[0-9])|(15[0-9])|(16[0-9])|(19[0-9])|(18[0-9])|(17[0-9]))+\\d{8})?$");
private static final Pattern PHONE_PATTERN = Pattern.compile("^(((13[0-9])|(15[0-9])|(18[0-9])|(17[0-9]))+\\d{8})?$");
private static final int PHONE_LENGTH = 11;
@@ -38,30 +36,6 @@ public class CommonUtil {
}
}
/**
* 将字符串str,此字符串可能带单位,转换为double数字类型
* 将数值小数点限制到4位
* @param str string
* @param unit 字符串单位
* @return string格式的 double 数字 小数点最大到4位
*/
public static String parseDoubleStr(String str, String unit) {
if (str == null || "".equals(str)) {
return null;
}
try {
if (unit != null && str.endsWith(unit)) {
str = str.substring(0, str.length() - unit.length());
}
BigDecimal bigDecimal = new BigDecimal(str);
double value = bigDecimal.setScale(4, RoundingMode.HALF_UP).doubleValue();
return String.valueOf(value);
} catch (Exception e) {
log.debug(e.getMessage(), e);
return null;
}
}
/**
* 邮箱格式校验
* @param email 邮箱

View File

@@ -1,40 +0,0 @@
package com.usthe.common.util;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author tom
* @date 2022/4/7 17:18
*/
class CommonUtilTest {
@Test
void testParseDoubleStr() {
assertEquals("9.3454",CommonUtil.parseDoubleStr("9.345435345", null));
assertEquals("9.3454",CommonUtil.parseDoubleStr("9.345435345%", "%"));
assertEquals("10.0",CommonUtil.parseDoubleStr("10%", "%"));
assertEquals("588.0",CommonUtil.parseDoubleStr("588Mb", "Mb"));
}
@Test
void validateEmail() {
assertTrue(CommonUtil.validateEmail("tom@usthe.com"));
assertTrue(CommonUtil.validateEmail("demo@qq.com"));
assertFalse(CommonUtil.validateEmail("tom.usthe.com"));
}
@Test
void validatePhoneNum() {
assertTrue(CommonUtil.validatePhoneNum("19234554432"));
assertTrue(CommonUtil.validatePhoneNum("13234554432"));
assertTrue(CommonUtil.validatePhoneNum("14234554432"));
assertTrue(CommonUtil.validatePhoneNum("16234554432"));
assertFalse(CommonUtil.validatePhoneNum("12234554432"));
assertFalse(CommonUtil.validatePhoneNum("11234554432"));
assertFalse(CommonUtil.validatePhoneNum("35234554432"));
assertFalse(CommonUtil.validatePhoneNum("46234554432"));
}
}

View File

@@ -1,92 +0,0 @@
---
title: HertzBeat入GVP啦并 v1.0.beta.7 发布,易用友好的云监控系统
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孵化的支持网站APIPING端口数据库全站操作系统等监控类型支持阈值告警告警通知(邮箱webhook钉钉企业微信飞书机器人),拥有易用友好的可视化操作界面的开源监控告警项目。
很高兴Hertzbeat被评定为GVP - Gitee最有价值开源项目
![截屏2022-04-08 09.14.44.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8899bc4e836943dba2ec9efeec4ff629~tplv-k3u1fbpfcp-watermark.image?)
老哥们帮忙在Gitee STAR起来https://gitee.com/dromara/hertzbeat
官网:hertzbeat.com | tancloud.cn
然后来说说最新的版本这个版本看这么多feature其实简单来说主要是这几个
支持了ORACLE数据库的监控包括ORACLE的基本信息表空间连接数TPSQPS等指标
支持了LINUX的CPU利用率内存利用率磁盘占用相关指标使LINUX监控贴合实际业务
还有前端参数支持了KEY-VALUE以后我们就可以在页面上配置HTTP Headers等类似参数了还有就是参数配置那优化改版把非常用告警参数隐藏起来了稍微好看些然后支持了windows下bat启动脚本更多的就是稳定性的提升和一些其它的小修复小需求啦
版本特性:
1. feature 支持oracle数据库监控类型-xgf 由 @gf-8 贡献 thanks
2. feature oracle监控支持tablespace,连接数,qps,tps等指标
3. feature linux监控支持设置超时时间 (#49)
4. feature 检测网站SSL证书是否过期 (#50) 由 @weihongbin 提出 thanks
5. feature 页面配置参数支持KEY-VALUE数组(#57)
6. feature API和网站监控支持页面配置Headers和Params (#58)(#59)
7. feature API和网站监控支持页面配置 basic auth, digest auth (#60)
8. feature http 端口跟随SSL是否启用变更443或80 (#61)
9. feature 修改默认超时时间3000毫秒为6000毫秒 (#55)
10. feature:make tdengine optional, not required (#62)
11. feature:support win bat service (#65)
12. feature:support hide advanced params define (#68)
13. feature:enable auto redirect when 301 302 http code (#69)
14. feature:only collect available metrics when detect (#70)
15. feature:[website api]monitor support keyword match (#72)
16. feature:support linux cpu usage,memory usage,disk free (#76)
BUG修复
1. 添加sqlserver关联文档fix connection指标入库tdengine失败 (#41)
2. 使用docker部署TDengine开放tcp访问端口!16 由 @老姜bei 贡献 thanks
3. 补充sureness配置文档 避免误配导致权限异常
4. bugfix:monitors always timeout alert (#67)
5. code format and optimization 由 @学习代码的小白 贡献 thanks
6. bugfix: remove oracle field - database_type due 11g not support 由 @syongaaa 贡献 thanks
7. bugfix:fix linux interface metrics no instance (#75)
欢迎在线试用 https://console.tancloud.cn.
-----------------------
> [HertzBeat赫兹跳动](https://github.com/dromara/hertzbeat) 是一个支持网站APIPING端口数据库操作系统等监控类型拥有易用友好的可视化操作界面的开源监控告警项目。
> 我们也提供了对应的 **[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/BV1DY4y1i7ts
欢迎在线试用 [https://console.tancloud.cn](https://gitee.com/link?target=https%3A%2F%2Fconsole.tancloud.cn)
优化后的参数输入界面:
![输入图片说明](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c4b07908ba5a4b50a094a02dde6a38f3~tplv-k3u1fbpfcp-zoom-1.image "截屏2022-04-07 21.32.52.png")
Linux新增指标:
![输入图片说明](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/92828224f8cd4cac84245aa4217b29e7~tplv-k3u1fbpfcp-zoom-1.image "截屏2022-04-07 17.50.22.png")
ORACLE监控:
哦豁oracle环境不在了之前没有截图先脑补一张
**仓库地址**
[Github](https://github.com/dromara/hertzbeat) https://github.com/dromara/hertzbeat
[Gitee](https://gitee.com/dromara/hertzbeat) https://gitee.com/dromara/hertzbeat
看到这里不妨给个Star支持下哦灰常感谢弯腰!!

View File

@@ -38,7 +38,6 @@ sidebar_label: Linux操作系统
| interrupt | 个数 | CPU中断数量 |
| load | 无 | CPU最近1/5/15分钟的平均负载 |
| context_switch | 个数 | 当前上下文切换数量 |
| usage | % | CPU使用率 |
#### 指标集合memory
@@ -50,7 +49,6 @@ sidebar_label: Linux操作系统
| free | Mb | 空闲内存容量 |
| buff_cache | Mb | 缓存占用内存 |
| available | Mb | 剩余可用内存容 |
| usage | % | 内存使用率 |
#### 指标集合disk
@@ -70,12 +68,3 @@ sidebar_label: Linux操作系统
| receive_bytes | byte | 入站数据流量(bytes) |
| transmit_bytes | byte | 出站数据流量(bytes) |
#### 指标集合disk_free
| 指标名称 | 指标单位 | 指标帮助描述 |
| ----------- | ----------- | ----------- |
| filesystem | 无 | 文件系统的名称 |
| used | Mb | 已使用磁盘大小 |
| available | Mb | 可用磁盘大小 |
| usage | % | 使用率 |
| mounted | 无 | 挂载点目录 |

View File

@@ -18,11 +18,10 @@ TDengine是一款国产的开源物联网时序型数据库我们使用其替
```
2. Docker安装TDengine
```
$ docker run -d -p 6030-6049:6030-6049 -p 6030-6049:6030-6049/udp -v /opt/taosdata:/var/lib/taos --name tdengine -e TZ=Asia/Shanghai tdengine/tdengine:2.4.0.12
$ docker run -d -p 6030-6049:6030-6049 -p 6030-6049:6030-6049/udp -v /opt/taosdata:/var/lib/taos --name tdengine tdengine/tdengine:2.4.0.12
526aa188da767ae94b244226a2b2eec2b5f17dd8eff594533d9ec0cd0f3a1ccd
```
`-v /opt/taosdata:/var/lib/taos` 为tdengine数据目录本地持久化挂载需将`/opt/taosdata`替换为实际本地存在的目录
`-e TZ="Asia/Shanghai"` 为tdengine设置时区这里可选设置对应的时区
使用```$ docker ps```查看数据库是否启动成功
### 创建数据库实例

View File

@@ -28,7 +28,7 @@ function Home() {
<h1 className="hero__title">
<img style={{width: '500px', marginTop: '100px'}} src={cdnTransfer('img/hertzbeat-brand.svg')} alt={'#'}/>
</h1>
<p className="hero__subtitle"><Translate>易用友好的监控系统</Translate></p>
<p className="hero__subtitle"><Translate>易用友好的监控告警系统</Translate></p>
<div className={styles.social}>
<a href="https://console.tancloud.cn"><img src={cdnTransfer('img/badge/web-monitor.svg')} alt={''}/></a>
<a href="https://console.tancloud.cn"><img src={cdnTransfer('img/badge/ping-connect.svg')} alt={''}/></a>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -30,6 +30,7 @@ import java.util.Date;
import java.util.List;
/**
* Alarm information storage and distribution
* 告警信息入库分发
*
* @author tom
@@ -71,7 +72,7 @@ public class DispatchAlarm {
try {
Alert alert = dataQueue.pollAlertData();
if (alert != null) {
// 判断告警类型入库
// Determining alarm type storage 判断告警类型入库
storeAlertData(alert);
// 通知分发
sendAlertDataListener(alert);
@@ -87,7 +88,7 @@ public class DispatchAlarm {
}
private void storeAlertData(Alert alert) {
// todo 使用缓存不直接操作库
// todo Using the cache does not directly manipulate the library 使用缓存不直接操作库
Monitor monitor = monitorService.getMonitor(alert.getMonitorId());
if (monitor == null) {
log.warn("Dispatch alarm the monitorId: {} not existed, ignored.", alert.getMonitorId());
@@ -95,34 +96,38 @@ public class DispatchAlarm {
}
alert.setMonitorName(monitor.getName());
if (monitor.getStatus() == CommonConstants.UN_MANAGE_CODE) {
// When monitoring is not managed, ignore and silence its alarm messages
// 当监控未管理时 忽略静默其告警信息
return;
}
if (monitor.getStatus() == CommonConstants.AVAILABLE_CODE) {
if (CommonConstants.AVAILABLE.equals(alert.getTarget())) {
// Availability Alarm Need to change the monitoring status to unavailable
// 可用性告警 需变更监控状态为不可用
monitorService.updateMonitorStatus(monitor.getId(), CommonConstants.UN_AVAILABLE_CODE);
} else if (CommonConstants.REACHABLE.equals(alert.getTarget())) {
// Reachability alarm The monitoring status needs to be changed to unreachable
// 可达性告警 需变更监控状态为不可达
monitorService.updateMonitorStatus(monitor.getId(), CommonConstants.UN_REACHABLE_CODE);
}
} else {
// If the alarm is restored, the monitoring state needs to be restored
// 若是恢复告警 需对监控状态进行恢复
if (alert.getStatus() == CommonConstants.ALERT_STATUS_CODE_RESTORED) {
monitorService.updateMonitorStatus(alert.getMonitorId(), CommonConstants.AVAILABLE_CODE);
}
}
// 告警落库
// Alarm drop library 告警落库
alertService.addAlert(alert);
}
private void sendAlertDataListener(Alert alert) {
// todo 转发配置的邮件 微信 webhook
// todo Forward configured email WeChat webhook 转发配置的邮件 微信 webhook
List<NoticeReceiver> receivers = matchReceiverByNoticeRules(alert);
// todo 发送通知这里暂时单线程
// todo Send notification here temporarily single thread 发送通知这里暂时单线程
for (NoticeReceiver receiver : receivers) {
switch (receiver.getType()) {
// todo 短信通知
// todo SMS notification 短信通知
case 0:
break;
case 1:
@@ -150,10 +155,11 @@ public class DispatchAlarm {
}
/**
* Send alert information through FeiShu
* 通过飞书发送告警信息
*
* @param receiver 接收人
* @param alert 告警信息
* @param receiver Notification configuration information 通知配置信息
* @param alert Alarm information 告警信息
*/
private void sendFlyBookAlert(NoticeReceiver receiver, Alert alert) {
FlyBookWebHookDto flyBookWebHookDto = new FlyBookWebHookDto();
@@ -199,10 +205,11 @@ public class DispatchAlarm {
}
/**
* Send alarm information through DingTalk robot
* 通过钉钉机器人发送告警信息
*
* @param receiver 通知配置信息
* @param alert 告警信息
* @param receiver Notification configuration information 通知配置信息
* @param alert Alarm information 告警信息
*/
private void sendDingTalkRobotAlert(NoticeReceiver receiver, Alert alert) {
DingTalkWebHookDto dingTalkWebHookDto = new DingTalkWebHookDto();
@@ -233,10 +240,11 @@ public class DispatchAlarm {
}
/**
* Send alarm information through enterprise WeChat
* 通过企业微信发送告警信息
*
* @param receiver 通知配置信息
* @param alert 告警信息
* @param receiver Notification configuration information 通知配置信息
* @param alert Alarm information 告警信息
*/
private void sendWeWorkRobotAlert(NoticeReceiver receiver, Alert alert) {
WeWorkWebHookDto weWorkWebHookDTO = new WeWorkWebHookDto();
@@ -296,23 +304,23 @@ public class DispatchAlarm {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
messageHelper.setSubject("TanCloud探云-监控告警");
//设置发件人Email
//Set sender Email 设置发件人Email
messageHelper.setFrom(emailFromUser);
//设定收件人Email
//Set recipient Email 设定收件人Email
messageHelper.setTo(receiver.getEmail());
messageHelper.setSentDate(new Date());
//构建邮件模版
//Build email templates 构建邮件模版
String process = mailService.buildAlertHtmlTemplate(alert);
//设置邮件内容模版
//Set Email Content Template 设置邮件内容模版
messageHelper.setText(process, true);
javaMailSender.send(mimeMessage);
} catch (Exception e) {
log.error("[邮箱告警] errorException information={}", e.getMessage());
log.error("[Email Alert] ExceptionException information={}", e.getMessage());
}
}
private List<NoticeReceiver> matchReceiverByNoticeRules(Alert alert) {
// todo 使用缓存
// todo use cache 使用缓存
return noticeConfigService.getReceiverFilterRule(alert);
}

View File

@@ -28,11 +28,13 @@ import java.util.List;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
/**
* Message Notification Configuration API
* 消息通知配置API
*
* @author tom
* @date 2021/12/16 16:18
*/
@Api(tags = "消息通知配置API")
@Api(tags = "en: Message Notification Configuration API,zh: 消息通知配置API")
@RestController()
@RequestMapping(value = "/notice", produces = {APPLICATION_JSON_VALUE})
public class NoticeConfigController {
@@ -41,33 +43,36 @@ public class NoticeConfigController {
private NoticeConfigService noticeConfigService;
@PostMapping(path = "/receiver")
@ApiOperation(value = "新增接收人", notes = "新增一个接收人")
@ApiOperation(value = "Add a recipient", notes = "新增一个接收人")
public ResponseEntity<Message<Void>> addNewNoticeReceiver(@Valid @RequestBody NoticeReceiver noticeReceiver) {
noticeConfigService.addReceiver(noticeReceiver);
return ResponseEntity.ok(new Message<>("Add success"));
}
@PutMapping(path = "/receiver")
@ApiOperation(value = "修改接收人", notes = "修改已存在的接收人信息")
@ApiOperation(value = "Modify existing recipient information", notes = "修改已存在的接收人信息")
public ResponseEntity<Message<Void>> editNoticeReceiver(@Valid @RequestBody NoticeReceiver noticeReceiver) {
noticeConfigService.editReceiver(noticeReceiver);
return ResponseEntity.ok(new Message<>("Edit success"));
}
@DeleteMapping(path = "/receiver/{id}")
@ApiOperation(value = "删除指定接收人", notes = "删除已存在的接收人信息")
@ApiOperation(value = "Delete existing recipient information", notes = "删除已存在的接收人信息")
public ResponseEntity<Message<Void>> deleteNoticeReceiver(
@ApiParam(value = "接收人ID", example = "6565463543") @PathVariable("id") final Long receiverId) {
// 不存在或删除成功都返回成功
@ApiParam(value = "en: Recipient ID,zh: 接收人ID", example = "6565463543") @PathVariable("id") final Long receiverId) {
// Returns success if it does not exist or if the deletion is successful
// todo 不存在或删除成功都返回成功
noticeConfigService.deleteReceiver(receiverId);
return ResponseEntity.ok(new Message<>("Delete success"));
}
@GetMapping(path = "/receivers")
@ApiOperation(value = "查询消息通知接收人", notes = "根据查询过滤项获取消息通知接收人列表")
@ApiOperation(value = "Get a list of message notification recipients based on query filter items",
notes = "根据查询过滤项获取消息通知接收人列表")
public ResponseEntity<Message<List<NoticeReceiver>>> getReceivers(
@ApiParam(value = "接收人名称,模糊查询", example = "tom") @RequestParam(required = false) final String name) {
@ApiParam(value = "en: Recipient name,zh: 接收人名称,模糊查询", example = "tom") @RequestParam(required = false) final String name) {
//todo Writing can be optimized 写法可优化
Specification<NoticeReceiver> specification = (root, query, criteriaBuilder) -> {
Predicate predicate = criteriaBuilder.conjunction();
if (name != null && !"".equals(name)) {
@@ -83,32 +88,34 @@ public class NoticeConfigController {
@PostMapping(path = "/rule")
@ApiOperation(value = "新增通知策略", notes = "新增一个通知策略")
@ApiOperation(value = "Add a notification policy", notes = "新增一个通知策略")
public ResponseEntity<Message<Void>> addNewNoticeRule(@Valid @RequestBody NoticeRule noticeRule) {
noticeConfigService.addNoticeRule(noticeRule);
return ResponseEntity.ok(new Message<>("Add success"));
}
@PutMapping(path = "/rule")
@ApiOperation(value = "修改通知策略", notes = "修改已存在的通知策略信息")
@ApiOperation(value = "Modify existing notification policy information", notes = "修改已存在的通知策略信息")
public ResponseEntity<Message<Void>> editNoticeRule(@Valid @RequestBody NoticeRule noticeRule) {
noticeConfigService.editNoticeRule(noticeRule);
return ResponseEntity.ok(new Message<>("Edit success"));
}
@DeleteMapping(path = "/rule/{id}")
@ApiOperation(value = "删除指定通知策略", notes = "删除已存在的通知策略信息")
@ApiOperation(value = "Delete existing notification policy information", notes = "删除已存在的通知策略信息")
public ResponseEntity<Message<Void>> deleteNoticeRule(
@ApiParam(value = "通知策略ID", example = "6565463543") @PathVariable("id") final Long ruleId) {
// 不存在或删除成功都返回成功
@ApiParam(value = "en: Notification Policy ID,zh: 通知策略ID", example = "6565463543") @PathVariable("id") final Long ruleId) {
// Returns success if it does not exist or if the deletion is successful
// todo 不存在或删除成功都返回成功
noticeConfigService.deleteNoticeRule(ruleId);
return ResponseEntity.ok(new Message<>("Delete success"));
}
@GetMapping(path = "/rules")
@ApiOperation(value = "查询消息通知策略", notes = "根据查询过滤项获取消息通知策略列表")
@ApiOperation(value = "Get a list of message notification policies based on query filter items",
notes = "根据查询过滤项获取消息通知策略列表")
public ResponseEntity<Message<List<NoticeRule>>> getRules(
@ApiParam(value = "接收人名称,模糊查询", example = "rule1") @RequestParam(required = false) final String name) {
@ApiParam(value = "en: Recipient name,zh: 接收人名称,模糊查询", example = "rule1") @RequestParam(required = false) final String name) {
Specification<NoticeRule> specification = (root, query, criteriaBuilder) -> {
Predicate predicate = criteriaBuilder.conjunction();

View File

@@ -18,11 +18,13 @@ import java.util.List;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
/**
* System Summary Statistics API
* 系统摘要统计API
*
* @author tom
* @date 2021/12/7 15:57
*/
@Api(tags = "系统摘要统计API")
@Api(tags = "en: System Summary Statistics API,zh: 系统摘要统计API")
@RestController
@RequestMapping(path = "/summary", produces = {APPLICATION_JSON_VALUE})
public class SummaryController {
@@ -31,7 +33,7 @@ public class SummaryController {
private MonitorService monitorService;
@GetMapping
@ApiOperation(value = "查询应用类别监控统计", notes = "查询所有应用类别监控统计信息")
@ApiOperation(value = "Query all application category monitoring statistics", notes = "查询所有应用类别监控统计信息")
public ResponseEntity<Message<Dashboard>> appMonitors() {
List<AppCount> appsCount = monitorService.getAllAppMonitorsCount();
Message<Dashboard> message = new Message<>(new Dashboard(appsCount));

View File

@@ -14,6 +14,7 @@ import java.util.Set;
/**
* AuthResources 数据库操作
*
* @author tomsun28
* @date 2021/11/14 11:24
*/
@@ -22,12 +23,14 @@ public interface MonitorDao extends JpaRepository<Monitor, Long>, JpaSpecificati
/**
* 根据监控ID列表删除监控
*
* @param monitorIds 监控ID列表
*/
void deleteAllByIdIn(Set<Long> monitorIds);
/**
* 根据监控ID列表查询监控
*
* @param monitorIds 监控ID列表
* @return 监控列表
*/
@@ -35,6 +38,7 @@ public interface MonitorDao extends JpaRepository<Monitor, Long>, JpaSpecificati
/**
* 根据监控类型查询监控
*
* @param app 监控类型
* @return 监控列表
*/
@@ -42,29 +46,35 @@ public interface MonitorDao extends JpaRepository<Monitor, Long>, JpaSpecificati
/**
* 查询已下发采集任务的监控
*
* @param status 监控状态
* @return 监控列表
*/
List<Monitor> findMonitorsByStatusNotInAndAndJobIdNotNull(List<Byte> status);
/**
* 根据监控名称查询监控
* @param name 监控名称
* @return 监控列表
* Query monitoring by monitoring name 根据监控名称查询监控
*
* @param name monitoring name 监控名称
* @return monitoring list 监控列表
*/
Optional<Monitor> findMonitorByNameEquals(String name);
/**
* Query the monitoring category - the number of monitoring corresponding to the status
* 查询监控类别-状态对应的监控数量
* @return 监控类别-状态与监控数量映射
*
* @return Monitoring Category-Status and Monitoring Quantity Mapping 监控类别-状态与监控数量映射
*/
@Query("select new com.usthe.manager.pojo.dto.AppCount(mo.app, mo.status, COUNT(mo.id)) from Monitor mo group by mo.app, mo.status")
List<AppCount> findAppsStatusCount();
/**
* Update the status of the specified monitor
* 更新指定监控的状态
* @param id 监控ID
* @param status 监控状态
*
* @param id Monitor ID 监控ID
* @param status 监控状态 Monitor Status
*/
@Modifying
@Query("update Monitor set status = :status where id = :id")

View File

@@ -6,7 +6,7 @@ import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
/**
* 邮箱发送服务
* Email delivery service 邮箱发送服务
*
* @author 花城
* @version 1.0
@@ -15,9 +15,11 @@ import org.springframework.stereotype.Service;
public interface MailService {
/**
* Build an alert email template
* 构建告警邮件模版
* @param alert 告警信息
* @return 邮件内容
*
* @param alert Alarm data element information 告警数据元信息
* @return content of email 邮件内容
*/
String buildAlertHtmlTemplate(Alert alert);
}

View File

@@ -15,6 +15,7 @@ import java.util.Set;
/**
* 监控管理服务
*
* @author tomsun28
* @date 2021/11/14 11:28
*/
@@ -23,6 +24,7 @@ public interface MonitorService {
/**
* 监控可用性探测
*
* @param monitor 监控实体信息
* @param params 参数信息
* @throws MonitorDetectException 探测失败抛出
@@ -31,6 +33,7 @@ public interface MonitorService {
/**
* 新增监控
*
* @param monitor 监控实体
* @param params 参数信息
* @throws RuntimeException 新增过程异常抛出
@@ -39,6 +42,7 @@ public interface MonitorService {
/**
* 校验请求数据参数正确性
*
* @param monitorDto monitorDto
* @param isModify 是否是修改监控
* @throws IllegalArgumentException 校验参数错误抛出
@@ -47,6 +51,7 @@ public interface MonitorService {
/**
* 修改更新监控
*
* @param monitor 监控实体
* @param params 参数信息
* @throws RuntimeException 修改过程中异常抛出
@@ -55,6 +60,7 @@ public interface MonitorService {
/**
* 删除监控
*
* @param id 监控ID
* @throws RuntimeException 删除过程中异常抛出
*/
@@ -62,6 +68,7 @@ public interface MonitorService {
/**
* 批量删除监控
*
* @param ids 监控ID
* @throws RuntimeException 删除过程中异常抛出
*/
@@ -69,6 +76,7 @@ public interface MonitorService {
/**
* 获取监控信息
*
* @param id 监控ID
* @return MonitorDto
* @throws RuntimeException 查询过程中异常抛出
@@ -77,6 +85,7 @@ public interface MonitorService {
/**
* 动态条件查询
*
* @param specification 查询条件
* @param pageRequest 分页参数
* @return 查询结果
@@ -85,38 +94,46 @@ public interface MonitorService {
/**
* 根据监控ID列表批量取消纳管监控项
*
* @param ids 监控IDs
*/
void cancelManageMonitors(HashSet<Long> ids);
/**
* 根据监控ID列表批量启动纳管监控项
*
* @param ids 监控IDs
*/
void enableManageMonitors(HashSet<Long> ids);
/**
* 查询监控类别及其对应的监控数量
*
* @return 监控类别与监控数量映射
*/
List<AppCount> getAllAppMonitorsCount();
/**
* Query monitoring
* 查询监控
* @param monitorId 监控ID
* @return 监控信息
*
* @param monitorId Monitor ID 监控ID
* @return Monitor information 监控信息
*/
Monitor getMonitor(Long monitorId);
/**
* Update the status of the specified monitor
* 更新指定监控的状态
* @param monitorId 监控ID
* @param status 监控状态
*
* @param monitorId monitorId 监控ID
* @param status monitor status 监控状态
*/
void updateMonitorStatus(Long monitorId, byte status);
/**
* 查询指定监控类型下的所有监控信息列表
*
* @param app 监控类型
* @return 监控列表
*/

View File

@@ -8,66 +8,86 @@ import org.springframework.data.jpa.domain.Specification;
import java.util.List;
/**
* Message notification configuration interface
* 消息通知配置接口
*
* @author tom
* @date 2021/12/16 16:14
*/
public interface NoticeConfigService {
/**
* Dynamic conditional query
* 动态条件查询
* @param specification 查询条件
* @return 查询结果
*
* @param specification Query conditions 查询条件
* @return Search result 查询结果
*/
List<NoticeReceiver> getNoticeReceivers(Specification<NoticeReceiver> specification);
/**
* Dynamic conditional query
* 动态条件查询
* @param specification 查询条件
* @return 查询结果
*
* @param specification Query conditions 查询条件
* @return Search result 查询结果
*/
List<NoticeRule> getNoticeRules(Specification<NoticeRule> specification);
/**
* Add a notification recipient
* 新增一个通知接收人
* @param noticeReceiver 接收人信息
*
* @param noticeReceiver recipient information 接收人信息
*/
void addReceiver(NoticeReceiver noticeReceiver);
/**
* Modify notification recipients
* 修改通知接收人
* @param noticeReceiver 接收人信息
*
* @param noticeReceiver recipient information 接收人信息
*/
void editReceiver(NoticeReceiver noticeReceiver);
/**
* Delete recipient information based on recipient ID
* 根据接收人ID删除接收人信息
* @param receiverId 接收人ID
*
* @param receiverId Recipient ID 接收人ID
*/
void deleteReceiver(Long receiverId);
/**
* Added notification policy
* 新增通知策略
* @param noticeRule 通知策略
*
* @param noticeRule Notification strategy 通知策略
*/
void addNoticeRule(NoticeRule noticeRule);
/**
* Modify Notification Policy
* 修改通知策略
* @param noticeRule 通知策略
*
* @param noticeRule Notification strategy 通知策略
*/
void editNoticeRule(NoticeRule noticeRule);
/**
* Delete the specified notification policy
* 删除指定的通知策略
* @param ruleId 通知策略ID
*
* @param ruleId Notification Policy ID 通知策略ID
*/
void deleteNoticeRule(Long ruleId);
/**
* According to the alarm information matching all notification policies, filter out the recipients who need to be notified
* 根据告警信息与所有通知策略匹配,过滤出需要通知的接收人
* @param alert 告警信息
* @return 接收人
*
* @param alert Alarm information 告警信息
* @return Receiver 接收人
*/
List<NoticeReceiver> getReceiverFilterRule(Alert alert);
}

View File

@@ -22,6 +22,7 @@ import com.usthe.manager.service.AppService;
import com.usthe.manager.service.MonitorService;
import com.usthe.manager.support.exception.MonitorDatabaseException;
import com.usthe.manager.support.exception.MonitorDetectException;
import jdk.nashorn.internal.runtime.regexp.joni.constants.Traverse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
@@ -40,6 +41,7 @@ import java.util.stream.Collectors;
/**
* 监控管理服务实现
*
* @author tomsun28
* @date 2021/11/14 13:06
*/
@@ -79,10 +81,6 @@ public class MonitorServiceImpl implements MonitorService {
List<Configmap> configmaps = params.stream().map(param ->
new Configmap(param.getField(), param.getValue(), param.getType())).collect(Collectors.toList());
appDefine.setConfigmap(configmaps);
// 探测可用性只需要采集优先级为0的可用性指标集合
List<Metrics> availableMetrics = appDefine.getMetrics().stream()
.filter(item -> item.getPriority() == 0).collect(Collectors.toList());
appDefine.setMetrics(availableMetrics);
List<CollectRep.MetricsData> collectRep = collectJobService.collectSyncJobData(appDefine);
// 判断探测结果 失败则抛出探测异常
if (collectRep == null || collectRep.isEmpty()) {
@@ -391,7 +389,8 @@ public class MonitorServiceImpl implements MonitorService {
if (appCounts == null) {
return null;
}
// 关联大类别信息 计算每个状态对应数量
//Statistical category information, calculate the number of corresponding states for each monitor
//统计类别信息,计算每个监控分别对应状态的数量
Map<String, AppCount> appCountMap = new HashMap<>(appCounts.size());
for (AppCount item : appCounts) {
AppCount appCount = appCountMap.getOrDefault(item.getApp(), new AppCount());
@@ -409,10 +408,13 @@ public class MonitorServiceImpl implements MonitorService {
case CommonConstants.UN_REACHABLE_CODE:
appCount.setUnReachableSize(appCount.getUnReachableSize() + item.getSize());
break;
default: break;
default:
break;
}
appCountMap.put(item.getApp(), appCount);
}
//Traverse the map obtained by statistics and convert it into a List<App Count> result set
//遍历统计得到的map转换成List<App Count>结果集
return appCountMap.values().stream().peek(item -> {
item.setSize(item.getAvailableSize() + item.getUnManageSize()
+ item.getUnReachableSize() + item.getUnAvailableSize());

View File

@@ -4,7 +4,7 @@ category: custom
app: example
name:
zh-CN: 模拟应用类型
en-US: EXAMPLE
en-US: EXAMPLE APP
# 参数映射map. type是参数类型: 0-number数字, 1-string明文字符串, 2-secret加密字符串, 3-map映射的json串
# 强制固定必须参数 - host
configmap:

View File

@@ -32,8 +32,6 @@ configmap:
type: 3
- key: params
type: 3
- key: keyword
type: 1
# 指标组列表
metrics:
# 第一个监控指标组 cpu
@@ -48,9 +46,6 @@ metrics:
- field: responseTime
type: 0
unit: ms
- field: keyword
type: 0
unit: 次数
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
protocol: http
# 当protocol为http协议时具体的采集配置
@@ -84,4 +79,3 @@ metrics:
# 响应数据解析方式: default-系统规则,jsonPath-jsonPath脚本,website-网站可用性指标监控
# todo xmlPath-xmlPath脚本,prometheus-Prometheus数据规则
parseType: website
keyword: ^_^keyword^_^

View File

@@ -2,7 +2,7 @@ category: service
app: fullsite
name:
zh-CN: 全站监控
en-US: SITE MAP
en-US: FULL WEBSITE MONITOR
configmap:
- key: host
type: 1

View File

@@ -68,26 +68,6 @@ metrics:
- field: context_switch
type: 0
unit: 个数
- field: usage
type: 0
unit: '%'
# (非必须)监控指标别名,与上面的指标名映射。用于采集接口数据字段不直接是最终指标名称,需要此别名做映射转换
aliasFields:
- info
- cores
- interrupt
- load
- context_switch
- idle
# (非必须)指标计算表达式,与上面的别名一起作用,计算出最终需要的指标值
# eg: cores=core1+core2, usage=usage, waitTime=allTime-runningTime
calculates:
- info=info
- cores=cores
- interrupt=interrupt
- load=load
- context_switch=context_switch
- usage=100-idle
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
protocol: ssh
# 当protocol为http协议时具体的采集配置
@@ -99,7 +79,7 @@ metrics:
username: ^_^username^_^
password: ^_^password^_^
timeout: ^_^timeout^_^
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}';vmstat 1 1 | awk 'NR==3{print $15}'"
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
@@ -121,25 +101,6 @@ metrics:
- field: available
type: 0
unit: Mb
- field: usage
type: 0
unit: '%'
# (非必须)监控指标别名,与上面的指标名映射。用于采集接口数据字段不直接是最终指标名称,需要此别名做映射转换
aliasFields:
- total
- used
- free
- buff_cache
- available
# (非必须)指标计算表达式,与上面的别名一起作用,计算出最终需要的指标值
# eg: cores=core1+core2, usage=usage, waitTime=allTime-runningTime
calculates:
- total=total
- used=used
- free=free
- buff_cache=buff_cache
- available=available
- usage=(used / total) * 100
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
protocol: ssh
# 当protocol为http协议时具体的采集配置
@@ -193,7 +154,6 @@ metrics:
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
- field: interface_name
type: 1
instance: true
- field: receive_bytes
type: 0
unit: byte
@@ -213,35 +173,3 @@ metrics:
timeout: ^_^timeout^_^
script: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print "interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}'
parseType: multiRow
- name: disk_free
priority: 5
fields:
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 instance是否为实例主键 unit:指标单位
- field: filesystem
type: 1
- field: used
type: 0
unit: Mb
- field: available
type: 0
unit: Mb
- field: usage
type: 0
unit: '%'
- field: mounted
type: 1
instance: true
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
protocol: ssh
# 当protocol为http协议时具体的采集配置
ssh:
# 主机host: ipv4 ipv6 域名
host: ^_^host^_^
# 端口
port: ^_^port^_^
username: ^_^username^_^
password: ^_^password^_^
timeout: ^_^timeout^_^
script: df -m | tail -n +2 | awk 'BEGIN{ print "filesystem used available usage mounted"} {print $1,$3,$4,$5,$6}'
parseType: multiRow

View File

@@ -32,6 +32,8 @@ metrics:
- field: database_version
type: 1
instance: true
- field: database_type
type: 1
- field: hostname
type: 1
- field: instance_name
@@ -43,6 +45,7 @@ metrics:
# (非必须)监控指标别名,与上面的指标名映射。用于采集接口数据字段不直接是最终指标名称,需要此别名做映射转换
aliasFields:
- VERSION
- DATABASE_TYPE
- HOST_NAME
- INSTANCE_NAME
- STARTUP_TIME
@@ -51,6 +54,7 @@ metrics:
# eg: cores=core1+core2, usage=usage, waitTime=allTime-runningTime
calculates:
- database_version=VERSION
- database_type=DATABASE_TYPE
- hostname=HOST_NAME
- instance_name=INSTANCE_NAME
- startup_time=STARTUP_TIME

View File

@@ -0,0 +1,25 @@
category: service
app: telnet
name:
zh-CN: TELNET端口可用性
en-US: PORT TELNET
configmap:
- key: host
type: 1
- key: port
type: 0
- key: timeout
type: 0
metrics:
- name: summary
priority: 0
fields:
- field: responseTime
type: 0
unit: ms
protocol: telnet
# 当protocol为telnet协议时具体的采集配置
telnet:
host: ^_^host^_^
port: ^_^port^_^
timeout: ^_^timeout^_^

View File

@@ -2,7 +2,7 @@ category: service
app: website
name:
zh-CN: 网站监测
en-US: WEBSITE
en-US: WEBSITE MONITOR
configmap:
- key: host
type: 1
@@ -18,12 +18,10 @@ configmap:
type: 1
- key: password
type: 2
- key: keyword
type: 1
# 指标组列表
metrics:
# 第一个监控指标组 cpu
# 注意:内置监控指标有 (responseTime - 响应时间, keyword - 关键字数量)
# 注意:内置监控指标有 (responseTime - 响应时间)
- name: summary
# 指标组调度优先级(0-127)越小优先级越高,优先级低的指标组会等优先级高的指标组采集完成后才会被调度,相同优先级的指标组会并行调度采集
# 优先级为0的指标组为可用性指标组,即它会被首先调度,采集成功才会继续调度其它指标组,采集失败则中断调度
@@ -34,9 +32,6 @@ metrics:
- field: responseTime
type: 0
unit: ms
- field: keyword
type: 0
unit: 次数
# 监控采集使用协议 eg: sql, ssh, http, telnet, wmi, snmp, sdk
protocol: http
# 当protocol为http协议时具体的采集配置
@@ -61,4 +56,3 @@ metrics:
# 响应数据解析方式: default-系统规则,jsonPath-jsonPath脚本,website-网站可用性指标监控
# todo xmlPath-xmlPath脚本,prometheus-Prometheus数据规则
parseType: website
keyword: ^_^keyword^_^

View File

@@ -26,12 +26,10 @@ param:
# 当type为text时,用limit表示字符串限制大小
limit: 20
required: false
hide: true
- field: password
name: 密码
type: password
required: false
hide: true
- field: ssl
name: 启动SSL
# 当type为boolean时,前端用switch展示开关

View File

@@ -60,18 +60,15 @@ param:
type: text
placeholder: '请求BODY资源类型'
required: false
hide: true
- field: payload
name: 请求BODY
type: textarea
placeholder: 'POST PUT请求时有效'
required: false
hide: true
- field: authType
name: 认证方式
type: radio
required: false
hide: true
# 当type为radio单选框,checkbox复选框时,option表示可选项值列表 {name1:value1,name2:value2}
options:
- label: Basic Auth
@@ -84,14 +81,7 @@ param:
# 当type为text时,用limit表示字符串限制大小
limit: 20
required: false
hide: true
- field: password
name: 密码
type: password
required: false
hide: true
- field: keyword
name: 关键字
type: text
required: false
hide: true

View File

@@ -17,7 +17,6 @@ param:
required: false
defaultValue: 6000
placeholder: '查询超时时间'
hide: true
- field: database
name: 数据库名称
type: text
@@ -35,4 +34,3 @@ param:
name: URL
type: text
required: false
hide: true

View File

@@ -15,7 +15,6 @@ param:
name: 查询超时时间
type: number
required: false
hide: true
defaultValue: 6000
placeholder: '查询超时时间'
- field: database
@@ -35,4 +34,3 @@ param:
name: URL
type: text
required: false
hide: true

View File

@@ -15,7 +15,6 @@ param:
name: 查询超时时间
type: number
required: false
hide: true
defaultValue: 6000
placeholder: '查询超时时间'
- field: database
@@ -35,4 +34,3 @@ param:
name: URL
type: text
required: false
hide: true

View File

@@ -15,7 +15,6 @@ param:
name: 查询超时时间
type: number
required: false
hide: true
defaultValue: 6000
placeholder: '查询超时时间'
- field: database
@@ -35,4 +34,3 @@ param:
name: URL
type: text
required: false
hide: true

View File

@@ -15,7 +15,6 @@ param:
name: 查询超时时间
type: number
required: false
hide: true
defaultValue: 6000
placeholder: '查询超时时间'
- field: database
@@ -35,4 +34,3 @@ param:
name: URL
type: text
required: false
hide: true

View File

@@ -0,0 +1,27 @@
# 监控应用类型名称(与文件名保持一致) eg: linux windows tomcat mysql aws...
app: telnet
# 强制固定必须参数 - host(ipv4,ipv6,域名)
param:
# field-字段名称标识符
- field: host
# name-参数字段显示名称
name: 主机Host
# type-字段类型,样式(大部分映射input标签type属性)
type: host
# 是否是必输项 true-必填 false-可选
required: true
- field: port
name: 端口
type: number
# 当type为number时,用range表示范围
range: '[0,65535]'
required: true
defaultValue: 80
- field: timeout
name: Telnet超时时间
type: number
# 当type为number时,用range表示范围
range: '[0,100000]'
required: true
placeholder: '请输入超时时间,单位毫秒'
defaultValue: 6000

View File

@@ -33,7 +33,6 @@ param:
name: 认证方式
type: radio
required: false
hide: true
# 当type为radio单选框,checkbox复选框时,option表示可选项值列表 {name1:value1,name2:value2}
options:
- label: Basic Auth
@@ -46,14 +45,7 @@ param:
# 当type为text时,用limit表示字符串限制大小
limit: 20
required: false
hide: true
- field: password
name: 密码
type: password
required: false
hide: true
- field: keyword
name: 关键字
type: text
required: false
hide: true

View File

@@ -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.7</id>
<id>1.0-beta.6</id>
<!--打包类型,可以设置多种类型,打包的时候不同的类型都会打包打出来-->
<formats>
<format>tar</format>

View File

@@ -28,7 +28,9 @@ if [ ! -d $LOGS_DIR ]; then
fi
# JVM Configuration
JAVA_MEM_OPTS=" -server -XX:SurvivorRatio=6 -XX:+UseParallelGC "
JAVA_OPTS=" -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true "
JAVA_MEM_OPTS=" -server -Xms256m -Xmx1024m -XX:SurvivorRatio=2 -XX:+UseParallelGC "
# 加载外部log文件的配置
LOG_IMPL_FILE=logback-spring.xml
@@ -39,4 +41,4 @@ then
fi
CONFIG_FILES=" -Dlogging.path=$LOGS_DIR $LOGGING_CONFIG -Dspring.config.location=$CONF_DIR/ "
echo -e "Starting the $SERVER_NAME ..."
java $JAVA_MEM_OPTS $CONFIG_FILES -jar $DEPLOY_DIR/$JAR_NAME --spring.profiles.active=prod
java $JAVA_OPTS $JAVA_MEM_OPTS $CONFIG_FILES -jar $DEPLOY_DIR/$JAR_NAME --spring.profiles.active=prod

View File

@@ -34,9 +34,9 @@ rem 项目日志输出绝对路径
set LOGS_DIR=%DEPLOY_DIR%\logs
rem JVM Configuration
set JAVA_OPTS= -Duser.timezone=Asia/Shanghai
set JAVA_OPTS= -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Duser.timezone=Asia/Shanghai
set JAVA_MEM_OPTS= -server -XX:SurvivorRatio=6 -XX:+UseParallelGC
set JAVA_MEM_OPTS= -server -Xms256m -Xmx1024m -XX:SurvivorRatio=2 -XX:+UseParallelGC
rem 加载外部log文件的配置
set LOGGING_CONFIG=-Dlogging.config=%CONF_DIR%\logback-spring.xml

View File

@@ -66,9 +66,9 @@ if [ ! -d $LOGS_DIR ]; then
fi
# JVM Configuration
JAVA_OPTS=" -Duser.timezone=Asia/Shanghai"
JAVA_OPTS=" -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Duser.timezone=Asia/Shanghai"
JAVA_MEM_OPTS=" -server -XX:SurvivorRatio=6 -XX:+UseParallelGC "
JAVA_MEM_OPTS=" -server -Xms256m -Xmx1024m -XX:SurvivorRatio=2 -XX:+UseParallelGC "
# 加载外部log文件的配置
LOG_IMPL_FILE=logback-spring.xml

View File

@@ -35,7 +35,7 @@ services:
- heartzbeat
hertzbeat:
image: "tancloud/hertzbeat:1.0-beta.7"
image: "tancloud/hertzbeat:1.0-beta.6"
container_name: hertzbeat
hostname: hertzbeat
restart: always

View File

@@ -2,7 +2,7 @@ FROM openjdk:8-alpine
MAINTAINER tomsun28 "tomsun28@outlook.com"
ADD hertzbeat-1.0-beta.7.tar /opt/
ADD hertzbeat-1.0-beta.6.tar /opt/
RUN apk add --no-cache tzdata

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 MiB

After

Width:  |  Height:  |  Size: 30 MiB

View File

@@ -71,9 +71,9 @@ import { environment } from '@env/environment';
<setting-drawer *ngIf="showSettingDrawer"></setting-drawer>
<theme-btn
[types]="[
{ key: 'default', text: 'app.theme.default' | i18n },
{ key: 'dark', text: 'app.theme.dark' | i18n },
{ key: 'compact', text: 'app.theme.compact' | i18n }
{ key: 'default', text: '浅色主题' },
{ key: 'dark', text: '深色主题' },
{ key: 'compact', text: '紧凑主题' }
]"
></theme-btn>
`

View File

@@ -1,6 +1,4 @@
import { ChangeDetectionStrategy, Component, HostListener, Inject } from '@angular/core';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
import { ChangeDetectionStrategy, Component, HostListener } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzModalService } from 'ng-zorro-antd/modal';
@@ -16,19 +14,15 @@ import { NzModalService } from 'ng-zorro-antd/modal';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class HeaderClearStorageComponent {
constructor(
private modalSrv: NzModalService,
private messageSrv: NzMessageService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
) {}
constructor(private modalSrv: NzModalService, private messageSrv: NzMessageService) {}
@HostListener('click')
_click(): void {
this.modalSrv.confirm({
nzTitle: this.i18nSvc.fanyi('common.confirm.clear-cache'),
nzTitle: '请确认是否清理缓存?',
nzOnOk: () => {
localStorage.clear();
this.messageSrv.success(this.i18nSvc.fanyi('common.notify.clear-success'));
this.messageSrv.success('清理成功!');
}
});
}

View File

@@ -26,11 +26,11 @@ import { AlertService } from '../../../service/alert.service';
export class HeaderNotifyComponent implements OnInit {
data: NoticeItem[] = [
{
title: this.i18nSvc.fanyi('dashboard.alerts.title-no'),
title: '近期未处理告警',
list: [],
emptyText: this.i18nSvc.fanyi('dashboard.alerts.no'),
emptyText: '暂无未处理告警',
emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg',
clearText: this.i18nSvc.fanyi('dashboard.alerts.enter')
clearText: '进入告警中心'
}
];
count = 0;
@@ -69,10 +69,10 @@ export class HeaderNotifyComponent implements OnInit {
let item = {
id: alert.id,
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
title: `${alert.monitorName}--${this.i18nSvc.fanyi(`alert.priority.${alert.priority}`)}`,
title: `监控-${alert.monitorName}-发出${this.i18nSvc.fanyi(`alert.priority.${alert.priority}`)}`,
datetime: alert.gmtCreate,
color: 'blue',
type: this.i18nSvc.fanyi('dashboard.alerts.title-no')
type: '近期未处理告警'
};
this.data[0].list.push(item);
});

View File

@@ -40,8 +40,8 @@ import { MonitorService } from '../../../service/monitor.service';
<nz-autocomplete nzBackfill="false" nzDefaultActiveFirstOption #auto>
<nz-auto-option *ngFor="let option of options" [nzValue]="option.id" [nzLabel]="option.name">
<a [routerLink]="['/monitors/' + option.id]">
{{ 'monitor.name' | i18n }} : {{ option.name }}
<span style="left:50% ; position: absolute;">{{ 'monitor.host' | i18n }} : {{ option.host }}</span>
监控名称: {{ option.name }}
<span style="left:50% ; position: absolute;">监控Host: {{ option.host }}</span>
<span style="right: 10px; position: absolute;"><i nz-icon nzType="arrow-right" nzTheme="outline"></i></span>
</a>
</nz-auto-option>

View File

@@ -6,15 +6,15 @@
<img class="logo" src="./assets/logo.svg" alt="" />
<span class="title">HertzBeat</span>
</div>
<div class="desc">{{ 'app.passport.desc' | i18n }}</div>
<div class="desc">TanCloud-易用友好的高性能监控云服务</div>
</div>
<router-outlet></router-outlet>
<global-footer [links]="links">
Copyright
<i nz-icon nzType="copyright" nzTheme="outline"></i>
2022
<a href="https://tancloud.cn" target="_blank">TanCloud tancloud.cn | </a>
<a href="https://hertzbeat.com" target="_blank">HertzBeat hertzbeat.com</a>
<a href="https://tancloud.cn" target="_blank">探云 tancloud.cn | </a>
<a href="https://hertzbeat.com" target="_blank">赫兹跳动 hertzbeat.com</a>
</global-footer>
</div>
</div>

View File

@@ -1,7 +1,5 @@
import { Component, Inject, OnInit } from '@angular/core';
import { I18NService } from '@core';
import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
@Component({
selector: 'layout-passport',
@@ -11,12 +9,12 @@ import { ALAIN_I18N_TOKEN } from '@delon/theme';
export class LayoutPassportComponent implements OnInit {
links = [
{
title: this.i18nSvc.fanyi('app.passport.welcome'),
title: '欢迎使用TanCloud探云-监控云服务-tancloud.cn',
href: 'https://tancloud.cn'
}
];
constructor(@Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService, @Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService) {}
constructor(@Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService) {}
ngOnInit(): void {
this.tokenService.clear();

View File

@@ -12,6 +12,4 @@ export class ParamDefine {
// 当type为key-value时有效,表示别名描述
keyAlias!: string;
valueAlias!: string;
// 此参数是否隐藏 即默认不显示, 在高级设置区显示
hide: boolean = false;
}

View File

@@ -3,12 +3,12 @@
<nz-breadcrumb-item>
<a [routerLink]="['/']">
<i nz-icon nzType="home"></i>
<span>{{ 'menu.dashboard' | i18n }}</span>
<span>仪表盘</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<i nz-icon nzType="alert"></i>
<span>{{ 'menu.alert.center' | i18n }}</span>
<span>告警中心</span>
</nz-breadcrumb-item>
</nz-breadcrumb>
<nz-divider></nz-divider>
@@ -16,28 +16,26 @@
<div>
<button nz-button nzType="primary" (click)="onDeleteAlerts()">
<i nz-icon nzType="delete" nzTheme="outline"></i>
{{ 'alert.center.delete' | i18n }}
删除告警
</button>
<button nz-button nzType="primary" (click)="onMarkReadAlerts()">
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
{{ 'alert.center.deal' | i18n }}
标记已处理
</button>
<button nz-button nzType="primary" (click)="onMarkUnReadAlerts()">
<i nz-icon nzType="up-circle" nzTheme="outline"></i>
{{ 'alert.center.no-deal' | i18n }}
标记未处理
</button>
<button nz-button nzType="primary" (click)="sync()" nz-tooltip [nzTooltipTitle]="'common.refresh' | i18n">
<button nz-button nzType="primary" (click)="sync()" nz-tooltip nzTooltipTitle="刷新">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
<button style="margin-right: 25px; float: right" nz-button nzType="primary" (click)="onFilterSearchAlerts()">
{{ 'common.search' | i18n }}
</button>
<button style="margin-right: 25px; float: right" nz-button nzType="primary" (click)="onFilterSearchAlerts()"> 搜索 </button>
<input
style="margin-right: 5px; float: right; width: 150px; border-radius: 9px; text-align: center"
nz-input
type="text"
[placeholder]="'alert.center.search' | i18n"
placeholder="搜索告警内容"
nzSize="default"
(keyup.enter)="onFilterSearchAlerts()"
[(ngModel)]="filterContent"
@@ -45,24 +43,23 @@
<nz-select
style="margin-right: 10px; float: right; width: 120px"
nzAllowClear
[nzPlaceHolder]="'alert.center.filter-status' | i18n"
[nzPlaceHolder]="'告警状态过滤'"
[(ngModel)]="filterStatus"
>
<nz-option [nzLabel]="'alert.status.all' | i18n" nzValue="9"></nz-option>
<nz-option [nzLabel]="'alert.status.0' | i18n" nzValue="0"></nz-option>
<nz-option [nzLabel]="'alert.status.2' | i18n" nzValue="2"></nz-option>
<nz-option [nzLabel]="'alert.status.3' | i18n" nzValue="3"></nz-option>
<nz-option nzLabel="全部状态" nzValue="9"></nz-option>
<nz-option nzLabel="未处理" nzValue="0"></nz-option>
<nz-option nzLabel="已处理" nzValue="3"></nz-option>
</nz-select>
<nz-select
style="margin-right: 10px; float: right; width: 120px"
nzAllowClear
[nzPlaceHolder]="'alert.center.filter-priority' | i18n"
[nzPlaceHolder]="'告警级别过滤'"
[(ngModel)]="filterPriority"
>
<nz-option [nzLabel]="'alert.priority.all' | i18n" nzValue="9"></nz-option>
<nz-option [nzLabel]="'alert.priority.2' | i18n" nzValue="2"></nz-option>
<nz-option [nzLabel]="'alert.priority.1' | i18n" nzValue="1"></nz-option>
<nz-option [nzLabel]="'alert.priority.0' | i18n" nzValue="0"></nz-option>
<nz-option nzLabel="全部级别" nzValue="9"></nz-option>
<nz-option nzLabel="警告级别" nzValue="2"></nz-option>
<nz-option nzLabel="严重级别" nzValue="1"></nz-option>
<nz-option nzLabel="紧急级别" nzValue="0"></nz-option>
</nz-select>
</div>
@@ -84,13 +81,13 @@
<thead>
<tr>
<th nzAlign="center" nzLeft nzWidth="4%" [(nzChecked)]="checkedAll" (nzCheckedChange)="onAllChecked($event)"></th>
<th nzAlign="center" nzLeft>{{ 'alert.center.target' | i18n }}</th>
<th nzAlign="center">{{ 'alert.center.monitor' | i18n }}</th>
<th nzAlign="center">{{ 'alert.center.priority' | i18n }}</th>
<th nzAlign="center">{{ 'alert.center.content' | i18n }}</th>
<th nzAlign="center">{{ 'alert.center.status' | i18n }}</th>
<th nzAlign="center">{{ 'alert.center.time' | i18n }}</th>
<th nzAlign="center">{{ 'common.edit' | i18n }}</th>
<th nzAlign="center" nzLeft>告警指标</th>
<th nzAlign="center">所属监控</th>
<th nzAlign="center">级别</th>
<th nzAlign="center">告警内容</th>
<th nzAlign="center">状态</th>
<th nzAlign="center">告警时间</th>
<th nzAlign="center">操作</th>
</tr>
</thead>
<tbody>
@@ -105,36 +102,30 @@
<td nzAlign="center">
<nz-tag *ngIf="data.priority == 0" nzColor="red">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>{{ 'alert.priority.0' | i18n }}</span>
<span>紧急告警</span>
</nz-tag>
<nz-tag *ngIf="data.priority == 1" nzColor="orange">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>{{ 'alert.priority.1' | i18n }}</span>
<span>严重告警</span>
</nz-tag>
<nz-tag *ngIf="data.priority == 2" nzColor="yellow">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>{{ 'alert.priority.2' | i18n }}</span>
<span>警告告警</span>
</nz-tag>
</td>
<td nzAlign="center">{{ data.content }}</td>
<td nzAlign="center">
{{ 'alert.status.' + data.status | i18n }}
{{ data.status === 0 ? '未处理' : '已处理' }}
</td>
<td nzAlign="center">{{ data.gmtCreate | date: 'YYYY-MM-dd HH:mm:ss' }}</td>
<td nzAlign="center">
<button nz-button nzType="primary" (click)="onDeleteOneAlert(data.id)" nz-tooltip [nzTooltipTitle]="'alert.center.delete' | i18n">
<button nz-button nzType="primary" (click)="onDeleteOneAlert(data.id)" nz-tooltip nzTooltipTitle="删除告警">
<i nz-icon nzType="delete" nzTheme="outline"></i>
</button>
<button nz-button nzType="primary" (click)="onMarkReadOneAlert(data.id)" nz-tooltip [nzTooltipTitle]="'alert.center.deal' | i18n">
<button nz-button nzType="primary" (click)="onMarkReadOneAlert(data.id)" nz-tooltip nzTooltipTitle="标记已处理">
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
</button>
<button
nz-button
nzType="primary"
(click)="onMarkUnReadOneAlert(data.id)"
nz-tooltip
[nzTooltipTitle]="'alert.center.no-deal' | i18n"
>
<button nz-button nzType="primary" (click)="onMarkUnReadOneAlert(data.id)" nz-tooltip nzTooltipTitle="标记未处理">
<i nz-icon nzType="up-circle" nzTheme="outline"></i>
</button>
</td>
@@ -142,4 +133,4 @@
</tbody>
</nz-table>
<ng-template #rangeTemplate> {{ 'common.total' | i18n }} {{ total }} </ng-template>
<ng-template #rangeTemplate> 总量 {{ total }} </ng-template>

View File

@@ -1,6 +1,4 @@
import { Component, Inject, OnInit } from '@angular/core';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
import { Component, OnInit } from '@angular/core';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { NzTableQueryParams } from 'ng-zorro-antd/table';
@@ -14,12 +12,7 @@ import { AlertService } from '../../../service/alert.service';
styles: []
})
export class AlertCenterComponent implements OnInit {
constructor(
private notifySvc: NzNotificationService,
private modal: NzModalService,
private alertSvc: AlertService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
) {}
constructor(private notifySvc: NzNotificationService, private modal: NzModalService, private alertSvc: AlertService) {}
pageIndex: number = 1;
pageSize: number = 8;
@@ -94,13 +87,13 @@ export class AlertCenterComponent implements OnInit {
onDeleteAlerts() {
if (this.checkedAlertIds == null || this.checkedAlertIds.size === 0) {
this.notifySvc.warning(this.i18nSvc.fanyi('alert.center.notify.no-delete'), '');
this.notifySvc.warning('未选中任何待删除项!', '');
return;
}
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('alert.center.confirm.delete-batch'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否批量删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteAlerts(this.checkedAlertIds)
@@ -109,13 +102,13 @@ export class AlertCenterComponent implements OnInit {
onMarkReadAlerts() {
if (this.checkedAlertIds == null || this.checkedAlertIds.size === 0) {
this.notifySvc.warning(this.i18nSvc.fanyi('alert.center.notify.no-mark'), '');
this.notifySvc.warning('未选中任何待标记项!', '');
return;
}
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('alert.center.confirm.mark-done-batch'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否批量标记已处理!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.updateAlertsStatus(this.checkedAlertIds, 3)
@@ -123,13 +116,13 @@ export class AlertCenterComponent implements OnInit {
}
onMarkUnReadAlerts() {
if (this.checkedAlertIds == null || this.checkedAlertIds.size === 0) {
this.notifySvc.warning(this.i18nSvc.fanyi('alert.center.notify.no-mark'), '');
this.notifySvc.warning('未选中任何待标记项!', '');
return;
}
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('alert.center.confirm.mark-no-batch'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否批量标记未处理!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.updateAlertsStatus(this.checkedAlertIds, 0)
@@ -140,9 +133,9 @@ export class AlertCenterComponent implements OnInit {
let alerts = new Set<number>();
alerts.add(alertId);
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('common.confirm.delete'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteAlerts(alerts)
@@ -153,9 +146,9 @@ export class AlertCenterComponent implements OnInit {
let alerts = new Set<number>();
alerts.add(alertId);
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('alert.center.confirm.mark-done'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否标记已处理!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.updateAlertsStatus(alerts, 3)
@@ -166,9 +159,9 @@ export class AlertCenterComponent implements OnInit {
let alerts = new Set<number>();
alerts.add(alertId);
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('alert.center.confirm.mark-no'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否标记未处理!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.updateAlertsStatus(alerts, 0)
@@ -181,17 +174,17 @@ export class AlertCenterComponent implements OnInit {
message => {
deleteAlerts$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.delete-success'), '');
this.notifySvc.success('删除成功!', '');
this.loadAlertsTable();
} else {
this.tableLoading = false;
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), message.msg);
this.notifySvc.error('删除失败!', message.msg);
}
},
error => {
this.tableLoading = false;
deleteAlerts$.unsubscribe();
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), error.msg);
this.notifySvc.error('删除失败!', error.msg);
}
);
}
@@ -202,17 +195,17 @@ export class AlertCenterComponent implements OnInit {
message => {
markAlertsStatus$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.mark-success'), '');
this.notifySvc.success('标记成功!', '');
this.loadAlertsTable();
} else {
this.tableLoading = false;
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.mark-fail'), message.msg);
this.notifySvc.error('标记失败!', message.msg);
}
},
error => {
this.tableLoading = false;
markAlertsStatus$.unsubscribe();
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.mark-fail'), error.msg);
this.notifySvc.error('标记失败!', error.msg);
}
);
}

View File

@@ -3,14 +3,14 @@
<nz-breadcrumb-item>
<a [routerLink]="['/']">
<i nz-icon nzType="home"></i>
<span>{{ 'menu.dashboard' | i18n }}</span>
<span>仪表盘</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<i nz-icon nzType="alert"></i>
<span>{{ 'menu.alert.dispatch' | i18n }}</span>
<span>告警通知配置</span>
<a href="https://tancloud.cn/docs/help/alert_email" target="_blank" style="float: right; margin-right: 5%">
<span>{{ 'common.button.help' | i18n }}&nbsp;</span>
<span>帮助&nbsp;</span>
<i nz-icon nzType="question-circle" nzTheme="outline"></i>
</a>
</nz-breadcrumb-item>
@@ -18,12 +18,12 @@
<nz-divider></nz-divider>
<nz-tabset nzSize="large">
<nz-tab [nzTitle]="'alert.notice.receiver' | i18n">
<nz-tab nzTitle="告警接收人">
<button nz-button nzType="primary" (click)="onNewNoticeReceiver()">
<i nz-icon nzType="appstore-add" nzTheme="outline"></i>
{{ 'alert.notice.receiver.new' | i18n }}
新增接收人
</button>
<button nz-button nzType="primary" (click)="syncReceiver()" nz-tooltip [nzTooltipTitle]="'common.refresh' | i18n">
<button nz-button nzType="primary" (click)="syncReceiver()" nz-tooltip nzTooltipTitle="刷新">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
<nz-table
@@ -35,11 +35,11 @@
>
<thead>
<tr>
<th nzAlign="center" nzWidth="10%">{{ 'alert.notice.receiver.people' | i18n }}</th>
<th nzAlign="center" nzWidth="20%">{{ 'alert.notice.receiver.type' | i18n }}</th>
<th nzAlign="center" nzWidth="20%">{{ 'alert.notice.receiver.setting' | i18n }}</th>
<th nzAlign="center" nzWidth="20%">{{ 'common.edit-time' | i18n }}</th>
<th nzAlign="center" nzWidth="30%">{{ 'common.edit' | i18n }}</th>
<th nzAlign="center" nzWidth="10%">接收人</th>
<th nzAlign="center" nzWidth="20%">通知方式</th>
<th nzAlign="center" nzWidth="20%">配置</th>
<th nzAlign="center" nzWidth="20%">最新修改时间</th>
<th nzAlign="center" nzWidth="30%">操作</th>
</tr>
</thead>
<tbody>
@@ -50,11 +50,11 @@
<td nzAlign="center">
<nz-tag *ngIf="data.type == 0" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
<span>{{ 'alert.notice.type.sms' | i18n }}</span>
<span>短信</span>
</nz-tag>
<nz-tag *ngIf="data.type == 1" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
<span>{{ 'alert.notice.type.email' | i18n }}</span>
<span>邮件</span>
</nz-tag>
<nz-tag *ngIf="data.type == 2" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
@@ -62,19 +62,19 @@
</nz-tag>
<nz-tag *ngIf="data.type == 3" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
<span>{{ 'alert.notice.type.wechat' | i18n }}</span>
<span>微信公众号</span>
</nz-tag>
<nz-tag *ngIf="data.type == 4" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
<span>{{ 'alert.notice.type.wework' | i18n }}</span>
<span>企业微信机器人</span>
</nz-tag>
<nz-tag *ngIf="data.type == 5" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
<span>{{ 'alert.notice.type.ding' | i18n }}</span>
<span>钉钉机器人</span>
</nz-tag>
<nz-tag *ngIf="data.type == 6" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
<span>{{ 'alert.notice.type.fei-shu' | i18n }}</span>
<span>飞书机器人</span>
</nz-tag>
</td>
<td nzAlign="center">
@@ -88,22 +88,10 @@
</td>
<td nzAlign="center">{{ (data.gmtUpdate ? data.gmtUpdate : data.gmtCreate) | date: 'YYYY-MM-dd HH:mm:ss' }}</td>
<td nzAlign="center">
<button
nz-button
nzType="primary"
(click)="onEditOneNoticeReceiver(data)"
nz-tooltip
[nzTooltipTitle]="'alert.notice.receiver.edit' | i18n"
>
<button nz-button nzType="primary" (click)="onEditOneNoticeReceiver(data)" nz-tooltip nzTooltipTitle="修改接收人">
<i nz-icon nzType="edit" nzTheme="outline"></i>
</button>
<button
nz-button
nzType="primary"
(click)="onDeleteOneNoticeReceiver(data.id)"
nz-tooltip
[nzTooltipTitle]="'alert.notice.receiver.delete' | i18n"
>
<button nz-button nzType="primary" (click)="onDeleteOneNoticeReceiver(data.id)" nz-tooltip nzTooltipTitle="删除接收人">
<i nz-icon nzType="delete" nzTheme="outline"></i>
</button>
</td>
@@ -111,12 +99,12 @@
</tbody>
</nz-table>
</nz-tab>
<nz-tab [nzTitle]="'alert.notice.rule' | i18n">
<nz-tab nzTitle="告警通知策略">
<button nz-button nzType="primary" (click)="onNewNoticeRule()">
<i nz-icon nzType="appstore-add" nzTheme="outline"></i>
{{ 'alert.notice.rule.new' | i18n }}
新增通知策略
</button>
<button nz-button nzType="primary" (click)="syncRule()" nz-tooltip [nzTooltipTitle]="'common.refresh' | i18n">
<button nz-button nzType="primary" (click)="syncRule()" nz-tooltip nzTooltipTitle="刷新">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
<nz-table
@@ -128,12 +116,12 @@
>
<thead>
<tr>
<th nzAlign="center" nzWidth="15%">{{ 'alert.notice.rule.name' | i18n }}</th>
<th nzAlign="center" nzWidth="12%">{{ 'alert.notice.receiver.people' | i18n }}</th>
<th nzAlign="center" nzWidth="12%">{{ 'alert.notice.rule.all' | i18n }}</th>
<th nzAlign="center" nzWidth="15%">{{ 'alert.notice.rule.enable' | i18n }}</th>
<th nzAlign="center" nzWidth="15%">{{ 'common.edit-time' | i18n }}</th>
<th nzAlign="center" nzWidth="25%">{{ 'common.edit' | i18n }}</th>
<th nzAlign="center" nzWidth="15%">策略名称</th>
<th nzAlign="center" nzWidth="12%">接收人</th>
<th nzAlign="center" nzWidth="12%">转发所有</th>
<th nzAlign="center" nzWidth="15%">是否启用</th>
<th nzAlign="center" nzWidth="15%">最新修改时间</th>
<th nzAlign="center" nzWidth="25%">操作</th>
</tr>
</thead>
<tbody>
@@ -146,38 +134,26 @@
</td>
<td nzAlign="center">
<nz-tag *ngIf="data.filterAll" nzColor="green">
<span>{{ 'common.yes' | i18n }}</span>
<span></span>
</nz-tag>
<nz-tag *ngIf="!data.filterAll" nzColor="orange">
<span>{{ 'common.no' | i18n }}</span>
<span></span>
</nz-tag>
</td>
<td nzAlign="center">
<nz-tag *ngIf="data.enable" nzColor="green">
<span>{{ 'common.enable' | i18n }}</span>
<span>开启</span>
</nz-tag>
<nz-tag *ngIf="!data.enable" nzColor="orange">
<span>{{ 'common.disable' | i18n }}</span>
<span>关闭</span>
</nz-tag>
</td>
<td nzAlign="center">{{ (data.gmtUpdate ? data.gmtUpdate : data.gmtCreate) | date: 'YYYY-MM-dd HH:mm:ss' }}</td>
<td nzAlign="center">
<button
nz-button
nzType="primary"
(click)="onEditOneNoticeRule(data)"
nz-tooltip
[nzTooltipTitle]="'alert.notice.rule.edit' | i18n"
>
<button nz-button nzType="primary" (click)="onEditOneNoticeRule(data)" nz-tooltip nzTooltipTitle="修改告警策略">
<i nz-icon nzType="edit" nzTheme="outline"></i>
</button>
<button
nz-button
nzType="primary"
(click)="onDeleteOneNoticeRule(data.id)"
nz-tooltip
[nzTooltipTitle]="'alert.notice.rule.delete' | i18n"
>
<button nz-button nzType="primary" (click)="onDeleteOneNoticeRule(data.id)" nz-tooltip nzTooltipTitle="删除告警策略">
<i nz-icon nzType="delete" nzTheme="outline"></i>
</button>
</td>
@@ -190,7 +166,7 @@
<!-- 新增或修改通知接收人弹出框 -->
<nz-modal
[(nzVisible)]="isManageReceiverModalVisible"
[nzTitle]="isManageReceiverModalAdd ? ('alert.notice.receiver.new' | i18n) : ('alert.notice.receiver.edit' | i18n)"
[nzTitle]="isManageReceiverModalAdd ? '新增接收人' : '修改接收人'"
(nzOnCancel)="onManageReceiverModalCancel()"
(nzOnOk)="onManageReceiverModalOk()"
nzMaskClosable="false"
@@ -200,27 +176,27 @@
<div *nzModalContent class="-inner-content">
<form nz-form #receiverForm="ngForm">
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="name" nzRequired="true">{{ 'alert.notice.receiver.people.name' | i18n }}</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="name" nzRequired="true">接收人名称</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.name" nz-input required name="name" type="text" id="name" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="type">{{ 'alert.notice.receiver.type' | i18n }} </nz-form-label>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="type">通知方式 </nz-form-label>
<nz-form-control nzSpan="12" [nzErrorTip]="'validation.required' | i18n">
<nz-select [(ngModel)]="receiver.type" nzPlaceHolder="Choose" required name="type" id="type">
<nz-option [nzValue]="0" nzDisabled [nzLabel]="'alert.notice.type.sms' | i18n"></nz-option>
<nz-option [nzValue]="1" [nzLabel]="'alert.notice.type.email' | i18n"></nz-option>
<nz-option [nzValue]="0" nzDisabled nzLabel="短信"></nz-option>
<nz-option [nzValue]="1" nzLabel="邮箱"></nz-option>
<nz-option [nzValue]="2" nzLabel="WebHook"></nz-option>
<nz-option [nzValue]="3" nzDisabled [nzLabel]="'alert.notice.type.wechat' | i18n"></nz-option>
<nz-option [nzValue]="4" [nzLabel]="'alert.notice.type.wework' | i18n"></nz-option>
<nz-option [nzValue]="5" [nzLabel]="'alert.notice.type.ding' | i18n"></nz-option>
<nz-option [nzValue]="6" [nzLabel]="'alert.notice.type.fei-shu' | i18n"></nz-option>
<nz-option [nzValue]="3" nzDisabled nzLabel="微信公众号"></nz-option>
<nz-option [nzValue]="4" nzLabel="企业微信机器人"></nz-option>
<nz-option [nzValue]="5" nzLabel="钉钉机器人"></nz-option>
<nz-option [nzValue]="6" nzLabel="飞书机器人"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 0">
<nz-form-label [nzSpan]="7" nzFor="phone" [nzRequired]="receiver.type === 0">{{ 'alert.notice.type.phone' | i18n }}</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="phone" [nzRequired]="receiver.type === 0">手机号</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.phone.invalid' | i18n">
<input
[(ngModel)]="receiver.phone"
@@ -234,45 +210,37 @@
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 1">
<nz-form-label [nzSpan]="7" nzFor="email" [nzRequired]="receiver.type === 1">{{ 'alert.notice.type.email' | i18n }}</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="email" [nzRequired]="receiver.type === 1">邮箱</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.email.invalid' | i18n">
<input [(ngModel)]="receiver.email" nz-input [required]="receiver.type === 1" email name="email" type="email" id="email" />
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 2">
<nz-form-label [nzSpan]="7" nzFor="hookUrl" [nzRequired]="receiver.type === 2">{{ 'alert.notice.type.url' | i18n }}</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="hookUrl" [nzRequired]="receiver.type === 2">URL地址</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.hookUrl" nz-input [required]="receiver.type === 2" name="hookUrl" type="url" id="hookUrl" />
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 3">
<nz-form-label [nzSpan]="7" nzFor="wechatId" [nzRequired]="receiver.type === 3">{{
'alert.notice.type.wechat-id' | i18n
}}</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="wechatId" [nzRequired]="receiver.type === 3">微信OPENID</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.wechatId" nz-input [required]="receiver.type === 3" name="wechatId" type="text" />
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 4">
<nz-form-label [nzSpan]="7" nzFor="wechatId" [nzRequired]="receiver.type === 4">{{
'alert.notice.type.wework-key' | i18n
}}</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="wechatId" [nzRequired]="receiver.type === 4">企业微信机器人KEY</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.wechatId" nz-input [required]="receiver.type === 4" name="wechatId" type="text" />
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 5">
<nz-form-label [nzSpan]="7" nzFor="accessToken" [nzRequired]="receiver.type === 5">{{
'alert.notice.type.access-token' | i18n
}}</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="accessToken" [nzRequired]="receiver.type === 5">机器人ACCESS_TOKEN</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.accessToken" nz-input [required]="receiver.type === 5" name="accessToken" type="text" />
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 6">
<nz-form-label [nzSpan]="7" nzFor="wechatId" [nzRequired]="receiver.type === 6">{{
'alert.notice.type.fei-shu-key' | i18n
}}</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="wechatId" [nzRequired]="receiver.type === 6">飞书机器人KEY</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.wechatId" nz-input [required]="receiver.type === 6" name="wechatId" type="text" />
</nz-form-control>
@@ -284,7 +252,7 @@
<!-- 新增或修改通知策略弹出框 -->
<nz-modal
[(nzVisible)]="isManageRuleModalVisible"
[nzTitle]="isManageRuleModalAdd ? ('alert.notice.rule.new' | i18n) : ('alert.notice.rule.edit' | i18n)"
[nzTitle]="isManageRuleModalAdd ? '新增策略' : '修改策略'"
(nzOnCancel)="onManageRuleModalCancel()"
(nzOnOk)="onManageRuleModalOk()"
nzMaskClosable="false"
@@ -294,19 +262,19 @@
<div *nzModalContent class="-inner-content">
<form nz-form #ruleForm="ngForm">
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="rule_name" nzRequired="true">{{ 'alert.notice.rule.name' | i18n }}</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="rule_name" nzRequired="true">策略名称</nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="rule.name" nz-input required name="rule_name" type="text" id="rule_name" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="filterAll">{{ 'alert.notice.rule.all' | i18n }}</nz-form-label>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="filterAll">转发所有</nz-form-label>
<nz-form-control nzSpan="8">
<nz-switch [(ngModel)]="rule.filterAll" disabled name="filterAll" id="filterAll"></nz-switch>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="receiver">{{ 'alert.notice.receiver.people' | i18n }}</nz-form-label>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="receiver">接收人</nz-form-label>
<nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<nz-select
[(ngModel)]="rule.receiverId"
@@ -323,7 +291,7 @@
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="enable">{{ 'alert.notice.rule.enable' | i18n }}</nz-form-label>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="enable">是否启用</nz-form-label>
<nz-form-control nzSpan="8">
<nz-switch [(ngModel)]="rule.enable" name="enable" id="enable"></nz-switch>
</nz-form-control>

View File

@@ -1,6 +1,4 @@
import { Component, Inject, OnInit } from '@angular/core';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
import { Component, OnInit } from '@angular/core';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { finalize } from 'rxjs/operators';
@@ -20,8 +18,7 @@ export class AlertNoticeComponent implements OnInit {
private notifySvc: NzNotificationService,
private noticeReceiverSvc: NoticeReceiverService,
private modal: NzModalService,
private noticeRuleSvc: NoticeRuleService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
private noticeRuleSvc: NoticeRuleService
) {}
receivers!: NoticeReceiver[];
@@ -81,9 +78,9 @@ export class AlertNoticeComponent implements OnInit {
onDeleteOneNoticeReceiver(receiveId: number) {
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('common.confirm.delete'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteOneNoticeReceiver(receiveId)
@@ -101,23 +98,23 @@ export class AlertNoticeComponent implements OnInit {
.subscribe(
message => {
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.delete-success'), '');
this.notifySvc.success('删除成功!', '');
this.loadReceiversTable();
} else {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), message.msg);
this.notifySvc.error('删除失败!', message.msg);
}
},
error => {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), error.msg);
this.notifySvc.error('删除失败!', error.msg);
}
);
}
onDeleteOneNoticeRule(ruleId: number) {
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('common.confirm.delete'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteOneNoticeRule(ruleId)
@@ -135,14 +132,14 @@ export class AlertNoticeComponent implements OnInit {
.subscribe(
message => {
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.delete-success'), '');
this.notifySvc.success('删除成功!', '');
this.loadRulesTable();
} else {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), message.msg);
this.notifySvc.error('删除失败!', message.msg);
}
},
error => {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), error.msg);
this.notifySvc.error('删除失败!', error.msg);
}
);
}
@@ -182,14 +179,14 @@ export class AlertNoticeComponent implements OnInit {
message => {
if (message.code === 0) {
this.isManageReceiverModalVisible = false;
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.new-success'), '');
this.notifySvc.success('新增成功!', '');
this.loadReceiversTable();
} else {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.new-fail'), message.msg);
this.notifySvc.error('新增失败!', message.msg);
}
},
error => {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.new-fail'), error.msg);
this.notifySvc.error('新增失败!', error.msg);
}
);
} else {
@@ -205,14 +202,14 @@ export class AlertNoticeComponent implements OnInit {
message => {
if (message.code === 0) {
this.isManageReceiverModalVisible = false;
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.edit-success'), '');
this.notifySvc.success('修改成功!', '');
this.loadReceiversTable();
} else {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), message.msg);
this.notifySvc.error('修改失败!', message.msg);
}
},
error => {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), error.msg);
this.notifySvc.error('修改失败!', error.msg);
}
);
}
@@ -313,14 +310,14 @@ export class AlertNoticeComponent implements OnInit {
message => {
if (message.code === 0) {
this.isManageRuleModalVisible = false;
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.new-success'), '');
this.notifySvc.success('新增成功!', '');
this.loadRulesTable();
} else {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.new-fail'), message.msg);
this.notifySvc.error('新增失败!', message.msg);
}
},
error => {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.new-fail'), error.msg);
this.notifySvc.error('新增失败!', error.msg);
}
);
} else {
@@ -336,14 +333,14 @@ export class AlertNoticeComponent implements OnInit {
message => {
if (message.code === 0) {
this.isManageRuleModalVisible = false;
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.edit-success'), '');
this.notifySvc.success('修改成功!', '');
this.loadRulesTable();
} else {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), message.msg);
this.notifySvc.error('修改失败!', message.msg);
}
},
error => {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), error.msg);
this.notifySvc.error('修改失败!', error.msg);
}
);
}

View File

@@ -3,14 +3,14 @@
<nz-breadcrumb-item>
<a [routerLink]="['/']">
<i nz-icon nzType="home"></i>
<span>{{ 'menu.dashboard' | i18n }}</span>
<span>仪表盘</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<i nz-icon nzType="alert"></i>
<span>{{ 'menu.alert.setting' | i18n }}</span>
<span>告警阈值配置</span>
<a href="https://tancloud.cn/docs/help/alert_threshold" target="_blank" style="float: right; margin-right: 5%">
<span>{{ 'common.button.help' | i18n }}&nbsp;</span>
<span>帮助&nbsp;</span>
<i nz-icon nzType="question-circle" nzTheme="outline"></i>
</a>
</nz-breadcrumb-item>
@@ -19,17 +19,17 @@
<button nz-button nzType="primary" (click)="onNewAlertDefine()">
<i nz-icon nzType="appstore-add" nzTheme="outline"></i>
{{ 'alert.setting.new' | i18n }}
新增阈值
</button>
<button nz-button nzType="primary" (click)="onEditAlertDefine()">
<i nz-icon nzType="edit" nzTheme="outline"></i>
{{ 'common.button.edit' | i18n }}
编辑
</button>
<button nz-button nzType="primary" (click)="onDeleteAlertDefines()">
<i nz-icon nzType="delete" nzTheme="outline"></i>
{{ 'common.button.delete' | i18n }}
删除
</button>
<button nz-button nzType="primary" (click)="sync()" nz-tooltip [nzTooltipTitle]="'common.refresh' | i18n">
<button nz-button nzType="primary" (click)="sync()" nz-tooltip nzTooltipTitle="刷新">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
@@ -51,14 +51,14 @@
<thead>
<tr>
<th nzAlign="center" nzLeft nzWidth="4%" [(nzChecked)]="checkedAll" (nzCheckedChange)="onAllChecked($event)"></th>
<th nzAlign="center" nzLeft>{{ 'alert.setting.target' | i18n }}</th>
<th nzAlign="center">{{ 'alert.setting.expr' | i18n }}</th>
<th nzAlign="center">{{ 'alert.priority' | i18n }}</th>
<th nzAlign="center">{{ 'alert.setting.times' | i18n }}</th>
<th nzAlign="center">{{ 'alert.setting.template' | i18n }}</th>
<th nzAlign="center">{{ 'alert.setting.default' | i18n }}</th>
<th nzAlign="center">{{ 'common.edit-time' | i18n }}</th>
<th nzAlign="center">{{ 'common.edit' | i18n }}</th>
<th nzAlign="center" nzLeft>指标对象</th>
<th nzAlign="center">阈值触发表达式</th>
<th nzAlign="center">告警级别</th>
<th nzAlign="center">触发次数</th>
<th nzAlign="center">通知模版</th>
<th nzAlign="center">全局默认</th>
<th nzAlign="center">最新修改时间</th>
<th nzAlign="center">操作</th>
</tr>
</thead>
<tbody>
@@ -73,54 +73,36 @@
<td nzAlign="center">
<nz-tag *ngIf="data.priority == 0" nzColor="red">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>{{ 'alert.priority.0' | i18n }}</span>
<span>紧急告警</span>
</nz-tag>
<nz-tag *ngIf="data.priority == 1" nzColor="orange">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>{{ 'alert.priority.1' | i18n }}</span>
<span>严重告警</span>
</nz-tag>
<nz-tag *ngIf="data.priority == 2" nzColor="yellow">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>{{ 'alert.priority.2' | i18n }}</span>
<span>警告告警</span>
</nz-tag>
</td>
<td nzAlign="center">{{ data.times }}</td>
<td nzAlign="center">{{ data.template }}</td>
<td nzAlign="center">
<nz-tag *ngIf="data.preset" nzColor="green">
<span>{{ 'common.yes' | i18n }}</span>
<span></span>
</nz-tag>
<nz-tag *ngIf="!data.preset" nzColor="orange">
<span>{{ 'common.no' | i18n }}</span>
<span></span>
</nz-tag>
</td>
<td nzAlign="center">{{ (data.gmtUpdate ? data.gmtUpdate : data.gmtCreate) | date: 'YYYY-MM-dd HH:mm:ss' }}</td>
<td nzAlign="center">
<button
nz-button
nzType="primary"
(click)="onOpenConnectModal(data.id, data.app)"
nz-tooltip
[nzTooltipTitle]="'alert.setting.connect' | i18n"
>
<button nz-button nzType="primary" (click)="onOpenConnectModal(data.id, data.app)" nz-tooltip nzTooltipTitle="配置关联监控">
<i nz-icon nzType="link" nzTheme="outline"></i>
</button>
<button
nz-button
nzType="primary"
(click)="onEditOneAlertDefine(data.id)"
nz-tooltip
[nzTooltipTitle]="'alert.setting.edit' | i18n"
>
<button nz-button nzType="primary" (click)="onEditOneAlertDefine(data.id)" nz-tooltip nzTooltipTitle="修改告警配置">
<i nz-icon nzType="edit" nzTheme="outline"></i>
</button>
<button
nz-button
nzType="primary"
(click)="onDeleteOneAlertDefine(data.id)"
nz-tooltip
[nzTooltipTitle]="'alert.setting.delete' | i18n"
>
<button nz-button nzType="primary" (click)="onDeleteOneAlertDefine(data.id)" nz-tooltip nzTooltipTitle="删除告警配置">
<i nz-icon nzType="delete" nzTheme="outline"></i>
</button>
</td>
@@ -128,12 +110,12 @@
</tbody>
</nz-table>
<ng-template #rangeTemplate> {{ 'common.total' | i18n }} {{ total }} </ng-template>
<ng-template #rangeTemplate> 总量 {{ total }} </ng-template>
<!-- 新增或修改告警定义弹出框 -->
<nz-modal
[(nzVisible)]="isManageModalVisible"
[nzTitle]="isManageModalAdd ? ('alert.setting.new' | i18n) : ('alert.setting.edit' | i18n)"
[nzTitle]="isManageModalAdd ? '新增告警阈值' : '修改告警阈值'"
(nzOnCancel)="onManageModalCancel()"
(nzOnOk)="onManageModalOk()"
nzMaskClosable="false"
@@ -143,7 +125,7 @@
<div *nzModalContent class="-inner-content">
<form nz-form #defineForm="ngForm">
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="target" nzRequired="true">{{ 'alert.setting.target' | i18n }}</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="target" nzRequired="true">指标对象</nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<nz-cascader
required
@@ -158,19 +140,19 @@
<nz-form-item>
<nz-col [nzSpan]="8" nzOffset="7">
<nz-collapse>
<nz-collapse-panel [nzActive]="isManageModalAdd" [nzHeader]="'alert.setting.expr.tip' | i18n">
<nz-collapse-panel [nzActive]="isManageModalAdd" nzHeader="支持的阈值触发表达式环境变量与操作符">
<nz-list nzSize="small" nzSplit="false">
<nz-list-item *ngIf="cascadeValues.length == 3">
<code>{{ cascadeValues[2] }} : {{ 'alert.setting.target.tip' | i18n }}</code>
<code>{{ cascadeValues[2] }} : 选中的指标对象</code>
</nz-list-item>
<nz-list-item *ngFor="let item of otherMetrics">
<code>{{ item }} : {{ 'alert.setting.target.other' | i18n }}</code>
<code>{{ item }} : 所属行其它指标对象</code>
</nz-list-item>
<nz-list-item *ngIf="otherMetrics.length != 0">
<code>instance : {{ 'alert.setting.target.instance' | i18n }}</code>
<code>instance : 所属行实例</code>
</nz-list-item>
<nz-list-item>
<code>{{ 'alert.setting.operator' | i18n }} : equals(str1,str2), ==, <, <=, >, >=, !=, ( ), +, -, &&, ||</code>
<code>支持操作符函数 : equals(str1,str2), ==, <, <=, >, >=, !=, ( ), +, -, &&, ||</code>
</nz-list-item>
</nz-list>
</nz-collapse-panel>
@@ -178,8 +160,13 @@
</nz-col>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="expr" nzRequired="true" [nzTooltipTitle]="'alert.setting.expr.label' | i18n">
{{ 'alert.setting.expr' | i18n }}
<nz-form-label
[nzSpan]="7"
nzFor="expr"
nzRequired="true"
nzTooltipTitle="根据此表达式来计算判断是否触发阈值,表达式环境变量和操作符见上方"
>
阈值触发表达式
</nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<nz-textarea-count [nzMaxCharacterCount]="100">
@@ -190,27 +177,32 @@
nz-input
name="expr"
id="expr"
[placeholder]="('alert.setting.expr.example' | i18n) + ': responseTime&gt;40'"
placeholder="根据此表达式计算判断是否触发阈值.&#10;示例: responseTime&gt;40"
>
</textarea>
</nz-textarea-count>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="priority" [nzTooltipTitle]="'alert.setting.priority.tip' | i18n">
{{ 'alert.priority' | i18n }}
<nz-form-label
nzSpan="7"
nzRequired="true"
nzFor="priority"
nzTooltipTitle="触发阈值的告警级别,从低到高依次为:警告-warning严重-critical紧急-emergency"
>
告警级别
</nz-form-label>
<nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<nz-select [(ngModel)]="define.priority" nzPlaceHolder="Choose" name="priority" id="priority">
<nz-option [nzValue]="0" [nzLabel]="'alert.priority.0' | i18n"></nz-option>
<nz-option [nzValue]="1" [nzLabel]="'alert.priority.1' | i18n"></nz-option>
<nz-option [nzValue]="2" [nzLabel]="'alert.priority.2' | i18n"></nz-option>
<nz-option [nzValue]="0" nzLabel="紧急告警"></nz-option>
<nz-option [nzValue]="1" nzLabel="严重告警"></nz-option>
<nz-option [nzValue]="2" nzLabel="警告告警"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="duration" [nzTooltipTitle]="'alert.setting.times.tip' | i18n">
{{ 'alert.setting.times' | i18n }}
<nz-form-label nzSpan="7" nzRequired="true" nzFor="duration" nzTooltipTitle="设置触发阈值多少次之后才会发送告警">
触发次数
</nz-form-label>
<nz-form-control nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<nz-input-number [(ngModel)]="define.times" [nzMin]="1" [nzMax]="10" [nzStep]="1" required name="duration" id="duration">
@@ -220,25 +212,25 @@
<nz-form-item>
<nz-col [nzSpan]="8" nzOffset="7">
<nz-collapse>
<nz-collapse-panel [nzActive]="isManageModalAdd" [nzHeader]="'alert.setting.template.tip' | i18n">
<nz-collapse-panel [nzActive]="isManageModalAdd" nzHeader="支持的通知模版环境变量">
<nz-list nzSize="small" nzSplit="false">
<nz-list-item>
<code>&#36;&#123;app&#125; : {{ 'alert.setting.template.monitor-type' | i18n }}</code>
<code>&#36;&#123;app&#125; : 监控类型名称</code>
</nz-list-item>
<nz-list-item>
<code>&#36;&#123;metrics&#125; : {{ 'alert.setting.template.metrics-name' | i18n }}</code>
<code>&#36;&#123;metrics&#125; : 监控指标集合名称</code>
</nz-list-item>
<nz-list-item *ngIf="cascadeValues.length == 3">
<code>&#36;&#123;metric&#125; : {{ 'alert.setting.template.metric-name' | i18n }}</code>
<code>&#36;&#123;metric&#125; : 监控指标名称</code>
</nz-list-item>
<nz-list-item *ngIf="cascadeValues.length == 3">
<code>&#36;{{ '{' + cascadeValues[2] + '}' }} : {{ 'alert.setting.template.metric-value' | i18n }}</code>
<code>&#36;{{ '{' + cascadeValues[2] + '}' }} : 监控指标对象值</code>
</nz-list-item>
<nz-list-item *ngFor="let item of otherMetrics">
<code>&#36;{{ '{' + item + '}' }} : {{ 'alert.setting.template.other-value' | i18n }}</code>
<code>&#36;{{ '{' + item + '}' }} : 所属行其它指标值</code>
</nz-list-item>
<nz-list-item>
<code>&#36;&#123;instance&#125; : {{ 'alert.setting.template.instance-value' | i18n }}</code>
<code>&#36;&#123;instance&#125; : 所属行实例值</code>
</nz-list-item>
</nz-list>
</nz-collapse-panel>
@@ -246,8 +238,8 @@
</nz-col>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="template" nzRequired="true" [nzTooltipTitle]="'alert.setting.template.label' | i18n">
{{ 'alert.setting.template' | i18n }}
<nz-form-label [nzSpan]="7" nzFor="template" nzRequired="true" nzTooltipTitle="告警触发后发送的通知信息模版,模版环境变量见上方">
通知模版
</nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<nz-textarea-count [nzMaxCharacterCount]="200">
@@ -258,24 +250,20 @@
required
name="template"
id="template"
[placeholder]="'alert.setting.template.example' | i18n"
placeholder="请输入告警的通知模版.&#10;示例: ${app}.${metrics}.${metric}'s value is too high"
>
</textarea>
</nz-textarea-count>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzFor="preset" [nzTooltipTitle]="'alert.setting.default.tip' | i18n">
{{ 'alert.setting.default' | i18n }}
</nz-form-label>
<nz-form-label nzSpan="7" nzFor="preset" nzTooltipTitle="此告警阈值配置是否应用于全局所有此类型监控"> 全局默认 </nz-form-label>
<nz-form-control nzSpan="8">
<nz-switch [(ngModel)]="define.preset" name="preset" id="preset"></nz-switch>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="enable" [nzTooltipTitle]="'alert.setting.enable.tip' | i18n">
{{ 'alert.setting.enable' | i18n }}
</nz-form-label>
<nz-form-label nzSpan="7" nzRequired="true" nzFor="enable" nzTooltipTitle="此告警阈值配置开启生效或关闭"> 启用告警 </nz-form-label>
<nz-form-control nzSpan="8">
<nz-switch [(ngModel)]="define.enable" [ngModelOptions]="{ standalone: true }" name="enable" id="enable"></nz-switch>
</nz-form-control>
@@ -288,7 +276,7 @@
<nz-modal
[(nzVisible)]="isConnectModalVisible"
[nzTitle]="'alert.setting.connect' | i18n"
nzTitle="告警定义关联监控"
(nzOnCancel)="onConnectModalCancel()"
(nzOnOk)="onConnectModalOk()"
nzMaskClosable="false"
@@ -315,8 +303,8 @@
<thead>
<tr>
<th [nzChecked]="stat.checkAll" [nzIndeterminate]="stat.checkHalf" (nzCheckedChange)="onItemSelectAll($event)"></th>
<th *ngIf="direction == 'left'">{{ 'alert.setting.connect.left' | i18n }}</th>
<th *ngIf="direction == 'right'">{{ 'alert.setting.connect.right' | i18n }}</th>
<th *ngIf="direction == 'left'">未关联监控</th>
<th *ngIf="direction == 'right'">已关联监控</th>
</tr>
</thead>
<tbody>

View File

@@ -1,6 +1,4 @@
import { Component, Inject, OnInit } from '@angular/core';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
import { Component, OnInit } from '@angular/core';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { NzTableQueryParams } from 'ng-zorro-antd/table';
@@ -27,8 +25,7 @@ export class AlertSettingComponent implements OnInit {
private notifySvc: NzNotificationService,
private appDefineSvc: AppDefineService,
private monitorSvc: MonitorService,
private alertDefineSvc: AlertDefineService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
private alertDefineSvc: AlertDefineService
) {}
pageIndex: number = 1;
@@ -101,7 +98,7 @@ export class AlertSettingComponent implements OnInit {
onEditOneAlertDefine(alertDefineId: number) {
if (alertDefineId == null) {
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-edit'), '');
this.notifySvc.warning('未选中任何待编辑项!', '');
return;
}
this.editAlertDefine(alertDefineId);
@@ -110,11 +107,11 @@ export class AlertSettingComponent implements OnInit {
onEditAlertDefine() {
// 编辑时只能选中一个
if (this.checkedDefineIds == null || this.checkedDefineIds.size === 0) {
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-edit'), '');
this.notifySvc.warning('未选中任何待编辑项!', '');
return;
}
if (this.checkedDefineIds.size > 1) {
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.one-select-edit'), '');
this.notifySvc.warning('只能对一个选中项进行编辑!', '');
return;
}
let alertDefineId = 0;
@@ -141,24 +138,24 @@ export class AlertSettingComponent implements OnInit {
this.cascadeValues = [this.define.app, this.define.metric, this.define.field];
this.cascadeOnChange(this.cascadeValues);
} else {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.monitor-fail'), message.msg);
this.notifySvc.error('查询此监控定义详情失败!', message.msg);
}
},
error => {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.monitor-fail'), error.msg);
this.notifySvc.error('查询此监控定义详情失败!', error.msg);
}
);
}
onDeleteAlertDefines() {
if (this.checkedDefineIds == null || this.checkedDefineIds.size === 0) {
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-delete'), '');
this.notifySvc.warning('未选中任何待删除项!', '');
return;
}
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('common.confirm.delete-batch'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否批量删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteAlertDefines(this.checkedDefineIds)
@@ -169,9 +166,9 @@ export class AlertSettingComponent implements OnInit {
let defineIds = new Set<number>();
defineIds.add(alertDefineId);
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('common.confirm.delete'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteAlertDefines(defineIds)
@@ -180,7 +177,7 @@ export class AlertSettingComponent implements OnInit {
deleteAlertDefines(defineIds: Set<number>) {
if (defineIds == null || defineIds.size == 0) {
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-delete'), '');
this.notifySvc.warning('未选中任何待删除项!', '');
return;
}
this.tableLoading = true;
@@ -188,17 +185,17 @@ export class AlertSettingComponent implements OnInit {
message => {
deleteDefines$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.delete-success'), '');
this.notifySvc.success('删除成功!', '');
this.loadAlertDefineTable();
} else {
this.tableLoading = false;
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), message.msg);
this.notifySvc.error('删除失败!', message.msg);
}
},
error => {
this.tableLoading = false;
deleteDefines$.unsubscribe();
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), error.msg);
this.notifySvc.error('删除失败!', error.msg);
}
);
}
@@ -245,7 +242,7 @@ export class AlertSettingComponent implements OnInit {
}
this.appHierarchies.forEach(hierarchy => {
if (hierarchy.value == values[0]) {
hierarchy.children.forEach((metrics: { value: string; children: any[] }) => {
hierarchy.children.forEach((metrics: { value: string; children: any[]}) => {
if (metrics.value == values[1]) {
this.otherMetrics = [];
metrics.children.forEach(item => {
@@ -279,14 +276,14 @@ export class AlertSettingComponent implements OnInit {
message => {
if (message.code === 0) {
this.isManageModalVisible = false;
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.new-success'), '');
this.notifySvc.success('新增成功!', '');
this.loadAlertDefineTable();
} else {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.new-fail'), message.msg);
this.notifySvc.error('新增失败!', message.msg);
}
},
error => {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.new-fail'), error.msg);
this.notifySvc.error('新增失败!', error.msg);
}
);
} else {
@@ -302,14 +299,14 @@ export class AlertSettingComponent implements OnInit {
message => {
if (message.code === 0) {
this.isManageModalVisible = false;
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.edit-success'), '');
this.notifySvc.success('修改成功!', '');
this.loadAlertDefineTable();
} else {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), message.msg);
this.notifySvc.error('修改失败!', message.msg);
}
},
error => {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), error.msg);
this.notifySvc.error('修改失败!', error.msg);
}
);
}
@@ -376,16 +373,16 @@ export class AlertSettingComponent implements OnInit {
message => {
this.isConnectModalOkLoading = false;
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.apply-success'), '');
this.notifySvc.success('应用成功!', '');
this.isConnectModalVisible = false;
this.loadAlertDefineTable();
} else {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.apply-fail'), message.msg);
this.notifySvc.error('应用失败!', message.msg);
}
},
error => {
this.isConnectModalOkLoading = false;
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.apply-fail'), error.msg);
this.notifySvc.error('应用失败!', error.msg);
}
);
}

View File

@@ -10,19 +10,16 @@
</div>
<div nz-col nzSpan="14" class="p-md text-white">
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.available' | i18n }} </span
><span style="font-weight: bolder">{{ appCountService.availableSize }}</span>
<span>正常 </span><span style="font-weight: bolder">{{ appCountService.availableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.unavailable' | i18n }} </span
><span style="font-weight: bolder">{{ appCountService.unAvailableSize }}</span>
<span>不可用 </span><span style="font-weight: bolder">{{ appCountService.unAvailableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.unreachable' | i18n }} </span
><span style="font-weight: bolder">{{ appCountService.unReachableSize }}</span>
<span>不可达 </span><span style="font-weight: bolder">{{ appCountService.unReachableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.un-manage' | i18n }} </span><span style="font-weight: bolder">{{ appCountService.unManageSize }}</span>
<span>未监控 </span><span style="font-weight: bolder">{{ appCountService.unManageSize }}</span>
</nz-tag>
</div>
</div>
@@ -38,16 +35,16 @@
</div>
<div nz-col nzSpan="14">
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.available' | i18n }} </span><span style="font-weight: bolder">{{ appCountDb.availableSize }}</span>
<span>正常 </span><span style="font-weight: bolder">{{ appCountDb.availableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.unavailable' | i18n }} </span><span style="font-weight: bolder">{{ appCountDb.unAvailableSize }}</span>
<span>不可用 </span><span style="font-weight: bolder">{{ appCountDb.unAvailableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.unreachable' | i18n }} </span><span style="font-weight: bolder">{{ appCountDb.unReachableSize }}</span>
<span>不可达 </span><span style="font-weight: bolder">{{ appCountDb.unReachableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.un-manage' | i18n }} </span><span style="font-weight: bolder">{{ appCountDb.unManageSize }}</span>
<span>未监控 </span><span style="font-weight: bolder">{{ appCountDb.unManageSize }}</span>
</nz-tag>
</div>
</div>
@@ -63,16 +60,16 @@
</div>
<div nz-col nzSpan="14">
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.available' | i18n }} </span><span style="font-weight: bolder">{{ appCountOs.availableSize }}</span>
<span>正常 </span><span style="font-weight: bolder">{{ appCountOs.availableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.unavailable' | i18n }} </span><span style="font-weight: bolder">{{ appCountOs.unAvailableSize }}</span>
<span>不可用 </span><span style="font-weight: bolder">{{ appCountOs.unAvailableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.unreachable' | i18n }} </span><span style="font-weight: bolder">{{ appCountOs.unReachableSize }}</span>
<span>不可达 </span><span style="font-weight: bolder">{{ appCountOs.unReachableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.un-manage' | i18n }} </span><span style="font-weight: bolder">{{ appCountOs.unManageSize }}</span>
<span>未监控 </span><span style="font-weight: bolder">{{ appCountOs.unManageSize }}</span>
</nz-tag>
</div>
</div>
@@ -88,16 +85,16 @@
</div>
<div nz-col nzSpan="14">
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.available' | i18n }} </span><span style="font-weight: bolder">{{ appCountCustom.availableSize }}</span>
<span>正常 </span><span style="font-weight: bolder">{{ appCountCustom.availableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.unavailable' | i18n }} </span><span style="font-weight: bolder">{{ appCountCustom.unAvailableSize }}</span>
<span>不可用 </span><span style="font-weight: bolder">{{ appCountCustom.unAvailableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.unreachable' | i18n }} </span><span style="font-weight: bolder">{{ appCountCustom.unReachableSize }}</span>
<span>不可达 </span><span style="font-weight: bolder">{{ appCountCustom.unReachableSize }}</span>
</nz-tag>
<nz-tag class="mb-xs">
<span>{{ 'monitor.status.un-manage' | i18n }} </span><span style="font-weight: bolder">{{ appCountCustom.unManageSize }}</span>
<span>未监控 </span><span style="font-weight: bolder">{{ appCountCustom.unManageSize }}</span>
</nz-tag>
</div>
</div>
@@ -117,21 +114,21 @@
<div nz-row nzGutter="16" style="margin-top: 10px">
<div nz-col nzXs="24" nzSm="24" nzMd="12" class="mb-md">
<nz-card nzHoverable [nzTitle]="'dashboard.alerts.title' | i18n" [nzExtra]="extraTemplate">
<nz-card nzHoverable nzTitle="最近告警列表" [nzExtra]="extraTemplate">
<nz-timeline nzMode="left">
<nz-timeline-item *ngFor="let alert of alerts; let i = index" [nzLabel]="(alert.gmtCreate | date: 'YYYY-MM-dd HH:mm:ss')?.trim()">
<p style="font-weight: 400">
<nz-tag *ngIf="alert.priority == 0" nzColor="red">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>{{ 'alert.priority.0' | i18n }}</span>
<span>紧急告警</span>
</nz-tag>
<nz-tag *ngIf="alert.priority == 1" nzColor="orange">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>{{ 'alert.priority.1' | i18n }}</span>
<span>严重告警</span>
</nz-tag>
<nz-tag *ngIf="alert.priority == 2" nzColor="yellow">
<i nz-icon nzType="bell" nzTheme="outline"></i>
<span>{{ 'alert.priority.2' | i18n }}</span>
<span>警告告警</span>
</nz-tag>
<span>[{{ alert.monitorName }}] </span>
{{ alert.content }}
@@ -165,5 +162,5 @@
</div>
<ng-template #extraTemplate>
<a [routerLink]="['/alert/center']">{{ 'dashboard.alerts.enter' | i18n }}</a>
<a [routerLink]="['/alert/center']">进入告警中心</a>
</ng-template>

View File

@@ -48,13 +48,13 @@ export class DashboardComponent implements OnInit, OnDestroy {
ngOnInit(): void {
this.appsCountTheme = {
title: {
text: this.i18nSvc.fanyi('dashboard.monitors.title'),
subtext: this.i18nSvc.fanyi('dashboard.monitors.sub-title'),
text: '监控总览',
subtext: '监控类型纳管数量分布',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: `{a} <br/>{b} : {c}${this.i18nSvc.fanyi('dashboard.monitors.formatter')}({d}%)`
formatter: '{a} <br/>{b} : {c}个监控 占比({d}%)'
},
legend: {
show: false,
@@ -66,7 +66,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
calculable: true,
series: [
{
name: this.i18nSvc.fanyi('dashboard.monitors.total'),
name: '总量',
type: 'pie',
selectedMode: 'single',
color: '#722ED1',
@@ -81,10 +81,10 @@ export class DashboardComponent implements OnInit, OnDestroy {
labelLine: {
show: false
},
data: [{ value: 0, name: this.i18nSvc.fanyi('dashboard.monitors.total') }]
data: [{ value: 0, name: '监控总量' }]
},
{
name: this.i18nSvc.fanyi('dashboard.monitors.distribute'),
name: '纳管数量分布',
type: 'pie',
radius: ['45%', '65%'],
labelLine: {
@@ -127,7 +127,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
};
this.alertsTheme = {
title: {
subtext: this.i18nSvc.fanyi('dashboard.alerts.distribute'),
subtext: '告警分布',
left: 'center'
},
tooltip: {
@@ -138,14 +138,14 @@ export class DashboardComponent implements OnInit, OnDestroy {
},
xAxis: {
type: 'category',
data: [this.i18nSvc.fanyi('alert.priority.2'), this.i18nSvc.fanyi('alert.priority.1'), this.i18nSvc.fanyi('alert.priority.0')]
data: ['警告告警', '严重告警', '紧急告警']
},
yAxis: {
type: 'value'
},
series: [
{
name: this.i18nSvc.fanyi('dashboard.alerts.num'),
name: '告警数量',
type: 'bar',
data: [
{
@@ -176,7 +176,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
};
this.alertsDealTheme = {
title: {
subtext: this.i18nSvc.fanyi('dashboard.alerts.deal'),
subtext: '告警处理',
left: 'center'
},
tooltip: {
@@ -184,7 +184,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
},
series: [
{
name: this.i18nSvc.fanyi('dashboard.alerts.deal-percent'),
name: '告警处理率',
type: 'gauge',
progress: {
show: true
@@ -196,7 +196,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
data: [
{
value: 100,
name: this.i18nSvc.fanyi('dashboard.alerts.deal-percent')
name: '告警处理率'
}
]
}
@@ -279,7 +279,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
}
});
// @ts-ignore
this.appsCountTheme.series[0].data = [{ value: total, name: this.i18nSvc.fanyi('dashboard.monitors.total') }];
this.appsCountTheme.series[0].data = [{ value: total, name: '监控总量' }];
// @ts-ignore
this.appsCountTheme.series[1].data = this.appsCountTableData;
this.appsCountEChartOption = this.appsCountTheme;
@@ -397,7 +397,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
this.alertsDealTheme.series[0].data = [
{
value: summary.rate,
name: this.i18nSvc.fanyi('dashboard.alerts.deal-percent')
name: '告警处理率'
}
];
this.alertsEChartOption = this.alertsTheme;

View File

@@ -1,6 +1,4 @@
import { Component, Inject, Input, OnInit } from '@angular/core';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
import { Component, Input, OnInit } from '@angular/core';
import { EChartsOption } from 'echarts';
import { finalize } from 'rxjs/operators';
@@ -34,7 +32,7 @@ export class MonitorDataChartComponent implements OnInit {
echartsInstance!: any;
// 查询历史数据时间段 默认最近6小时
timePeriod: string = '6h';
constructor(private monitorSvc: MonitorService, @Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService) {}
constructor(private monitorSvc: MonitorService) {}
ngOnInit(): void {
this.lineHistoryTheme = {
@@ -53,8 +51,8 @@ export class MonitorDataChartComponent implements OnInit {
dataZoom: {
yAxisIndex: 'none',
title: {
zoom: this.i18nSvc.fanyi('monitors.detail.chart.zoom'),
back: this.i18nSvc.fanyi('monitors.detail.chart.back')
zoom: '区域缩放',
back: '缩放还原'
},
emphasis: {
iconStyle: {
@@ -63,7 +61,7 @@ export class MonitorDataChartComponent implements OnInit {
}
},
saveAsImage: {
title: this.i18nSvc.fanyi('monitors.detail.chart.save'),
title: '保存图片',
emphasis: {
iconStyle: {
textPosition: 'left'
@@ -72,7 +70,7 @@ export class MonitorDataChartComponent implements OnInit {
},
myPeriod1h: {
show: true,
title: this.i18nSvc.fanyi('monitors.detail.chart.query-1h'),
title: '查询近1小时',
icon: 'path://M827.871087 196.128913C743.498468 111.756293 631.321596 65.290005 512 65.290005c-119.319549 0-231.499491 46.465265-315.871087 130.837884S65.290005 392.680451 65.290005 512s46.465265 231.499491 130.837884 315.871087 196.551538 130.837884 315.871087 130.837884c119.321596 0 231.499491-46.465265 315.871087-130.837884S958.708971 631.319549 958.708971 512 912.243707 280.500509 827.871087 196.128913zM531.556405 917.246651l0-74.145697c0-11.31572-9.174963-20.491707-20.491707-20.491707-11.316743 0-20.491707 9.174963-20.491707 20.491707l0 74.059739C283.276738 906.322857 116.693746 739.164766 106.755396 531.634176l72.351841 0c11.31572 0 20.491707-9.174963 20.491707-20.491707 0-11.31572-9.174963-20.491707-20.491707-20.491707l-72.273047 0c10.769274-206.737528 177.01253-373.005342 383.740848-383.813502l0 72.346725c0 11.316743 9.174963 20.491707 20.491707 20.491707 11.31572 0 20.491707-9.17394 20.491707-20.491707L531.558451 106.752326c207.593012 9.901511 374.807385 176.539762 385.609405 383.89946l-74.142627 0c-11.316743 0-20.491707 9.174963-20.491707 20.491707 0 11.316743 9.174963 20.491707 20.491707 20.491707l74.220399 0C907.275555 739.78796 739.720422 907.317511 531.556405 917.246651z;M532.098757 503.118726 532.098757 258.240529c0-11.316743-9.174963-20.491707-20.491707-20.491707-11.31572 0-20.491707 9.17394-20.491707 20.491707l0 254.66612c0 7.858992 4.429893 14.677281 10.924817 18.114566L693.447539 722.42757c4.002151 4.000104 9.245572 6.001691 14.490016 6.001691s10.487865-2.001587 14.490016-6.001691c8.002254-8.002254 8.002254-20.977777 0-28.980032L532.098757 503.118726z',
emphasis: {
iconStyle: {
@@ -85,7 +83,7 @@ export class MonitorDataChartComponent implements OnInit {
},
myPeriod6h: {
show: true,
title: this.i18nSvc.fanyi('monitors.detail.chart.query-6h'),
title: '查询近6小时',
icon: 'path://M827.871087 196.128913C743.498468 111.756293 631.321596 65.290005 512 65.290005c-119.319549 0-231.499491 46.465265-315.871087 130.837884S65.290005 392.680451 65.290005 512s46.465265 231.499491 130.837884 315.871087 196.551538 130.837884 315.871087 130.837884c119.321596 0 231.499491-46.465265 315.871087-130.837884S958.708971 631.319549 958.708971 512 912.243707 280.500509 827.871087 196.128913zM531.556405 917.246651l0-74.145697c0-11.31572-9.174963-20.491707-20.491707-20.491707-11.316743 0-20.491707 9.174963-20.491707 20.491707l0 74.059739C283.276738 906.322857 116.693746 739.164766 106.755396 531.634176l72.351841 0c11.31572 0 20.491707-9.174963 20.491707-20.491707 0-11.31572-9.174963-20.491707-20.491707-20.491707l-72.273047 0c10.769274-206.737528 177.01253-373.005342 383.740848-383.813502l0 72.346725c0 11.316743 9.174963 20.491707 20.491707 20.491707 11.31572 0 20.491707-9.17394 20.491707-20.491707L531.558451 106.752326c207.593012 9.901511 374.807385 176.539762 385.609405 383.89946l-74.142627 0c-11.316743 0-20.491707 9.174963-20.491707 20.491707 0 11.316743 9.174963 20.491707 20.491707 20.491707l74.220399 0C907.275555 739.78796 739.720422 907.317511 531.556405 917.246651z;M532.098757 503.118726 532.098757 258.240529c0-11.316743-9.174963-20.491707-20.491707-20.491707-11.31572 0-20.491707 9.17394-20.491707 20.491707l0 254.66612c0 7.858992 4.429893 14.677281 10.924817 18.114566L693.447539 722.42757c4.002151 4.000104 9.245572 6.001691 14.490016 6.001691s10.487865-2.001587 14.490016-6.001691c8.002254-8.002254 8.002254-20.977777 0-28.980032L532.098757 503.118726z',
emphasis: {
iconStyle: {
@@ -98,7 +96,7 @@ export class MonitorDataChartComponent implements OnInit {
},
myPeriod1d: {
show: true,
title: this.i18nSvc.fanyi('monitors.detail.chart.query-1d'),
title: '查询近1天',
icon: 'path://M827.871087 196.128913C743.498468 111.756293 631.321596 65.290005 512 65.290005c-119.319549 0-231.499491 46.465265-315.871087 130.837884S65.290005 392.680451 65.290005 512s46.465265 231.499491 130.837884 315.871087 196.551538 130.837884 315.871087 130.837884c119.321596 0 231.499491-46.465265 315.871087-130.837884S958.708971 631.319549 958.708971 512 912.243707 280.500509 827.871087 196.128913zM531.556405 917.246651l0-74.145697c0-11.31572-9.174963-20.491707-20.491707-20.491707-11.316743 0-20.491707 9.174963-20.491707 20.491707l0 74.059739C283.276738 906.322857 116.693746 739.164766 106.755396 531.634176l72.351841 0c11.31572 0 20.491707-9.174963 20.491707-20.491707 0-11.31572-9.174963-20.491707-20.491707-20.491707l-72.273047 0c10.769274-206.737528 177.01253-373.005342 383.740848-383.813502l0 72.346725c0 11.316743 9.174963 20.491707 20.491707 20.491707 11.31572 0 20.491707-9.17394 20.491707-20.491707L531.558451 106.752326c207.593012 9.901511 374.807385 176.539762 385.609405 383.89946l-74.142627 0c-11.316743 0-20.491707 9.174963-20.491707 20.491707 0 11.316743 9.174963 20.491707 20.491707 20.491707l74.220399 0C907.275555 739.78796 739.720422 907.317511 531.556405 917.246651z;M532.098757 503.118726 532.098757 258.240529c0-11.316743-9.174963-20.491707-20.491707-20.491707-11.31572 0-20.491707 9.17394-20.491707 20.491707l0 254.66612c0 7.858992 4.429893 14.677281 10.924817 18.114566L693.447539 722.42757c4.002151 4.000104 9.245572 6.001691 14.490016 6.001691s10.487865-2.001587 14.490016-6.001691c8.002254-8.002254 8.002254-20.977777 0-28.980032L532.098757 503.118726z',
emphasis: {
iconStyle: {
@@ -111,7 +109,7 @@ export class MonitorDataChartComponent implements OnInit {
},
myPeriod1w: {
show: true,
title: this.i18nSvc.fanyi('monitors.detail.chart.query-1w'),
title: '查询近1周',
icon: 'path://M827.871087 196.128913C743.498468 111.756293 631.321596 65.290005 512 65.290005c-119.319549 0-231.499491 46.465265-315.871087 130.837884S65.290005 392.680451 65.290005 512s46.465265 231.499491 130.837884 315.871087 196.551538 130.837884 315.871087 130.837884c119.321596 0 231.499491-46.465265 315.871087-130.837884S958.708971 631.319549 958.708971 512 912.243707 280.500509 827.871087 196.128913zM531.556405 917.246651l0-74.145697c0-11.31572-9.174963-20.491707-20.491707-20.491707-11.316743 0-20.491707 9.174963-20.491707 20.491707l0 74.059739C283.276738 906.322857 116.693746 739.164766 106.755396 531.634176l72.351841 0c11.31572 0 20.491707-9.174963 20.491707-20.491707 0-11.31572-9.174963-20.491707-20.491707-20.491707l-72.273047 0c10.769274-206.737528 177.01253-373.005342 383.740848-383.813502l0 72.346725c0 11.316743 9.174963 20.491707 20.491707 20.491707 11.31572 0 20.491707-9.17394 20.491707-20.491707L531.558451 106.752326c207.593012 9.901511 374.807385 176.539762 385.609405 383.89946l-74.142627 0c-11.316743 0-20.491707 9.174963-20.491707 20.491707 0 11.316743 9.174963 20.491707 20.491707 20.491707l74.220399 0C907.275555 739.78796 739.720422 907.317511 531.556405 917.246651z;M532.098757 503.118726 532.098757 258.240529c0-11.316743-9.174963-20.491707-20.491707-20.491707-11.31572 0-20.491707 9.17394-20.491707 20.491707l0 254.66612c0 7.858992 4.429893 14.677281 10.924817 18.114566L693.447539 722.42757c4.002151 4.000104 9.245572 6.001691 14.490016 6.001691s10.487865-2.001587 14.490016-6.001691c8.002254-8.002254 8.002254-20.977777 0-28.980032L532.098757 503.118726z',
emphasis: {
iconStyle: {
@@ -124,7 +122,7 @@ export class MonitorDataChartComponent implements OnInit {
},
myPeriod4w: {
show: true,
title: this.i18nSvc.fanyi('monitors.detail.chart.query-1m'),
title: '查询近1月',
icon: 'path://M827.871087 196.128913C743.498468 111.756293 631.321596 65.290005 512 65.290005c-119.319549 0-231.499491 46.465265-315.871087 130.837884S65.290005 392.680451 65.290005 512s46.465265 231.499491 130.837884 315.871087 196.551538 130.837884 315.871087 130.837884c119.321596 0 231.499491-46.465265 315.871087-130.837884S958.708971 631.319549 958.708971 512 912.243707 280.500509 827.871087 196.128913zM531.556405 917.246651l0-74.145697c0-11.31572-9.174963-20.491707-20.491707-20.491707-11.316743 0-20.491707 9.174963-20.491707 20.491707l0 74.059739C283.276738 906.322857 116.693746 739.164766 106.755396 531.634176l72.351841 0c11.31572 0 20.491707-9.174963 20.491707-20.491707 0-11.31572-9.174963-20.491707-20.491707-20.491707l-72.273047 0c10.769274-206.737528 177.01253-373.005342 383.740848-383.813502l0 72.346725c0 11.316743 9.174963 20.491707 20.491707 20.491707 11.31572 0 20.491707-9.17394 20.491707-20.491707L531.558451 106.752326c207.593012 9.901511 374.807385 176.539762 385.609405 383.89946l-74.142627 0c-11.316743 0-20.491707 9.174963-20.491707 20.491707 0 11.316743 9.174963 20.491707 20.491707 20.491707l74.220399 0C907.275555 739.78796 739.720422 907.317511 531.556405 917.246651z;M532.098757 503.118726 532.098757 258.240529c0-11.316743-9.174963-20.491707-20.491707-20.491707-11.31572 0-20.491707 9.17394-20.491707 20.491707l0 254.66612c0 7.858992 4.429893 14.677281 10.924817 18.114566L693.447539 722.42757c4.002151 4.000104 9.245572 6.001691 14.490016 6.001691s10.487865-2.001587 14.490016-6.001691c8.002254-8.002254 8.002254-20.977777 0-28.980032L532.098757 503.118726z',
emphasis: {
iconStyle: {
@@ -137,7 +135,7 @@ export class MonitorDataChartComponent implements OnInit {
},
myRefresh: {
show: true,
title: this.i18nSvc.fanyi('common.refresh'),
title: '刷新',
icon: 'path://M663.881 339.763l274.021-0.742 0.058-13.271 0.699 0c-0.204-0.48-0.495-0.945-0.699-1.426L938.658 65l-23.776 0.044L914.3 280.41C835.9 151.374 694.321 65 532.342 65c-246.869 0-447 200.132-447 447 0 246.84 200.131 447 447 447 180.343 0 335.657-106.919 406.316-260.75l-33.176 0C836.948 835.027 695.456 929.2 532.342 929.2c-230.048 0-417.2-187.152-417.2-417.2s187.152-417.2 417.2-417.2c158.895 0 297.068 89.487 367.466 220.547l-235.868 0.64L663.881 339.763z',
emphasis: {
iconStyle: {
@@ -185,7 +183,7 @@ export class MonitorDataChartComponent implements OnInit {
};
if (this.unit != undefined || this.unit != null) {
// @ts-ignore
this.lineHistoryTheme.title?.subtext = `${this.i18nSvc.fanyi('monitors.detail.chart.unit')} ${this.unit}`;
this.lineHistoryTheme.title?.subtext = `单位 ${this.unit}`;
}
this.loadData();
}
@@ -253,7 +251,7 @@ export class MonitorDataChartComponent implements OnInit {
} else {
this.eChartOption = this.lineHistoryTheme;
this.eChartOption.title = {
text: `${`${this.metrics}.${this.metric}` + '\n\n\n'}${this.i18nSvc.fanyi('monitors.detail.chart.no-data')}`,
text: `${this.metrics}.${this.metric}` + '\n\n\n' + '暂无数据',
textStyle: {
fontSize: 16,
fontFamily: 'monospace',

View File

@@ -17,8 +17,8 @@
<nz-table #smallTable nzSize="small" nzNoResult="No Metrics Data" nzFrontPagination="false" [nzData]="valueRows">
<thead>
<tr>
<th style="text-align: center">{{ 'common.name' | i18n }}</th>
<th style="text-align: center">{{ 'common.value' | i18n }}</th>
<th style="text-align: center">属性</th>
<th style="text-align: center"></th>
</tr>
</thead>
<tbody>
@@ -33,11 +33,17 @@
<ng-template #monitor_metrics_card_title>
<p style="font-size: small; text-align: center; margin-bottom: 3px">{{ metrics }}</p>
<div>
<a nz-popover [nzPopoverContent]="'Last Collect Time ' + (time | _date: 'yyyy-MM-dd HH:mm:ss')">
<a nz-popover [nzPopoverContent]="'最近采集时间 ' + (time | _date: 'yyyy-MM-dd HH:mm:ss')">
<i nz-icon nzType="field-time" nzTheme="outline"></i
></a>
<i style="font-size: 0.3px; font-weight: normal; color: rgba(112, 112, 112, 0.89)">
{{ 'monitors.collect.time' | i18n }}:{{ time | _date: 'HH:mm:ss' }}
</i>
<i style="font-size: 0.3px; font-weight: normal; color: rgba(112,112,112,0.89)">采集时间:{{ time | _date: 'HH:mm:ss' }}</i>
</div>
</ng-template>
<!--<nz-card *ngIf="!isTable" nzHoverable style="height:auto;margin-left: 14px;" [nzBordered]="true"-->
<!-- [nzTitle]="monitor_metrics_card_title" >-->
<!-- <div *ngFor="let field of fields;let i = index;" nz-row nzGutter="16">-->
<!-- <div nz-col nzSpan="10"><p style="text-align: right">{{field.name}}</p></div>-->
<!-- <div nz-col nzSpan="14"><p style="text-align: left">{{rowValues[i].origin}}</p></div>-->
<!-- </div>-->
<!--</nz-card>-->

View File

@@ -3,20 +3,20 @@
<nz-breadcrumb-item>
<a [routerLink]="['/']">
<i nz-icon nzType="home"></i>
<span>{{ 'menu.dashboard' | i18n }}</span>
<span>仪表盘</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<a [routerLink]="['/monitors']" [queryParams]="{ app: app ? app : '' }">
<i nz-icon nzType="monitor"></i>
<span>{{ 'monitors.list' | i18n }}</span>
<span>监控列表</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<i nz-icon nzType="pie-chart"></i>
<span>{{ 'monitor.app.' + app | i18n }} {{ 'monitors.detail' | i18n }}</span>
<span>{{ 'monitor.app.' + app | i18n }} 监控详情</span>
<a [href]="'https://tancloud.cn/docs/help/' + monitor.app" target="_blank" style="float: right; margin-right: 5%">
<span>{{ 'common.button.help' | i18n }} </span>
<span>帮助&nbsp;</span>
<i nz-icon nzType="question-circle" nzTheme="outline"></i>
</a>
</nz-breadcrumb-item>
@@ -33,9 +33,7 @@
>
</div>
<div nz-row nzGutter="16">
<div nz-col nzSpan="8"
><p style="text-align: right">{{ 'monitors.detail.name' | i18n }}</p></div
>
<div nz-col nzSpan="8"><p style="text-align: right">名称</p></div>
<div nz-col nzSpan="16"
><p style="text-align: left">{{ monitor?.name }}</p></div
>
@@ -47,64 +45,56 @@
>
</div>
<div nz-row nzGutter="16">
<div nz-col nzSpan="8"
><p style="text-align: right">{{ 'monitors.detail.port' | i18n }}</p></div
>
<div nz-col nzSpan="8"><p style="text-align: right">端口</p></div>
<div nz-col nzSpan="16"
><p style="text-align: left">{{ port }}</p></div
>
</div>
<div nz-row nzGutter="16">
<div nz-col nzSpan="8"
><p style="text-align: right">{{ 'monitors.detail.description' | i18n }}</p></div
>
<div nz-col nzSpan="8"><p style="text-align: right">描述</p></div>
<div nz-col nzSpan="16"
><p style="text-align: left">{{ monitor?.description }}</p></div
>
</div>
<div nz-row nzGutter="16">
<div nz-col nzSpan="8"
><p style="text-align: right">{{ 'monitors.detail.status' | i18n }}</p></div
>
<div nz-col nzSpan="8"><p style="text-align: right">状态</p></div>
<div nz-col nzSpan="16">
<nz-tag *ngIf="monitor?.status == 0" nzColor="default">
<i nz-icon nzType="robot" nzTheme="outline"></i>
<span>{{ 'monitor.status.un-manage' | i18n }}</span>
<span>未监控</span>
</nz-tag>
<nz-tag *ngIf="monitor?.status == 1" nzColor="success">
<i nz-icon nzType="smile" nzTheme="outline"></i>
<span>{{ 'monitor.status.available' | i18n }}</span>
<span>正常监控</span>
</nz-tag>
<nz-tag *ngIf="monitor?.status == 2" nzColor="warning">
<i nz-icon nzType="meh" nzTheme="outline"></i>
<span>{{ 'monitor.status.unavailable' | i18n }}</span>
<span>监控不可用</span>
</nz-tag>
<nz-tag *ngIf="monitor?.status == 3" nzColor="error">
<i nz-icon nzType="frown" nzTheme="outline"></i>
<span>{{ 'monitor.status.unreachable' | i18n }}</span>
<span>监控不可达</span>
</nz-tag>
<nz-tag *ngIf="monitor?.status == 4" nzColor="default">
<i nz-icon nzType="sync"></i>
<span>监控已挂起</span>
</nz-tag>
</div>
</div>
<div nz-row nzGutter="16">
<div nz-col nzSpan="8"
><p style="text-align: right">{{ 'monitor.intervals' | i18n }}</p></div
>
<div nz-col nzSpan="8"><p style="text-align: right">采集间隔</p></div>
<div nz-col nzSpan="16"
><p style="text-align: left">{{ monitor?.intervals }}s</p></div
>
</div>
<div nz-row nzGutter="16">
<div nz-col nzSpan="8"
><p style="text-align: right">{{ 'common.new-time' | i18n }}</p></div
>
<div nz-col nzSpan="8"><p style="text-align: right">创建时间</p></div>
<div nz-col nzSpan="16"
><p style="text-align: left">{{ monitor?.gmtCreate | date: 'YYYY-MM-dd HH:mm:ss' }}</p></div
>
</div>
<div nz-row nzGutter="16">
<div nz-col nzSpan="8"
><p style="text-align: right">{{ 'common.edit-time' | i18n }}</p></div
>
<div nz-col nzSpan="8"><p style="text-align: right">更新时间</p></div>
<div nz-col nzSpan="16"
><p style="text-align: left">{{ monitor?.gmtUpdate | date: 'YYYY-MM-dd HH:mm:ss' }}</p></div
>
@@ -117,7 +107,7 @@
<nz-tab [nzTitle]="titleTemplate">
<ng-template #titleTemplate>
<i nz-icon nzType="pic-right" style="margin-left: 10px"></i>
{{ 'monitors.detail.realtime' | i18n }}
监控实时数据详情
</ng-template>
<div style="display: flex; justify-content: flex-start; flex-wrap: wrap">
<div *ngFor="let metric of metrics; let i = index">
@@ -128,7 +118,7 @@
<nz-tab [nzTitle]="title2Template" (nzClick)="initMetricChart()">
<ng-template #title2Template>
<i nz-icon nzType="pic-right" style="margin-left: 10px"></i>
{{ 'monitors.detail.history' | i18n }}
监控历史图表详情
</ng-template>
<div style="display: flex; justify-content: flex-start; flex-wrap: wrap">
<div *ngFor="let item of chartMetrics; let i = index">
@@ -148,5 +138,5 @@
</nz-layout>
<ng-template #monitor_basic_card_title>
<p style="font-size: small; text-align: left; margin-bottom: 3px">{{ 'monitors.detail.basic' | i18n }}</p>
<p style="font-size: small; text-align: left; margin-bottom: 3px">监控基本属性</p>
</ng-template>

View File

@@ -3,20 +3,20 @@
<nz-breadcrumb-item>
<a [routerLink]="['/']">
<i nz-icon nzType="home"></i>
<span>{{ 'menu.dashboard' | i18n }}</span>
<span>仪表盘</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<a [routerLink]="['/monitors']" [queryParams]="{ app: monitor.app ? monitor.app : '' }">
<i nz-icon nzType="monitor"></i>
<span>{{ 'monitors.list' | i18n }}</span>
<span>监控列表</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<i nz-icon nzType="edit"></i>
<span>{{ 'monitors.edit' | i18n }} {{ 'monitor.app.' + monitor.app | i18n }} {{ 'monitor' | i18n }}</span>
<span>修改 {{ 'monitor.app.' + monitor.app | i18n }} 监控</span>
<a [href]="'https://tancloud.cn/docs/help/' + monitor.app" target="_blank" style="float: right; margin-right: 5%">
<span>{{ 'common.button.help' | i18n }} </span>
<span>帮助&nbsp;</span>
<i nz-icon nzType="question-circle" nzTheme="outline"></i>
</a>
</nz-breadcrumb-item>
@@ -27,19 +27,17 @@
<div class="-inner-content">
<form nz-form #editForm="ngForm">
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="host" nzRequired="true" [nzTooltipTitle]="'monitor.host.tip' | i18n">
{{ 'monitor.host' | i18n }}
</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="host" nzRequired="true" nzTooltipTitle="被监控的对端IP或域名"> 监控Host </nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="monitor.host" nz-input name="host" type="text" id="host" required [placeholder]="'monitor.host.tip' | i18n" />
<input [(ngModel)]="monitor.host" nz-input name="host" type="text" id="host" required placeholder="请输入域名或IP" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="name" nzRequired="true" [nzTooltipTitle]="'monitor.name.tip' | i18n">
{{ 'monitor.name' | i18n }}
<nz-form-label [nzSpan]="7" nzFor="name" nzRequired="true" nzTooltipTitle="标识此监控的名称,名称需要保证唯一性">
监控名称
</nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="monitor.name" nz-input required name="name" type="text" id="name" [placeholder]="'monitor.name.tip' | i18n" />
<input [(ngModel)]="monitor.name" nz-input required name="name" type="text" id="name" placeholder="监控名称需要保证唯一性" />
</nz-form-control>
</nz-form-item>
@@ -164,171 +162,25 @@
</nz-form-control>
</nz-form-item>
<nz-collapse [nzGhost]="true">
<nz-collapse-panel [nzHeader]="extraColHeader" [nzShowArrow]="false">
<nz-form-item *ngFor="let paramDefine of advancedParamDefines; let i = index">
<nz-form-label
*ngIf="paramDefine.field !== 'host' && paramDefine.type === 'text'"
nzSpan="7"
[nzRequired]="paramDefine.required"
[nzFor]="paramDefine.field"
>{{ paramDefine.name }}
</nz-form-label>
<nz-form-control
*ngIf="paramDefine.field !== 'host' && paramDefine.type === 'text'"
nzSpan="8"
[nzErrorTip]="'validation.required' | i18n"
>
<input
nz-input
[(ngModel)]="advancedParams[i].value"
[required]="paramDefine.required"
[name]="paramDefine.field"
[type]="paramDefine.type"
[id]="paramDefine.field"
[placeholder]="paramDefine.placeholder ? paramDefine.placeholder : ''"
/>
</nz-form-control>
<nz-form-label
*ngIf="paramDefine.type === 'textarea'"
nzSpan="7"
[nzRequired]="paramDefine.required"
[nzFor]="paramDefine.field"
>{{ paramDefine.name }}
</nz-form-label>
<nz-form-control *ngIf="paramDefine.type === 'textarea'" nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<textarea
nz-input
[(ngModel)]="advancedParams[i].value"
[required]="paramDefine.required"
[name]="paramDefine.field"
[id]="paramDefine.field"
[placeholder]="paramDefine.placeholder ? paramDefine.placeholder : ''"
rows="3"
></textarea>
</nz-form-control>
<nz-form-label
*ngIf="paramDefine.type === 'password'"
nzSpan="7"
[nzRequired]="paramDefine.required"
[nzFor]="paramDefine.field"
>{{ paramDefine.name }}
</nz-form-label>
<nz-form-control *ngIf="paramDefine.type === 'password'" nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<nz-input-group [nzSuffix]="suffixTemplate" style="width: 100%">
<input
[type]="passwordVisible ? 'text' : 'password'"
nz-input
placeholder="input password"
[required]="paramDefine.required"
[(ngModel)]="advancedParams[i].value"
[id]="paramDefine.field"
[name]="paramDefine.field"
[placeholder]="paramDefine.placeholder ? paramDefine.placeholder : ''"
/>
</nz-input-group>
<ng-template #suffixTemplate>
<i nz-icon [nzType]="passwordVisible ? 'eye-invisible' : 'eye'" (click)="passwordVisible = !passwordVisible"></i>
</ng-template>
</nz-form-control>
<nz-form-label *ngIf="paramDefine.type === 'number'" nzSpan="7" [nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
>{{ paramDefine.name }}
</nz-form-label>
<nz-form-control *ngIf="paramDefine.type === 'number'" nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<nz-input-number
[(ngModel)]="advancedParams[i].value"
[required]="paramDefine.required"
[nzMin]="-1000"
[nzMax]="65535"
[nzStep]="1"
[nzPlaceHolder]="paramDefine.placeholder ? paramDefine.placeholder : ''"
[name]="paramDefine.field"
[id]="paramDefine.field"
></nz-input-number>
</nz-form-control>
<nz-form-label *ngIf="paramDefine.type === 'boolean'" nzSpan="7" [nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
>{{ paramDefine.name }}
</nz-form-label>
<nz-form-control *ngIf="paramDefine.type === 'boolean'" nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<nz-switch
[(ngModel)]="advancedParams[i].value"
[required]="paramDefine.required"
[name]="paramDefine.field"
[id]="paramDefine.field"
></nz-switch>
</nz-form-control>
<nz-form-label *ngIf="paramDefine.type === 'radio'" nzSpan="7" [nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
>{{ paramDefine.name }}
</nz-form-label>
<nz-form-control *ngIf="paramDefine.type === 'radio'" nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<nz-radio-group
[(ngModel)]="advancedParams[i].value"
[required]="paramDefine.required"
nzButtonStyle="solid"
[name]="paramDefine.field"
[id]="paramDefine.field"
>
<label nz-radio-button [nzValue]="optionItem.value" *ngFor="let optionItem of paramDefine.options">
{{ optionItem.label }}
</label>
</nz-radio-group>
</nz-form-control>
<nz-form-label
*ngIf="paramDefine.type === 'key-value'"
nzSpan="7"
[nzRequired]="paramDefine.required"
[nzFor]="paramDefine.field"
>{{ paramDefine.name }}
</nz-form-label>
<nz-form-control *ngIf="paramDefine.type === 'key-value'" nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<app-key-value-input
[(value)]="advancedParams[i].value"
[id]="paramDefine.field"
keyAlias="Header Name"
valueAlias="Header Value"
></app-key-value-input>
</nz-form-control>
</nz-form-item>
</nz-collapse-panel>
</nz-collapse>
<ng-template #extraColHeader>
<button style="top: -10px; margin-left: 40%" nz-button nzType="dashed" nz-tooltip [nzTooltipTitle]="'monitors.advanced.tip' | i18n">
<span>{{ 'monitors.advanced' | i18n }}</span>
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
</button>
</ng-template>
<nz-divider></nz-divider>
<nz-form-item>
<nz-form-label nzSpan="7" nzFor="intervals" [nzTooltipTitle]="'monitor.intervals.tip' | i18n">
{{ 'monitor.intervals' | i18n }}
</nz-form-label>
<nz-form-control nzSpan="8">
<nz-form-label nzSpan="7" nzFor="intervals" nzTooltipTitle="监控周期性采集数据间隔时间,单位秒"> 采集间隔 </nz-form-label>
<nz-form-control nzSpan="10">
<nz-input-number [(ngModel)]="monitor.intervals" [nzMin]="10" [nzMax]="604800" [nzStep]="60" name="intervals" id="intervals">
</nz-input-number>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzFor="detect" [nzTooltipTitle]="'monitors.detect.tip' | i18n">
{{ 'monitors.detect' | i18n }}
</nz-form-label>
<nz-form-label nzSpan="7" nzFor="detect" nzTooltipTitle="新增监控前是否先探测检查监控可用性"> 测试连接 </nz-form-label>
<nz-form-control nzSpan="8">
<nz-switch [(ngModel)]="detected" name="detect" id="detect"></nz-switch>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="description" [nzTooltipTitle]="'monitor.description.tip' | i18n">
{{ 'monitor.description' | i18n }}
</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="description" nzTooltipTitle="更多标识和描述此监控的备注信息"> 描述备注 </nz-form-label>
<nz-form-control [nzSpan]="8">
<nz-textarea-count [nzMaxCharacterCount]="100">
<textarea [(ngModel)]="monitor.description" rows="3" nz-input name="description" id="description"></textarea>
@@ -338,9 +190,9 @@
<div nz-row>
<div nz-col nzSpan="8" nzOffset="9">
<button nz-button nzType="primary" type="submit" (click)="onDetect(editForm.form)"> {{ 'common.button.detect' | i18n }} </button>
<button nz-button nzType="primary" type="submit" (click)="onSubmit(editForm.form)"> {{ 'common.button.ok' | i18n }} </button>
<button nz-button nzType="primary" type="reset" (click)="onCancel()"> {{ 'common.button.cancel' | i18n }} </button>
<button nz-button nzType="primary" type="submit" (click)="onDetect(editForm.form)"> 测试 </button>
<button nz-button nzType="primary" type="submit" (click)="onSubmit(editForm.form)"> 确定 </button>
<button nz-button nzType="primary" type="reset" (click)="onCancel()"> 取消 </button>
</div>
</div>
</form>

View File

@@ -1,8 +1,7 @@
import { Component, Inject, OnInit } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN, TitleService } from '@delon/theme';
import { TitleService } from '@delon/theme';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { throwError } from 'rxjs';
import { switchMap } from 'rxjs/operators';
@@ -26,14 +25,11 @@ export class MonitorEditComponent implements OnInit {
private route: ActivatedRoute,
private router: Router,
private titleSvc: TitleService,
private notifySvc: NzNotificationService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
private notifySvc: NzNotificationService
) {}
paramDefines!: ParamDefine[];
params!: Param[];
advancedParamDefines!: ParamDefine[];
advancedParams!: Param[];
paramValueMap = new Map<String, Param>();
monitor = new Monitor();
profileForm: FormGroup = new FormGroup({});
@@ -63,22 +59,21 @@ export class MonitorEditComponent implements OnInit {
this.paramValueMap.set(item.field, item);
});
}
this.params = message.data.params;
this.detected = message.data.detected ? message.data.detected : true;
} else {
console.warn(message.msg);
this.notifySvc.error(this.i18nSvc.fanyi('monitors.not-found'), message.msg);
return throwError(this.i18nSvc.fanyi('monitors.not-found'));
this.notifySvc.error('查询异常,此监控不存在', message.msg);
return throwError('查询此监控异常');
}
return this.appDefineSvc.getAppParamsDefine(this.monitor.app);
})
)
.subscribe(message => {
if (message.code === 0) {
this.paramDefines = message.data;
this.params = [];
this.advancedParams = [];
this.paramDefines = [];
this.advancedParamDefines = [];
message.data.forEach(define => {
this.paramDefines.forEach(define => {
let param = this.paramValueMap.get(define.field);
if (param === undefined) {
param = new Param();
@@ -105,13 +100,7 @@ export class MonitorEditComponent implements OnInit {
}
}
}
if (define.hide) {
this.advancedParams.push(param);
this.advancedParamDefines.push(define);
} else {
this.params.push(param);
this.paramDefines.push(define);
}
});
} else {
console.warn(message.msg);
@@ -155,30 +144,25 @@ export class MonitorEditComponent implements OnInit {
param.value = (param.value as string).trim();
}
});
this.advancedParams.forEach(param => {
if (param.value != null && typeof param.value == 'string') {
param.value = (param.value as string).trim();
}
});
let addMonitor = {
detected: this.detected,
monitor: this.monitor,
params: this.params.concat(this.advancedParams)
params: this.params
};
this.isSpinning = true;
this.monitorSvc.editMonitor(addMonitor).subscribe(
message => {
this.isSpinning = false;
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('monitors.edit.success'), '');
this.notifySvc.success('修改监控成功', '');
this.router.navigateByUrl(`/monitors?app=${this.monitor.app}`);
} else {
this.notifySvc.error(this.i18nSvc.fanyi('monitors.edit.failed'), message.msg);
this.notifySvc.error('修改监控失败', message.msg);
}
},
error => {
this.isSpinning = false;
this.notifySvc.error(this.i18nSvc.fanyi('monitors.edit.failed'), error.error.msg);
this.notifySvc.error('修改监控失败', error.error.msg);
}
);
}
@@ -204,29 +188,24 @@ export class MonitorEditComponent implements OnInit {
param.value = (param.value as string).trim();
}
});
this.advancedParams.forEach(param => {
if (param.value != null && typeof param.value == 'string') {
param.value = (param.value as string).trim();
}
});
let detectMonitor = {
detected: this.detected,
monitor: this.monitor,
params: this.params.concat(this.advancedParams)
params: this.params
};
this.isSpinning = true;
this.monitorSvc.detectMonitor(detectMonitor).subscribe(
message => {
this.isSpinning = false;
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('monitors.detect.success'), '');
this.notifySvc.success('探测成功', '');
} else {
this.notifySvc.error(this.i18nSvc.fanyi('monitors.detect.failed'), message.msg);
this.notifySvc.error('探测失败', message.msg);
}
},
error => {
this.isSpinning = false;
this.notifySvc.error(this.i18nSvc.fanyi('monitors.detect.failed'), error.error.msg);
this.notifySvc.error('探测异常', error.error.msg);
}
);
}

View File

@@ -3,12 +3,12 @@
<nz-breadcrumb-item>
<a [routerLink]="['/']">
<i nz-icon nzType="home"></i>
<span>{{ 'menu.dashboard' | i18n }}</span>
<span>仪表盘</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<i nz-icon nzType="monitor"></i>
<span>{{ 'monitor.app.' + app | i18n }} {{ 'monitors.list' | i18n }}</span>
<span>{{ 'monitor.app.' + app | i18n }} 监控列表</span>
</nz-breadcrumb-item>
</nz-breadcrumb>
<nz-divider></nz-divider>
@@ -17,37 +17,35 @@
<button nz-button nzType="primary">
<a routerLink="/monitors/new" [queryParams]="{ app: app }">
<i nz-icon nzType="appstore-add" nzTheme="outline"></i>
{{ 'monitors.new' | i18n }} {{ 'monitor.app.' + app | i18n }}
新增 {{ 'monitor.app.' + app | i18n }}
</a>
</button>
<button nz-button nzType="primary" (click)="onEditMonitor()">
<i nz-icon nzType="edit" nzTheme="outline"></i>
{{ 'monitors.edit' | i18n }}
编辑
</button>
<button nz-button nzType="primary" (click)="onDeleteMonitors()">
<i nz-icon nzType="delete" nzTheme="outline"></i>
{{ 'monitors.delete' | i18n }}
删除
</button>
<button nz-button nzType="primary" (click)="onEnableManageMonitors()">
<i nz-icon nzType="up-circle" nzTheme="outline"></i>
{{ 'monitors.enable' | i18n }}
启用监控
</button>
<button nz-button nzType="primary" (click)="onCancelManageMonitors()">
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
{{ 'monitors.cancel' | i18n }}
取消监控
</button>
<button nz-button nzType="primary" (click)="sync()" nz-tooltip [nzTooltipTitle]="'common.refresh' | i18n">
<button nz-button nzType="primary" (click)="sync()" nz-tooltip nzTooltipTitle="刷新">
<i nz-icon nzType="sync" nzTheme="outline"></i>
</button>
<button style="margin-right: 25px; float: right" nz-button nzType="primary" (click)="onFilterSearchMonitors()">
{{ 'common.search' | i18n }}
</button>
<button style="margin-right: 25px; float: right" nz-button nzType="primary" (click)="onFilterSearchMonitors()"> 搜索 </button>
<input
style="margin-right: 5px; float: right; width: 150px; border-radius: 9px; text-align: center"
nz-input
type="text"
[placeholder]="'monitors.search.placeholder' | i18n"
placeholder="搜索监控"
nzSize="default"
(keyup.enter)="onFilterSearchMonitors()"
[(ngModel)]="filterContent"
@@ -55,14 +53,14 @@
<nz-select
style="margin-right: 10px; float: right; width: 120px"
nzAllowClear
[nzPlaceHolder]="'monitors.search.filter' | i18n"
[nzPlaceHolder]="'监控状态过滤'"
[(ngModel)]="filterStatus"
>
<nz-option [nzLabel]="'monitor.status.all' | i18n" nzValue="9"></nz-option>
<nz-option [nzLabel]="'monitor.status.available' | i18n" nzValue="1"></nz-option>
<nz-option [nzLabel]="'monitor.status.unavailable' | i18n" nzValue="2"></nz-option>
<nz-option [nzLabel]="'monitor.status.unreachable' | i18n" nzValue="3"></nz-option>
<nz-option [nzLabel]="'monitor.status.un-manage' | i18n" nzValue="0"></nz-option>
<nz-option nzLabel="全部状态" nzValue="9"></nz-option>
<nz-option nzLabel="监控正常" nzValue="1"></nz-option>
<nz-option nzLabel="不可用" nzValue="2"></nz-option>
<nz-option nzLabel="不可达" nzValue="3"></nz-option>
<nz-option nzLabel="未监控" nzValue="0"></nz-option>
</nz-select>
</div>
@@ -84,12 +82,12 @@
<thead>
<tr>
<th nzAlign="center" nzLeft nzWidth="4%" [(nzChecked)]="checkedAll" (nzCheckedChange)="onAllChecked($event)"></th>
<th nzAlign="center" nzLeft>{{ 'monitor.name' | i18n }}</th>
<th nzAlign="center">{{ 'monitor.status' | i18n }}</th>
<th nzAlign="center">{{ 'monitor.host' | i18n }}</th>
<th nzAlign="center">{{ 'monitor.app' | i18n }}</th>
<th nzAlign="center">{{ 'common.edit-time' | i18n }}</th>
<th nzAlign="center">{{ 'common.edit' | i18n }}</th>
<th nzAlign="center" nzLeft>监控名称</th>
<th nzAlign="center">监控状态</th>
<th nzAlign="center">监控Host</th>
<th nzAlign="center">监控类型</th>
<th nzAlign="center">最新修改时间</th>
<th nzAlign="center">操作</th>
</tr>
</thead>
<tbody>
@@ -103,19 +101,23 @@
<td nzAlign="center">
<nz-tag *ngIf="data.status == 0" nzColor="default">
<i nz-icon nzType="robot" nzTheme="outline"></i>
<span>{{ 'monitor.status.un-manage' | i18n }}</span>
<span>未监控</span>
</nz-tag>
<nz-tag *ngIf="data.status == 1" nzColor="success">
<i nz-icon nzType="smile" nzTheme="outline"></i>
<span>{{ 'monitor.status.available' | i18n }}</span>
<span>正常监控</span>
</nz-tag>
<nz-tag *ngIf="data.status == 2" nzColor="warning">
<i nz-icon nzType="meh" nzTheme="outline"></i>
<span>{{ 'monitor.status.unavailable' | i18n }}</span>
<span>监控不可用</span>
</nz-tag>
<nz-tag *ngIf="data.status == 3" nzColor="error">
<i nz-icon nzType="frown" nzTheme="outline"></i>
<span>{{ 'monitor.status.unreachable' | i18n }}</span>
<span>监控不可达</span>
</nz-tag>
<nz-tag *ngIf="data.status == 4" nzColor="default">
<i nz-icon nzType="sync"></i>
<span>监控已挂起</span>
</nz-tag>
</td>
<td nzAlign="center">{{ data.host }}</td>
@@ -127,34 +129,16 @@
</td>
<td nzAlign="center">{{ (data.gmtUpdate ? data.gmtUpdate : data.gmtCreate) | date: 'YYYY-MM-dd HH:mm:ss' }}</td>
<td nzAlign="center">
<button nz-button nzType="primary" (click)="onEditOneMonitor(data.id)" nz-tooltip [nzTooltipTitle]="'monitors.edit-monitor' | i18n">
<button nz-button nzType="primary" (click)="onEditOneMonitor(data.id)" nz-tooltip nzTooltipTitle="修改监控">
<i nz-icon nzType="edit" nzTheme="outline"></i>
</button>
<button
nz-button
nzType="primary"
(click)="onDeleteOneMonitor(data.id)"
nz-tooltip
[nzTooltipTitle]="'monitors.delete-monitor' | i18n"
>
<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]="'monitors.enable' | i18n"
>
<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]="'monitors.cancel' | i18n"
>
<button nz-button nzType="primary" (click)="onCancelManageOneMonitor(data.id)" nz-tooltip nzTooltipTitle="取消监控">
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
</button>
</td>
@@ -162,4 +146,4 @@
</tbody>
</nz-table>
<ng-template #rangeTemplate> {{ 'common.total' | i18n }} {{ total }} </ng-template>
<ng-template #rangeTemplate> 总量 {{ total }} </ng-template>

View File

@@ -1,7 +1,5 @@
import { Component, Inject, OnInit } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
@@ -22,8 +20,7 @@ export class MonitorListComponent implements OnInit {
private modal: NzModalService,
private notifySvc: NzNotificationService,
private msg: NzMessageService,
private monitorSvc: MonitorService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
private monitorSvc: MonitorService
) {}
app!: string;
@@ -105,7 +102,7 @@ export class MonitorListComponent implements OnInit {
onEditOneMonitor(monitorId: number) {
if (monitorId == null) {
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-edit'), '');
this.notifySvc.warning('未选中任何待编辑项!', '');
return;
}
this.router.navigateByUrl(`/monitors/${monitorId}/edit`);
@@ -116,11 +113,11 @@ export class MonitorListComponent implements OnInit {
onEditMonitor() {
// 编辑时只能选中一个监控
if (this.checkedMonitorIds == null || this.checkedMonitorIds.size === 0) {
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-edit'), '');
this.notifySvc.warning('未选中任何待编辑项!', '');
return;
}
if (this.checkedMonitorIds.size > 1) {
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.one-select-edit'), '');
this.notifySvc.warning('只能对一个选中项进行编辑!', '');
return;
}
let monitorId = 0;
@@ -132,9 +129,9 @@ export class MonitorListComponent implements OnInit {
let monitors = new Set<number>();
monitors.add(monitorId);
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('common.confirm.delete'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteMonitors(monitors)
@@ -143,13 +140,13 @@ export class MonitorListComponent implements OnInit {
onDeleteMonitors() {
if (this.checkedMonitorIds == null || this.checkedMonitorIds.size === 0) {
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-delete'), '');
this.notifySvc.warning('未选中任何待删除项!', '');
return;
}
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('common.confirm.delete-batch'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否批量删除!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.deleteMonitors(this.checkedMonitorIds)
@@ -158,7 +155,7 @@ export class MonitorListComponent implements OnInit {
deleteMonitors(monitors: Set<number>) {
if (monitors == null || monitors.size == 0) {
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-delete'), '');
this.notifySvc.warning('未选中任何待删除项!', '');
return;
}
this.tableLoading = true;
@@ -166,30 +163,30 @@ export class MonitorListComponent implements OnInit {
message => {
deleteMonitors$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.delete-success'), '');
this.notifySvc.success('删除成功!', '');
this.loadMonitorTable();
} else {
this.tableLoading = false;
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), message.msg);
this.notifySvc.error('删除失败!', message.msg);
}
},
error => {
this.tableLoading = false;
deleteMonitors$.unsubscribe();
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), error.msg);
this.notifySvc.error('删除失败!', error.msg);
}
);
}
onCancelManageMonitors() {
if (this.checkedMonitorIds == null || this.checkedMonitorIds.size === 0) {
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-cancel'), '');
this.notifySvc.warning('未选中任何待取消项!', '');
return;
}
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('common.confirm.cancel-batch'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否批量取消监控!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.cancelManageMonitors(this.checkedMonitorIds)
@@ -200,9 +197,9 @@ export class MonitorListComponent implements OnInit {
let monitors = new Set<number>();
monitors.add(monitorId);
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('common.confirm.cancel'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否取消监控!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.cancelManageMonitors(monitors)
@@ -215,30 +212,30 @@ export class MonitorListComponent implements OnInit {
message => {
cancelManage$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.cancel-success'), '');
this.notifySvc.success('取消监控成功!', '');
this.loadMonitorTable();
} else {
this.tableLoading = false;
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.cancel-fail'), message.msg);
this.notifySvc.error('取消监控失败!', message.msg);
}
},
error => {
this.tableLoading = false;
cancelManage$.unsubscribe();
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.cancel-fail'), error.msg);
this.notifySvc.error('取消监控失败!', error.msg);
}
);
}
onEnableManageMonitors() {
if (this.checkedMonitorIds == null || this.checkedMonitorIds.size === 0) {
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-enable'), '');
this.notifySvc.warning('未选中任何待启用监控项!', '');
return;
}
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('common.confirm.enable-batch'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否批量启用监控!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.enableManageMonitors(this.checkedMonitorIds)
@@ -249,9 +246,9 @@ export class MonitorListComponent implements OnInit {
let monitors = new Set<number>();
monitors.add(monitorId);
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('common.confirm.enable'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzTitle: '请确认是否启用监控!',
nzOkText: '确定',
nzCancelText: '取消',
nzOkDanger: true,
nzOkType: 'primary',
nzOnOk: () => this.enableManageMonitors(monitors)
@@ -264,17 +261,17 @@ export class MonitorListComponent implements OnInit {
message => {
enableManage$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.enable-success'), '');
this.notifySvc.success('启用监控成功!', '');
this.loadMonitorTable();
} else {
this.tableLoading = false;
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.enable-fail'), message.msg);
this.notifySvc.error('启用监控失败!', message.msg);
}
},
error => {
this.tableLoading = false;
enableManage$.unsubscribe();
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.enable-fail'), error.msg);
this.notifySvc.error('启用监控失败!', error.msg);
}
);
}

View File

@@ -3,20 +3,20 @@
<nz-breadcrumb-item>
<a [routerLink]="['/']">
<i nz-icon nzType="home"></i>
<span>{{ 'menu.dashboard' | i18n }}</span>
<span>仪表盘</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<a [routerLink]="['/monitors']" [queryParams]="{ app: monitor.app ? monitor.app : '' }">
<i nz-icon nzType="monitor"></i>
<span>{{ 'monitors.list' | i18n }}</span>
<span>监控列表</span>
</a>
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<i nz-icon nzType="plus-circle"></i>
<span>{{ 'monitors.new' | i18n }} {{ 'monitor.app.' + monitor.app | i18n }} {{ 'monitor' | i18n }}</span>
<span>新增 {{ 'monitor.app.' + monitor.app | i18n }} 监控</span>
<a [href]="'https://tancloud.cn/docs/help/' + monitor.app" target="_blank" style="float: right; margin-right: 5%">
<span>{{ 'common.button.help' | i18n }} </span>
<span>帮助&nbsp;</span>
<i nz-icon nzType="question-circle" nzTheme="outline"></i>
</a>
</nz-breadcrumb-item>
@@ -27,9 +27,7 @@
<div class="-inner-content">
<form nz-form #newForm="ngForm">
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="host" nzRequired="true" [nzTooltipTitle]="'monitor.host.tip' | i18n">
{{ 'monitor.host' | i18n }}
</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="host" nzRequired="true" nzTooltipTitle="被监控的对端IP或域名"> 监控Host </nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<input
[(ngModel)]="monitor.host"
@@ -38,17 +36,17 @@
type="text"
id="host"
required
[placeholder]="'monitor.host.tip' | i18n"
placeholder="请输入域名或IP"
(ngModelChange)="onHostChange($event)"
/>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="name" nzRequired="true" [nzTooltipTitle]="'monitor.name.tip' | i18n">
{{ 'monitor.name' | i18n }}
<nz-form-label [nzSpan]="7" nzFor="name" nzRequired="true" nzTooltipTitle="标识此监控的名称,名称需要保证唯一性">
监控名称
</nz-form-label>
<nz-form-control [nzSpan]="8" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="monitor.name" nz-input required name="name" type="text" id="name" [placeholder]="'monitor.name.tip' | i18n" />
<input [(ngModel)]="monitor.name" nz-input required name="name" type="text" id="name" placeholder="监控名称需要保证唯一性" />
</nz-form-control>
</nz-form-item>
@@ -173,152 +171,10 @@
</nz-form-control>
</nz-form-item>
<nz-collapse [nzGhost]="true">
<nz-collapse-panel [nzHeader]="extraColHeader" [nzShowArrow]="false">
<nz-form-item *ngFor="let paramDefine of advancedParamDefines; let i = index">
<nz-form-label
*ngIf="paramDefine.field !== 'host' && paramDefine.type === 'text'"
nzSpan="7"
[nzRequired]="paramDefine.required"
[nzFor]="paramDefine.field"
>{{ paramDefine.name }}
</nz-form-label>
<nz-form-control
*ngIf="paramDefine.field !== 'host' && paramDefine.type === 'text'"
nzSpan="8"
[nzErrorTip]="'validation.required' | i18n"
>
<input
nz-input
[(ngModel)]="advancedParams[i].value"
[required]="paramDefine.required"
[name]="paramDefine.field"
[type]="paramDefine.type"
[id]="paramDefine.field"
[placeholder]="paramDefine.placeholder ? paramDefine.placeholder : ''"
/>
</nz-form-control>
<nz-form-label
*ngIf="paramDefine.type === 'textarea'"
nzSpan="7"
[nzRequired]="paramDefine.required"
[nzFor]="paramDefine.field"
>{{ paramDefine.name }}
</nz-form-label>
<nz-form-control *ngIf="paramDefine.type === 'textarea'" nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<textarea
nz-input
[(ngModel)]="advancedParams[i].value"
[required]="paramDefine.required"
[name]="paramDefine.field"
[id]="paramDefine.field"
[placeholder]="paramDefine.placeholder ? paramDefine.placeholder : ''"
rows="3"
></textarea>
</nz-form-control>
<nz-form-label
*ngIf="paramDefine.type === 'password'"
nzSpan="7"
[nzRequired]="paramDefine.required"
[nzFor]="paramDefine.field"
>{{ paramDefine.name }}
</nz-form-label>
<nz-form-control *ngIf="paramDefine.type === 'password'" nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<nz-input-group [nzSuffix]="suffixTemplate" style="width: 100%">
<input
[type]="passwordVisible ? 'text' : 'password'"
nz-input
placeholder="input password"
[required]="paramDefine.required"
[(ngModel)]="advancedParams[i].value"
[id]="paramDefine.field"
[name]="paramDefine.field"
[placeholder]="paramDefine.placeholder ? paramDefine.placeholder : ''"
/>
</nz-input-group>
<ng-template #suffixTemplate>
<i nz-icon [nzType]="passwordVisible ? 'eye-invisible' : 'eye'" (click)="passwordVisible = !passwordVisible"></i>
</ng-template>
</nz-form-control>
<nz-form-label *ngIf="paramDefine.type === 'number'" nzSpan="7" [nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
>{{ paramDefine.name }}
</nz-form-label>
<nz-form-control *ngIf="paramDefine.type === 'number'" nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<nz-input-number
[(ngModel)]="advancedParams[i].value"
[required]="paramDefine.required"
[nzMin]="-1000"
[nzMax]="65535"
[nzStep]="1"
[nzPlaceHolder]="paramDefine.placeholder ? paramDefine.placeholder : ''"
[name]="paramDefine.field"
[id]="paramDefine.field"
></nz-input-number>
</nz-form-control>
<nz-form-label *ngIf="paramDefine.type === 'boolean'" nzSpan="7" [nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
>{{ paramDefine.name }}
</nz-form-label>
<nz-form-control *ngIf="paramDefine.type === 'boolean'" nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<nz-switch
[(ngModel)]="advancedParams[i].value"
[required]="paramDefine.required"
[name]="paramDefine.field"
[id]="paramDefine.field"
></nz-switch>
</nz-form-control>
<nz-form-label *ngIf="paramDefine.type === 'radio'" nzSpan="7" [nzRequired]="paramDefine.required" [nzFor]="paramDefine.field"
>{{ paramDefine.name }}
</nz-form-label>
<nz-form-control *ngIf="paramDefine.type === 'radio'" nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<nz-radio-group
[(ngModel)]="advancedParams[i].value"
[required]="paramDefine.required"
nzButtonStyle="solid"
[name]="paramDefine.field"
[id]="paramDefine.field"
>
<label nz-radio-button [nzValue]="optionItem.value" *ngFor="let optionItem of paramDefine.options">
{{ optionItem.label }}
</label>
</nz-radio-group>
</nz-form-control>
<nz-form-label
*ngIf="paramDefine.type === 'key-value'"
nzSpan="7"
[nzRequired]="paramDefine.required"
[nzFor]="paramDefine.field"
>{{ paramDefine.name }}
</nz-form-label>
<nz-form-control *ngIf="paramDefine.type === 'key-value'" nzSpan="8" [nzErrorTip]="'validation.required' | i18n">
<app-key-value-input
[(value)]="advancedParams[i].value"
[id]="paramDefine.field"
keyAlias="Header Name"
valueAlias="Header Value"
></app-key-value-input>
</nz-form-control>
</nz-form-item>
</nz-collapse-panel>
</nz-collapse>
<ng-template #extraColHeader>
<button style="top: -10px; margin-left: 40%" nz-button nzType="dashed" nz-tooltip [nzTooltipTitle]="'monitors.advanced.tip' | i18n">
<span>{{ 'monitors.advanced' | i18n }}</span>
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
</button>
</ng-template>
<nz-divider></nz-divider>
<nz-form-item>
<nz-form-label nzSpan="7" nzFor="intervals" [nzTooltipTitle]="'monitor.intervals.tip' | i18n">
{{ 'monitor.intervals' | i18n }}
</nz-form-label>
<nz-form-label nzSpan="7" nzFor="intervals" nzTooltipTitle="监控周期性采集数据间隔时间,单位秒"> 采集间隔 </nz-form-label>
<nz-form-control nzSpan="8">
<nz-input-number [(ngModel)]="monitor.intervals" [nzMin]="10" [nzMax]="604800" [nzStep]="60" name="intervals" id="intervals">
</nz-input-number>
@@ -326,18 +182,14 @@
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="7" nzFor="detect" [nzTooltipTitle]="'monitors.detect.tip' | i18n">
{{ 'monitors.detect' | i18n }}
</nz-form-label>
<nz-form-label nzSpan="7" nzFor="detect" nzTooltipTitle="新增监控前是否先探测检查监控可用性"> 测试连接 </nz-form-label>
<nz-form-control nzSpan="8">
<nz-switch [(ngModel)]="detected" name="detect" id="detect"></nz-switch>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="7" nzFor="description" [nzTooltipTitle]="'monitor.description.tip' | i18n">
{{ 'monitor.description' | i18n }}
</nz-form-label>
<nz-form-label [nzSpan]="7" nzFor="description" nzTooltipTitle="更多标识和描述此监控的备注信息"> 描述备注 </nz-form-label>
<nz-form-control [nzSpan]="8">
<nz-textarea-count [nzMaxCharacterCount]="100">
<textarea [(ngModel)]="monitor.description" rows="3" nz-input name="description" id="description"></textarea>
@@ -347,9 +199,9 @@
<div nz-row>
<div nz-col nzSpan="8" nzOffset="9">
<button nz-button nzType="primary" type="submit" (click)="onDetect(newForm.form)"> {{ 'common.button.detect' | i18n }} </button>
<button nz-button nzType="primary" type="submit" (click)="onSubmit(newForm.form)"> {{ 'common.button.ok' | i18n }} </button>
<button nz-button nzType="primary" type="reset" (click)="onCancel()"> {{ 'common.button.cancel' | i18n }} </button>
<button nz-button nzType="primary" type="submit" (click)="onDetect(newForm.form)"> 测试 </button>
<button nz-button nzType="primary" type="submit" (click)="onSubmit(newForm.form)"> 确定 </button>
<button nz-button nzType="primary" type="reset" (click)="onCancel()"> 取消 </button>
</div>
</div>
</form>

View File

@@ -1,8 +1,8 @@
import { ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core';
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN, TitleService } from '@delon/theme';
import { TitleService } from '@delon/theme';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { switchMap } from 'rxjs/operators';
@@ -20,8 +20,6 @@ import { MonitorService } from '../../../service/monitor.service';
export class MonitorNewComponent implements OnInit {
paramDefines!: ParamDefine[];
params!: Param[];
advancedParamDefines!: ParamDefine[];
advancedParams!: Param[];
monitor!: Monitor;
detected: boolean = true;
passwordVisible: boolean = false;
@@ -34,7 +32,7 @@ export class MonitorNewComponent implements OnInit {
private router: Router,
private notifySvc: NzNotificationService,
private cdr: ChangeDetectorRef,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService,
private i18n: I18NService,
private titleSvc: TitleService,
private formBuilder: FormBuilder
) {
@@ -55,11 +53,9 @@ export class MonitorNewComponent implements OnInit {
)
.subscribe(message => {
if (message.code === 0) {
this.paramDefines = message.data;
this.params = [];
this.advancedParams = [];
this.paramDefines = [];
this.advancedParamDefines = [];
message.data.forEach(define => {
this.paramDefines.forEach(define => {
let param = new Param();
param.field = define.field;
if (define.type === 'number') {
@@ -81,13 +77,7 @@ export class MonitorNewComponent implements OnInit {
param.value = define.defaultValue;
}
}
if (define.hide) {
this.advancedParams.push(param);
this.advancedParamDefines.push(define);
} else {
this.params.push(param);
this.paramDefines.push(define);
}
});
} else {
console.warn(message.msg);
@@ -135,30 +125,25 @@ export class MonitorNewComponent implements OnInit {
param.value = (param.value as string).trim();
}
});
this.advancedParams.forEach(param => {
if (param.value != null && typeof param.value == 'string') {
param.value = (param.value as string).trim();
}
});
let addMonitor = {
detected: this.detected,
monitor: this.monitor,
params: this.params.concat(this.advancedParams)
params: this.params
};
this.isSpinning = true;
this.monitorSvc.newMonitor(addMonitor).subscribe(
message => {
this.isSpinning = false;
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('monitors.new.success'), '');
this.notifySvc.success('新增监控成功', '');
this.router.navigateByUrl(`/monitors?app=${this.monitor.app}`);
} else {
this.notifySvc.error(this.i18nSvc.fanyi('monitors.new.failed'), message.msg);
this.notifySvc.error('新增监控失败', message.msg);
}
},
error => {
this.isSpinning = false;
this.notifySvc.error(this.i18nSvc.fanyi('monitors.new.failed'), error.error.msg);
this.notifySvc.error('新增监控失败', error.error.msg);
}
);
}
@@ -184,29 +169,24 @@ export class MonitorNewComponent implements OnInit {
param.value = (param.value as string).trim();
}
});
this.advancedParams.forEach(param => {
if (param.value != null && typeof param.value == 'string') {
param.value = (param.value as string).trim();
}
});
let detectMonitor = {
detected: true,
monitor: this.monitor,
params: this.params.concat(this.advancedParams)
params: this.params
};
this.isSpinning = true;
this.monitorSvc.detectMonitor(detectMonitor).subscribe(
message => {
this.isSpinning = false;
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('monitors.detect.success'), '');
this.notifySvc.success('探测成功', '');
} else {
this.notifySvc.error(this.i18nSvc.fanyi('monitors.detect.failed'), message.msg);
this.notifySvc.error('探测失败', message.msg);
}
},
error => {
this.isSpinning = false;
this.notifySvc.error(this.i18nSvc.fanyi('monitors.detect.failed'), error.error.msg);
this.notifySvc.error('探测异常', error.error.msg);
}
);
}

View File

@@ -1,7 +1,6 @@
import { NgModule, Type } from '@angular/core';
import { SharedModule } from '@shared';
import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';
import { NzCollapseModule } from 'ng-zorro-antd/collapse';
import { NzDividerModule } from 'ng-zorro-antd/divider';
import { NzLayoutModule } from 'ng-zorro-antd/layout';
import { NzRadioModule } from 'ng-zorro-antd/radio';
@@ -38,8 +37,7 @@ const COMPONENTS: Array<Type<void>> = [
NzRadioModule,
NgxEchartsModule,
NzLayoutModule,
NzSpaceModule,
NzCollapseModule
NzSpaceModule
],
declarations: COMPONENTS
})

View File

@@ -7,11 +7,11 @@
<nz-form-item>
<nz-form-control [nzErrorTip]="'validation.password.required' | i18n">
<nz-input-group nzSuffixIcon="lock">
<input type="text" nz-input formControlName="password" [placeholder]="'app.lock.placeholder' | i18n" />
<input type="text" nz-input formControlName="password" placeholder="输入任意解锁" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-row nzAlign="middle">
<nz-row nzType="flex" nzAlign="middle">
<nz-col [nzOffset]="12" [nzSpan]="12" style="text-align: right">
<button nz-button [disabled]="!f.valid" nzType="primary">{{ 'app.lock' | i18n }}</button>
</nz-col>

View File

@@ -3,16 +3,16 @@
<nz-tab [nzTitle]="'app.login.tab-login-credentials' | i18n">
<nz-alert *ngIf="error" [nzType]="'error'" [nzMessage]="error" [nzShowIcon]="true" class="mb-lg"></nz-alert>
<nz-form-item>
<nz-form-control [nzErrorTip]="'app.login.message-need-identifier' | i18n">
<nz-form-control nzErrorTip="请输入用户名">
<nz-input-group nzSize="large" nzPrefixIcon="user">
<input nz-input formControlName="userName" [placeholder]="'app.login.message-need-identifier' | i18n" />
<input nz-input formControlName="userName" placeholder="请输入用户名" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzErrorTip]="'app.login.message-need-credential' | i18n">
<nz-form-control nzErrorTip="请输入密码">
<nz-input-group nzSize="large" nzPrefixIcon="lock">
<input nz-input type="password" formControlName="password" [placeholder]="'app.login.message-need-credential' | i18n" />
<input nz-input type="password" formControlName="password" placeholder="请输入密码" />
</nz-input-group>
</nz-form-control>
</nz-form-item>

View File

@@ -1,10 +1,10 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnDestroy, Optional } from '@angular/core';
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { I18NService, StartupService } from '@core';
import { StartupService } from '@core';
import { ReuseTabService } from '@delon/abc/reuse-tab';
import { DA_SERVICE_TOKEN, ITokenService, SocialService } from '@delon/auth';
import { SettingsService, _HttpClient, ALAIN_I18N_TOKEN } from '@delon/theme';
import { DA_SERVICE_TOKEN, ITokenService, SocialOpenType, SocialService } from '@delon/auth';
import { SettingsService, _HttpClient } from '@delon/theme';
import { User } from '@delon/theme/src/services/settings/types';
import { NzTabChangeEvent } from 'ng-zorro-antd/tabs';
import { finalize } from 'rxjs/operators';
@@ -29,7 +29,6 @@ export class UserLoginComponent implements OnDestroy {
@Inject(ReuseTabService)
private reuseTabService: ReuseTabService,
@Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService,
private startupSrv: StartupService,
private http: _HttpClient,
private cdr: ChangeDetectorRef,
@@ -126,7 +125,7 @@ export class UserLoginComponent implements OnDestroy {
let user: User = {
name: this.userName.value,
avatar: './assets/img/avatar.svg',
email: this.i18nSvc.fanyi('app.role.admin')
email: '管理员'
};
this.settingsService.setUser(user);
// 重新获取 StartupService 内容,我们始终认为应用信息一般都会受当前用户授权范围而影响

View File

@@ -1,296 +1,138 @@
{
"menu": {
"main": "Main",
"lang": "Language",
"dashboard": "DashBoard",
"search.placeholder": "SearchMonitor Name、IP",
"fullscreen": "Full Screen",
"fullscreen.exit": "Exit",
"clear.local.storage": "Clear Local Storage",
"monitor": {
"": "Monitor",
"service": "Service Monitor",
"db": "DB Monitor",
"os": "OS Monitor",
"mid": "Mid Monitor",
"custom": "Custom Monitor"
},
"account": {
"": "Personal",
"center": "Personal Center",
"settings": "Account Setting",
"security": "Security Setting",
"binding": "Account Binding",
"trigger": "Trigger Error",
"logout": "Logout"
},
"alert": {
"": "Alert",
"center": "Alert Center",
"setting": "Alert Setting",
"dispatch": "Alert Notify"
},
"extras": {
"": "More",
"help": "Help Center",
"setting": "Setting"
},
"more": "More"
},
"monitor": {
"": "Monitor",
"name": "Monitor Name",
"name.tip": "Monitor name, the name needs to be unique",
"host": "Monitor Host",
"host.tip": "The monitored peer IP or domain name",
"description": "Description",
"description.tip": "Description and remarks",
"intervals": "Intervals",
"intervals.tip": "Monitor the interval time of periodic collection of data, second",
"category": {
"": "Category",
"service": "Service",
"db": "Database",
"os": "OS",
"mid": "Middleware",
"custom": "Custom"
},
"app": {
"": "Monitor Type",
"website": "Website Monitor",
"api": "HTTP API",
"http": "HTTP API",
"ping": "PING Connect",
"port": "Port Available",
"mysql": "Mysql",
"oracle": "Oracle",
"redis": "Redis",
"fullsite": "SiteMap Monitor"
},
"status": {
"": "Monitor Status",
"all": "All Status",
"available": "Available",
"unavailable": "UnAvailable",
"unreachable": "UnReachable",
"un-manage": "UnManaged"
}
},
"alert": {
"": "Alert",
"status": {
"": "Alert Status",
"all": "All Status",
"0": "Pending",
"2": "Restored",
"3": "Processed"
},
"priority": {
"": "Alarm Priority",
"all": "All Priority",
"0": "Emergency",
"1": "Critical",
"2": "Warning"
}
},
"alert.setting.new": "New Threshold",
"alert.setting.edit": "Edit Threshold",
"alert.setting.delete": "Delete Threshold",
"alert.setting.target": "Metric Target",
"alert.setting.expr": "Threshold Trigger Expr",
"alert.setting.times": "Trigger Times",
"alert.setting.times.tip": "Set how many times the threshold is triggered before sending an alert",
"alert.setting.template": "Notice Template",
"alert.setting.template.tip": "Supported notification template environment variables",
"alert.setting.template.label": "The notification information template sent after the alarm is triggered, see the template environment variable above",
"alert.setting.template.example": "Please input notice template.Eg: ${app}.${metrics}.${metric}'s value is too high",
"alert.setting.template.monitor-type": "Monitor Type Name",
"alert.setting.template.metrics-name": "Metrics Name",
"alert.setting.template.metric-name": "Metric Name",
"alert.setting.template.metric-value": "Metric Target Value",
"alert.setting.template.other-value": "Other Metric Value",
"alert.setting.template.instance-value": "Instance Value",
"alert.setting.default": "Global Default",
"alert.setting.default.tip": "Whether this alarm threshold configuration applies to all this type of monitoring globally",
"alert.setting.enable": "Enable Alert",
"alert.setting.enable.tip": "This alarm threshold configuration is enabled or disabled",
"alert.setting.connect": "Alert Associate Monitors",
"alert.setting.connect.left": "No Associate",
"alert.setting.connect.right": "Associated",
"alert.setting.expr.tip": "Supported Threshold Trigger Expression Environment Variables and Operators",
"alert.setting.expr.label": "Calculate and judge whether the threshold is triggered according to this expression. The expression environment variables and operators are shown above.",
"alert.setting.expr.example": "Calculate whether to trigger the threshold according to this expression.Eg",
"alert.setting.priority.tip": "The alarm level that triggers the threshold, from low to high:WarningCriticalEmergency",
"alert.setting.target.tip": "The selected metric object",
"alert.setting.target.other": "Other metric objects of the row",
"alert.setting.target.instance": "Instance of the row",
"alert.setting.operator": "Supported operator functions",
"alert.center.delete": "Delete Alerts",
"alert.center.deal": "Mark Processed",
"alert.center.no-deal": "Mark Pending",
"alert.center.search": "Search Alert Content",
"alert.center.filter-status": "Filter Alert Status",
"alert.center.filter-priority": "Filter Alert Priority",
"alert.center.target": "Metric Target",
"alert.center.monitor": "Belong Monitor",
"alert.center.priority": "Priority",
"alert.center.content": "Alert Content",
"alert.center.status": "Status",
"alert.center.time": "Alert Time",
"alert.center.notify.no-delete": "No items selected for deletion!",
"alert.center.confirm.delete": "Please confirm whether to delete!",
"alert.center.confirm.delete-batch": "Please confirm whether to delete in batch!",
"alert.center.notify.no-mark": "No items selected for mark!",
"alert.center.confirm.mark-done-batch": "Please confirm whether to mark processed in batch!",
"alert.center.confirm.mark-done": "Please confirm whether to mark processed!",
"alert.center.confirm.mark-no-batch": "Please confirm whether to mark Pending in batch!",
"alert.center.confirm.mark-no": "Please confirm whether to mark Pending!",
"alert.notice.receiver": "Alert Receiver",
"alert.notice.receiver.new": "New Receiver",
"alert.notice.receiver.edit": "Edit Receiver",
"alert.notice.receiver.delete": "Delete Receiver",
"alert.notice.receiver.people": "Receiver",
"alert.notice.receiver.people.name": "Receiver Name",
"alert.notice.receiver.type": "Notice Type",
"alert.notice.receiver.setting": "Setting",
"alert.notice.type.sms": "SMS",
"alert.notice.type.phone": "Phone",
"alert.notice.type.email": "Email",
"alert.notice.type.url": "URL",
"alert.notice.type.wechat": "Open WeChat",
"alert.notice.type.wechat-id": "WeChat OPENID",
"alert.notice.type.wework": "WeWork Robot",
"alert.notice.type.wework-key": "WeWork Robot KEY",
"alert.notice.type.access-token": "Robot ACCESS_TOKEN",
"alert.notice.type.ding": "DingDing Robot",
"alert.notice.type.fei-shu": "FeiShu Robot",
"alert.notice.type.fei-shu-key": "FeiShu Robot KEY",
"alert.notice.rule": "Alert Notice Rule",
"alert.notice.rule.new": "New Notice Rule",
"alert.notice.rule.edit": "Edit Notice Rule",
"alert.notice.rule.delete": "Delete Notice Rule",
"alert.notice.rule.name": "Rule Name",
"alert.notice.rule.all": "Dispatch ALl",
"alert.notice.rule.enable": "Enable",
"dashboard.alerts.title": "Recently Alerts List",
"dashboard.alerts.title-no": "Recently Pending Alerts",
"dashboard.alerts.no": "No Pending Alerts",
"dashboard.alerts.enter": "Go Alert Center",
"dashboard.alerts.distribute": "The Distribution Of Alerts",
"dashboard.alerts.num": "Alerts Num",
"dashboard.alerts.deal": "Alerts Dealing",
"dashboard.alerts.deal-percent": "Dealing Rate",
"dashboard.monitors.total": "Monitor Total",
"dashboard.monitors.title": "Monitoring Overview",
"dashboard.monitors.sub-title": "The Distribution Of Monitors",
"dashboard.monitors.formatter": " Monitors ",
"dashboard.monitors.distribute": "Monitor Distribution",
"monitors.list": "Monitor List",
"monitors.new": "New",
"monitors.new.success": "New Monitor Success",
"monitors.new.failed": "New Monitor Failed",
"monitors.edit": "Edit",
"monitors.edit.success": "Update Monitor Success",
"monitors.edit.failed": "Update Monitor Failed",
"monitors.not-found": "This Monitor Not Found",
"monitors.delete": "Delete",
"monitors.edit-monitor": "Edit Monitor",
"monitors.delete-monitor": "Delete Monitor",
"monitors.enable": "Enable Monitor",
"monitors.cancel": "Cancel Monitor",
"monitors.search.placeholder": "Search Monitor",
"monitors.search.filter": "Filter Monitor Status",
"monitors.total": "Total",
"monitors.advanced": "Advanced",
"monitors.advanced.tip": "Setting Advanced Param",
"monitors.detect": "Detect",
"monitors.detect.success": "Detect Success",
"monitors.detect.failed": "Detect Failed",
"monitors.detect.tip": "Detect monitor available before apply",
"monitors.detail": "Monitor Detail",
"monitors.detail.name": "Name",
"monitors.detail.port": "Port",
"monitors.detail.description": "Desc",
"monitors.detail.status": "Status",
"monitors.detail.basic": "Monitor Basic",
"monitors.detail.realtime": "Monitor Real-Time Detail",
"monitors.detail.history": "Monitor Historical Chart Detail",
"monitors.collect.time": "Collect Time",
"monitors.collect.time.tip": "Last collect time",
"monitors.detail.chart.zoom": "Zoom In",
"monitors.detail.chart.back": "Zoom restore",
"monitors.detail.chart.save": "Save as Image",
"monitors.detail.chart.query-1h": "Query 1 Hour",
"monitors.detail.chart.query-6h": "Query 6 Hours",
"monitors.detail.chart.query-1d": "Query 1 Day",
"monitors.detail.chart.query-1w": "Query 1 Week",
"monitors.detail.chart.query-1m": "Query 1 Month",
"monitors.detail.chart.no-data": "No Metrics Data",
"monitors.detail.chart.unit": "Unit",
"common.name": "Name",
"common.value": "Value",
"common.search": "Search",
"common.refresh": "Refresh",
"common.edit-time": "Last Update Time",
"common.new-time": "Create Time",
"common.edit": "Operate",
"common.total": "Total",
"common.yes": "Yes",
"common.no": "No",
"common.enable": "Enable",
"common.disable": "Disable",
"common.notify.no-select-edit": "No items selected for editing!",
"common.notify.one-select-edit": "Only one selection can be edited!",
"common.confirm.delete": "Please confirm whether to delete!",
"common.notify.no-select-delete": "No items selected for deletion!",
"common.confirm.delete-batch": "Please confirm whether to delete in batches!",
"common.notify.delete-success": "Delete Success!",
"common.notify.delete-fail": "Delete Failed!",
"common.notify.new-success": "Add Success!",
"common.notify.new-fail": "Add Failed!",
"common.notify.apply-success": "Apply Success!",
"common.notify.apply-fail": "Apply Failed!",
"common.notify.monitor-fail": "Query Monitor Failed!",
"common.notify.edit-success": "Edit Success!",
"common.notify.edit-fail": "Edit Failed!",
"common.notify.no-select-cancel": "No items selected for cancel!",
"common.confirm.cancel-batch": "Please confirm whether to cancel monitor in batches!",
"common.confirm.cancel": "Please confirm whether to cancel monitor!",
"common.notify.cancel-success": "Cancel Success!",
"common.notify.cancel-fail": "Cancel Failed!",
"common.notify.mark-success": "Mark Success!",
"common.notify.mark-fail": "Mark Failed!",
"common.notify.no-select-enable": "No items selected for enable!",
"common.confirm.enable-batch": "Please confirm whether to enable monitor in batches!",
"common.confirm.enable": "Please confirm whether to enable monitor!",
"common.notify.enable-success": "Enable Success!",
"common.notify.enable-fail": "Enable Failed!",
"common.confirm.clear-cache": "Please confirm whether to clear cache!",
"common.notify.clear-success": "Clear Success!",
"common.button.ok": "OK",
"common.button.cancel": "Cancel",
"common.button.help": "Help",
"common.button.edit": "Edit",
"common.button.delete": "Delete",
"common.button.detect": "Detect",
"validation.email.invalid": "Invalid email",
"validation.phone.invalid": "Invalid phone number",
"validation.verification-code.invalid": "Invalid verification code, should be 6 digits",
"validation.required": "Please fill in the required fields! ",
"app.theme.default": "Light Theme",
"app.theme.dark": "Dark Theme",
"app.theme.compact": "Compact Theme",
"app.role.admin": "Administrator",
"menu.search.placeholder": "Search for people, file, photos...",
"menu.fullscreen": "Fullscreen",
"menu.fullscreen.exit": "Exit Fullscreen",
"menu.clear.local.storage": "Clear Local Storage",
"menu.lang": "Language",
"menu.main": "Main Navigation",
"menu.dashboard": "Dashboard",
"menu.dashboard.v1": "Default",
"menu.dashboard.analysis": "Analysis",
"menu.dashboard.monitor": "Monitor",
"menu.dashboard.workplace": "Workplace",
"menu.shortcut": "Shortcut",
"menu.widgets": "Widgets",
"menu.alain": "Alain",
"menu.style": "Style",
"menu.style.typography": "Typography",
"menu.style.gridmasonry": "Grid Masonry",
"menu.style.colors": "Colors",
"menu.delon": "Delon Lib",
"menu.delon.form": "Dynamic Form",
"menu.delon.table": "Simple table",
"menu.delon.util": "Util",
"menu.delon.print": "Print",
"menu.delon.guard": "Route Guard",
"menu.delon.cache": "Cache",
"menu.delon.qr": "QR",
"menu.delon.acl": "ACL",
"menu.delon.downfile": "Download File",
"menu.delon.xlsx": "Excel",
"menu.delon.zip": "Zip",
"menu.pro": "Antd Pro",
"menu.form": "Form",
"menu.form.basicform": "Basic Form",
"menu.form.stepform": "Step Form",
"menu.form.stepform.info": "Step Form(write transfer information)",
"menu.form.stepform.confirm": "Step Form(confirm transfer information)",
"menu.form.stepform.result": "Step Form(finished)",
"menu.form.advancedform": "Advanced Form",
"menu.list": "List",
"menu.list.searchtable": "Search Table",
"menu.list.basiclist": "Basic List",
"menu.list.cardlist": "Card List",
"menu.list.searchlist": "Search List",
"menu.list.searchlist.articles": "Search List(articles)",
"menu.list.searchlist.projects": "Search List(projects)",
"menu.list.searchlist.applications": "Search List(applications)",
"menu.profile": "Profile",
"menu.profile.basic": "Basic Profile",
"menu.profile.advanced": "Advanced Profile",
"menu.result": "Result",
"menu.result.success": "Success",
"menu.result.fail": "Fail",
"menu.exception": "Exception",
"menu.exception.not-permission": "403",
"menu.exception.not-find": "404",
"menu.exception.server-error": "500",
"menu.account": "Account",
"menu.account.center": "Account Center",
"menu.account.settings": "Account Settings",
"menu.account.trigger": "Trigger Error",
"menu.account.logout": "Logout",
"menu.more": "More",
"menu.report": "Report",
"menu.report.relation": "Relation Map",
"menu.extras": "Extra",
"menu.extras.helpcenter": "Help Center",
"menu.extras.settings": "Settings",
"menu.extras.poi": "Poi",
"app.analysis.test": "Gongzhuan No.{{no}} shop",
"app.analysis.introduce": "Introduce",
"app.analysis.total-sales": "Total Sales",
"app.analysis.day-sales": "Day Sales",
"app.analysis.visits": "Visits",
"app.analysis.visits-trend": "Visits Trend",
"app.analysis.visits-ranking": "Visits Ranking",
"app.analysis.day-visits": "Day Visits",
"app.analysis.week": "Week Ratio",
"app.analysis.day": "Day Ratio",
"app.analysis.payments": "Payments",
"app.analysis.conversion-rate": "Conversion Rate",
"app.analysis.operational-effect": "Operational Effect",
"app.analysis.sales-trend": "Stores Sales Trend",
"app.analysis.sales-ranking": "Sales Ranking",
"app.analysis.all-year": "All Year",
"app.analysis.all-month": "All Month",
"app.analysis.all-week": "All Week",
"app.analysis.all-today": "All day",
"app.analysis.search-users": "Search Users",
"app.analysis.per-capita-search": "Per Capita Search",
"app.analysis.online-top-search": "Online Top Search",
"app.analysis.the-proportion-of-sales": "The Proportion Of Sales",
"app.analysis.channel.all": "ALL",
"app.analysis.channel.online": "Online",
"app.analysis.channel.stores": "Stores",
"app.analysis.sales": "Sales",
"app.analysis.traffic": "Traffic",
"app.analysis.table.rank": "Rank",
"app.analysis.table.search-keyword": "Keyword",
"app.analysis.table.users": "Users",
"app.analysis.table.weekly-range": "Weekly Range",
"app.monitor.trading-activity": "Real-Time Trading Activity",
"app.monitor.total-transactions": "Total transactions today",
"app.monitor.sales-target": "Sales target completion rate",
"app.monitor.remaining-time": "Remaining time of activity",
"app.monitor.total-transactions-per-second": "Total transactions per second",
"app.monitor.activity-forecast": "Activity forecast",
"app.monitor.efficiency": "Efficiency",
"app.monitor.ratio": "Ratio",
"app.monitor.proportion-per-category": "Proportion Per Category",
"app.monitor.fast-food": "Fast food",
"app.monitor.western-food": "Western food",
"app.monitor.hot-pot": "Hot pot",
"app.monitor.waiting-for-implementation": "Waiting for implementation",
"app.monitor.popular-searches": "Popular Searches",
"app.monitor.resource-surplus": "Resource Surplus",
"app.monitor.fund-surplus": "Fund Surplus",
"app.lock": "Lock",
"app.lock.placeholder": "Enter Any To Unlock",
"app.passport.desc": "TanCloud-Friendly High Performance Monitoring Cloud Service",
"app.passport.welcome": "Welcome To Use TanCloud-Monitoring Cloud Service-tancloud.cn",
"app.login.message-need-identifier": "Please enter your username",
"app.login.message-need-credential": "Please enter password",
"app.login.message-invalid-credentials": "Invalid username or password",
"app.login.message-invalid-credentials": "Invalid username or passwordadmin/ant.design",
"app.login.message-invalid-verification-code": "Invalid verification code",
"app.login.tab-login-credentials": "Credentials",
"app.login.tab-login-mobile": "Mobile number",
"app.login.remember-me": "Remember me",
"app.login.forgot-password": "Forgot your password?",
"app.login.sign-in-with": "Sign in with",
"app.login.signup": "Sign up",
"app.login.login": "Login",
"app.register.register": "Register",
"app.register.get-verification-code": "Get code",
"app.register.sign-in": "Already have an account?",
"app.register-result.msg": "Accountregistered at {{email}}",
"app.register-result.activation-email":
"The activation email has been sent to your email address and is valid for 24 hours. Please log in to the email in time and click on the link in the email to activate the account.",
"app.register-result.back-home": "Back to home",
"app.register-result.view-mailbox": "View mailbox",
"validation.email.required": "Please enter your email!",
"validation.email.wrong-format": "The email address is in the wrong format!",
"validation.password.required": "Please enter your password!",

View File

@@ -27,7 +27,7 @@
"alert": {
"": "告警",
"center": "告警中心",
"setting": "告警阈值",
"setting": "告警配置",
"dispatch": "告警通知"
},
"extras": {
@@ -39,14 +39,6 @@
},
"monitor": {
"": "监控",
"name": "监控名称",
"name.tip": "标识监控的名称,名称需要保证唯一性",
"host": "监控Host",
"host.tip": "被监控的对端IP或域名",
"description": "描述备注",
"description.tip": "更多标识和描述此监控的备注信息",
"intervals": "采集间隔",
"intervals.tip": "监控周期性采集数据间隔时间,单位秒",
"category": {
"": "监控类别",
"service": "应用服务",
@@ -66,227 +58,46 @@
"oracle": "Oracle",
"redis": "Redis",
"fullsite": "全站监控"
},
"status": {
"": "监控状态",
"all": "全部状态",
"available": "正常监控",
"unavailable": "不可用",
"unreachable": "不可达",
"un-manage": "未管理"
}
},
"alert": {
"": "告警",
"status": {
"": "告警状态",
"all": "全部状态",
"0": "未处理",
"0": "待处理",
"2": "已恢复",
"3": "已处理"
},
"priority": {
"": "告警级别",
"all": "全部级别",
"0": "紧急告警",
"1": "严重告警",
"2": "警告告警"
}
},
"alert.setting.new": "新增阈值",
"alert.setting.edit": "编辑阈值",
"alert.setting.delete": "删除阈值",
"alert.setting.target": "指标对象",
"alert.setting.expr": "阈值触发表达式",
"alert.setting.times": "触发次数",
"alert.setting.times.tip": "设置触发阈值多少次之后才会发送告警",
"alert.setting.template": "通知模版",
"alert.setting.template.tip": "支持的通知模版环境变量",
"alert.setting.template.label": "告警触发后发送的通知信息模版,模版环境变量见上方",
"alert.setting.template.example": "请输入告警的通知模版.示例: ${app}.${metrics}.${metric}'s value is too high",
"alert.setting.template.monitor-type": "监控类型名称",
"alert.setting.template.metrics-name": "监控指标集合名称",
"alert.setting.template.metric-name": "监控指标名称",
"alert.setting.template.metric-value": "监控指标对象值",
"alert.setting.template.other-value": "所属行其它指标值",
"alert.setting.template.instance-value": "所属行实例值",
"alert.setting.default": "全局默认",
"alert.setting.default.tip": "此告警阈值配置是否应用于全局所有此类型监控",
"alert.setting.enable": "启用告警",
"alert.setting.enable.tip": "此告警阈值配置开启生效或关闭",
"alert.setting.connect": "告警定义关联监控",
"alert.setting.connect.left": "未关联监控",
"alert.setting.connect.right": "已关联监控",
"alert.setting.expr.tip": "支持的阈值触发表达式环境变量与操作符",
"alert.setting.expr.label": "根据此表达式来计算判断是否触发阈值,表达式环境变量和操作符见上方",
"alert.setting.expr.example": "根据此表达式计算判断是否触发阈值.示例",
"alert.setting.priority.tip": "触发阈值的告警级别,从低到高依次为:警告-warning严重-critical紧急-emergency",
"alert.setting.target.tip": "选中的指标对象",
"alert.setting.target.other": "所属行其它指标对象",
"alert.setting.target.instance": "所属行实例",
"alert.setting.operator": "支持操作符函数",
"alert.center.delete": "删除告警",
"alert.center.deal": "标记已处理",
"alert.center.no-deal": "标记未处理",
"alert.center.search": "搜索告警内容",
"alert.center.filter-status": "告警状态过滤",
"alert.center.filter-priority": "告警级别过滤",
"alert.center.target": "告警指标",
"alert.center.monitor": "所属监控",
"alert.center.priority": "级别",
"alert.center.content": "告警内容",
"alert.center.status": "状态",
"alert.center.time": "告警时间",
"alert.center.notify.no-delete": "未选中任何待删除项!",
"alert.center.confirm.delete": "请确认是否删除!",
"alert.center.confirm.delete-batch": "请确认是否批量删除!",
"alert.center.notify.no-mark": "未选中任何待标记项!",
"alert.center.confirm.mark-done-batch": "请确认是否批量标记已处理!",
"alert.center.confirm.mark-done": "请确认是否标记已处理!",
"alert.center.confirm.mark-no-batch": "请确认是否批量标记未处理!",
"alert.center.confirm.mark-no": "请确认是否标记未处理!",
"alert.notice.receiver": "告警接收人",
"alert.notice.receiver.new": "新增接收人",
"alert.notice.receiver.edit": "编辑接收人",
"alert.notice.receiver.delete": "删除接收人",
"alert.notice.receiver.people": "接收人",
"alert.notice.receiver.people.name": "接收人名称",
"alert.notice.receiver.type": "通知方式",
"alert.notice.receiver.setting": "配置",
"alert.notice.type.sms": "短信",
"alert.notice.type.phone": "手机号",
"alert.notice.type.email": "邮箱",
"alert.notice.type.url": "URL地址",
"alert.notice.type.wechat": "微信公众号",
"alert.notice.type.wechat-id": "微信OPENID",
"alert.notice.type.wework": "企业微信机器人",
"alert.notice.type.wework-key": "企业微信机器人KEY",
"alert.notice.type.access-token": "机器人ACCESS_TOKEN",
"alert.notice.type.ding": "钉钉机器人",
"alert.notice.type.fei-shu": "飞书机器人",
"alert.notice.type.fei-shu-key": "飞书机器人KEY",
"alert.notice.rule": "告警通知策略",
"alert.notice.rule.new": "新增通知策略",
"alert.notice.rule.edit": "编辑通知策略",
"alert.notice.rule.delete": "删除通知策略",
"alert.notice.rule.name": "策略名称",
"alert.notice.rule.all": "转发所有",
"alert.notice.rule.enable": "是否启用",
"dashboard.alerts.title": "最近告警列表",
"dashboard.alerts.title-no": "最近未处理告警",
"dashboard.alerts.no": "暂无未处理告警",
"dashboard.alerts.enter": "进入告警中心",
"dashboard.alerts.distribute": "告警分布",
"dashboard.alerts.num": "告警数量",
"dashboard.alerts.deal": "告警处理",
"dashboard.alerts.deal-percent": "告警处理率",
"dashboard.monitors.total": "监控总量",
"dashboard.monitors.title": "监控总览",
"dashboard.monitors.sub-title": "监控类型纳管数量分布",
"dashboard.monitors.formatter": "个监控 占比",
"dashboard.monitors.distribute": "纳管数量分布",
"monitors.list": "监控列表",
"monitors.new": "新增",
"monitors.new.success": "新增监控成功",
"monitors.new.failed": "新增监控失败",
"monitors.edit": "编辑",
"monitors.edit.success": "修改监控成功",
"monitors.edit.failed": "修改监控失败",
"monitors.not-found": "查询异常,此监控不存在",
"monitors.delete": "删除",
"monitors.edit-monitor": "编辑监控",
"monitors.delete-monitor": "删除监控",
"monitors.enable": "启用监控",
"monitors.cancel": "取消监控",
"monitors.search.placeholder": "搜索监控",
"monitors.search.filter": "监控状态过滤",
"monitors.total": "总量",
"monitors.advanced": "高级设置",
"monitors.advanced.tip": "设置高级可选参数",
"monitors.detect": "测试连接",
"monitors.detect.success": "测试连接成功",
"monitors.detect.failed": "测试连接失败",
"monitors.detect.tip": "新增监控前是否先探测检查监控可用性",
"monitors.detail": "监控详情",
"monitors.detail.name": "名称",
"monitors.detail.port": "端口",
"monitors.detail.description": "描述",
"monitors.detail.status": "状态",
"monitors.detail.basic": "监控基本属性",
"monitors.detail.realtime": "监控实时数据详情",
"monitors.detail.history": "监控历史图表详情",
"monitors.collect.time": "采集时间",
"monitors.collect.time.tip": "最近采集时间",
"monitors.detail.chart.zoom": "区域缩放",
"monitors.detail.chart.back": "缩放还原",
"monitors.detail.chart.save": "保存图片",
"monitors.detail.chart.query-1h": "查询近1小时",
"monitors.detail.chart.query-6h": "查询近6小时",
"monitors.detail.chart.query-1d": "查询近1天",
"monitors.detail.chart.query-1w": "查询近1周",
"monitors.detail.chart.query-1m": "查询近1月",
"monitors.detail.chart.no-data": "暂无数据",
"monitors.detail.chart.unit": "单位",
"common.name": "名称",
"common.value": "值",
"common.search": "搜索",
"common.refresh": "刷新",
"common.edit-time": "更新时间",
"common.new-time": "创建时间",
"common.edit": "操作",
"common.total": "总量",
"common.yes": "是",
"common.no": "否",
"common.enable": "开启",
"common.disable": "关闭",
"common.notify.no-select-edit": "未选中任何待编辑项!",
"common.notify.one-select-edit": "只能对一个选中项进行编辑!",
"common.confirm.delete": "请确认是否删除!",
"common.notify.no-select-delete": "未选中任何待删除项!",
"common.confirm.delete-batch": "请确认是否批量删除!",
"common.notify.delete-success": "删除成功!",
"common.notify.delete-fail": "删除失败!",
"common.notify.new-success": "新增成功!",
"common.notify.new-fail": "新增失败!",
"common.notify.apply-success": "应用成功!",
"common.notify.apply-fail": "应用失败!",
"common.notify.monitor-fail": "查询此监控定义详情失败!",
"common.notify.edit-success": "修改成功!",
"common.notify.edit-fail": "修改失败!",
"common.notify.mark-success": "标记成功!",
"common.notify.mark-fail": "标记失败!",
"common.notify.no-select-cancel": "未选中任何待取消项!",
"common.confirm.cancel-batch": "请确认是否批量取消监控!",
"common.confirm.cancel": "请确认是否取消监控!",
"common.notify.cancel-success": "取消监控成功!",
"common.notify.cancel-fail": "取消监控失败!",
"common.notify.no-select-enable": "未选中任何待启用监控项!",
"common.confirm.enable-batch": "请确认是否批量启用监控!",
"common.confirm.enable": "请确认是否启用监控!",
"common.notify.enable-success": "启用监控成功!",
"common.notify.enable-fail": "启用监控失败!",
"common.confirm.clear-cache": "请确认是否清理缓存!",
"common.notify.clear-success": "清理成功!",
"common.button.ok": "确定",
"common.button.detect": "测试",
"common.button.cancel": "取消",
"common.button.help": "帮助",
"common.button.edit": "编辑",
"common.button.delete": "删除",
"app.theme.default": "浅色主题",
"app.theme.dark": "深色主题",
"app.theme.compact": "紧凑主题",
"app.role.admin": "管理员",
"app.lock": "锁屏",
"app.lock.placeholder": "输入任意解锁",
"app.passport.desc": "TanCloud-易用友好的高性能监控云服务",
"app.passport.welcome": "欢迎使用TanCloud探云-监控云服务-tancloud.cn",
"app.login.message-need-identifier": "请输入用户名",
"app.login.message-need-identifier": "输入邮箱或手机号",
"app.login.message-need-credential": "请输入密码",
"app.login.message-invalid-credentials": "账户或密码错误",
"app.login.message-invalid-verification-code": "验证码错误",
"app.login.tab-login-credentials": "账户密码登录",
"app.login.tab-login-mobile": "手机号登录",
"app.login.remember-me": "自动登录",
"app.login.forgot-password": "忘记密码",
"app.login.sign-in-with": "其他登录方式",
"app.login.signup": "注册账户",
"app.login.login": "登录",
"app.password.forgot": "忘记密码",
"app.password.reset": "重置密码",
"app.register.register": "注册",
"app.register.get-verification-code": "获取验证码",
"app.register.sign-in": "使用已有账户登录",
"app.register-result.msg": "你的账户:{{email}} 注册成功",
"app.register-result.activation-email":
"额外赠送监控额度邮件已发送到你的邮箱中。请及时登录邮箱,点击邮件中的链接领取。",
"app.register-result.login": "开始登录",
"app.register-result.back-home": "返回首页",
"app.register-result.view-mailbox": "查看邮箱",
"validation.email.required": "请输入邮箱地址!",
"validation.email.wrong-format": "邮箱地址格式错误!",
"validation.email.invalid": "无效的邮箱地址!",