diff --git a/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/controller/AlarmAnalysisNuclideParamController.java b/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/controller/AlarmAnalysisNuclideParamController.java index 0bfb63a6..f70406c0 100644 --- a/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/controller/AlarmAnalysisNuclideParamController.java +++ b/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/controller/AlarmAnalysisNuclideParamController.java @@ -18,12 +18,6 @@ import io.swagger.annotations.Api; @RequestMapping("nuclideParam") public class AlarmAnalysisNuclideParamController extends JeecgController { - @GetMapping("refresh") - @ApiOperation(value = "定时刷新核素计算参数信息",notes = "定时刷新核素计算参数信息") - public boolean refreshParam(){ - return service.refresh(); - } - @GetMapping("findInfo") @ApiOperation(value = "回显核素计算参数信息",notes = "回显核素计算参数信息") public Result findInfo(){ diff --git a/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/controller/CalculateConcController.java b/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/controller/CalculateConcController.java deleted file mode 100644 index 19462428..00000000 --- a/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/controller/CalculateConcController.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.jeecg.modules.controller; - -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.jeecg.modules.service.CalculateConcService; -import org.jeecg.modules.service.IAlarmAnalysisNuclideParamService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@Api(value = "定时计算核素浓度" ,tags="定时计算核素浓度") -@RestController -@RequestMapping("calculateConc") -public class CalculateConcController { - - @Autowired - private CalculateConcService calculateConcService; - - @GetMapping("caclAndSave") - @ApiOperation(value = "计算并保存核素浓度",notes = "计算并保存核素浓度") - public boolean caclAndSave(){ - return calculateConcService.calcAndSave(); - } - -} diff --git a/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/job/Job.java b/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/job/Job.java new file mode 100644 index 00000000..df7f8f70 --- /dev/null +++ b/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/job/Job.java @@ -0,0 +1,6 @@ +package org.jeecg.modules.job; + +public interface Job { + + void execute(); +} diff --git a/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/job/NuclideParamJob.java b/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/job/NuclideParamJob.java new file mode 100644 index 00000000..3dddf703 --- /dev/null +++ b/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/job/NuclideParamJob.java @@ -0,0 +1,19 @@ +package org.jeecg.modules.job; + +import lombok.extern.slf4j.Slf4j; +import org.jeecg.modules.service.IAlarmAnalysisNuclideParamService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class NuclideParamJob implements Job{ + + @Autowired + private IAlarmAnalysisNuclideParamService nuclideParamService; + + @Override + @Scheduled(cron = "${task.period-param:0 1 0 * * ?}") + public void execute() { nuclideParamService.refresh(); } +} diff --git a/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/job/NucliedAvgJob.java b/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/job/NucliedAvgJob.java new file mode 100644 index 00000000..71824dba --- /dev/null +++ b/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/job/NucliedAvgJob.java @@ -0,0 +1,21 @@ +package org.jeecg.modules.job; + +import lombok.extern.slf4j.Slf4j; +import org.jeecg.modules.service.CalculateConcService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class NucliedAvgJob implements Job{ + + @Autowired + private CalculateConcService calculateConcService; + + @Override + @Scheduled(cron = "${task.period-avg:0 2 0 * * ?}") + public void execute() { + calculateConcService.calcAndSave(); + } +} diff --git a/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/service/CalculateConcService.java b/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/service/CalculateConcService.java index 1936c1a0..d9196ab3 100644 --- a/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/service/CalculateConcService.java +++ b/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/service/CalculateConcService.java @@ -8,7 +8,7 @@ import java.util.Map; public interface CalculateConcService { - boolean calcAndSave(); + void calcAndSave(); Map calculate(List concDtos, BigDecimal index); } diff --git a/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/service/IAlarmAnalysisNuclideParamService.java b/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/service/IAlarmAnalysisNuclideParamService.java index 6fa0ea9d..d18c539a 100644 --- a/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/service/IAlarmAnalysisNuclideParamService.java +++ b/jeecg-module-abnormal-alarm/src/main/java/org/jeecg/modules/service/IAlarmAnalysisNuclideParamService.java @@ -7,7 +7,7 @@ public interface IAlarmAnalysisNuclideParamService extends IService implements IAlarmAnalysisNuclideParamService { @@ -24,7 +26,7 @@ public class AlarmAnalysisNuclideParamServiceImpl extends ServiceImpl item.setCycle(cycle).setCaclDate(dayAgo)); - + nuclideAvgService.saveBatch(allAvgs); // 记录日志 log.info(log(allAvgs)); - return nuclideAvgService.saveBatch(allAvgs); - }catch (Throwable e){ - e.printStackTrace(); - log.error("核素浓度计算过程异常: {}", e.getMessage()); - return false; + }catch (Exception e){ + log.error("NucliedAvgJob执行异常: {}", e.getMessage()); } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/feignclient/AbnormalAlarmClient.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/feignclient/AbnormalAlarmClient.java index 7ca3c5d2..653cf6c7 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/feignclient/AbnormalAlarmClient.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/feignclient/AbnormalAlarmClient.java @@ -29,14 +29,6 @@ public interface AbnormalAlarmClient { @PostMapping("/alarmLog/create") Result create(@RequestBody AlarmLog alarmLog); - /* CalculateConcController下相关接口 */ - @GetMapping("/calculateConc/caclAndSave") - boolean calculateConc(); - - /* AlarmAnalysisNuclideParamController下相关接口 */ - @GetMapping("/nuclideParam/refresh") - boolean refreshParam(); - /* SysDatabaseController下相关接口 */ @GetMapping("/sysDatabase/getNameById") String getDatabaseName(@RequestParam String id); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/job/NuclideParamJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/job/NuclideParamJob.java deleted file mode 100644 index b0352d0e..00000000 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/job/NuclideParamJob.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.jeecg.modules.quartz.job; - -import lombok.extern.slf4j.Slf4j; -import org.jeecg.common.config.mqtoken.UserTokenContext; -import org.jeecg.common.util.SpringContextUtils; -import org.jeecg.common.util.TokenUtils; -import org.jeecg.modules.feignclient.AbnormalAlarmClient; -import org.quartz.*; - - -/** - * 此处的同步是指:当定时任务的执行时间大于任务的时间 - * 间隔时会等待第一个任务执行完成才会走第二个任务 - */ - -/** - * 定时更新核素浓度计算参数 - */ -@Slf4j -@DisallowConcurrentExecution -@PersistJobDataAfterExecution -public class NuclideParamJob implements Job { - - @Override - public void execute(JobExecutionContext context) throws JobExecutionException { - try { - UserTokenContext.setToken(TokenUtils.getTempToken()); - AbnormalAlarmClient alarmClient = SpringContextUtils.getBean(AbnormalAlarmClient.class); - alarmClient.refreshParam(); - }catch (Exception e){ - log.error("定时任务[NuclideParamJob]执行异常: {}", e.getMessage()); - }finally { - UserTokenContext.remove(); - } - } -} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/job/NucliedAvgJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/job/NucliedAvgJob.java deleted file mode 100644 index 126c51a5..00000000 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/job/NucliedAvgJob.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.jeecg.modules.quartz.job; - -import lombok.extern.slf4j.Slf4j; -import org.jeecg.common.config.mqtoken.UserTokenContext; -import org.jeecg.common.constant.DateConstant; -import org.jeecg.common.util.SpringContextUtils; -import org.jeecg.common.util.TokenUtils; -import org.jeecg.modules.feignclient.AbnormalAlarmClient; -import org.quartz.*; - -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; - -/** - * 此处的同步是指:当定时任务的执行时间大于任务的时间 - * 间隔时会等待第一个任务执行完成才会走第二个任务 - */ - -/** - * 定时计算核素浓度均值 - */ -@Slf4j -@DisallowConcurrentExecution -@PersistJobDataAfterExecution -public class NucliedAvgJob implements Job { - - @Override - public void execute(JobExecutionContext context) throws JobExecutionException { - try { - UserTokenContext.setToken(TokenUtils.getTempToken()); - AbnormalAlarmClient alarmClient = SpringContextUtils.getBean(AbnormalAlarmClient.class); - alarmClient.calculateConc(); - log.info(log()); - }catch (Exception e){ - log.error("定时任务[NucliedAvgJob]执行异常: {}", e.getMessage()); - }finally { - UserTokenContext.remove(); - } - } - - private String log(){ - String now = LocalDateTime.now() - .format(DateTimeFormatter.ofPattern(DateConstant.DATE_TIME)); - return "计算核素浓度均值的定时任务成功执行, " + - "任务执行类: org.jeecg.modules.quartz.job.NucliedAvgJob, " + - "任务执行时间: " + now; - } -} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/jobs/DatabaseJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/jobs/DatabaseJob.java new file mode 100644 index 00000000..6a2fd875 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/jobs/DatabaseJob.java @@ -0,0 +1,156 @@ +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.Data; +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.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.feignclient.ManageUtil; +import org.jeecg.modules.quartz.entity.Monitor; +import org.quartz.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import static org.jeecg.modules.base.enums.SourceType.DATABASE; +import static org.jeecg.modules.base.enums.Template.MONITOR_DATABASE; +@Slf4j +@Component +public class DatabaseJob extends Monitor { + /** + * 解析Database预警规则 + **/ + @Scheduled(cron = "${task.period:0 0/1 * * * ?}") + public void execute(){ + init(); + + // 查询所有Database的报警规则,根据报警规则查询监控项数据 + String pattern = RedisConstant.PREFIX_RULE + DATABASE.getType(); + Set keys = getRedisStreamUtil().keys(pattern); + if (CollUtil.isEmpty(keys)) return; + + // 时间间隔为每分钟 + LocalDateTime now = LocalDateTime.now() + .withSecond(0) + .withNano(0); + LocalDateTime beforeMin = now.minusMinutes(1); + DateTimeFormatter formatter = DateTimeFormatter + .ofPattern(DateConstant.DATE_TIME); + String start = beforeMin.format(formatter); + String end = now.format(formatter); + + 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 type = alarmRule.getItemType(); + Integer itemType = StrUtil.isBlank(type) ? 0 : Integer.parseInt(type); + 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; + Number current = null; + switch (item){ + case DATABASE_CONN: // 监控项-2: 测试数据源是否可以连接成功 + current = isConnection(sourceId); + break; + // 追加的监控项... + default: + break; + }*/ + // 向运管查询监控项数据 + String token = ManageUtil.getToken(); + Result result = getMonitorSystem().itemBack(itemId, itemType, start, end, token); + ItemHistory itemHistory = result.getResult(); + if (ObjectUtil.isNull(itemHistory)){ + log.warn("Database监控异常: [{}]查询监控项历史数据为空", databaseName); + continue; + } + Double current = itemHistory.getNow(); + + // 解析预警规则,判断是否需要报警 + ObjectMapper mapper = new ObjectMapper(); + Rule rule = mapper.readValue(operator, Rule.class); + String op = rule.getOperator(); + Double threshold = rule.getThreshold(); + boolean needWarn = NumUtil.compare(current, threshold, op); + if (needWarn){ + // 记录报警日志 + AlarmLog alarmLog = new AlarmLog(); + alarmLog.setRuleId(ruleId); + alarmLog.setOperator(operator); + alarmLog.setAlarmValue(StrUtil.toString(current)); + + String ruleName = alarmRule.getName(); + Map data = DataTool.getInstance(). + put(databaseName).put(ruleName).put(rule.joint()).put(current).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预警规则: {}解析失败,失败原因: {}", operator, e.getMessage()); + }catch (Exception e){ + log.error("Database监控异常: {}", e.getMessage()); + } + } + 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; + }*/ +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/jobs/EmailJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/jobs/EmailJob.java new file mode 100644 index 00000000..ef51c991 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/jobs/EmailJob.java @@ -0,0 +1,130 @@ +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.Data; +import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.api.dto.message.MessageDTO; +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.NameValue; +import org.jeecg.modules.base.entity.Rule; +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.quartz.entity.Monitor; +import org.quartz.*; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import static org.jeecg.modules.base.enums.SourceType.EMAIL; +import static org.jeecg.modules.base.enums.Template.MONITOR_EMAIL; + +@Slf4j +@Component +public class EmailJob extends Monitor{ + /** + * 解析Email预警规则 + **/ + @Scheduled(cron = "${task.period:0 0/1 * * * ?}") + public void execute(){ + init(); + + // 查询所有Email的报警规则,根据报警规则查询监控项数据 + String pattern = RedisConstant.PREFIX_RULE + EMAIL.getType(); + Set 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查询Eamil信息(缓存) + String sourceId = alarmRule.getSourceId(); + String emailName = getAlarmClient().getEmailName(sourceId); + + // 根据监控项id选择要查询的监控项信息 + Item item = Item.of(itemId); + if (ObjectUtil.isNull(item)) continue; + Number current = null; + switch (item){ + case EMAIL_CONN: // 监控项-1: 测试邮箱服务是否可以连接成功 + current = isConnection(sourceId); + break; + // 追加的监控项... + default: + break; + } + // 解析预警规则,判断是否需要报警 + ObjectMapper mapper = new ObjectMapper(); + Rule rule = mapper.readValue(operator, Rule.class); + String op = rule.getOperator(); + Double threshold = rule.getThreshold(); + boolean needWarn = NumUtil.compare(current, threshold, op); + if (needWarn){ + // 记录报警日志 + AlarmLog alarmLog = new AlarmLog(); + alarmLog.setRuleId(ruleId); + alarmLog.setOperator(operator); + alarmLog.setAlarmValue(StrUtil.toString(current)); + + String ruleName = alarmRule.getName(); + Map data = DataTool.getInstance(). + put(emailName).put(ruleName).put(rule.joint()).put(current).get(); + MessageDTO messageDTO = TemplateUtil.parse(MONITOR_EMAIL.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("Email预警规则: {}解析失败,失败原因: {}", operator, e.getMessage()); + }catch (Exception e){ + log.error("Email监控异常: {}", e.getMessage()); + } + } + destroy(); + } + + /* + * 监控项-1: 测试邮箱服务是否可以连接成功 (0:失败 1:成功) + * */ + private Integer isConnection(String emailId){ + int res = 1; + String statusKey = RedisConstant.EMAIL_STATUS; + NameValue nameValue = (NameValue)getRedisUtil().hget(statusKey, emailId); + if (ObjectUtil.isNull(nameValue) || ObjectUtil.isNull(nameValue.getValue()) || !nameValue.getValue()) + res = 0; + return res; + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/jobs/ServerJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/jobs/ServerJob.java new file mode 100644 index 00000000..5ffa9e86 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/quartz/jobs/ServerJob.java @@ -0,0 +1,137 @@ +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 feign.FeignException; +import lombok.Data; +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.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.feignclient.ManageUtil; +import org.jeecg.modules.quartz.entity.Monitor; +import org.quartz.*; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Map; +import java.util.Set; + +import static org.jeecg.modules.base.enums.SourceType.SERVER; +import static org.jeecg.modules.base.enums.Template.MONITOR_SERVER; + +@Slf4j +@Component +public class ServerJob extends Monitor{ + /** + * 根据host定时查询服务器信息 + * 并向消息队列中推送信息 + * + */ + @Scheduled(cron = "${task.period:0 0/1 * * * ?}") + public void execute(){ + init(); + + // 查询所有Server的报警规则,根据报警规则查询监控项数据 + String pattern = RedisConstant.PREFIX_RULE + SERVER.getType(); + Set keys = getRedisStreamUtil().keys(pattern); + if (CollUtil.isEmpty(keys)) return; + + // 时间间隔为每分钟 + LocalDateTime now = LocalDateTime.now() + .withSecond(0) + .withNano(0); + LocalDateTime beforeMin = now.minusMinutes(1); + DateTimeFormatter formatter = DateTimeFormatter + .ofPattern(DateConstant.DATE_TIME); + String start = beforeMin.format(formatter); + String end = now.format(formatter); + + 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 type = alarmRule.getItemType(); + Integer itemType = StrUtil.isBlank(type) ? 0 : Integer.parseInt(type); + 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查询Server信息(缓存) + String sourceId = alarmRule.getSourceId(); + String serverName = getAlarmClient().getServerName(sourceId); + + // 向运管查询监控项数据 + String token = ManageUtil.getToken(); + Result result = getMonitorSystem().itemBack(itemId, itemType, start, end, token); + ItemHistory itemHistory = result.getResult(); + if (ObjectUtil.isNull(itemHistory)){ + log.warn("Server监控异常: [{}]查询监控项历史数据为空", serverName); + continue; + } + Double current = itemHistory.getNow(); + + // 解析预警规则,判断是否需要报警 + ObjectMapper mapper = new ObjectMapper(); + Rule rule = mapper.readValue(operator, Rule.class); + String op = rule.getOperator(); + Double threshold = rule.getThreshold(); + boolean needWarn = NumUtil.compare(current, threshold, op); + if (needWarn){ + // 记录报警日志 + AlarmLog alarmLog = new AlarmLog(); + alarmLog.setRuleId(ruleId); + alarmLog.setOperator(operator); + alarmLog.setAlarmValue(StrUtil.toString(current)); + + String ruleName = alarmRule.getName(); + Map data = DataTool.getInstance(). + put(serverName).put(ruleName).put(rule.joint()).put(current).get(); + MessageDTO messageDTO = TemplateUtil.parse(MONITOR_SERVER.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 (FeignException.Unauthorized e){ + ManageUtil.refreshToken(); + log.warn("向运管系统查询ItemHistory信息异常: Token失效,已刷新Token"); + } catch (JsonProcessingException e) { + log.error("Server预警规则: {}解析失败,失败原因: {}", operator, e.getMessage()); + }catch (Exception e){ + log.error("Server监控异常: {}", e.getMessage()); + } + } + destroy(); + } +}