[monitor]feature dashboard仪表盘重构 (#13)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package com.usthe.alert.controller;
|
||||
|
||||
import com.usthe.alert.dto.AlertSummary;
|
||||
import com.usthe.common.entity.alerter.Alert;
|
||||
import com.usthe.alert.service.AlertService;
|
||||
import com.usthe.common.entity.dto.Message;
|
||||
@@ -114,4 +115,11 @@ public class AlertsController {
|
||||
return ResponseEntity.ok(message);
|
||||
}
|
||||
|
||||
@GetMapping(path = "/summary")
|
||||
@ApiOperation(value = "获取告警统计信息", notes = "获取告警统计信息")
|
||||
public ResponseEntity<Message<AlertSummary>> getAlertsSummary() {
|
||||
AlertSummary alertSummary = alertService.getAlertsSummary();
|
||||
Message<AlertSummary> message = new Message<>(alertSummary);
|
||||
return ResponseEntity.ok(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.usthe.alert.dao;
|
||||
|
||||
import com.usthe.alert.dto.AlertPriorityNum;
|
||||
import com.usthe.common.entity.alerter.Alert;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
@@ -32,4 +33,10 @@ public interface AlertDao extends JpaRepository<Alert, Long>, JpaSpecificationEx
|
||||
@Query("update Alert set status = :status where id in :ids")
|
||||
void updateAlertsStatus(@Param(value = "status") Byte status, @Param(value = "ids") List<Long> ids);
|
||||
|
||||
/**
|
||||
* 查询各个告警级别的未处理告警数量
|
||||
* @return 告警数量
|
||||
*/
|
||||
@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();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.usthe.alert.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 监控级别告警数量
|
||||
* @author tom
|
||||
* @date 2022/3/6 19:52
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class AlertPriorityNum {
|
||||
|
||||
private byte priority;
|
||||
|
||||
private long num;
|
||||
}
|
||||
39
alerter/src/main/java/com/usthe/alert/dto/AlertSummary.java
Normal file
39
alerter/src/main/java/com/usthe/alert/dto/AlertSummary.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package com.usthe.alert.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import static io.swagger.annotations.ApiModelProperty.AccessMode.READ_ONLY;
|
||||
|
||||
/**
|
||||
* 告警统计信息
|
||||
* @author tom
|
||||
* @date 2022/3/6 19:25
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@ApiModel(description = "告警统计信息")
|
||||
public class AlertSummary {
|
||||
|
||||
@ApiModelProperty(value = "告警总数量(包括已处理未处理告警)", example = "134", accessMode = READ_ONLY, position = 0)
|
||||
private long total;
|
||||
|
||||
@ApiModelProperty(value = "已处理告警数量", example = "34", accessMode = READ_ONLY, position = 1)
|
||||
private long dealNum;
|
||||
|
||||
@ApiModelProperty(value = "告警处理率", example = "39.34", accessMode = READ_ONLY, position = 2)
|
||||
private float rate;
|
||||
|
||||
@ApiModelProperty(value = "告警级别为警告告警的告警数量(指未处理告警)", example = "43", accessMode = READ_ONLY, position = 3)
|
||||
private long priorityWarningNum;
|
||||
|
||||
@ApiModelProperty(value = "告警级别为严重告警的告警数量(指未处理告警)", example = "56", accessMode = READ_ONLY, position = 4)
|
||||
private long priorityCriticalNum;
|
||||
|
||||
@ApiModelProperty(value = "告警级别为紧急告警的告警数量(指未处理告警)", example = "23", accessMode = READ_ONLY, position = 5)
|
||||
private long priorityEmergencyNum;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.usthe.alert.service;
|
||||
|
||||
import com.usthe.alert.dto.AlertSummary;
|
||||
import com.usthe.common.entity.alerter.Alert;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
@@ -42,4 +43,11 @@ public interface AlertService {
|
||||
* @param ids 待修改的告警IDs
|
||||
*/
|
||||
void editAlertStatus(Byte status, List<Long> ids);
|
||||
|
||||
/**
|
||||
* 获取告警统计信息
|
||||
* @return 告警统计
|
||||
*/
|
||||
AlertSummary getAlertsSummary();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package com.usthe.alert.service.impl;
|
||||
|
||||
import com.usthe.alert.dao.AlertDao;
|
||||
import com.usthe.alert.dto.AlertPriorityNum;
|
||||
import com.usthe.alert.dto.AlertSummary;
|
||||
import com.usthe.common.entity.alerter.Alert;
|
||||
import com.usthe.alert.service.AlertService;
|
||||
import com.usthe.common.util.CommonConstants;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -11,6 +14,8 @@ import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
@@ -47,4 +52,37 @@ public class AlertServiceImpl implements AlertService {
|
||||
alertDao.updateAlertsStatus(status, ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlertSummary getAlertsSummary() {
|
||||
AlertSummary alertSummary = new AlertSummary();
|
||||
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;
|
||||
case CommonConstants.ALERT_PRIORITY_CODE_CRITICAL:
|
||||
alertSummary.setPriorityCriticalNum(priorityNum.getNum());break;
|
||||
case CommonConstants.ALERT_PRIORITY_CODE_EMERGENCY:
|
||||
alertSummary.setPriorityEmergencyNum(priorityNum.getNum());break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
long total = alertDao.count();
|
||||
long dealNum = total - alertSummary.getPriorityCriticalNum()
|
||||
- alertSummary.getPriorityEmergencyNum() - alertSummary.getPriorityWarningNum();
|
||||
alertSummary.setDealNum(dealNum);
|
||||
try {
|
||||
float rate = BigDecimal.valueOf(100 * (float) dealNum / total)
|
||||
.setScale(2, RoundingMode.HALF_UP)
|
||||
.floatValue();
|
||||
alertSummary.setRate(rate);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return alertSummary;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -55,11 +55,11 @@ public interface MonitorDao extends JpaRepository<Monitor, Long>, JpaSpecificati
|
||||
Optional<Monitor> findMonitorByNameEquals(String name);
|
||||
|
||||
/**
|
||||
* 查询监控类别及其对应的监控数量
|
||||
* @return 监控类别与监控数量映射
|
||||
* 查询监控类别-状态对应的监控数量
|
||||
* @return 监控类别-状态与监控数量映射
|
||||
*/
|
||||
@Query("select new com.usthe.manager.pojo.dto.AppCount(mo.app, COUNT(mo.id)) from Monitor mo group by mo.app")
|
||||
List<AppCount> findAppsCount();
|
||||
@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();
|
||||
|
||||
/**
|
||||
* 更新指定监控的状态
|
||||
|
||||
@@ -12,8 +12,43 @@ import lombok.NoArgsConstructor;
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class AppCount {
|
||||
/**监控类型**/
|
||||
|
||||
public AppCount(String app, byte status, Long size) {
|
||||
this.app = app;
|
||||
this.status = status;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 监控大类别
|
||||
*/
|
||||
private String category;
|
||||
/**
|
||||
* 监控类型
|
||||
*/
|
||||
private String app;
|
||||
/**监控数量**/
|
||||
private Long size;
|
||||
/**
|
||||
* 监控状态
|
||||
*/
|
||||
private transient byte status;
|
||||
/**
|
||||
* 监控数量
|
||||
*/
|
||||
private long size;
|
||||
/**
|
||||
* 监控状态可用的数量
|
||||
*/
|
||||
private long availableSize;
|
||||
/**
|
||||
* 监控状态未管理的数量
|
||||
*/
|
||||
private long unManageSize;
|
||||
/**
|
||||
* 监控状态不可用的数量
|
||||
*/
|
||||
private long unAvailableSize;
|
||||
/**
|
||||
* 监控状态不可达的数量
|
||||
*/
|
||||
private long unReachableSize;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -379,8 +380,40 @@ public class MonitorServiceImpl implements MonitorService {
|
||||
|
||||
@Override
|
||||
public List<AppCount> getAllAppMonitorsCount() {
|
||||
return monitorDao.findAppsCount();
|
||||
|
||||
List<AppCount> appCounts = monitorDao.findAppsStatusCount();
|
||||
if (appCounts == null) {
|
||||
return null;
|
||||
}
|
||||
// 关联大类别信息 计算每个状态对应数量
|
||||
Map<String, AppCount> appCountMap = new HashMap<>(appCounts.size());
|
||||
for (AppCount item : appCounts) {
|
||||
AppCount appCount = appCountMap.getOrDefault(item.getApp(), new AppCount());
|
||||
appCount.setApp(item.getApp());
|
||||
switch (item.getStatus()) {
|
||||
case CommonConstants.AVAILABLE_CODE:
|
||||
appCount.setAvailableSize(appCount.getAvailableSize() + item.getSize());
|
||||
break;
|
||||
case CommonConstants.UN_AVAILABLE_CODE:
|
||||
appCount.setUnAvailableSize(appCount.getUnAvailableSize() + item.getSize());
|
||||
break;
|
||||
case CommonConstants.UN_MANAGE_CODE:
|
||||
appCount.setUnManageSize(appCount.getUnManageSize() + item.getSize());
|
||||
break;
|
||||
case CommonConstants.UN_REACHABLE_CODE:
|
||||
appCount.setUnReachableSize(appCount.getUnReachableSize() + item.getSize());
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
appCountMap.put(item.getApp(), appCount);
|
||||
}
|
||||
return appCountMap.values().stream().peek(item -> {
|
||||
item.setSize(item.getAvailableSize() + item.getUnManageSize()
|
||||
+ item.getUnReachableSize() + item.getUnAvailableSize());
|
||||
Job job = appService.getAppDefine(item.getApp());
|
||||
if (job != null) {
|
||||
item.setCategory(job.getCategory());
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
9
web-app/src/app/pojo/AppCount.ts
Normal file
9
web-app/src/app/pojo/AppCount.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export class AppCount {
|
||||
category!: string;
|
||||
app!: string;
|
||||
size: number = 0;
|
||||
availableSize: number = 0;
|
||||
unManageSize: number = 0;
|
||||
unAvailableSize: number = 0;
|
||||
unReachableSize: number = 0;
|
||||
}
|
||||
@@ -1,3 +1,106 @@
|
||||
<div nz-row nzGutter="16" style="margin-top: 70px">
|
||||
<div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
|
||||
<div nz-row nzAlign="middle" class="bg-primary rounded-lg">
|
||||
<div nz-col nzSpan="10" class="p-md text-white">
|
||||
<div class="h2 mt0 font-weight-bold">{{ appCountService.size }}</div>
|
||||
<p class="h5 text-nowrap mb0">
|
||||
<i nz-icon nzType="cloud" nzTheme="outline"></i>
|
||||
{{ 'monitor.category.service' | i18n }}
|
||||
</p>
|
||||
</div>
|
||||
<div nz-col nzSpan="14" class="p-md text-white">
|
||||
<nz-tag class="mb-xs">
|
||||
<span>正常 </span><span style="font-weight: bolder">{{ appCountService.availableSize }}</span>
|
||||
</nz-tag>
|
||||
<nz-tag class="mb-xs">
|
||||
<span>不可用 </span><span style="font-weight: bolder">{{ appCountService.unAvailableSize }}</span>
|
||||
</nz-tag>
|
||||
<nz-tag class="mb-xs">
|
||||
<span>不可达 </span><span style="font-weight: bolder">{{ appCountService.unReachableSize }}</span>
|
||||
</nz-tag>
|
||||
<nz-tag class="mb-xs">
|
||||
<span>未监控 </span><span style="font-weight: bolder">{{ appCountService.unManageSize }}</span>
|
||||
</nz-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
|
||||
<div nz-row nzAlign="middle" class="bg-success rounded-lg">
|
||||
<div nz-col nzSpan="10" class="p-md text-white">
|
||||
<div class="h2 mt0 font-weight-bold">{{ appCountDb.size }}</div>
|
||||
<p class="h5 text-nowrap mb0">
|
||||
<i nz-icon nzType="database" nzTheme="outline"></i>
|
||||
{{ 'monitor.category.db' | i18n }}
|
||||
</p>
|
||||
</div>
|
||||
<div nz-col nzSpan="14">
|
||||
<nz-tag class="mb-xs">
|
||||
<span>正常 </span><span style="font-weight: bolder">{{ appCountDb.availableSize }}</span>
|
||||
</nz-tag>
|
||||
<nz-tag class="mb-xs">
|
||||
<span>不可用 </span><span style="font-weight: bolder">{{ appCountDb.unAvailableSize }}</span>
|
||||
</nz-tag>
|
||||
<nz-tag class="mb-xs">
|
||||
<span>不可达 </span><span style="font-weight: bolder">{{ appCountDb.unReachableSize }}</span>
|
||||
</nz-tag>
|
||||
<nz-tag class="mb-xs">
|
||||
<span>未监控 </span><span style="font-weight: bolder">{{ appCountDb.unManageSize }}</span>
|
||||
</nz-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
|
||||
<div nz-row nzAlign="middle" class="bg-orange rounded-lg">
|
||||
<div nz-col nzSpan="10" class="p-md text-white">
|
||||
<div class="h2 mt0 font-weight-bold">{{ appCountOs.size }}</div>
|
||||
<p class="h5 text-nowrap mb0">
|
||||
<i nz-icon nzType="windows" nzTheme="outline"></i>
|
||||
{{ 'monitor.category.os' | i18n }}
|
||||
</p>
|
||||
</div>
|
||||
<div nz-col nzSpan="14">
|
||||
<nz-tag class="mb-xs">
|
||||
<span>正常 </span><span style="font-weight: bolder">{{ appCountOs.availableSize }}</span>
|
||||
</nz-tag>
|
||||
<nz-tag class="mb-xs">
|
||||
<span>不可用 </span><span style="font-weight: bolder">{{ appCountOs.unAvailableSize }}</span>
|
||||
</nz-tag>
|
||||
<nz-tag class="mb-xs">
|
||||
<span>不可达 </span><span style="font-weight: bolder">{{ appCountOs.unReachableSize }}</span>
|
||||
</nz-tag>
|
||||
<nz-tag class="mb-xs">
|
||||
<span>未监控 </span><span style="font-weight: bolder">{{ appCountOs.unManageSize }}</span>
|
||||
</nz-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
|
||||
<div nz-row nzAlign="middle" class="bg-magenta rounded-lg">
|
||||
<div nz-col nzSpan="10" class="p-md text-white">
|
||||
<div class="h2 mt0 font-weight-bold">{{ appCountCustom.size }}</div>
|
||||
<p class="h5 text-nowrap mb0">
|
||||
<i nz-icon nzType="skin" nzTheme="outline"></i>
|
||||
{{ 'monitor.category.custom' | i18n }}
|
||||
</p>
|
||||
</div>
|
||||
<div nz-col nzSpan="14">
|
||||
<nz-tag class="mb-xs">
|
||||
<span>正常 </span><span style="font-weight: bolder">{{ appCountCustom.availableSize }}</span>
|
||||
</nz-tag>
|
||||
<nz-tag class="mb-xs">
|
||||
<span>不可用 </span><span style="font-weight: bolder">{{ appCountCustom.unAvailableSize }}</span>
|
||||
</nz-tag>
|
||||
<nz-tag class="mb-xs">
|
||||
<span>不可达 </span><span style="font-weight: bolder">{{ appCountCustom.unReachableSize }}</span>
|
||||
</nz-tag>
|
||||
<nz-tag class="mb-xs">
|
||||
<span>未监控 </span><span style="font-weight: bolder">{{ appCountCustom.unManageSize }}</span>
|
||||
</nz-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
echarts
|
||||
[options]="appsCountEChartOption"
|
||||
@@ -5,6 +108,59 @@
|
||||
[autoResize]="true"
|
||||
[loading]="appsCountLoading"
|
||||
(chartClick)="onChartClick($event)"
|
||||
(chartInit)="onChartInit($event)"
|
||||
style="width: 100%; height: 400px; margin-top: 5%"
|
||||
(chartInit)="onAppsCountChartInit($event)"
|
||||
style="width: 100%; height: 400px; margin-top: 1%"
|
||||
></div>
|
||||
|
||||
<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="最近告警列表" [nzExtra]="extraTemplate">
|
||||
<nz-timeline nzMode="left">
|
||||
<nz-timeline-item *ngFor="let alert of alerts; let i = index" [nzLabel]="alert.gmtCreate.toString()">
|
||||
<p style="font-weight: 400">
|
||||
<nz-tag *ngIf="alert.priority == 0" nzColor="red">
|
||||
<i nz-icon nzType="bell" nzTheme="outline"></i>
|
||||
<span>紧急告警</span>
|
||||
</nz-tag>
|
||||
<nz-tag *ngIf="alert.priority == 1" nzColor="orange">
|
||||
<i nz-icon nzType="bell" nzTheme="outline"></i>
|
||||
<span>严重告警</span>
|
||||
</nz-tag>
|
||||
<nz-tag *ngIf="alert.priority == 2" nzColor="yellow">
|
||||
<i nz-icon nzType="bell" nzTheme="outline"></i>
|
||||
<span>警告告警</span>
|
||||
</nz-tag>
|
||||
<span>[{{ alert.monitorName }}] </span>
|
||||
{{ alert.content }}
|
||||
</p>
|
||||
</nz-timeline-item>
|
||||
</nz-timeline>
|
||||
</nz-card>
|
||||
</div>
|
||||
<div nz-col nzXs="24" nzSm="12" nzMd="7" class="mb-md">
|
||||
<div
|
||||
echarts
|
||||
[options]="alertsEChartOption"
|
||||
theme="default"
|
||||
[autoResize]="true"
|
||||
[loading]="alertsLoading"
|
||||
(chartInit)="onAlertNumChartInit($event)"
|
||||
style="width: 100%; height: 100%"
|
||||
></div>
|
||||
</div>
|
||||
<div nz-col nzXs="24" nzSm="12" nzMd="5" class="mb-md">
|
||||
<div
|
||||
echarts
|
||||
[options]="alertsDealEChartOption"
|
||||
theme="default"
|
||||
[autoResize]="true"
|
||||
[loading]="alertsDealLoading"
|
||||
(chartInit)="onAlertRateChartInit($event)"
|
||||
style="width: 100%; height: 100%"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #extraTemplate>
|
||||
<a [routerLink]="['/alert/center']">进入告警中心</a>
|
||||
</ng-template>
|
||||
|
||||
@@ -1,3 +1,97 @@
|
||||
.demo-chart {
|
||||
height: auto;
|
||||
@import '~@delon/theme/index';
|
||||
:host ::ng-deep {
|
||||
.ant-timeline {
|
||||
.ant-timeline-label {
|
||||
left: 20%;
|
||||
width: calc(20% - 12px);
|
||||
}
|
||||
.ant-timeline-item-tail {
|
||||
left: 20%;
|
||||
}
|
||||
.ant-timeline-item-head {
|
||||
left: 20%;
|
||||
}
|
||||
.ant-timeline-item-label {
|
||||
width: calc(20% - 12px);
|
||||
}
|
||||
.ant-timeline-item-left {
|
||||
.ant-timeline-item-content {
|
||||
left: calc(20% - 4px);
|
||||
width: calc(80% - 14px);
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-card-head-title {
|
||||
padding-top: 6px;
|
||||
padding-right: 0;
|
||||
padding-bottom: 6px;
|
||||
padding-left: 0;
|
||||
}
|
||||
.ant-card-head {
|
||||
min-height: 24px;
|
||||
padding: 0 12px;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
}
|
||||
.ant-card-body {
|
||||
padding-top: 24px;
|
||||
padding-right: 24px;
|
||||
padding-bottom: 6px;
|
||||
padding-left: 24px;
|
||||
}
|
||||
.ant-timeline-item {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme='dark'] {
|
||||
:host ::ng-deep {
|
||||
.ant-timeline {
|
||||
.ant-timeline-label {
|
||||
left: 20%;
|
||||
width: calc(20% - 12px);
|
||||
}
|
||||
.ant-timeline-item-tail {
|
||||
left: 20%;
|
||||
}
|
||||
.ant-timeline-item-head {
|
||||
left: 20%;
|
||||
}
|
||||
.ant-timeline-item-label {
|
||||
width: calc(20% - 12px);
|
||||
}
|
||||
.ant-timeline-item-left {
|
||||
.ant-timeline-item-content {
|
||||
left: calc(20% - 4px);
|
||||
width: calc(80% - 14px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme='compact'] {
|
||||
:host ::ng-deep {
|
||||
.ant-timeline {
|
||||
.ant-timeline-label {
|
||||
left: 20%;
|
||||
width: calc(20% - 12px);
|
||||
}
|
||||
.ant-timeline-item-tail {
|
||||
left: 20%;
|
||||
}
|
||||
.ant-timeline-item-head {
|
||||
left: 20%;
|
||||
}
|
||||
.ant-timeline-item-label {
|
||||
width: calc(20% - 12px);
|
||||
}
|
||||
.ant-timeline-item-left {
|
||||
.ant-timeline-item-content {
|
||||
left: calc(20% - 4px);
|
||||
width: calc(80% - 14px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@ import { EChartsOption } from 'echarts';
|
||||
import { NzMessageService } from 'ng-zorro-antd/message';
|
||||
import { fromEvent } from 'rxjs';
|
||||
|
||||
import { Alert } from '../../pojo/Alert';
|
||||
import { AppCount } from '../../pojo/AppCount';
|
||||
import { AlertService } from '../../service/alert.service';
|
||||
import { MonitorService } from '../../service/monitor.service';
|
||||
|
||||
@Component({
|
||||
@@ -18,21 +21,31 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
constructor(
|
||||
private msg: NzMessageService,
|
||||
private monitorSvc: MonitorService,
|
||||
private alertSvc: AlertService,
|
||||
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService,
|
||||
private router: Router,
|
||||
private cdr: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
// start 大类别数量信息
|
||||
appCountService: AppCount = new AppCount();
|
||||
appCountOs: AppCount = new AppCount();
|
||||
appCountDb: AppCount = new AppCount();
|
||||
appCountCustom: AppCount = new AppCount();
|
||||
|
||||
// start 数量全局概览
|
||||
interval$!: number;
|
||||
appsCountLoading: boolean = true;
|
||||
appsCountTableData: any[] = [];
|
||||
appsCountEChartOption!: EChartsOption;
|
||||
appsCountTheme!: EChartsOption;
|
||||
echartsInstance!: any;
|
||||
appsCountEchartsInstance!: any;
|
||||
pageResize$!: any;
|
||||
|
||||
// 告警列表
|
||||
alerts!: Alert[];
|
||||
|
||||
ngOnInit(): void {
|
||||
this.appsCountLoading = true;
|
||||
this.appsCountTheme = {
|
||||
title: {
|
||||
text: '监控总览',
|
||||
@@ -112,8 +125,86 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
]
|
||||
};
|
||||
this.alertsTheme = {
|
||||
title: {
|
||||
subtext: '告警等级分布',
|
||||
left: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['警告告警', '严重告警', '紧急告警']
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '告警数量',
|
||||
type: 'bar',
|
||||
data: [
|
||||
{
|
||||
value: 0,
|
||||
// 设置单个柱子的样式
|
||||
itemStyle: {
|
||||
color: '#ffb72b',
|
||||
shadowColor: '#91cc75'
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
itemStyle: {
|
||||
color: '#fa6202',
|
||||
shadowColor: '#91cc75'
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
itemStyle: {
|
||||
color: '#dc1313',
|
||||
shadowColor: '#91cc75'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
this.alertsDealTheme = {
|
||||
title: {
|
||||
subtext: '告警处理',
|
||||
left: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
formatter: '{b} : {c}%'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '告警处理率',
|
||||
type: 'gauge',
|
||||
progress: {
|
||||
show: true
|
||||
},
|
||||
detail: {
|
||||
valueAnimation: true,
|
||||
formatter: '{value}'
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: 0,
|
||||
name: '告警处理率'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
this.appsCountLoading = true;
|
||||
this.alertsLoading = true;
|
||||
this.refresh();
|
||||
this.appsCountLoading = false;
|
||||
// https://stackoverflow.com/questions/43908009/why-is-setinterval-in-an-angular-service-only-firing-one-time
|
||||
this.interval$ = setInterval(this.refresh.bind(this), 30000);
|
||||
this.pageResize$ = fromEvent(window, 'resize').subscribe(event => {
|
||||
@@ -129,12 +220,21 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
refresh(): void {
|
||||
this.refreshAppsCount();
|
||||
this.refreshAlertContentList();
|
||||
this.refreshAlertSummary();
|
||||
}
|
||||
refreshAppsCount(): void {
|
||||
this.appCountService = new AppCount();
|
||||
this.appCountOs = new AppCount();
|
||||
this.appCountDb = new AppCount();
|
||||
this.appCountCustom = new AppCount();
|
||||
let dashboard$ = this.monitorSvc.getAppsMonitorSummary().subscribe(
|
||||
message => {
|
||||
dashboard$.unsubscribe();
|
||||
if (message.code === 0 && message.data.apps != undefined) {
|
||||
// {app:'linux',size: 12}
|
||||
let apps: any[] = message.data.apps;
|
||||
let apps: AppCount[] = message.data.apps;
|
||||
this.appsCountTableData = [];
|
||||
let total = 0;
|
||||
apps.forEach(app => {
|
||||
@@ -147,6 +247,36 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
value: app.size
|
||||
});
|
||||
total = total + (app.size ? app.size : 0);
|
||||
switch (app.category) {
|
||||
case 'service':
|
||||
this.appCountService.size += app.size;
|
||||
this.appCountService.availableSize += app.availableSize;
|
||||
this.appCountService.unAvailableSize += app.unAvailableSize;
|
||||
this.appCountService.unManageSize += app.unManageSize;
|
||||
this.appCountService.unReachableSize += app.unReachableSize;
|
||||
break;
|
||||
case 'db':
|
||||
this.appCountDb.size += app.size;
|
||||
this.appCountDb.availableSize += app.availableSize;
|
||||
this.appCountDb.unAvailableSize += app.unAvailableSize;
|
||||
this.appCountDb.unManageSize += app.unManageSize;
|
||||
this.appCountDb.unReachableSize += app.unReachableSize;
|
||||
break;
|
||||
case 'os':
|
||||
this.appCountOs.size += app.size;
|
||||
this.appCountOs.availableSize += app.availableSize;
|
||||
this.appCountOs.unAvailableSize += app.unAvailableSize;
|
||||
this.appCountOs.unManageSize += app.unManageSize;
|
||||
this.appCountOs.unReachableSize += app.unReachableSize;
|
||||
break;
|
||||
case 'custom':
|
||||
this.appCountCustom.size += app.size;
|
||||
this.appCountCustom.availableSize += app.availableSize;
|
||||
this.appCountCustom.unAvailableSize += app.unAvailableSize;
|
||||
this.appCountCustom.unManageSize += app.unManageSize;
|
||||
this.appCountCustom.unReachableSize += app.unReachableSize;
|
||||
break;
|
||||
}
|
||||
});
|
||||
// @ts-ignore
|
||||
this.appsCountTheme.series[0].data = [{ value: total, name: '监控总量' }];
|
||||
@@ -158,9 +288,11 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
this.appsCountEChartOption = this.appsCountTheme;
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
this.appsCountLoading = false;
|
||||
},
|
||||
error => {
|
||||
console.error(error);
|
||||
this.appsCountLoading = false;
|
||||
dashboard$.unsubscribe();
|
||||
}
|
||||
);
|
||||
@@ -175,12 +307,113 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
onChartInit(ec: any) {
|
||||
this.echartsInstance = ec;
|
||||
onAppsCountChartInit(ec: any) {
|
||||
this.appsCountEchartsInstance = ec;
|
||||
}
|
||||
onAlertNumChartInit(ec: any) {
|
||||
this.alertsEchartsInstance = ec;
|
||||
}
|
||||
onAlertRateChartInit(ec: any) {
|
||||
this.alertsDealEchartsInstance = ec;
|
||||
}
|
||||
resizeChart() {
|
||||
if (this.echartsInstance) {
|
||||
this.echartsInstance.resize();
|
||||
if (this.appsCountEchartsInstance) {
|
||||
this.appsCountEchartsInstance.resize();
|
||||
}
|
||||
if (this.alertsEchartsInstance) {
|
||||
this.alertsEchartsInstance.resize();
|
||||
}
|
||||
if (this.alertsDealEchartsInstance) {
|
||||
this.alertsDealEchartsInstance.resize();
|
||||
}
|
||||
}
|
||||
|
||||
// start 告警分布
|
||||
alertsEChartOption!: EChartsOption;
|
||||
alertsTheme!: EChartsOption;
|
||||
alertsEchartsInstance!: any;
|
||||
alertsLoading: boolean = true;
|
||||
|
||||
refreshAlerts(): void {
|
||||
this.alertsEChartOption = this.alertsTheme;
|
||||
this.cdr.detectChanges();
|
||||
this.alertsLoading = false;
|
||||
}
|
||||
|
||||
// start 告警处理率
|
||||
alertsDealEChartOption!: EChartsOption;
|
||||
alertsDealTheme!: EChartsOption;
|
||||
alertsDealEchartsInstance!: any;
|
||||
alertsDealLoading: boolean = true;
|
||||
|
||||
refreshAlertContentList(): void {
|
||||
let alertsInit$ = this.alertSvc.getAlerts(0, 4).subscribe(
|
||||
message => {
|
||||
if (message.code === 0) {
|
||||
let page = message.data;
|
||||
this.alerts = page.content;
|
||||
} else {
|
||||
console.warn(message.msg);
|
||||
}
|
||||
alertsInit$.unsubscribe();
|
||||
},
|
||||
error => {
|
||||
alertsInit$.unsubscribe();
|
||||
console.error(error.msg);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
refreshAlertSummary(): void {
|
||||
let alertSummaryInit$ = this.alertSvc.getAlertsSummary().subscribe(
|
||||
message => {
|
||||
if (message.code === 0) {
|
||||
let summary = message.data;
|
||||
// @ts-ignore
|
||||
this.alertsTheme.series[0].data = [
|
||||
{
|
||||
value: summary.priorityWarningNum,
|
||||
itemStyle: {
|
||||
color: '#ffb72b',
|
||||
shadowColor: '#91cc75'
|
||||
}
|
||||
},
|
||||
{
|
||||
value: summary.priorityCriticalNum,
|
||||
itemStyle: {
|
||||
color: '#fa6202',
|
||||
shadowColor: '#91cc75'
|
||||
}
|
||||
},
|
||||
{
|
||||
value: summary.priorityEmergencyNum,
|
||||
itemStyle: {
|
||||
color: '#dc1313',
|
||||
shadowColor: '#91cc75'
|
||||
}
|
||||
}
|
||||
];
|
||||
// @ts-ignore
|
||||
this.alertsDealTheme.series[0].data = [
|
||||
{
|
||||
value: summary.rate,
|
||||
name: '告警处理率'
|
||||
}
|
||||
];
|
||||
this.alertsEChartOption = this.alertsTheme;
|
||||
this.alertsDealEChartOption = this.alertsDealTheme;
|
||||
this.cdr.detectChanges();
|
||||
} else {
|
||||
console.warn(message.msg);
|
||||
}
|
||||
alertSummaryInit$.unsubscribe();
|
||||
},
|
||||
error => {
|
||||
alertSummaryInit$.unsubscribe();
|
||||
this.alertsDealLoading = false;
|
||||
this.alertsLoading = false;
|
||||
console.error(error.msg);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import { UserLockComponent } from './passport/lock/lock.component';
|
||||
// passport pages
|
||||
import { UserLoginComponent } from './passport/login/login.component';
|
||||
import { RouteRoutingModule } from './routes-routing.module';
|
||||
import { NzTagModule } from 'ng-zorro-antd/tag';
|
||||
import { NzTimelineModule } from 'ng-zorro-antd/timeline';
|
||||
|
||||
const COMPONENTS: Array<Type<void>> = [
|
||||
DashboardComponent,
|
||||
@@ -20,7 +22,7 @@ const COMPONENTS: Array<Type<void>> = [
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [SharedModule, RouteRoutingModule, NgxEchartsModule],
|
||||
imports: [SharedModule, RouteRoutingModule, NgxEchartsModule, NzTagModule, NzTimelineModule],
|
||||
declarations: COMPONENTS
|
||||
})
|
||||
export class RoutesModule {}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Message } from '../pojo/Message';
|
||||
import { Page } from '../pojo/Page';
|
||||
|
||||
const alerts_uri = '/alerts';
|
||||
|
||||
const alerts_summary_uri = '/alerts/summary';
|
||||
const alerts_status_uri = '/alerts/status';
|
||||
|
||||
@Injectable({
|
||||
@@ -82,4 +82,8 @@ export class AlertService {
|
||||
const options = { params: httpParams };
|
||||
return this.http.put<Message<any>>(`${alerts_status_uri}/${status}`, null, options);
|
||||
}
|
||||
|
||||
public getAlertsSummary(): Observable<Message<any>> {
|
||||
return this.http.get<Message<any>>(alerts_summary_uri);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
{
|
||||
"key": "os",
|
||||
"text": "操作系统",
|
||||
"hide": true,
|
||||
"hide": false,
|
||||
"i18n": "menu.monitor.os",
|
||||
"icon": "anticon-windows"
|
||||
},
|
||||
|
||||
@@ -44,7 +44,8 @@
|
||||
"service": "应用服务",
|
||||
"db": "数据库",
|
||||
"os": "操作系统",
|
||||
"mid": "中间件"
|
||||
"mid": "中间件",
|
||||
"custom": "自定义监控"
|
||||
},
|
||||
"app": {
|
||||
"": "监控类型",
|
||||
|
||||
Reference in New Issue
Block a user