feat:1.增加表空间监控2.bug修复

This commit is contained in:
nieziyan 2024-03-01 18:27:15 +08:00
parent 8ad0d9db38
commit 18722cfe78
10 changed files with 250 additions and 41 deletions

View File

@ -1,11 +1,14 @@
package org.jeecg.common.util;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;
import static org.jeecg.modules.base.enums.Op.*;
import static org.jeecg.modules.base.enums.Op.LE;
@ -126,6 +129,34 @@ public class NumUtil {
}
}
public static Map<String, Boolean> compare(Map<String, Double> current, Double threshold, String op){
boolean cNull = MapUtil.isEmpty(current);
boolean tNull = ObjectUtil.isNull(threshold);
Map<String, Boolean> result = new HashMap<>();
if (cNull || tNull) return result;
double thresholdV = threshold;
for (Map.Entry<String, Double> entry : current.entrySet()) {
String key = entry.getKey();
double currentV = entry.getValue();
if (EQ.getOp().equals(op)){
result.put(key, currentV == thresholdV);
} else if (GT.getOp().equals(op)) {
result.put(key, currentV > thresholdV);
} else if (GE.getOp().equals(op)) {
result.put(key, currentV >= thresholdV);
} else if (LT.getOp().equals(op)) {
result.put(key, currentV < thresholdV);
} else if (LE.getOp().equals(op)) {
result.put(key, currentV <= thresholdV);
}else {
result.put(key, false);
}
}
return result;
}
public static String kb2Gb(String kb, int scale){
if (StrUtil.isBlank(kb))
return null;

View File

@ -7,8 +7,8 @@ import lombok.Getter;
@Getter
@AllArgsConstructor
public enum Item {
EMAIL_CONN("1", "邮箱服务连接情况"),
DATABASE_CONN("2", "数据源连接情况");
EMAIL_CONN("1", "Connection Status"),
TABLESPACE_USAGE("2", "TableSpace Usage");
private String value;

View File

@ -12,7 +12,7 @@ public interface IAlarmItemService extends IService<AlarmItem> {
List<AlarmItem> alarmItemsServer(String sourceId);
List<AlarmItem> alarmItemsDatabase(String sourceId);
List<ItemDto> alarmItemsDatabase(String sourceType, String sourceId);
List<ItemDto> allItems(String sourceType, String sourceId);
}

View File

@ -1,15 +1,20 @@
package org.jeecg.modules.service.impl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.enums.DbType;
import org.jeecg.modules.base.dto.ItemDto;
import org.jeecg.modules.base.entity.postgre.AlarmItem;
import org.jeecg.modules.base.entity.postgre.AlarmItemDe;
import org.jeecg.modules.base.entity.postgre.SysDatabase;
import org.jeecg.modules.base.enums.SourceType;
import org.jeecg.modules.mapper.AlarmItemMapper;
import org.jeecg.modules.service.IAlarmItemDeService;
import org.jeecg.modules.service.IAlarmItemService;
import org.jeecg.modules.service.ISysDatabaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -22,6 +27,9 @@ import java.util.stream.Collectors;
@Slf4j
public class AlarmItemServiceImpl extends ServiceImpl<AlarmItemMapper, AlarmItem> implements IAlarmItemService {
@Autowired
private ISysDatabaseService databaseService;
@Autowired
private IAlarmItemDeService alarmItemDeService;
@ -44,8 +52,16 @@ public class AlarmItemServiceImpl extends ServiceImpl<AlarmItemMapper, AlarmItem
}
@Override
public List<AlarmItem> alarmItemsDatabase(String sourceId) {
return baseMapper.alarmItemsDatabase(sourceId);
public List<ItemDto> alarmItemsDatabase(String sourceType, String sourceId) {
List<ItemDto> itemDtos = baseMapper.alarmItemsDatabase(sourceId).stream()
.map(ItemDto::new).collect(Collectors.toList());
SysDatabase database = databaseService.getById(sourceId);
String dbType = database.getDbType();
// 如果数据库类型是Oracle 则添加额外的监控项表空间使用率
if (StrUtil.equals(dbType, DbType.ORACLE.getType()))
itemDtos.addAll(alarmItemDeService.alarmItemDes(sourceType).stream()
.map(ItemDto::new).collect(Collectors.toList()));
return itemDtos;
}
/*
@ -63,8 +79,7 @@ public class AlarmItemServiceImpl extends ServiceImpl<AlarmItemMapper, AlarmItem
.map(ItemDto::new).collect(Collectors.toList());
break;
case DATABASE:
itemDtos = alarmItemsDatabase(sourceId).stream()
.map(ItemDto::new).collect(Collectors.toList());
itemDtos = alarmItemsDatabase(sourceType, sourceId);
break;
case EMAIL:
itemDtos = alarmItemDeService.alarmItemDes(sourceType).stream()

View File

@ -94,10 +94,8 @@ public class AlarmRuleServiceImpl extends ServiceImpl<AlarmRuleMapper, AlarmRule
@Override
public Result<?> update(AlarmRule alarmRule) {
AlarmRule alarmRuleOld = getById(alarmRule.getId());
if (ObjectUtil.isNull(alarmRuleOld)){
return Result.error(Prompt.DATA_NOT_EXITS);
}
String ruleId = alarmRuleOld.getId();
Integer enabled = alarmRuleOld.getEnabled();
// 保存oldRule的sourceType 避免修改了sourceType
String sourceTypeOld = alarmRuleOld.getSourceType();
Rule rule = alarmRule.getRule();
@ -105,10 +103,10 @@ public class AlarmRuleServiceImpl extends ServiceImpl<AlarmRuleMapper, AlarmRule
String operator = JSON.toJSONString(rule);
alarmRule.setOperator(operator);
}
alarmRule.setEnabled(enabled);
boolean success = updateById(alarmRule);
if (success){
// 如果当前规则是生效状态 则将修改后的规则同步到Redis
Integer enabled = alarmRuleOld.getEnabled();
if (Enabled.valueOf(enabled) == ENABLED)
updateRule(ruleId, sourceTypeOld);
return Result.OK(Prompt.UPDATE_SUCC);

View File

@ -6,6 +6,7 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -21,6 +22,7 @@ import org.jeecg.modules.service.IGardsNuclLinesLibService;
import org.jeecg.modules.service.ISysDefaultNuclideService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import java.util.*;
@ -58,13 +60,18 @@ public class SysDefaultNuclideServiceImpl extends ServiceImpl<SysDefaultNuclideM
}
@Override
public Result<?> add(List<String> nuclideNames,String nuclideType,Integer useType) {
@Transactional
public Result<?> add(List<String> nuclideNames, String nuclideType, Integer useType) {
if (CollUtil.isEmpty(nuclideNames))
return Result.error(Prompt.PARAM_NOT_EMPTY);
if (StrUtil.isBlank(nuclideType))
return Result.error("nuclideType" + Prompt.PARAM_REQUIRED);
if (ObjectUtil.isNull(useType))
return Result.error("useType" + Prompt.PARAM_REQUIRED);
LambdaUpdateWrapper<SysDefaultNuclide> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(SysDefaultNuclide::getNuclideType, nuclideType);
wrapper.eq(SysDefaultNuclide::getUseType, useType);
this.remove(wrapper);
List<SysDefaultNuclide> SysDefaultNuclides = new ArrayList<>();
for (String nuclideName : nuclideNames) {
SysDefaultNuclide sysDefaultNuclide = new SysDefaultNuclide();
@ -73,7 +80,7 @@ public class SysDefaultNuclideServiceImpl extends ServiceImpl<SysDefaultNuclideM
sysDefaultNuclide.setUseType(useType);
SysDefaultNuclides.add(sysDefaultNuclide);
}
boolean success = saveBatch(SysDefaultNuclides);
boolean success = this.saveBatch(SysDefaultNuclides);
if (success)
return Result.OK(Prompt.ADD_SUCC);
return Result.error(Prompt.ADD_ERR);
@ -128,4 +135,19 @@ public class SysDefaultNuclideServiceImpl extends ServiceImpl<SysDefaultNuclideM
redisUtil.set(key,mapLines);
}
}
public static void main(String[] args) {
List<String> newList = ListUtil.toList("A", "F");
List<String> oldList = ListUtil.toList("A", "B", "C");
Collection<String> intersection = CollUtil.intersection(newList, oldList);
newList = newList.stream()
.filter(item -> !CollUtil.contains(intersection, item))
.collect(Collectors.toList());
System.out.println("add: " + newList);
oldList = oldList.stream()
.filter(item -> !CollUtil.contains(intersection, item))
.collect(Collectors.toList());
System.out.println("del: " + oldList);
}
}

View File

@ -1,6 +1,7 @@
package org.jeecg.modules.feignclient;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.base.dto.SpaceInfo;
import org.jeecg.modules.base.entity.postgre.AlarmLog;
import org.jeecg.modules.base.entity.postgre.SysDatabase;
import org.jeecg.modules.base.entity.postgre.SysEmail;
@ -36,6 +37,9 @@ public interface AbnormalAlarmClient {
@PutMapping("/sysDatabase/updateStatus")
void updateDatabase(@RequestBody SysDatabase database);
@GetMapping("/sysDatabase/spaceInfo")
Result<List<SpaceInfo>> spaceInfo(@RequestParam String sourceId);
/* SysServerController下相关接口 */
@GetMapping("/sysServer/getNameById")
String getServerName(@RequestParam String id);

View File

@ -61,8 +61,7 @@ public class EmailPushMsgHandle implements ISendMsgHandle {
String context = messageDTO.getContent();
String alarmTitle = "邮件发送失败提醒";
StringBuilder alarmContext = new StringBuilder();
alarmContext.append("系统给您发送的邮件 [标题: ").append(title)
.append(", 内容: ").append(context).append("]发送失败,失败原因: ");
alarmContext.append("系统给您发送的邮件 [标题: ").append(title).append(", 内容: ").append(context).append("]发送失败,失败原因: ");
// 循环给每一个用户发送邮件
for (Map.Entry<String, String> userEmails : messageDTO.getUserEmail().entrySet()) {
String username = userEmails.getKey();
@ -71,9 +70,9 @@ public class EmailPushMsgHandle implements ISendMsgHandle {
messageDTO.setToUser(email);
emailService.sendMailToOne(messageDTO);
} catch (MessagingException e) {
if (e instanceof SMTPAddressFailedException) { // 无效的电子邮箱异常
if (e instanceof SMTPAddressFailedException) {
alarmContext.append("无效的电子邮箱: ").append(email);
} else if (e instanceof SendFailedException) { // 邮件发送失败异常
} else {
alarmContext.append(e.getMessage());
}
// 邮件发送失败 给用户发送站内提示消息

View File

@ -1,6 +1,7 @@
package org.jeecg.modules.quartz.jobs;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
@ -18,6 +19,7 @@ import org.jeecg.modules.base.entity.Rule;
import org.jeecg.modules.base.entity.monitor.ItemHistory;
import org.jeecg.modules.base.entity.postgre.AlarmLog;
import org.jeecg.modules.base.entity.postgre.AlarmRule;
import org.jeecg.modules.base.enums.Item;
import org.jeecg.modules.feignclient.ManageUtil;
import org.jeecg.modules.quartz.entity.Monitor;
import org.quartz.*;
@ -67,6 +69,8 @@ public class DatabaseJob extends Monitor {
operator = alarmRule.getOperator();
String ruleId = alarmRule.getId();
String itemId = alarmRule.getItemId();
// 如果是其它自定义监控项(表空间使用率...) 则跳过
if (CollUtil.contains(ListUtil.toList(Item.TABLESPACE_USAGE.getValue()), itemId)) continue;
String type = alarmRule.getItemType();
Integer itemType = StrUtil.isBlank(type) ? 0 : Integer.parseInt(type);
String silenceKey = prefixSilence + ruleId;
@ -80,18 +84,6 @@ public class DatabaseJob extends Monitor {
String sourceId = alarmRule.getSourceId();
String databaseName = getAlarmClient().getDatabaseName(sourceId);
/*// 根据监控项id选择要查询的监控项信息
Item item = Item.of(itemId);
if (ObjectUtil.isNull(item)) continue;
Number current = null;
switch (item){
case DATABASE_CONN: // 监控项-2: 测试数据源是否可以连接成功
current = isConnection(sourceId);
break;
// 追加的监控项...
default:
break;
}*/
// 向运管查询监控项数据
String token = ManageUtil.getToken();
Result<ItemHistory> result = getMonitorSystem().itemBack(itemId, itemType, start, end, token);
@ -141,16 +133,4 @@ public class DatabaseJob extends Monitor {
}
destroy();
}
/*
* 监控项-2: 测试数据源是否可以连接成功 (0:失败 1:成功)
* */
/*private Integer isConnection(String databaseId){
int res = 1;
String statusKey = RedisConstant.DATABASE_STATUS;
NameValue nameValue = (NameValue)getRedisUtil().hget(statusKey, databaseId);
if (ObjectUtil.isNull(nameValue) || ObjectUtil.isNull(nameValue.getValue()) || !nameValue.getValue())
res = 0;
return res;
}*/
}

View File

@ -0,0 +1,160 @@
package org.jeecg.modules.quartz.jobs;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.dto.message.MessageDTO;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.DateConstant;
import org.jeecg.common.constant.RedisConstant;
import org.jeecg.common.util.DataTool;
import org.jeecg.common.util.NumUtil;
import org.jeecg.common.util.TemplateUtil;
import org.jeecg.modules.base.dto.SpaceInfo;
import org.jeecg.modules.base.entity.Rule;
import org.jeecg.modules.base.entity.monitor.ItemHistory;
import org.jeecg.modules.base.entity.postgre.AlarmLog;
import org.jeecg.modules.base.entity.postgre.AlarmRule;
import org.jeecg.modules.base.enums.Item;
import org.jeecg.modules.feignclient.ManageUtil;
import org.jeecg.modules.quartz.entity.Monitor;
import org.jeecg.modules.system.service.ISysDataSourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static org.jeecg.modules.base.enums.Item.TABLESPACE_USAGE;
import static org.jeecg.modules.base.enums.SourceType.DATABASE;
import static org.jeecg.modules.base.enums.Template.MONITOR_DATABASE;
@Slf4j
@Component
public class TableSpaceJob extends Monitor {
/**
* 解析Oracle 表空间预警规则
**/
@Scheduled(cron = "${task.period-space:0 0/1 * * * ?}")
public void execute(){
init();
// 查询所有Database的报警规则,根据报警规则查询监控项数据
String pattern = RedisConstant.PREFIX_RULE + DATABASE.getType();
Set<String> keys = getRedisStreamUtil().keys(pattern);
if (CollUtil.isEmpty(keys)) return;
String prefixSilence = RedisConstant.PREFIX_SILENCE;
String operator = null;
for (String ruleKey : keys) {
try {
AlarmRule alarmRule = (AlarmRule) getRedisStreamUtil().get(ruleKey);
// 如果报警规则为空,或者在沉默周期内,跳过当前规则
operator = alarmRule.getOperator();
String ruleId = alarmRule.getId();
String itemId = alarmRule.getItemId();
String silenceKey = prefixSilence + ruleId;
boolean hasKey = getRedisStreamUtil().hasKey(silenceKey);
boolean blank1 = StrUtil.isBlank(operator);
boolean blank2 = StrUtil.isBlank(itemId);
if (blank1 || blank2 || hasKey) continue;
// 根据sourceId查询Database信息(缓存)
String sourceId = alarmRule.getSourceId();
String databaseName = getAlarmClient().getDatabaseName(sourceId);
// 根据监控项id选择要查询的监控项信息
Item item = Item.of(itemId);
if (ObjectUtil.isNull(item)) continue;
// 解析预警规则,判断是否需要报警
boolean needWarn = false;
Map<String, Boolean> result = null;
Map<String, Double> spaceMap = null;
ObjectMapper mapper = new ObjectMapper();
Rule rule = mapper.readValue(operator, Rule.class);
String op = rule.getOperator();
Double threshold = rule.getThreshold();
if (item == TABLESPACE_USAGE){ // 监控项id: 2 Oracle表空间使用率
List<SpaceInfo> spaceInfos = getAlarmClient().spaceInfo(sourceId).getResult();
if (CollUtil.isEmpty(spaceInfos)) continue;
spaceMap = spaceInfos.stream().collect(Collectors.toMap(SpaceInfo::getSpaceName, SpaceInfo::getUsed));
result = NumUtil.compare(spaceMap, threshold, op);
needWarn = result.containsValue(true);
}
// 如果当前值超过阈值 则需要发送报警信息
if (needWarn){
// 记录报警日志
AlarmLog alarmLog = new AlarmLog();
alarmLog.setRuleId(ruleId);
alarmLog.setOperator(operator);
alarmLog.setAlarmValue(value(spaceMap, result));
String ruleName = alarmRule.getName();
Map<String, Object> data = DataTool.getInstance().
put(databaseName).put(ruleName).put(rule.joint()).put(info(spaceMap, result)).get();
MessageDTO messageDTO = TemplateUtil.parse(MONITOR_DATABASE.getCode(), data);
alarmLog.setAlarmInfo(messageDTO.getContent());
getAlarmClient().create(alarmLog);
// 规则触发报警后,设置该规则的沉默周期(如果有)
// 沉默周期失效之前,该规则不会再次被触发
Long silenceCycle = alarmRule.getSilenceCycle();
ruleSilence(silenceKey, silenceCycle);
// 发送报警信息
String groupId = alarmRule.getContactId();
String notific = alarmRule.getNotification();
getSendMessage().send(messageDTO, groupId, notific);
getPushAppUtil().pushToSingle(messageDTO, groupId);
}
} catch (JsonProcessingException e) {
log.error("Database-TableSpace预警规则: {}解析失败,失败原因: {}", operator, e.getMessage());
}catch (Exception e){
log.error("Database-TableSpace监控异常: {}", e.getMessage());
}
}
destroy();
}
/*
* 所有的预警值 ,分割
* */
private String value(Map<String, Double> sapceMap, Map<String, Boolean> result){
List<String> keys = result.entrySet().stream()
.filter(Map.Entry::getValue)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
return sapceMap.entrySet().stream()
.filter(entry -> CollUtil.contains(keys, entry.getKey()))
.map(entry -> String.valueOf(entry.getValue()))
.collect(Collectors.joining(", "));
}
/*
* [表空间名1: 预警值1, 表空间名2: 预警值2]
* */
private String info(Map<String, Double> sapceMap, Map<String, Boolean> result){
List<String> keys = result.entrySet().stream()
.filter(Map.Entry::getValue)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
return "[" + sapceMap.entrySet().stream()
.filter(entry -> CollUtil.contains(keys, entry.getKey()))
.map(entry -> entry.getKey() + ": " + entry.getValue())
.collect(Collectors.joining(", ")) +
"]";
}
}