增加ssh链接框架
This commit is contained in:
parent
e5bd51b4b5
commit
03f2146546
@ -1,6 +1,6 @@
|
|||||||
package com.qqchen.deploy.backend.deploy.dto;
|
package com.qqchen.deploy.backend.deploy.dto;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.deploy.enums.AlertTypeEnum;
|
import com.qqchen.deploy.backend.framework.enums.MonitorMetricEnum;
|
||||||
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import jakarta.validation.constraints.*;
|
import jakarta.validation.constraints.*;
|
||||||
@ -25,9 +25,9 @@ public class ServerAlertRuleDTO extends BaseDTO {
|
|||||||
@Size(max = 100, message = "规则名称长度不能超过100个字符")
|
@Size(max = 100, message = "规则名称长度不能超过100个字符")
|
||||||
private String ruleName;
|
private String ruleName;
|
||||||
|
|
||||||
@Schema(description = "告警类型: CPU/MEMORY/DISK", required = true)
|
@Schema(description = "监控指标类型: CPU/MEMORY/DISK/NETWORK", required = true)
|
||||||
@NotNull(message = "告警类型不能为空")
|
@NotNull(message = "监控指标类型不能为空")
|
||||||
private AlertTypeEnum alertType;
|
private MonitorMetricEnum alertType;
|
||||||
|
|
||||||
@Schema(description = "警告阈值(%)", required = true, example = "80.00")
|
@Schema(description = "警告阈值(%)", required = true, example = "80.00")
|
||||||
@NotNull(message = "警告阈值不能为空")
|
@NotNull(message = "警告阈值不能为空")
|
||||||
@ -48,13 +48,6 @@ public class ServerAlertRuleDTO extends BaseDTO {
|
|||||||
@Schema(description = "是否启用")
|
@Schema(description = "是否启用")
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
|
|
||||||
@Schema(description = "通知方式: EMAIL/SMS/WEBHOOK")
|
|
||||||
@Size(max = 50, message = "通知方式长度不能超过50个字符")
|
|
||||||
private String notifyMethod;
|
|
||||||
|
|
||||||
@Schema(description = "通知联系人(JSON格式)")
|
|
||||||
private String notifyContacts;
|
|
||||||
|
|
||||||
@Schema(description = "规则描述")
|
@Schema(description = "规则描述")
|
||||||
@Size(max = 500, message = "描述长度不能超过500个字符")
|
@Size(max = 500, message = "描述长度不能超过500个字符")
|
||||||
private String description;
|
private String description;
|
||||||
|
|||||||
@ -36,6 +36,9 @@ public class ServerMonitorDataDTO {
|
|||||||
@Schema(description = "各分区磁盘使用率")
|
@Schema(description = "各分区磁盘使用率")
|
||||||
private List<DiskUsageInfo> diskUsage;
|
private List<DiskUsageInfo> diskUsage;
|
||||||
|
|
||||||
|
@Schema(description = "网络使用率(MB/s)")
|
||||||
|
private BigDecimal networkUsage;
|
||||||
|
|
||||||
@Schema(description = "采集时间")
|
@Schema(description = "采集时间")
|
||||||
private LocalDateTime collectTime;
|
private LocalDateTime collectTime;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package com.qqchen.deploy.backend.deploy.entity;
|
package com.qqchen.deploy.backend.deploy.entity;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.deploy.enums.AlertLevelEnum;
|
import com.qqchen.deploy.backend.framework.enums.MonitorAlertLevelEnum;
|
||||||
import com.qqchen.deploy.backend.deploy.enums.AlertTypeEnum;
|
import com.qqchen.deploy.backend.framework.enums.MonitorMetricEnum;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
@ -39,18 +39,18 @@ public class ServerAlertLog {
|
|||||||
private Long ruleId;
|
private Long ruleId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 告警类型
|
* 监控指标类型
|
||||||
*/
|
*/
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
@Column(name = "alert_type", nullable = false, length = 20)
|
@Column(name = "alert_type", nullable = false, length = 20)
|
||||||
private AlertTypeEnum alertType;
|
private MonitorMetricEnum alertType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 告警级别
|
* 告警级别
|
||||||
*/
|
*/
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
@Column(name = "alert_level", nullable = false, length = 20)
|
@Column(name = "alert_level", nullable = false, length = 20)
|
||||||
private AlertLevelEnum alertLevel;
|
private MonitorAlertLevelEnum alertLevel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前值
|
* 当前值
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package com.qqchen.deploy.backend.deploy.entity;
|
package com.qqchen.deploy.backend.deploy.entity;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.deploy.enums.AlertTypeEnum;
|
|
||||||
import com.qqchen.deploy.backend.framework.annotation.LogicDelete;
|
import com.qqchen.deploy.backend.framework.annotation.LogicDelete;
|
||||||
|
import com.qqchen.deploy.backend.framework.enums.MonitorMetricEnum;
|
||||||
import com.qqchen.deploy.backend.framework.domain.Entity;
|
import com.qqchen.deploy.backend.framework.domain.Entity;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@ -36,11 +36,11 @@ public class ServerAlertRule extends Entity<Long> {
|
|||||||
private String ruleName;
|
private String ruleName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 告警类型
|
* 监控指标类型
|
||||||
*/
|
*/
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
@Column(name = "alert_type", nullable = false, length = 20)
|
@Column(name = "alert_type", nullable = false, length = 20)
|
||||||
private AlertTypeEnum alertType;
|
private MonitorMetricEnum alertType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 警告阈值(%)
|
* 警告阈值(%)
|
||||||
@ -66,18 +66,6 @@ public class ServerAlertRule extends Entity<Long> {
|
|||||||
@Column(name = "enabled")
|
@Column(name = "enabled")
|
||||||
private Boolean enabled = true;
|
private Boolean enabled = true;
|
||||||
|
|
||||||
/**
|
|
||||||
* 通知方式: EMAIL/SMS/WEBHOOK
|
|
||||||
*/
|
|
||||||
@Column(name = "notify_method", length = 50)
|
|
||||||
private String notifyMethod;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通知联系人(JSON格式)
|
|
||||||
*/
|
|
||||||
@Column(name = "notify_contacts", columnDefinition = "JSON")
|
|
||||||
private String notifyContacts;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 规则描述
|
* 规则描述
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,29 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.deploy.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 告警类型枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum AlertTypeEnum {
|
|
||||||
/**
|
|
||||||
* CPU告警
|
|
||||||
*/
|
|
||||||
CPU("CPU", "CPU使用率"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 内存告警
|
|
||||||
*/
|
|
||||||
MEMORY("MEMORY", "内存使用率"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 磁盘告警
|
|
||||||
*/
|
|
||||||
DISK("DISK", "磁盘使用率");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String description;
|
|
||||||
}
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
package com.qqchen.deploy.backend.deploy.integration.impl;
|
package com.qqchen.deploy.backend.deploy.integration.impl;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
|
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
|
||||||
import com.qqchen.deploy.backend.framework.util.SensitiveDataEncryptor;
|
import com.qqchen.deploy.backend.framework.utils.SensitiveDataEncryptor;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|||||||
@ -0,0 +1,52 @@
|
|||||||
|
package com.qqchen.deploy.backend.deploy.monitor;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.deploy.dto.ServerMonitorDataDTO;
|
||||||
|
import com.qqchen.deploy.backend.framework.enums.MonitorMetricEnum;
|
||||||
|
import com.qqchen.deploy.backend.framework.monitor.ServerThresholdCheckerFactory;
|
||||||
|
import com.qqchen.deploy.backend.framework.monitor.impl.CpuThresholdChecker;
|
||||||
|
import com.qqchen.deploy.backend.framework.monitor.impl.DiskThresholdChecker;
|
||||||
|
import com.qqchen.deploy.backend.framework.monitor.impl.MemoryThresholdChecker;
|
||||||
|
import com.qqchen.deploy.backend.framework.monitor.impl.NetworkThresholdChecker;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务器监控阈值检测器工厂
|
||||||
|
* Deploy 业务层使用 Framework 提供的检测器能力
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @since 2025-12-07
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ServerMonitorThresholdCheckerFactory extends ServerThresholdCheckerFactory<ServerMonitorDataDTO> {
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
@Override
|
||||||
|
protected void registerCheckers() {
|
||||||
|
// 注册 CPU 检测器
|
||||||
|
checkers.put(MonitorMetricEnum.CPU,
|
||||||
|
new CpuThresholdChecker<>(ServerMonitorDataDTO::getCpuUsage));
|
||||||
|
|
||||||
|
// 注册内存检测器
|
||||||
|
checkers.put(MonitorMetricEnum.MEMORY,
|
||||||
|
new MemoryThresholdChecker<>(ServerMonitorDataDTO::getMemoryUsage));
|
||||||
|
|
||||||
|
// 注册磁盘检测器(取所有分区中使用率最高的)
|
||||||
|
checkers.put(MonitorMetricEnum.DISK,
|
||||||
|
new DiskThresholdChecker<>(data -> {
|
||||||
|
if (data == null || data.getDiskUsage() == null || data.getDiskUsage().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return data.getDiskUsage().stream()
|
||||||
|
.map(disk -> disk.getUsagePercent())
|
||||||
|
.max(BigDecimal::compareTo)
|
||||||
|
.orElse(null);
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 注册网络检测器
|
||||||
|
checkers.put(MonitorMetricEnum.NETWORK,
|
||||||
|
new NetworkThresholdChecker<>(ServerMonitorDataDTO::getNetworkUsage));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package com.qqchen.deploy.backend.deploy.query;
|
package com.qqchen.deploy.backend.deploy.query;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.deploy.enums.AlertTypeEnum;
|
import com.qqchen.deploy.backend.framework.enums.MonitorMetricEnum;
|
||||||
import com.qqchen.deploy.backend.framework.annotation.QueryField;
|
import com.qqchen.deploy.backend.framework.annotation.QueryField;
|
||||||
import com.qqchen.deploy.backend.framework.enums.QueryType;
|
import com.qqchen.deploy.backend.framework.enums.QueryType;
|
||||||
import com.qqchen.deploy.backend.framework.query.BaseQuery;
|
import com.qqchen.deploy.backend.framework.query.BaseQuery;
|
||||||
@ -24,9 +24,9 @@ public class ServerAlertRuleQuery extends BaseQuery {
|
|||||||
@QueryField(field = "ruleName", type = QueryType.LIKE)
|
@QueryField(field = "ruleName", type = QueryType.LIKE)
|
||||||
private String ruleName;
|
private String ruleName;
|
||||||
|
|
||||||
@Schema(description = "告警类型")
|
@Schema(description = "监控指标类型")
|
||||||
@QueryField(field = "alertType")
|
@QueryField(type = QueryType.EQUAL)
|
||||||
private AlertTypeEnum alertType;
|
private MonitorMetricEnum alertType;
|
||||||
|
|
||||||
@Schema(description = "是否启用")
|
@Schema(description = "是否启用")
|
||||||
@QueryField(field = "enabled")
|
@QueryField(field = "enabled")
|
||||||
|
|||||||
@ -52,32 +52,44 @@ public class ServerMonitorScheduler {
|
|||||||
* 采集所有在线服务器的监控数据
|
* 采集所有在线服务器的监控数据
|
||||||
* 此方法由定时任务管理系统调用
|
* 此方法由定时任务管理系统调用
|
||||||
*
|
*
|
||||||
* @param config 通知配置(可选,为null则只记录数据不发通知)
|
* @param notificationChannelId 通知渠道ID(可选,为null则不发送通知)
|
||||||
|
* @param serverOfflineTemplateId 服务器离线通知模板ID(可选)
|
||||||
|
* @param resourceAlertTemplateId 资源告警通知模板ID(可选)
|
||||||
*/
|
*/
|
||||||
public void collectServerMetrics(ServerMonitorNotificationConfig config) {
|
public void collectServerMetrics(Long notificationChannelId,
|
||||||
if (config != null) {
|
Long serverOfflineTemplateId,
|
||||||
|
Long resourceAlertTemplateId) {
|
||||||
|
// 构建通知配置对象
|
||||||
|
ServerMonitorNotificationConfig config = null;
|
||||||
|
if (notificationChannelId != null) {
|
||||||
|
config = new ServerMonitorNotificationConfig();
|
||||||
|
config.setNotificationChannelId(notificationChannelId);
|
||||||
|
config.setServerOfflineTemplateId(serverOfflineTemplateId);
|
||||||
|
config.setResourceAlertTemplateId(resourceAlertTemplateId);
|
||||||
|
|
||||||
log.info("========== 开始采集服务器监控数据 ========== channelId={}, offlineTemplateId={}, alertTemplateId={}",
|
log.info("========== 开始采集服务器监控数据 ========== channelId={}, offlineTemplateId={}, alertTemplateId={}",
|
||||||
config.getNotificationChannelId(), config.getServerOfflineTemplateId(), config.getResourceAlertTemplateId());
|
notificationChannelId, serverOfflineTemplateId, resourceAlertTemplateId);
|
||||||
} else {
|
} else {
|
||||||
log.info("========== 开始采集服务器监控数据(不发送通知) ==========");
|
log.info("========== 开始采集服务器监控数据(不发送通知) ==========");
|
||||||
}
|
}
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. 查询所有应该在线的服务器(状态为ONLINE)
|
// 1. 查询所有服务器(不管当前状态),准备检测在线状态
|
||||||
List<Server> shouldBeOnlineServers = serverRepository
|
List<Server> allServers = serverRepository.findAll();
|
||||||
.findByStatusAndDeleted(ServerStatusEnum.ONLINE, false);
|
|
||||||
|
|
||||||
if (shouldBeOnlineServers.isEmpty()) {
|
if (allServers.isEmpty()) {
|
||||||
log.debug("没有需要监控的服务器,跳过监控采集");
|
log.debug("没有需要监控的服务器,跳过监控采集");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("发现 {} 台应在线服务器,开始检测状态", shouldBeOnlineServers.size());
|
log.info("发现 {} 台服务器,开始检测在线状态并采集监控数据", allServers.size());
|
||||||
|
|
||||||
// 2. 并发检测服务器连接状态并采集监控数据
|
// 2. 并发检测所有服务器的连接状态并采集监控数据
|
||||||
|
// - 连接失败 → 发送离线通知
|
||||||
|
// - 连接成功 → 采集数据,检查阈值告警
|
||||||
final ServerMonitorNotificationConfig finalConfig = config;
|
final ServerMonitorNotificationConfig finalConfig = config;
|
||||||
List<CompletableFuture<ServerMonitorDataDTO>> futures = shouldBeOnlineServers.stream()
|
List<CompletableFuture<ServerMonitorDataDTO>> futures = allServers.stream()
|
||||||
.map(server -> CompletableFuture.supplyAsync(() ->
|
.map(server -> CompletableFuture.supplyAsync(() ->
|
||||||
collectSingleServerWithStatusCheck(server, finalConfig)))
|
collectSingleServerWithStatusCheck(server, finalConfig)))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
@ -95,8 +107,8 @@ public class ServerMonitorScheduler {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
long duration = System.currentTimeMillis() - startTime;
|
long duration = System.currentTimeMillis() - startTime;
|
||||||
log.info("========== 监控数据采集完成: 成功={}/{}, 耗时={}ms ==========",
|
log.info("========== 监控数据采集完成: 在线={}/{}, 耗时={}ms ==========",
|
||||||
monitorDataList.size(), shouldBeOnlineServers.size(), duration);
|
monitorDataList.size(), allServers.size(), duration);
|
||||||
|
|
||||||
// 5. 批量保存监控数据到数据库
|
// 5. 批量保存监控数据到数据库
|
||||||
if (!monitorDataList.isEmpty()) {
|
if (!monitorDataList.isEmpty()) {
|
||||||
@ -152,7 +164,8 @@ public class ServerMonitorScheduler {
|
|||||||
Map<String, Object> templateParams = new HashMap<>();
|
Map<String, Object> templateParams = new HashMap<>();
|
||||||
templateParams.put("serverName", server.getServerName());
|
templateParams.put("serverName", server.getServerName());
|
||||||
templateParams.put("serverIp", server.getHostIp());
|
templateParams.put("serverIp", server.getHostIp());
|
||||||
templateParams.put("offlineTime", LocalDateTime.now().toString());
|
templateParams.put("offlineTime", LocalDateTime.now().format(
|
||||||
|
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||||
|
|
||||||
// 2. 构建SendNotificationRequest
|
// 2. 构建SendNotificationRequest
|
||||||
SendNotificationRequest request = new SendNotificationRequest();
|
SendNotificationRequest request = new SendNotificationRequest();
|
||||||
|
|||||||
@ -14,14 +14,13 @@ import com.qqchen.deploy.backend.deploy.service.IJenkinsBuildService;
|
|||||||
import com.qqchen.deploy.backend.deploy.service.IJenkinsJobService;
|
import com.qqchen.deploy.backend.deploy.service.IJenkinsJobService;
|
||||||
import com.qqchen.deploy.backend.deploy.service.IJenkinsViewService;
|
import com.qqchen.deploy.backend.deploy.service.IJenkinsViewService;
|
||||||
import com.qqchen.deploy.backend.system.enums.ExternalSystemAuthTypeEnum;
|
import com.qqchen.deploy.backend.system.enums.ExternalSystemAuthTypeEnum;
|
||||||
import com.qqchen.deploy.backend.system.enums.ExternalSystemSyncStatusEnum;
|
|
||||||
import com.qqchen.deploy.backend.system.enums.ExternalSystemTypeEnum;
|
import com.qqchen.deploy.backend.system.enums.ExternalSystemTypeEnum;
|
||||||
import com.qqchen.deploy.backend.framework.annotation.ServiceType;
|
import com.qqchen.deploy.backend.framework.annotation.ServiceType;
|
||||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||||
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
||||||
import com.qqchen.deploy.backend.framework.exception.UniqueConstraintException;
|
import com.qqchen.deploy.backend.framework.exception.UniqueConstraintException;
|
||||||
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
|
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
|
||||||
import com.qqchen.deploy.backend.framework.util.SensitiveDataEncryptor;
|
import com.qqchen.deploy.backend.framework.utils.SensitiveDataEncryptor;
|
||||||
import com.qqchen.deploy.backend.deploy.integration.IExternalSystemIntegration;
|
import com.qqchen.deploy.backend.deploy.integration.IExternalSystemIntegration;
|
||||||
import com.qqchen.deploy.backend.system.model.ExternalSystemDTO;
|
import com.qqchen.deploy.backend.system.model.ExternalSystemDTO;
|
||||||
import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository;
|
import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository;
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import com.qqchen.deploy.backend.deploy.dto.ServerMonitorNotificationConfig;
|
|||||||
import com.qqchen.deploy.backend.deploy.entity.Server;
|
import com.qqchen.deploy.backend.deploy.entity.Server;
|
||||||
import com.qqchen.deploy.backend.deploy.entity.ServerAlertLog;
|
import com.qqchen.deploy.backend.deploy.entity.ServerAlertLog;
|
||||||
import com.qqchen.deploy.backend.deploy.entity.ServerAlertRule;
|
import com.qqchen.deploy.backend.deploy.entity.ServerAlertRule;
|
||||||
import com.qqchen.deploy.backend.deploy.enums.AlertLevelEnum;
|
import com.qqchen.deploy.backend.framework.enums.MonitorAlertLevelEnum;
|
||||||
import com.qqchen.deploy.backend.deploy.enums.AlertTypeEnum;
|
import com.qqchen.deploy.backend.framework.enums.MonitorMetricEnum;
|
||||||
import com.qqchen.deploy.backend.deploy.repository.IServerAlertLogRepository;
|
import com.qqchen.deploy.backend.deploy.repository.IServerAlertLogRepository;
|
||||||
import com.qqchen.deploy.backend.deploy.repository.IServerAlertRuleRepository;
|
import com.qqchen.deploy.backend.deploy.repository.IServerAlertRuleRepository;
|
||||||
import com.qqchen.deploy.backend.deploy.repository.IServerRepository;
|
import com.qqchen.deploy.backend.deploy.repository.IServerRepository;
|
||||||
@ -98,14 +98,14 @@ public class ServerAlertServiceImpl implements IServerAlertService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 判断告警级别
|
// 判断告警级别
|
||||||
AlertLevelEnum alertLevel = null;
|
MonitorAlertLevelEnum alertLevel = null;
|
||||||
BigDecimal threshold = null;
|
BigDecimal threshold = null;
|
||||||
|
|
||||||
if (currentValue.compareTo(rule.getCriticalThreshold()) >= 0) {
|
if (currentValue.compareTo(rule.getCriticalThreshold()) >= 0) {
|
||||||
alertLevel = AlertLevelEnum.CRITICAL;
|
alertLevel = MonitorAlertLevelEnum.CRITICAL;
|
||||||
threshold = rule.getCriticalThreshold();
|
threshold = rule.getCriticalThreshold();
|
||||||
} else if (currentValue.compareTo(rule.getWarningThreshold()) >= 0) {
|
} else if (currentValue.compareTo(rule.getWarningThreshold()) >= 0) {
|
||||||
alertLevel = AlertLevelEnum.WARNING;
|
alertLevel = MonitorAlertLevelEnum.WARNING;
|
||||||
threshold = rule.getWarningThreshold();
|
threshold = rule.getWarningThreshold();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +117,7 @@ public class ServerAlertServiceImpl implements IServerAlertService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查磁盘告警
|
* 检查磁盘告警
|
||||||
|
* 策略:计算所有分区的总使用率 = (所有已用空间总和) / (所有总容量) * 100%
|
||||||
*/
|
*/
|
||||||
private void checkDiskAlert(Long serverId, ServerMonitorDataDTO monitorData, ServerAlertRule rule,
|
private void checkDiskAlert(Long serverId, ServerMonitorDataDTO monitorData, ServerAlertRule rule,
|
||||||
ServerMonitorNotificationConfig config) {
|
ServerMonitorNotificationConfig config) {
|
||||||
@ -125,34 +126,50 @@ public class ServerAlertServiceImpl implements IServerAlertService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (DiskUsageInfo diskUsage : diskUsageList) {
|
// 计算所有分区的总容量和已用空间
|
||||||
BigDecimal usagePercent = diskUsage.getUsagePercent();
|
BigDecimal totalCapacity = BigDecimal.ZERO; // 总容量(GB)
|
||||||
if (usagePercent == null) {
|
BigDecimal totalUsed = BigDecimal.ZERO; // 已用空间(GB)
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AlertLevelEnum alertLevel = null;
|
for (DiskUsageInfo disk : diskUsageList) {
|
||||||
BigDecimal threshold = null;
|
if (disk.getTotalSize() != null && disk.getUsedSize() != null) {
|
||||||
|
totalCapacity = totalCapacity.add(disk.getTotalSize());
|
||||||
if (usagePercent.compareTo(rule.getCriticalThreshold()) >= 0) {
|
totalUsed = totalUsed.add(disk.getUsedSize());
|
||||||
alertLevel = AlertLevelEnum.CRITICAL;
|
|
||||||
threshold = rule.getCriticalThreshold();
|
|
||||||
} else if (usagePercent.compareTo(rule.getWarningThreshold()) >= 0) {
|
|
||||||
alertLevel = AlertLevelEnum.WARNING;
|
|
||||||
threshold = rule.getWarningThreshold();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (alertLevel != null) {
|
if (totalCapacity.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
String resourceInfo = "磁盘[" + diskUsage.getMountPoint() + "]";
|
return;
|
||||||
triggerAlert(serverId, rule, alertLevel, usagePercent, threshold, resourceInfo, config);
|
}
|
||||||
}
|
|
||||||
|
// 计算总磁盘使用率
|
||||||
|
BigDecimal totalUsagePercent = totalUsed
|
||||||
|
.multiply(new BigDecimal(100))
|
||||||
|
.divide(totalCapacity, 2, BigDecimal.ROUND_HALF_UP);
|
||||||
|
|
||||||
|
// 判断是否超过阈值
|
||||||
|
MonitorAlertLevelEnum alertLevel = null;
|
||||||
|
BigDecimal threshold = null;
|
||||||
|
|
||||||
|
if (totalUsagePercent.compareTo(rule.getCriticalThreshold()) >= 0) {
|
||||||
|
alertLevel = MonitorAlertLevelEnum.CRITICAL;
|
||||||
|
threshold = rule.getCriticalThreshold();
|
||||||
|
} else if (totalUsagePercent.compareTo(rule.getWarningThreshold()) >= 0) {
|
||||||
|
alertLevel = MonitorAlertLevelEnum.WARNING;
|
||||||
|
threshold = rule.getWarningThreshold();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触发告警
|
||||||
|
if (alertLevel != null) {
|
||||||
|
String resourceInfo = String.format("总磁盘(%d个分区,总容量%.0fGB,已用%.0fGB)",
|
||||||
|
diskUsageList.size(), totalCapacity.doubleValue(), totalUsed.doubleValue());
|
||||||
|
triggerAlert(serverId, rule, alertLevel, totalUsagePercent, threshold, resourceInfo, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 触发告警
|
* 触发告警
|
||||||
*/
|
*/
|
||||||
private void triggerAlert(Long serverId, ServerAlertRule rule, AlertLevelEnum level,
|
private void triggerAlert(Long serverId, ServerAlertRule rule, MonitorAlertLevelEnum level,
|
||||||
BigDecimal currentValue, BigDecimal threshold, String resourceInfo,
|
BigDecimal currentValue, BigDecimal threshold, String resourceInfo,
|
||||||
ServerMonitorNotificationConfig config) {
|
ServerMonitorNotificationConfig config) {
|
||||||
// 1. 记录告警日志到数据库
|
// 1. 记录告警日志到数据库
|
||||||
@ -199,7 +216,7 @@ public class ServerAlertServiceImpl implements IServerAlertService {
|
|||||||
/**
|
/**
|
||||||
* 发送告警通知
|
* 发送告警通知
|
||||||
*/
|
*/
|
||||||
private void sendAlertNotification(Long serverId, ServerAlertRule rule, AlertLevelEnum level,
|
private void sendAlertNotification(Long serverId, ServerAlertRule rule, MonitorAlertLevelEnum level,
|
||||||
BigDecimal currentValue, BigDecimal threshold, String resourceInfo,
|
BigDecimal currentValue, BigDecimal threshold, String resourceInfo,
|
||||||
ServerMonitorNotificationConfig config) {
|
ServerMonitorNotificationConfig config) {
|
||||||
try {
|
try {
|
||||||
@ -220,7 +237,8 @@ public class ServerAlertServiceImpl implements IServerAlertService {
|
|||||||
templateParams.put("resourceInfo", resourceInfo);
|
templateParams.put("resourceInfo", resourceInfo);
|
||||||
templateParams.put("currentValue", String.format("%.2f", currentValue));
|
templateParams.put("currentValue", String.format("%.2f", currentValue));
|
||||||
templateParams.put("threshold", String.format("%.2f", threshold));
|
templateParams.put("threshold", String.format("%.2f", threshold));
|
||||||
templateParams.put("alertTime", LocalDateTime.now().toString());
|
templateParams.put("alertTime", LocalDateTime.now().format(
|
||||||
|
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||||
|
|
||||||
// 3. 构建SendNotificationRequest
|
// 3. 构建SendNotificationRequest
|
||||||
SendNotificationRequest request = new SendNotificationRequest();
|
SendNotificationRequest request = new SendNotificationRequest();
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
package com.qqchen.deploy.backend.deploy.enums;
|
package com.qqchen.deploy.backend.framework.enums;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 告警级别枚举
|
* 监控告警级别枚举
|
||||||
|
* Framework 提供的服务器监控告警级别
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @since 2025-12-07
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum AlertLevelEnum {
|
public enum MonitorAlertLevelEnum {
|
||||||
/**
|
/**
|
||||||
* 警告
|
* 警告
|
||||||
*/
|
*/
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监控指标枚举
|
||||||
|
* Framework 提供的服务器监控指标类型
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @since 2025-12-07
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum MonitorMetricEnum {
|
||||||
|
/**
|
||||||
|
* CPU告警(百分比)
|
||||||
|
*/
|
||||||
|
CPU("CPU", "CPU使用率", "%"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内存告警(百分比)
|
||||||
|
*/
|
||||||
|
MEMORY("MEMORY", "内存使用率", "%"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 磁盘告警(百分比)
|
||||||
|
*/
|
||||||
|
DISK("DISK", "磁盘使用率", "%"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网络告警(MB/s)
|
||||||
|
*/
|
||||||
|
NETWORK("NETWORK", "网络使用率", "MB/s");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 度量单位
|
||||||
|
*/
|
||||||
|
private final String unit;
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.monitor;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.enums.MonitorAlertLevelEnum;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务器阈值检测器抽象基类
|
||||||
|
* 提供通用的阈值检测逻辑
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @since 2025-12-07
|
||||||
|
*/
|
||||||
|
public abstract class AbstractServerThresholdChecker<T> implements IServerThresholdChecker<T> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MonitorAlertLevelEnum checkThreshold(BigDecimal currentValue,
|
||||||
|
BigDecimal warningThreshold,
|
||||||
|
BigDecimal criticalThreshold) {
|
||||||
|
if (currentValue == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否超过严重阈值
|
||||||
|
if (criticalThreshold != null && currentValue.compareTo(criticalThreshold) >= 0) {
|
||||||
|
return MonitorAlertLevelEnum.CRITICAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否超过警告阈值
|
||||||
|
if (warningThreshold != null && currentValue.compareTo(warningThreshold) >= 0) {
|
||||||
|
return MonitorAlertLevelEnum.WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 未超过阈值
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.monitor;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.enums.MonitorAlertLevelEnum;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务器阈值检测器接口
|
||||||
|
* Framework 提供的服务器监控指标阈值检测能力
|
||||||
|
*
|
||||||
|
* 每种监控指标(CPU/内存/磁盘/网络)实现自己的阈值检测逻辑
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @since 2025-12-07
|
||||||
|
*/
|
||||||
|
public interface IServerThresholdChecker<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前指标值
|
||||||
|
*
|
||||||
|
* @param monitorData 监控数据
|
||||||
|
* @return 当前指标值
|
||||||
|
*/
|
||||||
|
BigDecimal getCurrentValue(T monitorData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否超过阈值并触发告警
|
||||||
|
*
|
||||||
|
* @param currentValue 当前值
|
||||||
|
* @param warningThreshold 警告阈值
|
||||||
|
* @param criticalThreshold 严重阈值
|
||||||
|
* @return 告警级别(null表示未超过阈值)
|
||||||
|
*/
|
||||||
|
MonitorAlertLevelEnum checkThreshold(BigDecimal currentValue, BigDecimal warningThreshold, BigDecimal criticalThreshold);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取资源信息描述(用于通知消息)
|
||||||
|
*
|
||||||
|
* @param monitorData 监控数据
|
||||||
|
* @return 资源描述,如 "CPU使用率", "内存使用率", "磁盘(/data)使用率"
|
||||||
|
*/
|
||||||
|
String getResourceInfo(T monitorData);
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.monitor;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.enums.MonitorAlertLevelEnum;
|
||||||
|
import com.qqchen.deploy.backend.framework.enums.MonitorMetricEnum;
|
||||||
|
import com.qqchen.deploy.backend.framework.monitor.dto.ThresholdCheckResult;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务器监控服务
|
||||||
|
* Framework 提供的阈值检测能力
|
||||||
|
*
|
||||||
|
* SSH采集由业务层自行处理(ServerMonitorScheduler)
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @since 2025-12-07
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class ServerMonitorService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查阈值
|
||||||
|
* 使用检测器检查指标是否超过阈值
|
||||||
|
*
|
||||||
|
* @param metric 监控指标类型
|
||||||
|
* @param monitorData 监控数据
|
||||||
|
* @param warningThreshold 警告阈值
|
||||||
|
* @param criticalThreshold 严重阈值
|
||||||
|
* @param checker 阈值检测器
|
||||||
|
* @return 检测结果
|
||||||
|
*/
|
||||||
|
public <T> ThresholdCheckResult checkThreshold(MonitorMetricEnum metric,
|
||||||
|
T monitorData,
|
||||||
|
BigDecimal warningThreshold,
|
||||||
|
BigDecimal criticalThreshold,
|
||||||
|
IServerThresholdChecker<T> checker) {
|
||||||
|
// 获取当前值
|
||||||
|
BigDecimal currentValue = checker.getCurrentValue(monitorData);
|
||||||
|
|
||||||
|
// 检查阈值
|
||||||
|
MonitorAlertLevelEnum alertLevel = checker.checkThreshold(
|
||||||
|
currentValue, warningThreshold, criticalThreshold);
|
||||||
|
|
||||||
|
// 构建结果
|
||||||
|
return ThresholdCheckResult.builder()
|
||||||
|
.metric(metric)
|
||||||
|
.currentValue(currentValue)
|
||||||
|
.alertLevel(alertLevel)
|
||||||
|
.resourceInfo(checker.getResourceInfo(monitorData))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.monitor;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.enums.MonitorMetricEnum;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务器阈值检测器工厂抽象类
|
||||||
|
* Framework 提供的工厂能力
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @since 2025-12-07
|
||||||
|
*/
|
||||||
|
public abstract class ServerThresholdCheckerFactory<T> {
|
||||||
|
|
||||||
|
protected Map<MonitorMetricEnum, IServerThresholdChecker<T>> checkers = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定监控指标的检测器
|
||||||
|
*
|
||||||
|
* @param metric 监控指标类型
|
||||||
|
* @return 对应的检测器
|
||||||
|
* @throws IllegalArgumentException 如果找不到对应的检测器
|
||||||
|
*/
|
||||||
|
public IServerThresholdChecker<T> getChecker(MonitorMetricEnum metric) {
|
||||||
|
IServerThresholdChecker<T> checker = checkers.get(metric);
|
||||||
|
if (checker == null) {
|
||||||
|
throw new IllegalArgumentException("未找到监控指标的检测器: " + metric);
|
||||||
|
}
|
||||||
|
return checker;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册检测器
|
||||||
|
* 子类需要实现此方法来注册所有检测器
|
||||||
|
*/
|
||||||
|
protected abstract void registerCheckers();
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.monitor.dto;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.enums.MonitorAlertLevelEnum;
|
||||||
|
import com.qqchen.deploy.backend.framework.enums.MonitorMetricEnum;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 阈值检测结果
|
||||||
|
* Framework 提供的检测结果数据结构
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @since 2025-12-07
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ThresholdCheckResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监控指标类型
|
||||||
|
*/
|
||||||
|
private MonitorMetricEnum metric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前值
|
||||||
|
*/
|
||||||
|
private BigDecimal currentValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 告警级别(null表示未超过阈值)
|
||||||
|
*/
|
||||||
|
private MonitorAlertLevelEnum alertLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源信息描述
|
||||||
|
*/
|
||||||
|
private String resourceInfo;
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.monitor.impl;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.monitor.AbstractServerThresholdChecker;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CPU阈值检测器
|
||||||
|
* Framework 提供的CPU使用率检测能力
|
||||||
|
*
|
||||||
|
* 通过函数式接口传入取值逻辑,实现通用性
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @since 2025-12-07
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class CpuThresholdChecker<T> extends AbstractServerThresholdChecker<T> {
|
||||||
|
|
||||||
|
private final java.util.function.Function<T, BigDecimal> valueExtractor;
|
||||||
|
|
||||||
|
public CpuThresholdChecker(java.util.function.Function<T, BigDecimal> valueExtractor) {
|
||||||
|
this.valueExtractor = valueExtractor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigDecimal getCurrentValue(T monitorData) {
|
||||||
|
return monitorData != null ? valueExtractor.apply(monitorData) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getResourceInfo(T monitorData) {
|
||||||
|
return "CPU使用率";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.monitor.impl;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.monitor.AbstractServerThresholdChecker;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 磁盘阈值检测器
|
||||||
|
* Framework 提供的磁盘使用率检测能力
|
||||||
|
*
|
||||||
|
* 通过函数式接口传入取值逻辑,实现通用性
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @since 2025-12-07
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class DiskThresholdChecker<T> extends AbstractServerThresholdChecker<T> {
|
||||||
|
|
||||||
|
private final java.util.function.Function<T, BigDecimal> valueExtractor;
|
||||||
|
|
||||||
|
public DiskThresholdChecker(java.util.function.Function<T, BigDecimal> valueExtractor) {
|
||||||
|
this.valueExtractor = valueExtractor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigDecimal getCurrentValue(T monitorData) {
|
||||||
|
return monitorData != null ? valueExtractor.apply(monitorData) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getResourceInfo(T monitorData) {
|
||||||
|
return "磁盘使用率";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.monitor.impl;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.monitor.AbstractServerThresholdChecker;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内存阈值检测器
|
||||||
|
* Framework 提供的内存使用率检测能力
|
||||||
|
*
|
||||||
|
* 通过函数式接口传入取值逻辑,实现通用性
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @since 2025-12-07
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class MemoryThresholdChecker<T> extends AbstractServerThresholdChecker<T> {
|
||||||
|
|
||||||
|
private final java.util.function.Function<T, BigDecimal> valueExtractor;
|
||||||
|
|
||||||
|
public MemoryThresholdChecker(java.util.function.Function<T, BigDecimal> valueExtractor) {
|
||||||
|
this.valueExtractor = valueExtractor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigDecimal getCurrentValue(T monitorData) {
|
||||||
|
return monitorData != null ? valueExtractor.apply(monitorData) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getResourceInfo(T monitorData) {
|
||||||
|
return "内存使用率";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package com.qqchen.deploy.backend.framework.monitor.impl;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.framework.monitor.AbstractServerThresholdChecker;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网络阈值检测器
|
||||||
|
* Framework 提供的网络使用率检测能力
|
||||||
|
*
|
||||||
|
* 通过函数式接口传入取值逻辑,实现通用性
|
||||||
|
*
|
||||||
|
* @author qqchen
|
||||||
|
* @since 2025-12-07
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class NetworkThresholdChecker<T> extends AbstractServerThresholdChecker<T> {
|
||||||
|
|
||||||
|
private final java.util.function.Function<T, BigDecimal> valueExtractor;
|
||||||
|
|
||||||
|
public NetworkThresholdChecker(java.util.function.Function<T, BigDecimal> valueExtractor) {
|
||||||
|
this.valueExtractor = valueExtractor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigDecimal getCurrentValue(T monitorData) {
|
||||||
|
return monitorData != null ? valueExtractor.apply(monitorData) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getResourceInfo(T monitorData) {
|
||||||
|
return "网络使用率";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.qqchen.deploy.backend.framework.util;
|
package com.qqchen.deploy.backend.framework.utils;
|
||||||
|
|
||||||
import org.springframework.security.crypto.encrypt.Encryptors;
|
import org.springframework.security.crypto.encrypt.Encryptors;
|
||||||
import org.springframework.security.crypto.encrypt.TextEncryptor;
|
import org.springframework.security.crypto.encrypt.TextEncryptor;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.qqchen.deploy.backend.framework.util;
|
package com.qqchen.deploy.backend.framework.utils;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@ -40,6 +40,8 @@ public class NotificationChannelServiceImpl extends BaseServiceImpl<Notification
|
|||||||
@Resource
|
@Resource
|
||||||
private INotificationChannelRepository notificationChannelRepository;
|
private INotificationChannelRepository notificationChannelRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private INotificationSendService notificationSendService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private NotificationChannelAdapterFactory adapterFactory;
|
private NotificationChannelAdapterFactory adapterFactory;
|
||||||
@ -59,30 +61,58 @@ public class NotificationChannelServiceImpl extends BaseServiceImpl<Notification
|
|||||||
NotificationChannel channel = notificationChannelRepository.findById(id)
|
NotificationChannel channel = notificationChannelRepository.findById(id)
|
||||||
.orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND));
|
.orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND));
|
||||||
|
|
||||||
log.info("开始测试通知渠道连接: id={}, name={}, type={}",
|
log.info("开始测试通知渠道: id={}, name={}, type={}",
|
||||||
id, channel.getName(), channel.getChannelType());
|
id, channel.getName(), channel.getChannelType());
|
||||||
|
|
||||||
// 2. 获取对应的适配器
|
// 2. 创建测试消息
|
||||||
INotificationChannelAdapter adapter;
|
BaseSendNotificationRequest testRequest = createTestRequest(channel);
|
||||||
try {
|
|
||||||
adapter = adapterFactory.getAdapter(channel.getChannelType());
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
log.error("获取通知渠道适配器失败: {}", e.getMessage());
|
|
||||||
throw new BusinessException(ResponseCode.ERROR, new Object[] {"不支持的渠道类型: " + channel.getChannelType()});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 转换配置
|
// 3. 发送测试消息(复用 send 逻辑,测试完整的发送流程)
|
||||||
BaseNotificationConfig config = convertConfig(channel);
|
|
||||||
|
|
||||||
// 4. 执行连接测试
|
|
||||||
try {
|
try {
|
||||||
adapter.testConnection(config);
|
notificationSendService.send(channel, testRequest);
|
||||||
log.info("通知渠道连接测试成功: id={}, name={}", id, channel.getName());
|
log.info("通知渠道测试成功: id={}, name={}", id, channel.getName());
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("通知渠道连接测试失败: id={}, name={}, 错误: {}",
|
log.error("通知渠道测试失败: id={}, name={}, 错误: {}",
|
||||||
id, channel.getName(), e.getMessage(), e);
|
id, channel.getName(), e.getMessage(), e);
|
||||||
throw new BusinessException(ResponseCode.ERROR, new Object[] {"连接测试失败: " + e.getMessage()});
|
throw new BusinessException(ResponseCode.ERROR, new Object[] {"测试失败: " + e.getMessage()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建测试消息
|
||||||
|
*/
|
||||||
|
private BaseSendNotificationRequest createTestRequest(NotificationChannel channel) {
|
||||||
|
String testContent = String.format(
|
||||||
|
"【通知渠道测试】\n" +
|
||||||
|
"渠道名称:%s\n" +
|
||||||
|
"渠道类型:%s\n" +
|
||||||
|
"测试时间:%s\n\n" +
|
||||||
|
"如果您收到此消息,说明通知渠道配置正确!",
|
||||||
|
channel.getName(),
|
||||||
|
channel.getChannelType().getDescription(),
|
||||||
|
java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
|
||||||
|
);
|
||||||
|
|
||||||
|
switch (channel.getChannelType()) {
|
||||||
|
case WEWORK -> {
|
||||||
|
com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest request =
|
||||||
|
new com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest();
|
||||||
|
request.setContent(testContent);
|
||||||
|
request.setTitle("【测试消息】通知渠道连接测试");
|
||||||
|
request.setMessageType(com.qqchen.deploy.backend.notification.enums.WeworkMessageTypeEnum.TEXT);
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
case EMAIL -> {
|
||||||
|
com.qqchen.deploy.backend.notification.dto.EmailSendNotificationRequest request =
|
||||||
|
new com.qqchen.deploy.backend.notification.dto.EmailSendNotificationRequest();
|
||||||
|
request.setContent(testContent);
|
||||||
|
request.setTitle("【测试消息】通知渠道连接测试");
|
||||||
|
request.setToReceivers(java.util.Arrays.asList("admin@company.com"));
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
default -> throw new BusinessException(ResponseCode.ERROR,
|
||||||
|
new Object[]{"不支持的渠道类型: " + channel.getChannelType()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1212,10 +1212,6 @@ CREATE TABLE deploy_server_alert_rule
|
|||||||
-- 是否启用
|
-- 是否启用
|
||||||
enabled BOOLEAN DEFAULT TRUE COMMENT '是否启用',
|
enabled BOOLEAN DEFAULT TRUE COMMENT '是否启用',
|
||||||
|
|
||||||
-- 通知方式
|
|
||||||
notify_method VARCHAR(50) NULL COMMENT '通知方式: EMAIL/SMS/WEBHOOK',
|
|
||||||
notify_contacts JSON NULL COMMENT '通知联系人',
|
|
||||||
|
|
||||||
-- 描述
|
-- 描述
|
||||||
description VARCHAR(500) NULL COMMENT '规则描述',
|
description VARCHAR(500) NULL COMMENT '规则描述',
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user