@@ -1,6 +1,6 @@
|
||||
version: '3.3'
|
||||
|
||||
# latest = 2.5.3
|
||||
# latest = 2.5.4
|
||||
|
||||
# 支持以下源
|
||||
# lijiahangmax/*
|
||||
|
||||
@@ -7,7 +7,7 @@ set -e
|
||||
source ./project-build.sh "$@"
|
||||
|
||||
# 版本号
|
||||
version=2.5.3
|
||||
version=2.5.4
|
||||
# 是否推送镜像
|
||||
push_image=false
|
||||
# 是否构建 latest
|
||||
|
||||
@@ -4,7 +4,7 @@ set -e
|
||||
# DockerContext: orion-visor
|
||||
|
||||
# 版本号
|
||||
version=2.5.3
|
||||
version=2.5.4
|
||||
# 是否构建 service
|
||||
export build_service=false
|
||||
# 是否构建 ui
|
||||
|
||||
@@ -36,7 +36,7 @@ public interface AppConst extends OrionConst {
|
||||
/**
|
||||
* 同 ${orion.version} 迭代时候需要手动更改
|
||||
*/
|
||||
String VERSION = "2.5.3";
|
||||
String VERSION = "2.5.4";
|
||||
|
||||
/**
|
||||
* 同 ${spring.application.name}
|
||||
|
||||
@@ -34,116 +34,116 @@ public interface ConfigKeys {
|
||||
/**
|
||||
* SFTP 文件预览大小
|
||||
*/
|
||||
String SFTP_PREVIEW_SIZE = "sftp_previewSize";
|
||||
String SFTP_PREVIEW_SIZE = "sftp.preview-size";
|
||||
|
||||
/**
|
||||
* SFTP 重复文件备份
|
||||
*/
|
||||
String SFTP_UPLOAD_PRESENT_BACKUP = "sftp_uploadPresentBackup";
|
||||
String SFTP_UPLOAD_PRESENT_BACKUP = "sftp.upload-present-backup";
|
||||
|
||||
/**
|
||||
* SFTP 备份文件名称
|
||||
*/
|
||||
String SFTP_UPLOAD_BACKUP_FILE_NAME = "sftp_uploadBackupFileName";
|
||||
String SFTP_UPLOAD_BACKUP_FILE_NAME = "sftp.upload-backup-file-name";
|
||||
|
||||
/**
|
||||
* 加密公钥
|
||||
*/
|
||||
String ENCRYPT_PUBLIC_KEY = "encrypt_publicKey";
|
||||
String ENCRYPT_PUBLIC_KEY = "encrypt.public-key";
|
||||
|
||||
/**
|
||||
* 加密私钥
|
||||
*/
|
||||
String ENCRYPT_PRIVATE_KEY = "encrypt_privateKey";
|
||||
String ENCRYPT_PRIVATE_KEY = "encrypt.private-key";
|
||||
|
||||
/**
|
||||
* 日志前端显示行数
|
||||
*/
|
||||
String LOG_WEB_SCROLL_LINES = "log_webScrollLines";
|
||||
String LOG_WEB_SCROLL_LINES = "log.web-scroll-lines";
|
||||
|
||||
/**
|
||||
* 日志加载偏移行
|
||||
*/
|
||||
String LOG_TRACKER_LOAD_LINES = "log_trackerLoadLines";
|
||||
String LOG_TRACKER_LOAD_LINES = "log.tracker-load-lines";
|
||||
|
||||
/**
|
||||
* 日志加载间隔毫秒
|
||||
*/
|
||||
String LOG_TRACKER_LOAD_INTERVAL = "log_trackerLoadInterval";
|
||||
String LOG_TRACKER_LOAD_INTERVAL = "log.tracker-load-interval";
|
||||
|
||||
/**
|
||||
* 是否生成详细的执行日志
|
||||
*/
|
||||
String LOG_EXEC_DETAIL_LOG = "log_execDetailLog";
|
||||
String LOG_EXEC_DETAIL_ENABLED = "log.exec-detail.enabled";
|
||||
|
||||
/**
|
||||
* 凭证有效期分
|
||||
* 凭证有效期 分
|
||||
*/
|
||||
String LOGIN_LOGIN_SESSION_TIME = "login_loginSessionTime";
|
||||
String LOGIN_LOGIN_SESSION_TIME = "login.login-session-time";
|
||||
|
||||
/**
|
||||
* 允许多端登录
|
||||
*/
|
||||
String LOGIN_ALLOW_MULTI_DEVICE = "login_allowMultiDevice";
|
||||
String LOGIN_ALLOW_MULTI_DEVICE = "login.allow-multi-device";
|
||||
|
||||
/**
|
||||
* 允许凭证续签
|
||||
*/
|
||||
String LOGIN_ALLOW_REFRESH = "login_allowRefresh";
|
||||
String LOGIN_ALLOW_REFRESH = "login.allow-refresh";
|
||||
|
||||
/**
|
||||
* 凭证续签最大次数
|
||||
*/
|
||||
String LOGIN_MAX_REFRESH_COUNT = "login_maxRefreshCount";
|
||||
String LOGIN_MAX_REFRESH_COUNT = "login.max-refresh-count";
|
||||
|
||||
/**
|
||||
* 凭证续签间隔分
|
||||
*/
|
||||
String LOGIN_REFRESH_INTERVAL = "login_refreshInterval";
|
||||
String LOGIN_REFRESH_INTERVAL = "login.refresh-interval";
|
||||
|
||||
/**
|
||||
* 登录失败锁定
|
||||
*/
|
||||
String LOGIN_LOGIN_FAILED_LOCK = "login_loginFailedLock";
|
||||
String LOGIN_LOGIN_FAILED_LOCK = "login.login-failed-lock";
|
||||
|
||||
/**
|
||||
* 登录失败锁定阈值分
|
||||
* 登录失败锁定阈值
|
||||
*/
|
||||
String LOGIN_LOGIN_FAILED_LOCK_THRESHOLD = "login_loginFailedLockThreshold";
|
||||
String LOGIN_LOGIN_FAILED_LOCK_THRESHOLD = "login.login-failed-lock-threshold";
|
||||
|
||||
/**
|
||||
* 登录失败锁定时间分
|
||||
* 登录失败锁定时间 分
|
||||
*/
|
||||
String LOGIN_LOGIN_FAILED_LOCK_TIME = "login_loginFailedLockTime";
|
||||
String LOGIN_LOGIN_FAILED_LOCK_TIME = "login.login-failed-lock-time";
|
||||
|
||||
/**
|
||||
* 登录失败发信
|
||||
*/
|
||||
String LOGIN_LOGIN_FAILED_SEND = "login_loginFailedSend";
|
||||
String LOGIN_LOGIN_FAILED_SEND = "login.login-failed-send";
|
||||
|
||||
/**
|
||||
* 登录失败发信阈值
|
||||
*/
|
||||
String LOGIN_LOGIN_FAILED_SEND_THRESHOLD = "login_loginFailedSendThreshold";
|
||||
String LOGIN_LOGIN_FAILED_SEND_THRESHOLD = "login.login-failed-send-threshold";
|
||||
|
||||
/**
|
||||
* 是否开启自动清理命令记录
|
||||
*/
|
||||
String AUTO_CLEAR_EXEC_LOG_ENABLED = "autoClear_execLogEnabled";
|
||||
String AUTO_CLEAR_EXEC_LOG_ENABLED = "auto-clear.exec-log.enabled";
|
||||
|
||||
/**
|
||||
* 自动清理命令记录保留天数
|
||||
*/
|
||||
String AUTO_CLEAR_EXEC_LOG_KEEP_DAYS = "autoClear_execLogKeepDays";
|
||||
String AUTO_CLEAR_EXEC_LOG_KEEP_DAYS = "auto-clear.exec-log.keep-days";
|
||||
|
||||
/**
|
||||
* 是否开启自动清理终端连接记录
|
||||
*/
|
||||
String AUTO_CLEAR_TERMINAL_LOG_ENABLED = "autoClear_terminalLogEnabled";
|
||||
String AUTO_CLEAR_TERMINAL_LOG_ENABLED = "auto-clear.terminal-log.enabled";
|
||||
|
||||
/**
|
||||
* 自动清理终端连接记录保留天数
|
||||
*/
|
||||
String AUTO_CLEAR_TERMINAL_LOG_KEEP_DAYS = "autoClear_terminalLogKeepDays";
|
||||
String AUTO_CLEAR_TERMINAL_LOG_KEEP_DAYS = "auto-clear.terminal-log.keep-days";
|
||||
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
<url>https://github.com/dromara/orion-visor</url>
|
||||
|
||||
<properties>
|
||||
<revision>2.5.3</revision>
|
||||
<revision>2.5.4</revision>
|
||||
<spring.boot.version>2.7.17</spring.boot.version>
|
||||
<spring.boot.admin.version>2.7.15</spring.boot.admin.version>
|
||||
<flatten.maven.plugin.version>1.5.0</flatten.maven.plugin.version>
|
||||
<orion.kit.version>2.0.4</orion.kit.version>
|
||||
<orion.kit.version>2.0.5</orion.kit.version>
|
||||
<aspectj.version>1.9.7</aspectj.version>
|
||||
<lombok.version>1.18.26</lombok.version>
|
||||
<springdoc.version>1.6.15</springdoc.version>
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
<a-table row-key="id"
|
||||
#end
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="tableColumns"
|
||||
#if($vue.enableRowSelection)
|
||||
@@ -99,6 +100,7 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
#foreach($field in ${table.fields})
|
||||
|
||||
@@ -14,7 +14,7 @@ spring:
|
||||
port: ${REDIS_PORT:6379}
|
||||
password: ${REDIS_PASSWORD:Data@123456}
|
||||
database: ${REDIS_DATABASE:1}
|
||||
data-version: ${REDIS_DATA_VERSION:1}
|
||||
data-version: ${REDIS_DATA_VERSION:2}
|
||||
mock: false
|
||||
redisson:
|
||||
threads: 2
|
||||
|
||||
@@ -25,7 +25,7 @@ spring:
|
||||
port: ${REDIS_PORT:6379}
|
||||
password: ${REDIS_PASSWORD:Data@123456}
|
||||
database: ${REDIS_DATABASE:0}
|
||||
data-version: ${REDIS_DATA_VERSION:1}
|
||||
data-version: ${REDIS_DATA_VERSION:2}
|
||||
redisson:
|
||||
threads: 4
|
||||
netty-threads: 4
|
||||
|
||||
@@ -39,9 +39,9 @@ import java.util.function.Function;
|
||||
*/
|
||||
public class ReplaceVersion {
|
||||
|
||||
private static final String TARGET_VERSION = "2.5.2";
|
||||
private static final String TARGET_VERSION = "2.5.3";
|
||||
|
||||
private static final String REPLACE_VERSION = "2.5.3";
|
||||
private static final String REPLACE_VERSION = "2.5.4";
|
||||
|
||||
private static final String PATH = new File("").getAbsolutePath();
|
||||
|
||||
|
||||
@@ -50,12 +50,12 @@ public class AppLogConfig {
|
||||
/**
|
||||
* 是否生成详细的执行日志
|
||||
*/
|
||||
private final ConfigRef<Boolean> execDetailLog;
|
||||
private final ConfigRef<Boolean> execDetailEnabled;
|
||||
|
||||
public AppLogConfig(ConfigStore configStore) {
|
||||
this.trackerLoadLines = configStore.int32(ConfigKeys.LOG_TRACKER_LOAD_LINES);
|
||||
this.trackerLoadInterval = configStore.int32(ConfigKeys.LOG_TRACKER_LOAD_INTERVAL);
|
||||
this.execDetailLog = configStore.bool(ConfigKeys.LOG_EXEC_DETAIL_LOG);
|
||||
this.execDetailEnabled = configStore.bool(ConfigKeys.LOG_EXEC_DETAIL_ENABLED);
|
||||
}
|
||||
|
||||
public Integer getTrackerLoadLines() {
|
||||
@@ -66,8 +66,8 @@ public class AppLogConfig {
|
||||
return trackerLoadInterval.value;
|
||||
}
|
||||
|
||||
public Boolean getExecDetailLog() {
|
||||
return execDetailLog.value;
|
||||
public Boolean getExecDetailEnabled() {
|
||||
return execDetailEnabled.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ public class ExecTaskHandler implements IExecTaskHandler {
|
||||
* @return handler
|
||||
*/
|
||||
private IExecCommandHandler createCommandHandler(Long execHostId) {
|
||||
if (Booleans.isTrue(appLogConfig.getExecDetailLog())) {
|
||||
if (Booleans.isTrue(appLogConfig.getExecDetailEnabled())) {
|
||||
// 详细日志
|
||||
return new ExecCommandDetailHandler(execHostId, execLog, builtParams, timeoutChecker);
|
||||
} else {
|
||||
|
||||
@@ -45,20 +45,27 @@ public interface DataGroupDAO extends IMapper<DataGroupDO> {
|
||||
*
|
||||
* @param parentId parentId
|
||||
* @param type type
|
||||
* @param userId userId
|
||||
* @return max(sort)
|
||||
*/
|
||||
Integer selectMaxSort(@Param("parentId") Long parentId, @Param("type") String type);
|
||||
Integer selectMaxSort(@Param("parentId") Long parentId,
|
||||
@Param("type") String type,
|
||||
@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 修改排序
|
||||
*
|
||||
* @param parentId parentId
|
||||
* @param type type
|
||||
* @param userId userId
|
||||
* @param condition 条件
|
||||
* @param referSort 对比值
|
||||
* @param addition 自增步长
|
||||
* @return effect
|
||||
*/
|
||||
Integer updateSort(@Param("parentId") Long parentId,
|
||||
@Param("type") String type,
|
||||
@Param("userId") Long userId,
|
||||
@Param("condition") String condition,
|
||||
@Param("referSort") Integer referSort,
|
||||
@Param("addition") Integer addition);
|
||||
|
||||
@@ -59,6 +59,7 @@ public interface UserCacheKeyDefine {
|
||||
CacheKeyDefine LOGIN_FAILED_COUNT = new CacheKeyBuilder()
|
||||
.key("user:login-failed:{}")
|
||||
.desc("用户登录失败次数 ${username}")
|
||||
.noPrefix()
|
||||
.type(Integer.class)
|
||||
.struct(RedisCacheStruct.STRING)
|
||||
.build();
|
||||
|
||||
@@ -82,7 +82,7 @@ public class DataGroupServiceImpl implements DataGroupService {
|
||||
// 查询数据是否冲突
|
||||
this.checkDataGroupPresent(record);
|
||||
// 查询最大排序
|
||||
Integer sort = dataGroupDAO.selectMaxSort(request.getParentId(), request.getType());
|
||||
Integer sort = dataGroupDAO.selectMaxSort(request.getParentId(), request.getType(), request.getUserId());
|
||||
record.setSort(sort + Const.DEFAULT_SORT);
|
||||
// 插入
|
||||
int effect = dataGroupDAO.insert(record);
|
||||
@@ -130,14 +130,19 @@ public class DataGroupServiceImpl implements DataGroupService {
|
||||
Assert.notNull(targetRecord, ErrorMessage.GROUP_ABSENT);
|
||||
// 更新
|
||||
String type = moveRecord.getType();
|
||||
Long userId = moveRecord.getUserId();
|
||||
Long targetParentId = targetRecord.getParentId();
|
||||
int effect = 0;
|
||||
// 修改排序
|
||||
if (MovePosition.TOP.equals(position)) {
|
||||
// 移动到元素上 将大于等于 targetRecord 的排序都加 10
|
||||
dataGroupDAO.updateSort(targetParentId, ">=",
|
||||
targetRecord.getSort(), Const.DEFAULT_SORT);
|
||||
// 修改 parentId sort
|
||||
dataGroupDAO.updateSort(targetParentId,
|
||||
type,
|
||||
userId,
|
||||
">=",
|
||||
targetRecord.getSort(),
|
||||
Const.DEFAULT_SORT);
|
||||
// 修改关联以及排序
|
||||
DataGroupDO update = DataGroupDO.builder()
|
||||
.id(id)
|
||||
.parentId(targetParentId)
|
||||
@@ -146,8 +151,8 @@ public class DataGroupServiceImpl implements DataGroupService {
|
||||
effect = dataGroupDAO.updateById(update);
|
||||
} else if (MovePosition.IN.equals(position)) {
|
||||
// 移动到元素中 获取最大排序
|
||||
Integer newSort = dataGroupDAO.selectMaxSort(targetId, type) + Const.DEFAULT_SORT;
|
||||
// 修改 parentId sort
|
||||
Integer newSort = dataGroupDAO.selectMaxSort(targetId, type, userId) + Const.DEFAULT_SORT;
|
||||
// 修改关联以及排序
|
||||
DataGroupDO update = DataGroupDO.builder()
|
||||
.id(id)
|
||||
.parentId(targetId)
|
||||
@@ -156,9 +161,13 @@ public class DataGroupServiceImpl implements DataGroupService {
|
||||
effect = dataGroupDAO.updateById(update);
|
||||
} else if (MovePosition.BOTTOM.equals(position)) {
|
||||
// 移动到元素下 将大于 targetRecord 的排序都加 10
|
||||
dataGroupDAO.updateSort(targetParentId, ">",
|
||||
targetRecord.getSort(), Const.DEFAULT_SORT);
|
||||
// 修改 parentId sort
|
||||
dataGroupDAO.updateSort(targetParentId,
|
||||
type,
|
||||
userId,
|
||||
">",
|
||||
targetRecord.getSort(),
|
||||
Const.DEFAULT_SORT);
|
||||
// 修改关联以及排序
|
||||
DataGroupDO update = DataGroupDO.builder()
|
||||
.id(id)
|
||||
.parentId(targetParentId)
|
||||
@@ -167,7 +176,7 @@ public class DataGroupServiceImpl implements DataGroupService {
|
||||
effect = dataGroupDAO.updateById(update);
|
||||
}
|
||||
// 删除缓存
|
||||
this.deleteCache(type, moveRecord.getUserId());
|
||||
this.deleteCache(type, userId);
|
||||
// 添加日志参数
|
||||
OperatorLogs.add(OperatorLogs.SOURCE, moveRecord.getName());
|
||||
OperatorLogs.add(OperatorLogs.TARGET, targetRecord.getName());
|
||||
|
||||
@@ -22,19 +22,27 @@
|
||||
id, parent_id, type, user_id, name, sort, create_time, update_time, creator, updater, deleted
|
||||
</sql>
|
||||
|
||||
<update id="updateSort">
|
||||
UPDATE data_group
|
||||
SET sort = sort + #{addition}
|
||||
WHERE parent_id = #{parentId}
|
||||
AND sort ${condition} #{referSort}
|
||||
</update>
|
||||
|
||||
<select id="selectMaxSort" resultType="java.lang.Integer">
|
||||
SELECT IFNULL(MAX(sort), 0)
|
||||
FROM data_group
|
||||
WHERE deleted = 0
|
||||
AND type = #{type}
|
||||
AND parent_id = #{parentId}
|
||||
AND type = #{type}
|
||||
AND parent_id = #{parentId}
|
||||
<if test="userId != null">
|
||||
AND user_id = #{userId}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<update id="updateSort">
|
||||
UPDATE data_group
|
||||
SET sort = sort + #{addition}
|
||||
WHERE deleted = 0
|
||||
AND type = #{type}
|
||||
AND parent_id = #{parentId}
|
||||
AND sort ${condition} #{referSort}
|
||||
<if test="userId != null">
|
||||
AND user_id = #{userId}
|
||||
</if>
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.monitor.engine;
|
||||
package org.dromara.visor.module.monitor.context;
|
||||
|
||||
import cn.orionsec.kit.lang.define.cache.TimedCache;
|
||||
import cn.orionsec.kit.lang.define.cache.TimedCacheBuilder;
|
||||
@@ -29,15 +29,11 @@ import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.module.monitor.convert.MonitorHostConvert;
|
||||
import org.dromara.visor.module.monitor.convert.MonitorMetricsConvert;
|
||||
import org.dromara.visor.module.monitor.dao.MonitorHostDAO;
|
||||
import org.dromara.visor.module.monitor.dao.MonitorMetricsDAO;
|
||||
import org.dromara.visor.module.monitor.entity.domain.MonitorHostDO;
|
||||
import org.dromara.visor.module.monitor.entity.domain.MonitorMetricsDO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.AgentMetricsDataDTO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.MonitorHostConfigDTO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.MonitorHostContextDTO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.MonitorMetricsContextDTO;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
@@ -47,7 +43,7 @@ import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 监控上下文
|
||||
* 监控探针上下文
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
@@ -55,23 +51,13 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MonitorContext {
|
||||
public class MonitorAgentContext {
|
||||
|
||||
/**
|
||||
* 监控主机缓存
|
||||
*/
|
||||
private static final ConcurrentHashMap<String, MonitorHostContextDTO> MONITOR_HOST_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 监控指标缓存
|
||||
*/
|
||||
private static final ConcurrentHashMap<Long, MonitorMetricsContextDTO> MONITOR_METRICS_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 监控指标引用缓存
|
||||
*/
|
||||
private static final ConcurrentHashMap<String, Long> MONITOR_METRICS_KEY_REL = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 最后心跳时间缓存 3min
|
||||
*/
|
||||
@@ -88,9 +74,6 @@ public class MonitorContext {
|
||||
.checkInterval(Const.MS_S_60)
|
||||
.build();
|
||||
|
||||
@Resource
|
||||
private MonitorMetricsDAO monitorMetricsDAO;
|
||||
|
||||
@Resource
|
||||
private MonitorHostDAO monitorHostDAO;
|
||||
|
||||
@@ -103,10 +86,6 @@ public class MonitorContext {
|
||||
log.info("MonitorContext-init hosts start.");
|
||||
this.loadMonitorHost();
|
||||
log.info("MonitorContext-init hosts end.");
|
||||
// 初始化监控指标
|
||||
log.info("MonitorContext-init metrics start.");
|
||||
this.loadMonitorMetrics();
|
||||
log.info("MonitorContext-init metrics end.");
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
@@ -128,17 +107,6 @@ public class MonitorContext {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载监控指标
|
||||
*/
|
||||
public void loadMonitorMetrics() {
|
||||
MONITOR_METRICS_CACHE.clear();
|
||||
// 查询全部指标
|
||||
List<MonitorMetricsDO> metrics = monitorMetricsDAO.selectList(null);
|
||||
metrics.forEach(s -> MONITOR_METRICS_CACHE.put(s.getId(), MonitorMetricsConvert.MAPPER.toContext(s)));
|
||||
metrics.forEach(s -> MONITOR_METRICS_KEY_REL.put(this.getMonitorMetricsKey(s.getMeasurement(), s.getValue()), s.getId()));
|
||||
}
|
||||
|
||||
// ----------------------- 监控主机 ----------------------
|
||||
|
||||
/**
|
||||
@@ -194,7 +162,7 @@ public class MonitorContext {
|
||||
* @param metrics 指标
|
||||
*/
|
||||
public void setAgentMetrics(String agentKey, AgentMetricsDataDTO metrics) {
|
||||
// 设置指标数据
|
||||
// 设置指标数据
|
||||
LATEST_METRICS_CACHE.put(agentKey, metrics);
|
||||
// 更新心跳时间
|
||||
AGENT_LAST_ACTIVE_TIME.put(agentKey, System.currentTimeMillis());
|
||||
@@ -237,72 +205,4 @@ public class MonitorContext {
|
||||
return AGENT_LAST_ACTIVE_TIME.get(agentKey) != null;
|
||||
}
|
||||
|
||||
// ----------------------- 监控指标 ----------------------
|
||||
|
||||
/**
|
||||
* 重新加载监控指标
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public void reloadMonitorMetrics(Long id) {
|
||||
// 删除指标缓存
|
||||
MONITOR_METRICS_CACHE.remove(id);
|
||||
// 删除指标引用
|
||||
MONITOR_METRICS_KEY_REL.entrySet().removeIf(entry -> entry.getValue().equals(id));
|
||||
// 重新加载指标
|
||||
MonitorMetricsDO metrics = monitorMetricsDAO.selectById(id);
|
||||
if (metrics == null) {
|
||||
return;
|
||||
}
|
||||
MONITOR_METRICS_CACHE.put(metrics.getId(), MonitorMetricsConvert.MAPPER.toContext(metrics));
|
||||
MONITOR_METRICS_KEY_REL.put(this.getMonitorMetricsKey(metrics.getMeasurement(), metrics.getValue()), metrics.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取监控指标
|
||||
*
|
||||
* @param id id
|
||||
* @return cache
|
||||
*/
|
||||
public MonitorMetricsContextDTO getMonitorMetrics(Long id) {
|
||||
return MONITOR_METRICS_CACHE.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取监控指标
|
||||
*
|
||||
* @param measurement measurement
|
||||
* @param field field
|
||||
* @return cache
|
||||
*/
|
||||
public MonitorMetricsContextDTO getMonitorMetrics(String measurement, String field) {
|
||||
Long id = MONITOR_METRICS_KEY_REL.get(this.getMonitorMetricsKey(measurement, field));
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
return MONITOR_METRICS_CACHE.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取监控指标 id
|
||||
*
|
||||
* @param measurement measurement
|
||||
* @param field field
|
||||
* @return id
|
||||
*/
|
||||
public Long getMonitorMetricsId(String measurement, String field) {
|
||||
return MONITOR_METRICS_KEY_REL.get(this.getMonitorMetricsKey(measurement, field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取监控指标 key
|
||||
*
|
||||
* @param measurement measurement
|
||||
* @param field field
|
||||
* @return key
|
||||
*/
|
||||
private String getMonitorMetricsKey(String measurement, String field) {
|
||||
return measurement + "_" + field;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.monitor.context;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.module.monitor.convert.MonitorMetricsConvert;
|
||||
import org.dromara.visor.module.monitor.dao.MonitorMetricsDAO;
|
||||
import org.dromara.visor.module.monitor.entity.domain.MonitorMetricsDO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.MonitorMetricsContextDTO;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 监控指标上下文
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2025/10/12 19:39
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MonitorMetricsContext {
|
||||
|
||||
/**
|
||||
* 监控指标缓存
|
||||
*/
|
||||
private static final ConcurrentHashMap<Long, MonitorMetricsContextDTO> MONITOR_METRICS_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 监控指标引用缓存
|
||||
*/
|
||||
private static final ConcurrentHashMap<String, Long> MONITOR_METRICS_KEY_REL = new ConcurrentHashMap<>();
|
||||
|
||||
@Resource
|
||||
private MonitorMetricsDAO monitorMetricsDAO;
|
||||
|
||||
/**
|
||||
* 初始化监控上下文
|
||||
*/
|
||||
@PostConstruct
|
||||
public void initMonitorContext() {
|
||||
// 初始化监控指标
|
||||
log.info("MetricsContext-init start.");
|
||||
this.loadMonitorMetrics();
|
||||
log.info("MetricsContext-init end.");
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载监控指标
|
||||
*/
|
||||
public void loadMonitorMetrics() {
|
||||
MONITOR_METRICS_CACHE.clear();
|
||||
// 查询全部指标
|
||||
List<MonitorMetricsDO> metrics = monitorMetricsDAO.selectList(null);
|
||||
metrics.forEach(s -> MONITOR_METRICS_CACHE.put(s.getId(), MonitorMetricsConvert.MAPPER.toContext(s)));
|
||||
metrics.forEach(s -> MONITOR_METRICS_KEY_REL.put(this.getMonitorMetricsKey(s.getMeasurement(), s.getValue()), s.getId()));
|
||||
}
|
||||
|
||||
|
||||
// ----------------------- 监控指标 ----------------------
|
||||
|
||||
/**
|
||||
* 重新加载监控指标
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public void reloadMonitorMetrics(Long id) {
|
||||
// 删除指标缓存
|
||||
MONITOR_METRICS_CACHE.remove(id);
|
||||
// 删除指标引用
|
||||
MONITOR_METRICS_KEY_REL.entrySet().removeIf(entry -> entry.getValue().equals(id));
|
||||
// 重新加载指标
|
||||
MonitorMetricsDO metrics = monitorMetricsDAO.selectById(id);
|
||||
if (metrics == null) {
|
||||
return;
|
||||
}
|
||||
MONITOR_METRICS_CACHE.put(metrics.getId(), MonitorMetricsConvert.MAPPER.toContext(metrics));
|
||||
MONITOR_METRICS_KEY_REL.put(this.getMonitorMetricsKey(metrics.getMeasurement(), metrics.getValue()), metrics.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取监控指标
|
||||
*
|
||||
* @param id id
|
||||
* @return cache
|
||||
*/
|
||||
public MonitorMetricsContextDTO getMonitorMetrics(Long id) {
|
||||
return MONITOR_METRICS_CACHE.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取监控指标
|
||||
*
|
||||
* @param measurement measurement
|
||||
* @param field field
|
||||
* @return cache
|
||||
*/
|
||||
public MonitorMetricsContextDTO getMonitorMetrics(String measurement, String field) {
|
||||
Long id = MONITOR_METRICS_KEY_REL.get(this.getMonitorMetricsKey(measurement, field));
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
return MONITOR_METRICS_CACHE.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取监控指标 id
|
||||
*
|
||||
* @param measurement measurement
|
||||
* @param field field
|
||||
* @return id
|
||||
*/
|
||||
public Long getMonitorMetricsId(String measurement, String field) {
|
||||
return MONITOR_METRICS_KEY_REL.get(this.getMonitorMetricsKey(measurement, field));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取监控指标 key
|
||||
*
|
||||
* @param measurement measurement
|
||||
* @param field field
|
||||
* @return key
|
||||
*/
|
||||
private String getMonitorMetricsKey(String measurement, String field) {
|
||||
return measurement + "_" + field;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -104,9 +104,10 @@ public class AlarmPolicyController {
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询全部监控告警策略")
|
||||
@Parameter(name = "type", description = "type", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('monitor:alarm-policy:query')")
|
||||
public List<AlarmPolicyVO> getAlarmPolicyList() {
|
||||
return alarmPolicyService.getAlarmPolicyListByCache();
|
||||
public List<AlarmPolicyVO> getAlarmPolicyList(@RequestParam("type") String type) {
|
||||
return alarmPolicyService.getAlarmPolicyListByCache(type);
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
|
||||
@@ -35,8 +35,8 @@ import org.dromara.visor.framework.log.core.annotation.IgnoreLog;
|
||||
import org.dromara.visor.framework.log.core.enums.IgnoreLogMode;
|
||||
import org.dromara.visor.framework.web.core.annotation.DemoDisableApi;
|
||||
import org.dromara.visor.framework.web.core.annotation.RestWrapper;
|
||||
import org.dromara.visor.module.monitor.context.MonitorAgentContext;
|
||||
import org.dromara.visor.module.monitor.define.operator.MonitorHostOperatorType;
|
||||
import org.dromara.visor.module.monitor.engine.MonitorContext;
|
||||
import org.dromara.visor.module.monitor.entity.dto.AgentMetricsDataDTO;
|
||||
import org.dromara.visor.module.monitor.entity.request.host.*;
|
||||
import org.dromara.visor.module.monitor.entity.vo.MonitorHostMetricsDataVO;
|
||||
@@ -68,7 +68,7 @@ public class MonitorHostController {
|
||||
private MonitorHostService monitorHostService;
|
||||
|
||||
@Resource
|
||||
private MonitorContext monitorContext;
|
||||
private MonitorAgentContext monitorAgentContext;
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
@PostMapping("/query")
|
||||
@@ -84,7 +84,7 @@ public class MonitorHostController {
|
||||
@Parameter(name = "agentKey", description = "agentKey", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('monitor:monitor-host:query')")
|
||||
public AgentMetricsDataDTO getMonitorHostOverride(@RequestParam("agentKey") String agentKey) {
|
||||
return monitorContext.getAgentMetrics(agentKey);
|
||||
return monitorAgentContext.getAgentMetrics(agentKey);
|
||||
}
|
||||
|
||||
@IgnoreLog(IgnoreLogMode.RET)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
package org.dromara.visor.module.monitor.convert;
|
||||
|
||||
import org.dromara.visor.common.mapstruct.JsonConversion;
|
||||
import org.dromara.visor.module.monitor.entity.domain.AlarmEventDO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.AlarmEventTriggerDTO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.AlarmPolicyAlarmCountDTO;
|
||||
@@ -40,7 +41,7 @@ import java.util.List;
|
||||
* @version 1.0.0
|
||||
* @since 2025-9-17 21:31
|
||||
*/
|
||||
@Mapper
|
||||
@Mapper(uses = JsonConversion.class)
|
||||
public interface AlarmEventConvert {
|
||||
|
||||
AlarmEventConvert MAPPER = Mappers.getMapper(AlarmEventConvert.class);
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
*/
|
||||
package org.dromara.visor.module.monitor.convert;
|
||||
|
||||
import org.dromara.visor.module.monitor.engine.AlarmEngineRule;
|
||||
import org.dromara.visor.module.monitor.entity.domain.AlarmPolicyRuleDO;
|
||||
import org.dromara.visor.module.monitor.entity.request.alarm.AlarmPolicyRuleCreateRequest;
|
||||
import org.dromara.visor.module.monitor.entity.request.alarm.AlarmPolicyRuleUpdateRequest;
|
||||
import org.dromara.visor.module.monitor.entity.vo.AlarmPolicyRuleVO;
|
||||
import org.dromara.visor.module.monitor.handler.alarm.model.AlarmEngineRule;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
package org.dromara.visor.module.monitor.convert;
|
||||
|
||||
import org.dromara.visor.common.mapstruct.StringConversion;
|
||||
import org.dromara.visor.module.asset.entity.dto.host.HostDTO;
|
||||
import org.dromara.visor.module.asset.entity.dto.host.HostQueryDTO;
|
||||
import org.dromara.visor.module.monitor.entity.domain.MonitorHostDO;
|
||||
@@ -40,7 +41,7 @@ import org.mapstruct.factory.Mappers;
|
||||
* @version 1.0.0
|
||||
* @since 2025-8-14 16:27
|
||||
*/
|
||||
@Mapper
|
||||
@Mapper(uses = StringConversion.class)
|
||||
public interface MonitorHostConvert {
|
||||
|
||||
MonitorHostConvert MAPPER = Mappers.getMapper(MonitorHostConvert.class);
|
||||
|
||||
@@ -59,4 +59,13 @@ public interface AlarmPolicyRuleDAO extends IMapper<AlarmPolicyRuleDO> {
|
||||
return this.selectList(Conditions.eq(AlarmPolicyRuleDO::getPolicyId, policyId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 policyId 删除
|
||||
*
|
||||
* @param policyId policyId
|
||||
*/
|
||||
default void deleteByPolicyId(Long policyId) {
|
||||
this.delete(Conditions.eq(AlarmPolicyRuleDO::getPolicyId, policyId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@ import java.util.concurrent.TimeUnit;
|
||||
public interface AlarmPolicyCacheKeyDefine {
|
||||
|
||||
CacheKeyDefine ALARM_POLICY = new CacheKeyBuilder()
|
||||
.key("alarm:policy:list")
|
||||
.desc("告警策略")
|
||||
.key("alarm:policy:list:{}")
|
||||
.desc("告警策略 ${type}")
|
||||
.type(AlarmPolicyCacheDTO.class)
|
||||
.struct(RedisCacheStruct.HASH)
|
||||
.timeout(8, TimeUnit.HOURS)
|
||||
@@ -49,6 +49,7 @@ public interface AlarmPolicyCacheKeyDefine {
|
||||
CacheKeyDefine ALARM_RULE_SILENCE = new CacheKeyBuilder()
|
||||
.key("alarm:silence:{}:{}")
|
||||
.desc("告警规则沉默标志 ${agentKey} ${ruleId}")
|
||||
.noPrefix()
|
||||
.type(Long.class)
|
||||
.struct(RedisCacheStruct.STRING)
|
||||
.build();
|
||||
|
||||
@@ -57,17 +57,17 @@ public class AlarmEventDO extends BaseDO {
|
||||
@TableField("agent_key")
|
||||
private String agentKey;
|
||||
|
||||
@Schema(description = "主机id")
|
||||
@TableField("host_id")
|
||||
private Long hostId;
|
||||
@Schema(description = "事件来源")
|
||||
@TableField("source_type")
|
||||
private String sourceType;
|
||||
|
||||
@Schema(description = "主机名称")
|
||||
@TableField("host_name")
|
||||
private String hostName;
|
||||
@Schema(description = "事件来源id")
|
||||
@TableField("source_id")
|
||||
private Long sourceId;
|
||||
|
||||
@Schema(description = "主机地址")
|
||||
@TableField("host_address")
|
||||
private String hostAddress;
|
||||
@Schema(description = "事件来源id")
|
||||
@TableField("source_info")
|
||||
private String sourceInfo;
|
||||
|
||||
@Schema(description = "策略id")
|
||||
@TableField("policy_id")
|
||||
|
||||
@@ -50,6 +50,10 @@ public class AlarmPolicyDO extends BaseDO {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "策略类型")
|
||||
@TableField("type")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "策略名称")
|
||||
@TableField("name")
|
||||
private String name;
|
||||
|
||||
@@ -56,14 +56,14 @@ public class AlarmEventTriggerDTO extends BaseDO {
|
||||
@Schema(description = "agentKey")
|
||||
private String agentKey;
|
||||
|
||||
@Schema(description = "主机id")
|
||||
private Long hostId;
|
||||
@Schema(description = "事件来源")
|
||||
private String sourceType;
|
||||
|
||||
@Schema(description = "主机名称")
|
||||
private String hostName;
|
||||
@Schema(description = "事件来源id")
|
||||
private Long sourceId;
|
||||
|
||||
@Schema(description = "主机地址")
|
||||
private String hostAddress;
|
||||
@Schema(description = "事件来源id")
|
||||
private String sourceInfo;
|
||||
|
||||
@Schema(description = "策略id")
|
||||
private Long policyId;
|
||||
|
||||
@@ -48,13 +48,16 @@ public class AlarmEventQueryRequest extends BaseQueryRequest {
|
||||
@Schema(description = "id")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "主机名称")
|
||||
private Long hostId;
|
||||
|
||||
@Size(max = 32)
|
||||
@Schema(description = "agentKey")
|
||||
private String agentKey;
|
||||
|
||||
@Schema(description = "事件来源")
|
||||
private String sourceType;
|
||||
|
||||
@Schema(description = "事件来源id")
|
||||
private Long sourceId;
|
||||
|
||||
@Schema(description = "策略id")
|
||||
private Long policyId;
|
||||
|
||||
|
||||
@@ -47,6 +47,10 @@ public class AlarmPolicyCreateRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NotBlank
|
||||
@Schema(description = "策略类型")
|
||||
private String type;
|
||||
|
||||
@NotBlank
|
||||
@Size(max = 64)
|
||||
@Schema(description = "策略名称")
|
||||
|
||||
@@ -26,6 +26,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
import org.dromara.visor.common.entity.BaseQueryRequest;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
@@ -46,6 +47,10 @@ public class AlarmPolicyQueryRequest extends BaseQueryRequest {
|
||||
@Schema(description = "id")
|
||||
private Long id;
|
||||
|
||||
@NotBlank
|
||||
@Schema(description = "策略类型")
|
||||
private String type;
|
||||
|
||||
@Size(max = 64)
|
||||
@Schema(description = "策略名称")
|
||||
private String name;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
package org.dromara.visor.module.monitor.entity.vo;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
@@ -51,14 +52,14 @@ public class AlarmEventVO implements Serializable {
|
||||
@Schema(description = "id")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "主机名称")
|
||||
private Long hostId;
|
||||
@Schema(description = "事件来源")
|
||||
private String sourceType;
|
||||
|
||||
@Schema(description = "主机名称")
|
||||
private String hostName;
|
||||
@Schema(description = "事件来源id")
|
||||
private Long sourceId;
|
||||
|
||||
@Schema(description = "主机地址")
|
||||
private String hostAddress;
|
||||
@Schema(description = "事件来源id")
|
||||
private JSONObject sourceInfo;
|
||||
|
||||
@Schema(description = "agentKey")
|
||||
private String agentKey;
|
||||
|
||||
@@ -51,6 +51,9 @@ public class AlarmPolicyVO implements Serializable {
|
||||
@Schema(description = "id")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "策略类型")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "策略名称")
|
||||
private String name;
|
||||
|
||||
|
||||
@@ -76,6 +76,9 @@ public class MonitorHostVO implements Serializable {
|
||||
@Schema(description = "主机地址")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "主机类型")
|
||||
private List<String> types;
|
||||
|
||||
@Schema(description = "主机状态")
|
||||
private String status;
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.monitor.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 告警事件来源
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2025/10/13 22:03
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AlarmEventSourceTypeEnum {
|
||||
|
||||
/**
|
||||
* 主机告警
|
||||
*/
|
||||
HOST,
|
||||
|
||||
/**
|
||||
* 拨测告警
|
||||
*/
|
||||
UPTIME,
|
||||
|
||||
;
|
||||
|
||||
public static AlarmEventSourceTypeEnum of(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
for (AlarmEventSourceTypeEnum item : values()) {
|
||||
if (item.name().equals(value)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.monitor.engine;
|
||||
package org.dromara.visor.module.monitor.handler.alarm;
|
||||
|
||||
import cn.orionsec.kit.lang.utils.Strings;
|
||||
import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||
@@ -37,6 +37,8 @@ import org.dromara.visor.module.monitor.entity.domain.AlarmPolicyDO;
|
||||
import org.dromara.visor.module.monitor.entity.domain.AlarmPolicyNotifyDO;
|
||||
import org.dromara.visor.module.monitor.entity.domain.AlarmPolicyRuleDO;
|
||||
import org.dromara.visor.module.monitor.enums.AlarmSwitchEnum;
|
||||
import org.dromara.visor.module.monitor.handler.alarm.model.AlarmEnginePolicy;
|
||||
import org.dromara.visor.module.monitor.handler.alarm.model.AlarmEngineRule;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
@@ -20,7 +20,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.monitor.engine;
|
||||
package org.dromara.visor.module.monitor.handler.alarm;
|
||||
|
||||
import cn.orionsec.kit.lang.define.cache.TimedCache;
|
||||
import cn.orionsec.kit.lang.define.cache.TimedCacheBuilder;
|
||||
@@ -32,23 +32,23 @@ import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||
import cn.orionsec.kit.lang.utils.collect.Maps;
|
||||
import cn.orionsec.kit.lang.utils.io.Streams;
|
||||
import cn.orionsec.kit.lang.utils.time.Dates;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.common.entity.PushUser;
|
||||
import org.dromara.visor.common.enums.BooleanBit;
|
||||
import org.dromara.visor.framework.biz.push.core.utils.PushUtils;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisStrings;
|
||||
import org.dromara.visor.module.asset.api.HostAgentApi;
|
||||
import org.dromara.visor.module.asset.entity.dto.host.HostBaseDTO;
|
||||
import org.dromara.visor.module.infra.api.SystemUserApi;
|
||||
import org.dromara.visor.module.monitor.convert.AlarmEventConvert;
|
||||
import org.dromara.visor.module.monitor.context.MonitorAgentContext;
|
||||
import org.dromara.visor.module.monitor.context.MonitorMetricsContext;
|
||||
import org.dromara.visor.module.monitor.define.cache.AlarmPolicyCacheKeyDefine;
|
||||
import org.dromara.visor.module.monitor.entity.domain.AlarmEventDO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.*;
|
||||
import org.dromara.visor.module.monitor.enums.*;
|
||||
import org.dromara.visor.module.monitor.enums.AlarmLevelEnum;
|
||||
import org.dromara.visor.module.monitor.enums.AlarmTriggerConditionEnum;
|
||||
import org.dromara.visor.module.monitor.enums.MetricsUnitEnum;
|
||||
import org.dromara.visor.module.monitor.handler.alarm.model.AlarmEnginePolicy;
|
||||
import org.dromara.visor.module.monitor.handler.alarm.model.AlarmEngineRule;
|
||||
import org.dromara.visor.module.monitor.service.AlarmEventService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.annotation.Resource;
|
||||
@@ -57,62 +57,50 @@ import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 告警引擎
|
||||
* 告警引擎基类
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2025/8/21 17:26
|
||||
* @since 2025/10/13 10:12
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AlarmEngine {
|
||||
public abstract class BaseAlarmEngine implements IAlarmEngine {
|
||||
|
||||
/**
|
||||
* 告警触发状态缓存 10min
|
||||
*/
|
||||
private static final TimedCache<AlarmTriggerStateDTO> TRIGGER_STATE_CACHE = TimedCacheBuilder.<AlarmTriggerStateDTO>create()
|
||||
protected static final TimedCache<AlarmTriggerStateDTO> TRIGGER_STATE_CACHE = TimedCacheBuilder.<AlarmTriggerStateDTO>create()
|
||||
.expireAfter(10 * Const.MS_S_60)
|
||||
.checkInterval(Const.MS_S_60)
|
||||
.build();
|
||||
|
||||
@Resource
|
||||
private AlarmEngineContext alarmEngineContext;
|
||||
protected AlarmEngineContext alarmEngineContext;
|
||||
|
||||
@Resource
|
||||
private MonitorContext monitorContext;
|
||||
protected MonitorAgentContext monitorAgentContext;
|
||||
|
||||
@Resource
|
||||
private AlarmEventService alarmEventService;
|
||||
protected MonitorMetricsContext monitorMetricsContext;
|
||||
|
||||
@Resource
|
||||
private HostAgentApi hostAgentApi;
|
||||
protected AlarmEventService alarmEventService;
|
||||
|
||||
@Resource
|
||||
private SystemUserApi systemUserApi;
|
||||
protected SystemUserApi systemUserApi;
|
||||
|
||||
@PreDestroy
|
||||
public void destroyTimedCache() {
|
||||
Streams.close(TRIGGER_STATE_CACHE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查并且告警
|
||||
*
|
||||
* @param agentKey agentKey
|
||||
* @param prevMetrics prevMetrics
|
||||
* @param newMetrics newMetrics
|
||||
*/
|
||||
@Override
|
||||
public void checkAndAlarm(String agentKey,
|
||||
AgentMetricsDataDTO prevMetrics,
|
||||
AgentMetricsDataDTO newMetrics) {
|
||||
// 获取主机信息
|
||||
MonitorHostContextDTO monitorHost = monitorContext.getMonitorHost(agentKey);
|
||||
if (monitorHost == null) {
|
||||
return;
|
||||
}
|
||||
// 检查策略是否开启
|
||||
Long policyId = monitorHost.getPolicyId();
|
||||
if (policyId == null || AlarmSwitchEnum.isOff(monitorHost.getAlarmSwitch())) {
|
||||
// 获取告警策略
|
||||
Long policyId = this.getAlarmPolicyId(agentKey);
|
||||
if (policyId == null) {
|
||||
return;
|
||||
}
|
||||
// 获取对应的策略
|
||||
@@ -132,7 +120,7 @@ public class AlarmEngine {
|
||||
// 检查指标
|
||||
AlarmEventTriggerDTO event = this.checkAndAlarm(agentKey,
|
||||
prevMetrics, newMetrics, agentMetrics, metricsField,
|
||||
policy, monitorHost);
|
||||
policy);
|
||||
if (event != null) {
|
||||
alarmEvents.add(event);
|
||||
}
|
||||
@@ -147,6 +135,14 @@ public class AlarmEngine {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取告警策略 id
|
||||
*
|
||||
* @param agentKey agentKey
|
||||
* @return policyId
|
||||
*/
|
||||
protected abstract Long getAlarmPolicyId(String agentKey);
|
||||
|
||||
/**
|
||||
* 检查并且告警
|
||||
*
|
||||
@@ -156,25 +152,22 @@ public class AlarmEngine {
|
||||
* @param agentMetrics agentMetrics
|
||||
* @param metricsField metricsField
|
||||
* @param policy policy
|
||||
* @param monitorHost monitorHost
|
||||
* @return event
|
||||
*/
|
||||
private AlarmEventTriggerDTO checkAndAlarm(String agentKey,
|
||||
AgentMetricsDataDTO prevMetrics,
|
||||
AgentMetricsDataDTO newMetrics,
|
||||
AgentMetricsDTO agentMetrics,
|
||||
String metricsField,
|
||||
AlarmEnginePolicy policy,
|
||||
MonitorHostContextDTO monitorHost) {
|
||||
Long timestamp = newMetrics.getTimestamp();
|
||||
protected AlarmEventTriggerDTO checkAndAlarm(String agentKey,
|
||||
AgentMetricsDataDTO prevMetrics,
|
||||
AgentMetricsDataDTO newMetrics,
|
||||
AgentMetricsDTO agentMetrics,
|
||||
String metricsField,
|
||||
AlarmEnginePolicy policy) {
|
||||
Long alarmTimestamp = newMetrics.getTimestamp();
|
||||
// 指标id
|
||||
Long metricsId = monitorContext.getMonitorMetricsId(agentMetrics.getType(), metricsField);
|
||||
Long metricsId = monitorMetricsContext.getMonitorMetricsId(agentMetrics.getType(), metricsField);
|
||||
if (metricsId == null) {
|
||||
return null;
|
||||
}
|
||||
// 指标值
|
||||
BigDecimal metricsValue;
|
||||
metricsValue = agentMetrics.getValues().getBigDecimal(metricsField);
|
||||
BigDecimal metricsValue = agentMetrics.getValues().getBigDecimal(metricsField);
|
||||
if (metricsValue == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -200,14 +193,30 @@ public class AlarmEngine {
|
||||
return null;
|
||||
}
|
||||
// 检查是否在静默期
|
||||
boolean inSilence = this.checkAndSetInSilencePeriod(agentKey, timestamp, matchedRule);
|
||||
boolean inSilence = this.checkAndSetInSilencePeriod(agentKey, alarmTimestamp, matchedRule);
|
||||
if (inSilence) {
|
||||
return null;
|
||||
}
|
||||
// 创建告警事件
|
||||
return this.createAlarmEvent(agentKey, monitorHost, timestamp, agentMetrics, metricsValue, matchedRule);
|
||||
return this.createAlarmEvent(agentKey, alarmTimestamp, agentMetrics, metricsValue, matchedRule);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建告警事件
|
||||
*
|
||||
* @param agentKey agentKey
|
||||
* @param alarmTimestamp alarmTimestamp
|
||||
* @param agentMetrics agentMetrics
|
||||
* @param metricsValue metricsValue
|
||||
* @param rule rule
|
||||
* @return event
|
||||
*/
|
||||
protected abstract AlarmEventTriggerDTO createAlarmEvent(String agentKey,
|
||||
Long alarmTimestamp,
|
||||
AgentMetricsDTO agentMetrics,
|
||||
BigDecimal metricsValue,
|
||||
AlarmEngineRule rule);
|
||||
|
||||
/**
|
||||
* 获取到第一个匹配到达阈值的规则 包含 tag
|
||||
*
|
||||
@@ -216,9 +225,9 @@ public class AlarmEngine {
|
||||
* @param metricsValue metricsValue
|
||||
* @return rule
|
||||
*/
|
||||
private AlarmEngineRule matchTaggedAgentMetricsRule(List<AlarmEngineRule> rules,
|
||||
Map<String, String> metricsTags,
|
||||
BigDecimal metricsValue) {
|
||||
protected AlarmEngineRule matchTaggedAgentMetricsRule(List<AlarmEngineRule> rules,
|
||||
Map<String, String> metricsTags,
|
||||
BigDecimal metricsValue) {
|
||||
AlarmEngineRule matchedRule = null;
|
||||
// context 根据 level 排序了
|
||||
for (AlarmEngineRule rule : rules) {
|
||||
@@ -265,7 +274,7 @@ public class AlarmEngine {
|
||||
* @param metricsValue metricsValue
|
||||
* @return rule
|
||||
*/
|
||||
private AlarmEngineRule matchAgentMetricsRule(List<AlarmEngineRule> rules, BigDecimal metricsValue) {
|
||||
protected AlarmEngineRule matchAgentMetricsRule(List<AlarmEngineRule> rules, BigDecimal metricsValue) {
|
||||
AlarmEngineRule matchedRule = null;
|
||||
// context 根据 level 排序了
|
||||
for (AlarmEngineRule rule : rules) {
|
||||
@@ -289,13 +298,13 @@ public class AlarmEngine {
|
||||
* @param rule rule
|
||||
* @param metricValue metricValue
|
||||
*/
|
||||
private boolean checkAlarmCondition(AlarmEngineRule rule, BigDecimal metricValue) {
|
||||
protected boolean checkAlarmCondition(AlarmEngineRule rule, BigDecimal metricValue) {
|
||||
// 获取指标值
|
||||
if (metricValue == null) {
|
||||
return false;
|
||||
}
|
||||
// 获取指标单位
|
||||
MonitorMetricsContextDTO metrics = monitorContext.getMonitorMetrics(rule.getMetricsId());
|
||||
MonitorMetricsContextDTO metrics = monitorMetricsContext.getMonitorMetrics(rule.getMetricsId());
|
||||
MetricsUnitEnum unit = Optional.ofNullable(metrics)
|
||||
.map(MonitorMetricsContextDTO::getUnit)
|
||||
.map(MetricsUnitEnum::of)
|
||||
@@ -310,13 +319,8 @@ public class AlarmEngine {
|
||||
}
|
||||
// 将阈值转换为原始值
|
||||
threshold = unit.getThresholdOriginalValue(threshold);
|
||||
// 触发条件
|
||||
AlarmTriggerConditionEnum condition = AlarmTriggerConditionEnum.of(rule.getTriggerCondition());
|
||||
if (condition == null) {
|
||||
return false;
|
||||
}
|
||||
// 判断是否达到触发条件
|
||||
return this.evaluateCondition(condition, metricValue, threshold);
|
||||
return this.evaluateCondition(rule.getTriggerCondition(), metricValue, threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -327,10 +331,12 @@ public class AlarmEngine {
|
||||
* @param threshold threshold
|
||||
* @return eval
|
||||
*/
|
||||
private boolean evaluateCondition(AlarmTriggerConditionEnum condition,
|
||||
BigDecimal metricValue,
|
||||
BigDecimal threshold) {
|
||||
switch (condition) {
|
||||
protected boolean evaluateCondition(String condition,
|
||||
BigDecimal metricValue,
|
||||
BigDecimal threshold) {
|
||||
// 触发条件
|
||||
AlarmTriggerConditionEnum triggerCondition = AlarmTriggerConditionEnum.of(condition);
|
||||
switch (triggerCondition) {
|
||||
case GT:
|
||||
return metricValue.compareTo(threshold) > 0;
|
||||
case GE:
|
||||
@@ -356,10 +362,10 @@ public class AlarmEngine {
|
||||
* @param rule rule
|
||||
* @return result
|
||||
*/
|
||||
private boolean checkConsecutiveCount(String agentKey,
|
||||
AgentMetricsDataDTO prevMetrics,
|
||||
AgentMetricsDataDTO newMetrics,
|
||||
AlarmEngineRule rule) {
|
||||
protected boolean checkConsecutiveCount(String agentKey,
|
||||
AgentMetricsDataDTO prevMetrics,
|
||||
AgentMetricsDataDTO newMetrics,
|
||||
AlarmEngineRule rule) {
|
||||
// 获取规则连续触发次数
|
||||
Integer ruleConsecutiveCount = Objects1.def(rule.getConsecutiveCount(), 1);
|
||||
// 获取指标连续触发次数
|
||||
@@ -393,8 +399,8 @@ public class AlarmEngine {
|
||||
* @param prevMetrics prevMetrics
|
||||
* @return isConsecutiveTrigger
|
||||
*/
|
||||
private boolean isConsecutiveTrigger(AlarmTriggerStateDTO triggerState,
|
||||
AgentMetricsDataDTO prevMetrics) {
|
||||
protected boolean isConsecutiveTrigger(AlarmTriggerStateDTO triggerState,
|
||||
AgentMetricsDataDTO prevMetrics) {
|
||||
if (prevMetrics == null || triggerState == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -404,14 +410,14 @@ public class AlarmEngine {
|
||||
/**
|
||||
* 检查并且设置静默期
|
||||
*
|
||||
* @param agentKey agentKey
|
||||
* @param timestamp timestamp
|
||||
* @param rule rule
|
||||
* @param agentKey agentKey
|
||||
* @param alarmTimestamp alarmTimestamp
|
||||
* @param rule rule
|
||||
* @return inSilence
|
||||
*/
|
||||
private boolean checkAndSetInSilencePeriod(String agentKey,
|
||||
Long timestamp,
|
||||
AlarmEngineRule rule) {
|
||||
protected boolean checkAndSetInSilencePeriod(String agentKey,
|
||||
Long alarmTimestamp,
|
||||
AlarmEngineRule rule) {
|
||||
Integer silencePeriod = Objects1.def(rule.getSilencePeriod(), 0);
|
||||
// 无静默期则触发
|
||||
if (silencePeriod <= 0) {
|
||||
@@ -427,75 +433,11 @@ public class AlarmEngine {
|
||||
.noPrefix()
|
||||
.timeout(silencePeriod, TimeUnit.MINUTES)
|
||||
.build();
|
||||
RedisStrings.set(key, timestamp);
|
||||
RedisStrings.set(key, alarmTimestamp);
|
||||
}
|
||||
return inSilence;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建告警事件
|
||||
*
|
||||
* @param agentKey agentKey
|
||||
* @param monitorHost monitorHost
|
||||
* @param timestamp timestamp
|
||||
* @param agentMetrics agentMetrics
|
||||
* @param metricsValue metricsValue
|
||||
* @param rule rule
|
||||
* @return event
|
||||
*/
|
||||
private AlarmEventTriggerDTO createAlarmEvent(String agentKey,
|
||||
MonitorHostContextDTO monitorHost,
|
||||
Long timestamp,
|
||||
AgentMetricsDTO agentMetrics,
|
||||
BigDecimal metricsValue,
|
||||
AlarmEngineRule rule) {
|
||||
// 查询主机信息
|
||||
HostBaseDTO host = hostAgentApi.getHostCacheByAgentKey(agentKey);
|
||||
if (host == null) {
|
||||
host = new HostBaseDTO();
|
||||
}
|
||||
// 获取指标
|
||||
MonitorMetricsContextDTO metrics = monitorContext.getMonitorMetrics(rule.getMetricsId());
|
||||
// 指标单位
|
||||
MetricsUnitEnum unit = MetricsUnitEnum.of(metrics.getUnit());
|
||||
// 获取连续触发次数
|
||||
Integer consecutiveCount = Optional.ofNullable(TRIGGER_STATE_CACHE.get(this.getTriggerStateCacheKey(agentKey, rule)))
|
||||
.map(AlarmTriggerStateDTO::getConsecutiveCount)
|
||||
.orElse(1);
|
||||
// 构建告警信息
|
||||
String alarmInfo = this.buildAlarmInfo(metrics, rule, unit, metricsValue, consecutiveCount);
|
||||
// 创建告警事件记录
|
||||
Map<String, String> tags = agentMetrics.getTags();
|
||||
AlarmEventDO alarmEvent = AlarmEventDO.builder()
|
||||
.agentKey(agentKey)
|
||||
.hostId(host.getId())
|
||||
.hostName(host.getName())
|
||||
.hostAddress(host.getAddress())
|
||||
.policyId(rule.getPolicyId())
|
||||
.policyRuleId(rule.getId())
|
||||
.metricsId(rule.getMetricsId())
|
||||
.metricsMeasurement(metrics.getMeasurement())
|
||||
.alarmTags(tags == null ? Const.EMPTY_OBJECT : JSON.toJSONString(tags))
|
||||
.alarmValue(metricsValue)
|
||||
.alarmThreshold(unit.getThresholdOriginalValue(rule.getThreshold()))
|
||||
.alarmInfo(alarmInfo)
|
||||
.alarmLevel(rule.getLevel())
|
||||
.triggerCondition(rule.getTriggerCondition())
|
||||
.consecutiveCount(consecutiveCount)
|
||||
.falseAlarm(BooleanBit.FALSE.getValue())
|
||||
.handleStatus(AlarmHandleStatusEnum.NEW.name())
|
||||
.handleUserId(monitorHost.getOwnerUserId())
|
||||
.handleUsername(monitorHost.getOwnerUsername())
|
||||
.createTime(new Date(timestamp))
|
||||
.updateTime(new Date(timestamp))
|
||||
.build();
|
||||
|
||||
// 保存告警事件
|
||||
alarmEventService.createAlarmEvent(alarmEvent);
|
||||
// 填充其他参数
|
||||
return AlarmEventConvert.MAPPER.toTrigger(alarmEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建告警信息
|
||||
*
|
||||
@@ -506,11 +448,11 @@ public class AlarmEngine {
|
||||
* @param consecutiveCount consecutiveCount
|
||||
* @return alarmInfo
|
||||
*/
|
||||
private String buildAlarmInfo(MonitorMetricsContextDTO metrics,
|
||||
AlarmEngineRule rule,
|
||||
MetricsUnitEnum unit,
|
||||
BigDecimal metricsValue,
|
||||
Integer consecutiveCount) {
|
||||
protected String buildAlarmInfo(MonitorMetricsContextDTO metrics,
|
||||
AlarmEngineRule rule,
|
||||
MetricsUnitEnum unit,
|
||||
BigDecimal metricsValue,
|
||||
Integer consecutiveCount) {
|
||||
return metrics.getName()
|
||||
+ Const.SPACE + AlarmTriggerConditionEnum.of(rule.getTriggerCondition()).getCondition()
|
||||
+ Const.SPACE + unit.format(rule.getThreshold(), new MetricsUnitEnum.FormatOptions(2, metrics.getSuffix()))
|
||||
@@ -525,7 +467,7 @@ public class AlarmEngine {
|
||||
* @param rule rule
|
||||
* @return cacheKey
|
||||
*/
|
||||
private String getTriggerStateCacheKey(String agentKey, AlarmEngineRule rule) {
|
||||
protected String getTriggerStateCacheKey(String agentKey, AlarmEngineRule rule) {
|
||||
return agentKey + ":" + rule.getId();
|
||||
}
|
||||
|
||||
@@ -535,7 +477,7 @@ public class AlarmEngine {
|
||||
* @param policy policy
|
||||
* @param alarmEvents alarmEvents
|
||||
*/
|
||||
private void notifyAlarmPolicyChannels(AlarmEnginePolicy policy, List<AlarmEventTriggerDTO> alarmEvents) {
|
||||
protected void notifyAlarmPolicyChannels(AlarmEnginePolicy policy, List<AlarmEventTriggerDTO> alarmEvents) {
|
||||
List<Long> notifyIdList = policy.getNotifyIdList();
|
||||
if (Lists.isEmpty(notifyIdList)) {
|
||||
return;
|
||||
@@ -549,38 +491,41 @@ public class AlarmEngine {
|
||||
// 构建参数
|
||||
List<Map<String, Object>> paramsList = new ArrayList<>();
|
||||
for (AlarmEventTriggerDTO event : alarmEvents) {
|
||||
MonitorMetricsContextDTO metrics = monitorContext.getMonitorMetrics(event.getMetricsId());
|
||||
MetricsUnitEnum unit = MetricsUnitEnum.of(metrics.getUnit());
|
||||
AlarmLevelEnum level = AlarmLevelEnum.of(event.getAlarmLevel());
|
||||
AlarmTriggerConditionEnum triggerCondition = AlarmTriggerConditionEnum.of(event.getTriggerCondition());
|
||||
try {
|
||||
MonitorMetricsContextDTO metrics = monitorMetricsContext.getMonitorMetrics(event.getMetricsId());
|
||||
MetricsUnitEnum unit = MetricsUnitEnum.of(metrics.getUnit());
|
||||
AlarmLevelEnum level = AlarmLevelEnum.of(event.getAlarmLevel());
|
||||
AlarmTriggerConditionEnum triggerCondition = AlarmTriggerConditionEnum.of(event.getTriggerCondition());
|
||||
|
||||
// 告警事件参数
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", event.getId());
|
||||
params.put("relKey", event.getId());
|
||||
params.put("policyId", policy.getId());
|
||||
params.put("policyName", policy.getName());
|
||||
params.put("ruleId", event.getPolicyRuleId());
|
||||
params.put("hostId", event.getHostId());
|
||||
params.put("hostName", event.getHostName());
|
||||
params.put("hostAddress", event.getHostAddress());
|
||||
params.put("metrics", metrics.getMeasurement() + "." + metrics.getValue());
|
||||
params.put("metricsId", metrics.getId());
|
||||
params.put("metricsName", metrics.getName());
|
||||
params.put("metricsField", metrics.getValue());
|
||||
params.put("metricsMeasurement", metrics.getMeasurement());
|
||||
params.put("tags", event.getAlarmTags());
|
||||
params.put("level", level.name());
|
||||
params.put("levelLabel", level.getLabel());
|
||||
params.put("levelSeverity", level.getSeverity());
|
||||
params.put("levelColor", level.getColor());
|
||||
params.put("consecutiveCount", event.getConsecutiveCount());
|
||||
params.put("triggerCondition", triggerCondition.getCondition());
|
||||
params.put("alarmInfo", event.getAlarmInfo());
|
||||
params.put("alarmValue", unit.format(event.getAlarmValue(), new MetricsUnitEnum.FormatOptions(2, metrics.getSuffix())));
|
||||
params.put("alarmThreshold", unit.format(event.getAlarmThreshold(), new MetricsUnitEnum.FormatOptions(4, metrics.getSuffix())));
|
||||
params.put("alarmTime", Dates.format(event.getCreateTime()));
|
||||
paramsList.add(params);
|
||||
// 告警事件参数
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", event.getId());
|
||||
params.put("relKey", event.getId());
|
||||
params.put("policyId", policy.getId());
|
||||
params.put("policyName", policy.getName());
|
||||
params.put("ruleId", event.getPolicyRuleId());
|
||||
params.put("metrics", metrics.getMeasurement() + "." + metrics.getValue());
|
||||
params.put("metricsId", metrics.getId());
|
||||
params.put("metricsName", metrics.getName());
|
||||
params.put("metricsField", metrics.getValue());
|
||||
params.put("metricsMeasurement", metrics.getMeasurement());
|
||||
params.put("tags", event.getAlarmTags());
|
||||
params.put("level", level.name());
|
||||
params.put("levelLabel", level.getLabel());
|
||||
params.put("levelSeverity", level.getSeverity());
|
||||
params.put("levelColor", level.getColor());
|
||||
params.put("consecutiveCount", event.getConsecutiveCount());
|
||||
params.put("triggerCondition", triggerCondition.getCondition());
|
||||
params.put("alarmInfo", event.getAlarmInfo());
|
||||
params.put("alarmValue", unit.format(event.getAlarmValue(), new MetricsUnitEnum.FormatOptions(2, metrics.getSuffix())));
|
||||
params.put("alarmThreshold", unit.format(event.getAlarmThreshold(), new MetricsUnitEnum.FormatOptions(4, metrics.getSuffix())));
|
||||
params.put("alarmTime", Dates.format(event.getCreateTime()));
|
||||
// 设置额外告警推送参数
|
||||
this.setExtraAlarmPushParams(params, event);
|
||||
paramsList.add(params);
|
||||
} catch (Exception e) {
|
||||
log.info("AlarmEngine-setAlarmParams error", e);
|
||||
}
|
||||
}
|
||||
// 推送消息
|
||||
for (Map<String, Object> params : paramsList) {
|
||||
@@ -590,4 +535,12 @@ public class AlarmEngine {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* 设置告警推送参数
|
||||
*
|
||||
* @param params params
|
||||
* @param event event
|
||||
*/
|
||||
protected abstract void setExtraAlarmPushParams(Map<String, Object> params, AlarmEventTriggerDTO event);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.monitor.handler.alarm;
|
||||
|
||||
import org.dromara.visor.module.monitor.entity.dto.AgentMetricsDataDTO;
|
||||
|
||||
/**
|
||||
* 告警引擎
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2025/10/13 10:22
|
||||
*/
|
||||
public interface IAlarmEngine {
|
||||
|
||||
/**
|
||||
* 检查并且告警
|
||||
*
|
||||
* @param agentKey agentKey
|
||||
* @param prevMetrics prevMetrics
|
||||
* @param newMetrics newMetrics
|
||||
*/
|
||||
void checkAndAlarm(String agentKey,
|
||||
AgentMetricsDataDTO prevMetrics,
|
||||
AgentMetricsDataDTO newMetrics);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2023 - present Dromara, All rights reserved.
|
||||
*
|
||||
* https://visor.dromara.org
|
||||
* https://visor.dromara.org.cn
|
||||
* https://visor.orionsec.cn
|
||||
*
|
||||
* Members:
|
||||
* Jiahang Li - ljh1553488six@139.com - author
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.monitor.handler.alarm;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.common.enums.BooleanBit;
|
||||
import org.dromara.visor.module.asset.api.HostAgentApi;
|
||||
import org.dromara.visor.module.asset.entity.dto.host.HostBaseDTO;
|
||||
import org.dromara.visor.module.monitor.convert.AlarmEventConvert;
|
||||
import org.dromara.visor.module.monitor.entity.domain.AlarmEventDO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.*;
|
||||
import org.dromara.visor.module.monitor.enums.AlarmEventSourceTypeEnum;
|
||||
import org.dromara.visor.module.monitor.enums.AlarmHandleStatusEnum;
|
||||
import org.dromara.visor.module.monitor.enums.AlarmSwitchEnum;
|
||||
import org.dromara.visor.module.monitor.enums.MetricsUnitEnum;
|
||||
import org.dromara.visor.module.monitor.handler.alarm.model.AlarmEngineRule;
|
||||
import org.dromara.visor.module.monitor.handler.alarm.model.HostAlarmSourceInfo;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 告警引擎
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2025/8/21 17:26
|
||||
*/
|
||||
@Slf4j
|
||||
@Component("metricsAlarmEngine")
|
||||
public class MetricsAlarmEngine extends BaseAlarmEngine {
|
||||
|
||||
@Resource
|
||||
protected HostAgentApi hostAgentApi;
|
||||
|
||||
@Override
|
||||
protected Long getAlarmPolicyId(String agentKey) {
|
||||
// 获取主机信息
|
||||
MonitorHostContextDTO monitorHost = monitorAgentContext.getMonitorHost(agentKey);
|
||||
if (monitorHost == null) {
|
||||
return null;
|
||||
}
|
||||
// 检查策略是否开启
|
||||
Long policyId = monitorHost.getPolicyId();
|
||||
if (policyId == null || AlarmSwitchEnum.isOff(monitorHost.getAlarmSwitch())) {
|
||||
return null;
|
||||
}
|
||||
return policyId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AlarmEventTriggerDTO createAlarmEvent(String agentKey,
|
||||
Long alarmTimestamp,
|
||||
AgentMetricsDTO agentMetrics,
|
||||
BigDecimal metricsValue,
|
||||
AlarmEngineRule rule) {
|
||||
MonitorHostContextDTO monitorHost = monitorAgentContext.getMonitorHost(agentKey);
|
||||
// 查询主机信息
|
||||
HostBaseDTO host = hostAgentApi.getHostCacheByAgentKey(agentKey);
|
||||
if (host == null) {
|
||||
host = new HostBaseDTO();
|
||||
}
|
||||
// 获取指标
|
||||
MonitorMetricsContextDTO metrics = monitorMetricsContext.getMonitorMetrics(rule.getMetricsId());
|
||||
// 指标单位
|
||||
MetricsUnitEnum unit = MetricsUnitEnum.of(metrics.getUnit());
|
||||
// 获取连续触发次数
|
||||
Integer consecutiveCount = Optional.ofNullable(TRIGGER_STATE_CACHE.get(this.getTriggerStateCacheKey(agentKey, rule)))
|
||||
.map(AlarmTriggerStateDTO::getConsecutiveCount)
|
||||
.orElse(1);
|
||||
// 构建告警信息
|
||||
String alarmInfo = this.buildAlarmInfo(metrics, rule, unit, metricsValue, consecutiveCount);
|
||||
// 创建告警事件记录
|
||||
Map<String, String> tags = agentMetrics.getTags();
|
||||
AlarmEventDO alarmEvent = AlarmEventDO.builder()
|
||||
.agentKey(agentKey)
|
||||
.sourceType(AlarmEventSourceTypeEnum.HOST.name())
|
||||
.sourceId(host.getId())
|
||||
.sourceInfo(HostAlarmSourceInfo.builder()
|
||||
.name(host.getName())
|
||||
.code(host.getCode())
|
||||
.address(host.getAddress())
|
||||
.build()
|
||||
.toJsonString())
|
||||
.policyId(rule.getPolicyId())
|
||||
.policyRuleId(rule.getId())
|
||||
.metricsId(rule.getMetricsId())
|
||||
.metricsMeasurement(metrics.getMeasurement())
|
||||
.alarmTags(tags == null ? Const.EMPTY_OBJECT : JSON.toJSONString(tags))
|
||||
.alarmValue(metricsValue)
|
||||
.alarmThreshold(unit.getThresholdOriginalValue(rule.getThreshold()))
|
||||
.alarmInfo(alarmInfo)
|
||||
.alarmLevel(rule.getLevel())
|
||||
.triggerCondition(rule.getTriggerCondition())
|
||||
.consecutiveCount(consecutiveCount)
|
||||
.falseAlarm(BooleanBit.FALSE.getValue())
|
||||
.handleStatus(AlarmHandleStatusEnum.NEW.name())
|
||||
.handleUserId(monitorHost.getOwnerUserId())
|
||||
.handleUsername(monitorHost.getOwnerUsername())
|
||||
.createTime(new Date(alarmTimestamp))
|
||||
.updateTime(new Date(alarmTimestamp))
|
||||
.build();
|
||||
|
||||
// 保存告警事件
|
||||
alarmEventService.createAlarmEvent(alarmEvent);
|
||||
// 填充其他参数
|
||||
return AlarmEventConvert.MAPPER.toTrigger(alarmEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setExtraAlarmPushParams(Map<String, Object> params, AlarmEventTriggerDTO event) {
|
||||
HostAlarmSourceInfo sourceInfo = JSON.parseObject(event.getSourceInfo(), HostAlarmSourceInfo.class);
|
||||
params.put("hostId", event.getSourceId());
|
||||
params.put("hostName", sourceInfo.getName());
|
||||
params.put("hostCode", sourceInfo.getCode());
|
||||
params.put("hostAddress", sourceInfo.getAddress());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.monitor.engine;
|
||||
package org.dromara.visor.module.monitor.handler.alarm.model;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -48,6 +48,9 @@ public class AlarmEnginePolicy {
|
||||
@Schema(description = "策略id")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "策略类型")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "策略名称")
|
||||
private String name;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.monitor.engine;
|
||||
package org.dromara.visor.module.monitor.handler.alarm.model;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -20,40 +20,36 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.dromara.visor.module.monitor.engine;
|
||||
package org.dromara.visor.module.monitor.handler.alarm.model;
|
||||
|
||||
import cn.orionsec.kit.lang.able.IJsonObject;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 告警触发状态 - 轻量级缓存对象
|
||||
* 用于减少内存占用,只保存必要的触发状态信息
|
||||
* 主机告警源信息
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/6/3 18:00
|
||||
* @since 2025/10/13 22:09
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AlarmTriggerState {
|
||||
@Schema(name = "HostAlarmSourceInfo", description = "主机告警源信息")
|
||||
public class HostAlarmSourceInfo implements IJsonObject {
|
||||
|
||||
/**
|
||||
* 时间戳
|
||||
*/
|
||||
private Long timestamp;
|
||||
@Schema(description = "主机名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 是否触发告警
|
||||
*/
|
||||
private Boolean triggered;
|
||||
@Schema(description = "主机编码")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 规则键
|
||||
*/
|
||||
private String ruleKey;
|
||||
@Schema(description = "主机地址")
|
||||
private String address;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
package org.dromara.visor.module.monitor.listener;
|
||||
|
||||
import org.dromara.visor.module.asset.entity.event.AgentOfflineEvent;
|
||||
import org.dromara.visor.module.monitor.engine.MonitorContext;
|
||||
import org.dromara.visor.module.monitor.context.MonitorAgentContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -41,13 +41,13 @@ import java.util.List;
|
||||
public class AgentOfflineEventListener implements ApplicationListener<AgentOfflineEvent> {
|
||||
|
||||
@Resource
|
||||
private MonitorContext monitorContext;
|
||||
private MonitorAgentContext monitorAgentContext;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void onApplicationEvent(AgentOfflineEvent event) {
|
||||
List<String> agentKeys = (List<String>) event.getSource();
|
||||
agentKeys.forEach(monitorContext::setAgentOffline);
|
||||
agentKeys.forEach(monitorAgentContext::setAgentOffline);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -77,9 +77,10 @@ public interface AlarmPolicyService {
|
||||
/**
|
||||
* 通过缓存查询监控告警策略
|
||||
*
|
||||
* @param type type
|
||||
* @return rows
|
||||
*/
|
||||
List<AlarmPolicyVO> getAlarmPolicyListByCache();
|
||||
List<AlarmPolicyVO> getAlarmPolicyListByCache(String type);
|
||||
|
||||
/**
|
||||
* 分页查询监控告警策略
|
||||
|
||||
@@ -223,7 +223,8 @@ public class AlarmEventServiceImpl implements AlarmEventService {
|
||||
public LambdaQueryWrapper<AlarmEventDO> buildQueryWrapper(AlarmEventQueryRequest request) {
|
||||
return alarmEventDAO.wrapper()
|
||||
.eq(AlarmEventDO::getId, request.getId())
|
||||
.eq(AlarmEventDO::getHostId, request.getHostId())
|
||||
.eq(AlarmEventDO::getSourceType, request.getSourceType())
|
||||
.eq(AlarmEventDO::getSourceId, request.getSourceId())
|
||||
.eq(AlarmEventDO::getAgentKey, request.getAgentKey())
|
||||
.eq(AlarmEventDO::getPolicyId, request.getPolicyId())
|
||||
.eq(AlarmEventDO::getMetricsId, request.getMetricsId())
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.dromara.visor.module.monitor.convert.AlarmPolicyRuleConvert;
|
||||
import org.dromara.visor.module.monitor.dao.AlarmPolicyDAO;
|
||||
import org.dromara.visor.module.monitor.dao.AlarmPolicyRuleDAO;
|
||||
import org.dromara.visor.module.monitor.dao.MonitorMetricsDAO;
|
||||
import org.dromara.visor.module.monitor.engine.AlarmEngineContext;
|
||||
import org.dromara.visor.module.monitor.entity.domain.AlarmPolicyDO;
|
||||
import org.dromara.visor.module.monitor.entity.domain.AlarmPolicyRuleDO;
|
||||
import org.dromara.visor.module.monitor.entity.domain.MonitorMetricsDO;
|
||||
@@ -44,6 +43,7 @@ import org.dromara.visor.module.monitor.entity.request.alarm.AlarmPolicyRuleUpda
|
||||
import org.dromara.visor.module.monitor.entity.request.alarm.AlarmPolicyRuleUpdateSwitchRequest;
|
||||
import org.dromara.visor.module.monitor.entity.vo.AlarmPolicyRuleVO;
|
||||
import org.dromara.visor.module.monitor.enums.AlarmSwitchEnum;
|
||||
import org.dromara.visor.module.monitor.handler.alarm.AlarmEngineContext;
|
||||
import org.dromara.visor.module.monitor.service.AlarmPolicyRuleService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -27,6 +27,7 @@ import cn.orionsec.kit.lang.utils.Booleans;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.visor.common.constant.Const;
|
||||
import org.dromara.visor.common.constant.ErrorMessage;
|
||||
import org.dromara.visor.common.utils.Assert;
|
||||
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
||||
@@ -38,7 +39,6 @@ import org.dromara.visor.module.monitor.dao.AlarmPolicyNotifyDAO;
|
||||
import org.dromara.visor.module.monitor.dao.AlarmPolicyRuleDAO;
|
||||
import org.dromara.visor.module.monitor.dao.MonitorHostDAO;
|
||||
import org.dromara.visor.module.monitor.define.cache.AlarmPolicyCacheKeyDefine;
|
||||
import org.dromara.visor.module.monitor.engine.AlarmEngineContext;
|
||||
import org.dromara.visor.module.monitor.entity.domain.AlarmPolicyDO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.AlarmPolicyAlarmCountDTO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.AlarmPolicyCacheDTO;
|
||||
@@ -49,6 +49,7 @@ import org.dromara.visor.module.monitor.entity.request.alarm.AlarmPolicyCreateRe
|
||||
import org.dromara.visor.module.monitor.entity.request.alarm.AlarmPolicyQueryRequest;
|
||||
import org.dromara.visor.module.monitor.entity.request.alarm.AlarmPolicyUpdateRequest;
|
||||
import org.dromara.visor.module.monitor.entity.vo.AlarmPolicyVO;
|
||||
import org.dromara.visor.module.monitor.handler.alarm.AlarmEngineContext;
|
||||
import org.dromara.visor.module.monitor.service.AlarmEventService;
|
||||
import org.dromara.visor.module.monitor.service.AlarmPolicyNotifyService;
|
||||
import org.dromara.visor.module.monitor.service.AlarmPolicyRuleService;
|
||||
@@ -110,8 +111,11 @@ public class AlarmPolicyServiceImpl implements AlarmPolicyService {
|
||||
Long id = record.getId();
|
||||
// 设置告警通知
|
||||
alarmPolicyNotifyService.setAlarmPolicyNotify(id, request.getNotifyIdList());
|
||||
// 删除缓存
|
||||
// 重新加载上下文
|
||||
alarmEngineContext.reloadPolicy(id);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(record.getType()),
|
||||
AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(Const.ALL));
|
||||
// 设置日志参数
|
||||
OperatorLogs.add(OperatorLogs.ID, id);
|
||||
log.info("AlarmPolicyService-createAlarmPolicy id: {}, effect: {}", id, effect);
|
||||
@@ -130,6 +134,11 @@ public class AlarmPolicyServiceImpl implements AlarmPolicyService {
|
||||
Long newId = this.createAlarmPolicy(request);
|
||||
// 复制策略规则
|
||||
alarmPolicyRuleService.copyAlarmPolicyRule(id, newId);
|
||||
// 重新加载上下文
|
||||
alarmEngineContext.reloadPolicy(id);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(record.getType()),
|
||||
AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(Const.ALL));
|
||||
return newId;
|
||||
}
|
||||
|
||||
@@ -143,6 +152,7 @@ public class AlarmPolicyServiceImpl implements AlarmPolicyService {
|
||||
Assert.notNull(record, ErrorMessage.DATA_ABSENT);
|
||||
// 转换
|
||||
AlarmPolicyDO updateRecord = AlarmPolicyConvert.MAPPER.to(request);
|
||||
updateRecord.setType(record.getType());
|
||||
// 查询数据是否冲突
|
||||
this.checkAlarmPolicyPresent(updateRecord);
|
||||
// 更新
|
||||
@@ -152,8 +162,11 @@ public class AlarmPolicyServiceImpl implements AlarmPolicyService {
|
||||
alarmPolicyNotifyService.setAlarmPolicyNotify(id, request.getNotifyIdList());
|
||||
}
|
||||
log.info("AlarmPolicyService-updateAlarmPolicyById effect: {}", effect);
|
||||
// 删除缓存
|
||||
// 重新加载上下文
|
||||
alarmEngineContext.reloadPolicy(id);
|
||||
// 删除缓存
|
||||
RedisMaps.delete(AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(record.getType()),
|
||||
AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(Const.ALL));
|
||||
return effect;
|
||||
}
|
||||
|
||||
@@ -171,16 +184,21 @@ public class AlarmPolicyServiceImpl implements AlarmPolicyService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AlarmPolicyVO> getAlarmPolicyListByCache() {
|
||||
public List<AlarmPolicyVO> getAlarmPolicyListByCache(String type) {
|
||||
String cacheKey = AlarmPolicyCacheKeyDefine.ALARM_POLICY.format(type);
|
||||
// 查询缓存
|
||||
List<AlarmPolicyCacheDTO> list = RedisMaps.valuesJson(AlarmPolicyCacheKeyDefine.ALARM_POLICY);
|
||||
List<AlarmPolicyCacheDTO> list = RedisMaps.valuesJson(cacheKey, AlarmPolicyCacheKeyDefine.ALARM_POLICY);
|
||||
if (list.isEmpty()) {
|
||||
// 查询数据库
|
||||
list = alarmPolicyDAO.of().list(AlarmPolicyConvert.MAPPER::toCache);
|
||||
list = alarmPolicyDAO.of()
|
||||
.createWrapper()
|
||||
.eq(!Const.ALL.equals(type), AlarmPolicyDO::getType, type)
|
||||
.then()
|
||||
.list(AlarmPolicyConvert.MAPPER::toCache);
|
||||
// 设置屏障 防止穿透
|
||||
CacheBarriers.checkBarrier(list, AlarmPolicyCacheDTO::new);
|
||||
// 设置缓存
|
||||
RedisMaps.putAllJson(AlarmPolicyCacheKeyDefine.ALARM_POLICY, s -> s.getId().toString(), list);
|
||||
RedisMaps.putAllJson(cacheKey, AlarmPolicyCacheKeyDefine.ALARM_POLICY, s -> s.getId().toString(), list);
|
||||
}
|
||||
// 删除屏障
|
||||
CacheBarriers.removeBarrier(list);
|
||||
@@ -248,7 +266,7 @@ public class AlarmPolicyServiceImpl implements AlarmPolicyService {
|
||||
// 删除策略通知
|
||||
alarmPolicyNotifyDAO.deleteByPolicyId(id);
|
||||
// 删除策略规则
|
||||
alarmPolicyRuleService.deleteByPolicyId(id);
|
||||
alarmPolicyRuleDAO.deleteByPolicyId(id);
|
||||
// 删除缓存
|
||||
alarmEngineContext.reloadPolicy(id);
|
||||
log.info("AlarmPolicyService-deleteAlarmPolicyById effect: {}", effect);
|
||||
@@ -259,6 +277,7 @@ public class AlarmPolicyServiceImpl implements AlarmPolicyService {
|
||||
public LambdaQueryWrapper<AlarmPolicyDO> buildQueryWrapper(AlarmPolicyQueryRequest request) {
|
||||
return alarmPolicyDAO.wrapper()
|
||||
.eq(AlarmPolicyDO::getId, request.getId())
|
||||
.eq(AlarmPolicyDO::getType, request.getType())
|
||||
.like(AlarmPolicyDO::getName, request.getName())
|
||||
.like(AlarmPolicyDO::getDescription, request.getDescription());
|
||||
}
|
||||
@@ -274,6 +293,7 @@ public class AlarmPolicyServiceImpl implements AlarmPolicyService {
|
||||
// 更新时忽略当前记录
|
||||
.ne(AlarmPolicyDO::getId, domain.getId())
|
||||
// 用其他字段做重复校验
|
||||
.eq(AlarmPolicyDO::getType, domain.getType())
|
||||
.eq(AlarmPolicyDO::getName, domain.getName());
|
||||
// 检查是否存在
|
||||
boolean present = alarmPolicyDAO.of(wrapper).present();
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
package org.dromara.visor.module.monitor.service.impl;
|
||||
|
||||
import cn.orionsec.kit.lang.able.Executable;
|
||||
import cn.orionsec.kit.lang.annotation.Keep;
|
||||
import cn.orionsec.kit.lang.utils.Strings;
|
||||
import cn.orionsec.kit.lang.utils.collect.Lists;
|
||||
import cn.orionsec.kit.lang.utils.collect.Maps;
|
||||
@@ -38,14 +39,14 @@ import org.dromara.visor.framework.influxdb.core.utils.InfluxdbUtils;
|
||||
import org.dromara.visor.module.asset.api.HostApi;
|
||||
import org.dromara.visor.module.asset.entity.dto.host.HostDTO;
|
||||
import org.dromara.visor.module.infra.api.SystemUserApi;
|
||||
import org.dromara.visor.module.monitor.context.MonitorAgentContext;
|
||||
import org.dromara.visor.module.monitor.dao.MonitorHostDAO;
|
||||
import org.dromara.visor.module.monitor.engine.AlarmEngine;
|
||||
import org.dromara.visor.module.monitor.engine.MonitorContext;
|
||||
import org.dromara.visor.module.monitor.entity.domain.MonitorHostDO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.AgentMetricsDataDTO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.HostMetaDTO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.MonitorHostConfigDTO;
|
||||
import org.dromara.visor.module.monitor.enums.AlarmSwitchEnum;
|
||||
import org.dromara.visor.module.monitor.handler.alarm.IAlarmEngine;
|
||||
import org.dromara.visor.module.monitor.service.MonitorAgentEndpointService;
|
||||
import org.dromara.visor.module.monitor.utils.MetricsUtils;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
@@ -79,18 +80,19 @@ public class MonitorAgentEndpointServiceImpl implements MonitorAgentEndpointServ
|
||||
private SystemUserApi systemUserApi;
|
||||
|
||||
@Resource
|
||||
private MonitorContext monitorContext;
|
||||
private MonitorAgentContext monitorAgentContext;
|
||||
|
||||
@Keep
|
||||
@Resource
|
||||
private AlarmEngine alarmEngine;
|
||||
private IAlarmEngine metricsAlarmEngine;
|
||||
|
||||
@Override
|
||||
@Async("metricsExecutor")
|
||||
public void addMetrics(String agentKey, AgentMetricsDataDTO newMetrics) {
|
||||
log.info("MonitorAgentEndpointService.addMetrics start agentKey: {}", agentKey);
|
||||
// 设置数据缓存
|
||||
AgentMetricsDataDTO prevMetrics = monitorContext.getAgentMetrics(agentKey);
|
||||
monitorContext.setAgentMetrics(agentKey, newMetrics);
|
||||
AgentMetricsDataDTO prevMetrics = monitorAgentContext.getAgentMetrics(agentKey);
|
||||
monitorAgentContext.setAgentMetrics(agentKey, newMetrics);
|
||||
// 数据点
|
||||
List<Point> points = newMetrics.getMetrics()
|
||||
.stream()
|
||||
@@ -102,7 +104,7 @@ public class MonitorAgentEndpointServiceImpl implements MonitorAgentEndpointServ
|
||||
// 写入数据点
|
||||
InfluxdbUtils.writePoints(points);
|
||||
// 告警
|
||||
alarmEngine.checkAndAlarm(agentKey, prevMetrics, newMetrics);
|
||||
metricsAlarmEngine.checkAndAlarm(agentKey, prevMetrics, newMetrics);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -149,7 +151,7 @@ public class MonitorAgentEndpointServiceImpl implements MonitorAgentEndpointServ
|
||||
}
|
||||
// 重新加载监控主机上下文
|
||||
if (newConfig != null) {
|
||||
monitorContext.reloadMonitorHost(agentKey);
|
||||
monitorAgentContext.reloadMonitorHost(agentKey);
|
||||
}
|
||||
};
|
||||
// 获取锁并执行同步逻辑
|
||||
|
||||
@@ -48,10 +48,10 @@ import org.dromara.visor.module.asset.entity.dto.host.HostQueryDTO;
|
||||
import org.dromara.visor.module.asset.enums.AgentOnlineStatusEnum;
|
||||
import org.dromara.visor.module.infra.api.SystemUserApi;
|
||||
import org.dromara.visor.module.monitor.constant.MetricsConst;
|
||||
import org.dromara.visor.module.monitor.context.MonitorAgentContext;
|
||||
import org.dromara.visor.module.monitor.convert.MonitorHostConvert;
|
||||
import org.dromara.visor.module.monitor.dao.AlarmPolicyDAO;
|
||||
import org.dromara.visor.module.monitor.dao.MonitorHostDAO;
|
||||
import org.dromara.visor.module.monitor.engine.MonitorContext;
|
||||
import org.dromara.visor.module.monitor.entity.domain.AlarmPolicyDO;
|
||||
import org.dromara.visor.module.monitor.entity.domain.MonitorHostDO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.*;
|
||||
@@ -102,7 +102,7 @@ public class MonitorHostServiceImpl implements MonitorHostService {
|
||||
private MonitorMetricsService monitorMetricsService;
|
||||
|
||||
@Resource
|
||||
private MonitorContext monitorContext;
|
||||
private MonitorAgentContext monitorAgentContext;
|
||||
|
||||
@Override
|
||||
public DataGrid<MonitorHostVO> getMonitorHostPage(MonitorHostQueryRequest request) {
|
||||
@@ -308,7 +308,7 @@ public class MonitorHostServiceImpl implements MonitorHostService {
|
||||
monitorHostDAO.setPolicyIdWithNullById(id);
|
||||
}
|
||||
// 重新加载监控主机上下文
|
||||
monitorContext.reloadMonitorHost(host.getAgentKey());
|
||||
monitorAgentContext.reloadMonitorHost(host.getAgentKey());
|
||||
log.info("MonitorHostService-updateMonitorHostById effect: {}", effect);
|
||||
return effect;
|
||||
}
|
||||
@@ -334,7 +334,7 @@ public class MonitorHostServiceImpl implements MonitorHostService {
|
||||
log.info("MonitorHostService-updateMonitorHostAlarmSwitch effect: {}", effect);
|
||||
// 更新缓存
|
||||
for (HostDTO host : hostList) {
|
||||
monitorContext.reloadMonitorHost(host.getAgentKey());
|
||||
monitorAgentContext.reloadMonitorHost(host.getAgentKey());
|
||||
}
|
||||
return effect;
|
||||
}
|
||||
@@ -350,7 +350,7 @@ public class MonitorHostServiceImpl implements MonitorHostService {
|
||||
// 删除
|
||||
int effect = monitorHostDAO.deleteByHostIdList(hostIdList);
|
||||
// 删除缓存
|
||||
hosts.forEach(s -> monitorContext.removeMonitorHost(s.getAgentKey()));
|
||||
hosts.forEach(s -> monitorAgentContext.removeMonitorHost(s.getAgentKey()));
|
||||
log.info("MonitorHostService.deleteByHostIdList finish effect: {}", effect);
|
||||
return effect;
|
||||
}
|
||||
@@ -394,7 +394,7 @@ public class MonitorHostServiceImpl implements MonitorHostService {
|
||||
List<String> fields = request.getFields();
|
||||
// 获取配置信息
|
||||
List<MonitorHostConfigDTO> configList = agentKeys.stream()
|
||||
.map(monitorContext::getMonitorHost)
|
||||
.map(monitorAgentContext::getMonitorHost)
|
||||
.map(MonitorHostContextDTO::getConfig)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
@@ -446,7 +446,7 @@ public class MonitorHostServiceImpl implements MonitorHostService {
|
||||
* @return data
|
||||
*/
|
||||
public MonitorHostMetricsDataVO getHostMetricsData(String agentKey, MonitorHostConfigDTO config) {
|
||||
AgentMetricsDataDTO metrics = monitorContext.getAgentMetrics(agentKey);
|
||||
AgentMetricsDataDTO metrics = monitorAgentContext.getAgentMetrics(agentKey);
|
||||
// 无数据
|
||||
if (metrics == null) {
|
||||
return MonitorHostMetricsDataVO.noData(agentKey);
|
||||
@@ -454,7 +454,7 @@ public class MonitorHostServiceImpl implements MonitorHostService {
|
||||
// 从缓存中获取配置
|
||||
if (config == null) {
|
||||
config = Optional.of(agentKey)
|
||||
.map(monitorContext::getMonitorHost)
|
||||
.map(monitorAgentContext::getMonitorHost)
|
||||
.map(MonitorHostContextDTO::getConfig)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@@ -31,10 +31,10 @@ import org.dromara.visor.common.utils.Assert;
|
||||
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
|
||||
import org.dromara.visor.framework.redis.core.utils.RedisMaps;
|
||||
import org.dromara.visor.framework.redis.core.utils.barrier.CacheBarriers;
|
||||
import org.dromara.visor.module.monitor.context.MonitorMetricsContext;
|
||||
import org.dromara.visor.module.monitor.convert.MonitorMetricsConvert;
|
||||
import org.dromara.visor.module.monitor.dao.MonitorMetricsDAO;
|
||||
import org.dromara.visor.module.monitor.define.cache.MonitorMetricsCacheKeyDefine;
|
||||
import org.dromara.visor.module.monitor.engine.MonitorContext;
|
||||
import org.dromara.visor.module.monitor.entity.domain.MonitorMetricsDO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.MonitorMetricsCacheDTO;
|
||||
import org.dromara.visor.module.monitor.entity.dto.MonitorMetricsContextDTO;
|
||||
@@ -70,7 +70,7 @@ public class MonitorMetricsServiceImpl implements MonitorMetricsService {
|
||||
private AlarmPolicyRuleService alarmPolicyRuleService;
|
||||
|
||||
@Resource
|
||||
private MonitorContext monitorContext;
|
||||
private MonitorMetricsContext monitorMetricsContext;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@@ -88,7 +88,7 @@ public class MonitorMetricsServiceImpl implements MonitorMetricsService {
|
||||
// 设置日志参数
|
||||
OperatorLogs.add(OperatorLogs.ID, id);
|
||||
// 重新加载本地缓存
|
||||
monitorContext.reloadMonitorMetrics(id);
|
||||
monitorMetricsContext.reloadMonitorMetrics(id);
|
||||
log.info("MonitorMetricsService-createMonitorMetrics id: {}, effect: {}", id, effect);
|
||||
return id;
|
||||
}
|
||||
@@ -112,7 +112,7 @@ public class MonitorMetricsServiceImpl implements MonitorMetricsService {
|
||||
// 删除缓存
|
||||
RedisMaps.delete(MonitorMetricsCacheKeyDefine.MONITOR_METRICS);
|
||||
// 重新加载本地缓存
|
||||
monitorContext.reloadMonitorMetrics(id);
|
||||
monitorMetricsContext.reloadMonitorMetrics(id);
|
||||
return effect;
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ public class MonitorMetricsServiceImpl implements MonitorMetricsService {
|
||||
|
||||
@Override
|
||||
public String getMetricName(String measurement, String value) {
|
||||
MonitorMetricsContextDTO metrics = monitorContext.getMonitorMetrics(measurement, value);
|
||||
MonitorMetricsContextDTO metrics = monitorMetricsContext.getMonitorMetrics(measurement, value);
|
||||
if (metrics == null) {
|
||||
return value;
|
||||
}
|
||||
@@ -172,7 +172,7 @@ public class MonitorMetricsServiceImpl implements MonitorMetricsService {
|
||||
// 删除缓存
|
||||
RedisMaps.delete(MonitorMetricsCacheKeyDefine.MONITOR_METRICS, id);
|
||||
// 重新加载本地缓存
|
||||
monitorContext.reloadMonitorMetrics(id);
|
||||
monitorMetricsContext.reloadMonitorMetrics(id);
|
||||
// 设置日志参数
|
||||
OperatorLogs.add(OperatorLogs.NAME, record.getName());
|
||||
log.info("MonitorMetricsService-deleteMonitorMetricsById id: {}, effect: {}", id, effect);
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<!-- 通用查询映射结果 -->
|
||||
<resultMap id="BaseResultMap" type="org.dromara.visor.module.monitor.entity.domain.AlarmEventDO">
|
||||
<id column="id" property="id"/>
|
||||
<result column="host_id" property="hostId"/>
|
||||
<result column="host_name" property="hostName"/>
|
||||
<result column="host_address" property="hostAddress"/>
|
||||
<result column="source_type" property="sourceType"/>
|
||||
<result column="source_id" property="sourceId"/>
|
||||
<result column="source_info" property="sourceInfo"/>
|
||||
<result column="agent_key" property="agentKey"/>
|
||||
<result column="policy_id" property="policyId"/>
|
||||
<result column="policy_rule_id" property="policyRuleId"/>
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, host_id, host_name, host_address, agent_key, policy_id, policy_rule_id, metrics_id, metrics_measurement, alarm_tags, alarm_value, alarm_threshold, alarm_info, alarm_level, trigger_condition, consecutive_count, false_alarm, handle_status, handle_time, handle_remark, handle_user_id, handle_username, create_time, update_time, creator, updater, deleted
|
||||
id, event_source, source_id, source_info, agent_key, policy_id, policy_rule_id, metrics_id, metrics_measurement, alarm_tags, alarm_value, alarm_threshold, alarm_info, alarm_level, trigger_condition, consecutive_count, false_alarm, handle_status, handle_time, handle_remark, handle_user_id, handle_username, create_time, update_time, creator, updater, deleted
|
||||
</sql>
|
||||
|
||||
<select id="selectPolicyEventCount" resultMap="CountResultMap">
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<!-- 通用查询映射结果 -->
|
||||
<resultMap id="BaseResultMap" type="org.dromara.visor.module.monitor.entity.domain.AlarmPolicyDO">
|
||||
<id column="id" property="id"/>
|
||||
<result column="type" property="type"/>
|
||||
<result column="name" property="name"/>
|
||||
<result column="description" property="description"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
@@ -16,7 +17,7 @@
|
||||
|
||||
<!-- 通用查询结果列 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, name, description, create_time, update_time, creator, updater, deleted
|
||||
id, type, name, description, create_time, update_time, creator, updater, deleted
|
||||
</sql>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -3,4 +3,4 @@ VITE_API_BASE_URL=http://127.0.0.1:9200/orion-visor/api
|
||||
# websocket 路径
|
||||
VITE_WS_BASE_URL=ws://127.0.0.1:9200/orion-visor/keep-alive
|
||||
# 版本号
|
||||
VITE_APP_VERSION=2.5.3
|
||||
VITE_APP_VERSION=2.5.4
|
||||
|
||||
@@ -3,4 +3,4 @@ VITE_API_BASE_URL=/orion-visor/api
|
||||
# websocket 路径
|
||||
VITE_WS_BASE_URL=/orion-visor/keep-alive
|
||||
# 版本号
|
||||
VITE_APP_VERSION=2.5.3
|
||||
VITE_APP_VERSION=2.5.4
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "orion-visor-ui",
|
||||
"description": "Orion Visor UI",
|
||||
"version": "2.5.3",
|
||||
"version": "2.5.4",
|
||||
"private": true,
|
||||
"author": "Jiahang Li",
|
||||
"license": "Apache 2.0",
|
||||
|
||||
12
orion-visor-ui/src/api/error.ts
Normal file
12
orion-visor-ui/src/api/error.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { AxiosResponse } from 'axios';
|
||||
|
||||
// api 错误
|
||||
export class ApiError extends Error {
|
||||
data: AxiosResponse;
|
||||
|
||||
constructor(message: string, data: AxiosResponse) {
|
||||
super(message);
|
||||
this.name = 'ApiError';
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { useUserStore } from '@/store';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { httpBaseUrl } from '@/utils/env';
|
||||
import { reLoginTipsKey } from '@/types/symbol';
|
||||
import { ApiError } from '@/api/error';
|
||||
|
||||
axios.defaults.timeout = 15000;
|
||||
axios.defaults.setAuthorization = true;
|
||||
@@ -72,7 +73,7 @@ axios.interceptors.response.use(
|
||||
});
|
||||
}
|
||||
}
|
||||
return Promise.reject(new Error(res.msg || 'Error'));
|
||||
return Promise.reject(new ApiError(res.msg || 'Error', res));
|
||||
},
|
||||
(error) => {
|
||||
// 判断是否弹出请求错误信息
|
||||
|
||||
@@ -25,7 +25,8 @@ export interface AlarmEventFalseAlarmRequest {
|
||||
*/
|
||||
export interface AlarmEventQueryRequest extends Pagination, OrderDirection {
|
||||
id?: number;
|
||||
hostId?: number;
|
||||
sourceType?: string;
|
||||
sourceId?: number;
|
||||
agentKey?: string;
|
||||
policyId?: number;
|
||||
metricsId?: number;
|
||||
@@ -49,7 +50,9 @@ export interface AlarmEventClearRequest extends AlarmEventQueryRequest, ClearReq
|
||||
*/
|
||||
export interface AlarmEventQueryResponse extends TableData {
|
||||
id: number;
|
||||
hostId: number;
|
||||
sourceType: string;
|
||||
sourceId: number;
|
||||
sourceInfo: Record<string, any>;
|
||||
hostName: string;
|
||||
hostAddress: string;
|
||||
agentKey: string;
|
||||
|
||||
@@ -7,6 +7,7 @@ import axios from 'axios';
|
||||
*/
|
||||
export interface AlarmPolicyCreateRequest {
|
||||
name?: string;
|
||||
type?: string;
|
||||
description?: string;
|
||||
notifyIdList?: Array<number>;
|
||||
}
|
||||
@@ -24,6 +25,7 @@ export interface AlarmPolicyUpdateRequest extends AlarmPolicyCreateRequest {
|
||||
*/
|
||||
export interface AlarmPolicyQueryRequest extends Pagination, OrderDirection {
|
||||
id?: number;
|
||||
type?: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
}
|
||||
@@ -33,6 +35,7 @@ export interface AlarmPolicyQueryRequest extends Pagination, OrderDirection {
|
||||
*/
|
||||
export interface AlarmPolicyQueryResponse extends TableData {
|
||||
id: number;
|
||||
type: string;
|
||||
name: string;
|
||||
description: string;
|
||||
notifyIdList: Array<number>;
|
||||
@@ -73,8 +76,8 @@ export function getAlarmPolicy(id: number) {
|
||||
/**
|
||||
* 查询全部监控告警策略
|
||||
*/
|
||||
export function getAlarmPolicyList() {
|
||||
return axios.get<Array<AlarmPolicyQueryResponse>>('/monitor/alarm-policy/list');
|
||||
export function getAlarmPolicyList(type: string) {
|
||||
return axios.get<Array<AlarmPolicyQueryResponse>>('/monitor/alarm-policy/list', { params: { type } });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -96,6 +96,7 @@ export interface MonitorHostQueryResponse extends TableData {
|
||||
code: string;
|
||||
address: string;
|
||||
status: string;
|
||||
types: Array<string>;
|
||||
agentKey: string;
|
||||
agentVersion: string;
|
||||
latestVersion: string;
|
||||
|
||||
@@ -45,53 +45,53 @@ export type SystemSetting = SftpSetting
|
||||
* SFTP 设置
|
||||
*/
|
||||
export interface SftpSetting {
|
||||
sftp_previewSize: number;
|
||||
sftp_uploadPresentBackup: string;
|
||||
sftp_uploadBackupFileName: string;
|
||||
['sftp.preview-size']: number;
|
||||
['sftp.upload-present-backup']: string;
|
||||
['sftp.upload-backup-file-name']: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录设置
|
||||
*/
|
||||
export interface LoginSetting {
|
||||
login_allowMultiDevice: string;
|
||||
login_allowRefresh: string;
|
||||
login_maxRefreshCount: number;
|
||||
login_refreshInterval: number;
|
||||
login_loginFailedLock: string;
|
||||
login_loginFailedLockThreshold: number;
|
||||
login_loginFailedLockTime: number;
|
||||
login_loginFailedSend: string;
|
||||
login_loginFailedSendThreshold: number;
|
||||
login_loginSessionTime: number;
|
||||
['login.allow-multi-device']: string;
|
||||
['login.allow-refresh']: string;
|
||||
['login.max-refresh-count']: number;
|
||||
['login.refresh-interval']: number;
|
||||
['login.login-failed-lock']: string;
|
||||
['login.login-failed-lock-threshold']: number;
|
||||
['login.login-failed-lock-time']: number;
|
||||
['login.login-failed-send']: string;
|
||||
['login.login-failed-send-threshold']: number;
|
||||
['login.login-session-time']: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密设置
|
||||
*/
|
||||
export interface EncryptSetting {
|
||||
encrypt_publicKey: string;
|
||||
encrypt_privateKey: string;
|
||||
['encrypt.public-key']: string;
|
||||
['encrypt.private-key']: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志设置
|
||||
*/
|
||||
export interface LogSetting {
|
||||
log_webScrollLines: number;
|
||||
log_trackerLoadLines: number;
|
||||
log_trackerLoadInterval: number;
|
||||
log_execDetailLog: string;
|
||||
['log.web-scroll-lines']: number;
|
||||
['log.tracker-load-lines']: number;
|
||||
['log.tracker-load-interval']: number;
|
||||
['log.exec-detail.enabled']: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动清理设置
|
||||
*/
|
||||
export interface AutoClearSetting {
|
||||
autoClear_execLogEnabled: string;
|
||||
autoClear_execLogKeepDays: number;
|
||||
autoClear_terminalLogEnabled: string;
|
||||
autoClear_terminalLogKeepDays: number;
|
||||
['auto-clear.exec-log.enabled']: string;
|
||||
['auto-clear.exec-log.keep-days']: number;
|
||||
['auto-clear.terminal-log.enabled']: string;
|
||||
['auto-clear.terminal-log.keep-days']: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { MenuQueryResponse } from '@/api/system/menu';
|
||||
import type { AxiosResponse } from 'axios';
|
||||
import type { HttpResponse } from '@/types/global';
|
||||
import axios from 'axios';
|
||||
|
||||
/**
|
||||
@@ -36,7 +36,7 @@ export interface UserUpdatePasswordResponse {
|
||||
* 获取用户聚合信息
|
||||
*/
|
||||
export function getUserAggregateInfo() {
|
||||
return axios.get<AxiosResponse<UserAggregateResponse>>('/infra/user-aggregate/user', {
|
||||
return axios.get<HttpResponse<UserAggregateResponse>>('/infra/user-aggregate/user', {
|
||||
unwrap: true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -66,6 +66,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 可调节列宽
|
||||
.table-resize .arco-table-th:not(.arco-table-th-expand):not(.arco-table-operation)::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 25%;
|
||||
right: 0;
|
||||
width: 1px;
|
||||
height: 50%;
|
||||
background-color: var(--color-neutral-3);
|
||||
}
|
||||
|
||||
// 垂直滚动
|
||||
.arco-scrollbar-track-direction-vertical {
|
||||
width: 10px;
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
.table-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
font-size: 1.17em;
|
||||
font-weight: 600;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
<template>
|
||||
<a-table row-key="id"
|
||||
<a-table v-model:selected-keys="selectedKeysValue"
|
||||
row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:columns="columns"
|
||||
v-model:selected-keys="selectedKeysValue"
|
||||
:row-selection="rowSelection"
|
||||
row-class="pointer"
|
||||
:data="hostList"
|
||||
:scroll="{ y: '100%' }"
|
||||
:pagination="false"
|
||||
:bordered="true"
|
||||
:column-resizable="true"
|
||||
@row-click="clickRow">
|
||||
<!-- 空 -->
|
||||
<template #empty>
|
||||
|
||||
@@ -55,8 +55,8 @@
|
||||
execLog.value = { ...record };
|
||||
currentHostExecId.value = record.hosts[0].id;
|
||||
// 获取最大显示行数
|
||||
const { log_webScrollLines } = await useCacheStore().loadSystemSetting();
|
||||
const scrollLines = toAnonymousNumber(log_webScrollLines) || 1000;
|
||||
const { 'log.web-scroll-lines': webScrollLines } = await useCacheStore().loadSystemSetting();
|
||||
const scrollLines = toAnonymousNumber(webScrollLines) || 1000;
|
||||
// 创建 appender
|
||||
appender.value = markRaw(new LogAppender({
|
||||
id: record.id,
|
||||
|
||||
@@ -45,11 +45,13 @@
|
||||
<!-- table -->
|
||||
<a-table row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
:scroll="{ x: '100%', y: '60vh' }"
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
|
||||
@@ -19,6 +19,12 @@
|
||||
import { useCacheStore } from '@/store';
|
||||
import useLoading from '@/hooks/loading';
|
||||
|
||||
const props = withDefaults(defineProps<Partial<{
|
||||
type?: string;
|
||||
}>>(), {
|
||||
type: 'all',
|
||||
});
|
||||
|
||||
const modelValue = defineModel({ type: Number });
|
||||
|
||||
const { loading, setLoading } = useLoading();
|
||||
@@ -30,7 +36,7 @@
|
||||
const initOptions = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const values = await cacheStore.loadMonitorAlarmPolicy();
|
||||
const values = await cacheStore.loadMonitorAlarmPolicy(props.type);
|
||||
optionData.value = values.map(s => {
|
||||
return {
|
||||
label: s.name,
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<a-select v-model:model-value="modelValue"
|
||||
:options="optionData"
|
||||
:loading="loading"
|
||||
:multiple="multiple"
|
||||
placeholder="请选择监控项"
|
||||
allow-clear />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'monitorHostSelector'
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { SelectOptionData } from '@arco-design/web-vue';
|
||||
import type { HostType } from '@/api/asset/host';
|
||||
import { onActivated, onMounted, ref } from 'vue';
|
||||
import { useCacheStore } from '@/store';
|
||||
import useLoading from '@/hooks/loading';
|
||||
|
||||
const props = withDefaults(defineProps<Partial<{
|
||||
type: HostType;
|
||||
status: string | undefined;
|
||||
multiple: boolean;
|
||||
}>>(), {
|
||||
type: undefined,
|
||||
status: undefined,
|
||||
multiple: false,
|
||||
});
|
||||
|
||||
const modelValue = defineModel<string | Array<string>>();
|
||||
|
||||
const { loading, setLoading } = useLoading();
|
||||
const cacheStore = useCacheStore();
|
||||
const optionData = ref<Array<SelectOptionData>>([]);
|
||||
|
||||
// 初始化选项
|
||||
const initOptions = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const hosts = await cacheStore.loadHosts(props.type);
|
||||
optionData.value = hosts.filter(s => !props.status || s.status === props.status)
|
||||
.map(s => {
|
||||
return {
|
||||
label: `${s.name} - ${s.address}`,
|
||||
value: s.agentKey,
|
||||
};
|
||||
});
|
||||
} catch (e) {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化选项
|
||||
onMounted(initOptions);
|
||||
onActivated(initOptions);
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
</style>
|
||||
@@ -31,7 +31,10 @@ export default function setupUserLoginInfoGuard(router: Router) {
|
||||
next();
|
||||
}
|
||||
} catch (error) {
|
||||
Message.error('获取用户信息失败');
|
||||
// 登录过期
|
||||
if ((error as any)?.data?.data?.code !== 401) {
|
||||
Message.error('获取用户信息失败');
|
||||
}
|
||||
// 获取失败退出登录
|
||||
await userStore.logout();
|
||||
next({
|
||||
|
||||
@@ -177,8 +177,8 @@ export default defineStore('cache', {
|
||||
},
|
||||
|
||||
// 查询监控告警策略列表
|
||||
async loadMonitorAlarmPolicy(force = false) {
|
||||
return await this.load('alarmPolicy', getAlarmPolicyList, ['monitor:alarm-policy:query'], force);
|
||||
async loadMonitorAlarmPolicy(type: string = 'all', force = false) {
|
||||
return await this.load(`alarmPolicy_${type}`, () => getAlarmPolicyList(type), ['monitor:alarm-policy:query'], force);
|
||||
},
|
||||
|
||||
// 查询监控指标列表
|
||||
|
||||
@@ -7,7 +7,7 @@ export type CacheType = 'users' | 'menus' | 'roles'
|
||||
| 'authorizedHostKeys' | 'authorizedHostIdentities'
|
||||
| 'commandSnippetGroups' | 'pathBookmarkGroups'
|
||||
| 'commandSnippets' | 'pathBookmarks'
|
||||
| 'alarmPolicy' | 'monitorMetrics'
|
||||
| 'alarmPolicy_*' | 'monitorMetrics'
|
||||
| 'systemSetting' | 'notifyTemplate*'
|
||||
| '*_Tags' | 'preference_*'
|
||||
| string
|
||||
|
||||
@@ -7,6 +7,7 @@ import { clearToken, setToken } from '@/utils/auth';
|
||||
import { removeRouteListener } from '@/utils/route-listener';
|
||||
import { getUserAggregateInfo } from '@/api/user/user-aggregate';
|
||||
import { useAppStore, useCacheStore, useMenuStore, useTabBarStore, useTipsStore } from '@/store';
|
||||
import { ApiError } from '@/api/error';
|
||||
|
||||
const CHECK_APP_VERSION_KEY = 'check-app-version';
|
||||
|
||||
@@ -67,9 +68,13 @@ export default defineStore('user', {
|
||||
|
||||
// 获取用户信息
|
||||
async getUserInfo() {
|
||||
const { data: { data }, headers } = await getUserAggregateInfo();
|
||||
const resp = await getUserAggregateInfo();
|
||||
const { data: { code, msg, data }, headers } = resp;
|
||||
// 检查版本更新
|
||||
checkForVersionUpdate(headers?.['x-app-version']);
|
||||
if (code !== 200) {
|
||||
throw new ApiError(msg, resp);
|
||||
}
|
||||
// 设置用户信息
|
||||
this.setUserInfo({
|
||||
id: data.user.id,
|
||||
|
||||
@@ -12,7 +12,7 @@ export const encrypt = async (data: string | undefined): Promise<string | undefi
|
||||
return data;
|
||||
}
|
||||
// 获取公钥
|
||||
const publicKey = (await useCacheStore().loadSystemSetting()).encrypt_publicKey;
|
||||
const publicKey = (await useCacheStore().loadSystemSetting())['encrypt.public-key'];
|
||||
const encryptor = new JSEncrypt();
|
||||
encryptor.setPublicKey(publicKey);
|
||||
|
||||
|
||||
@@ -99,12 +99,14 @@
|
||||
<a-table v-model:selected-keys="selectedKeys"
|
||||
row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:row-selection="rowSelection"
|
||||
:columns="tableColumns"
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 连接用户 -->
|
||||
|
||||
@@ -53,11 +53,13 @@
|
||||
<!-- table -->
|
||||
<a-table row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableRenderData"
|
||||
:pagination="false"
|
||||
:bordered="false">
|
||||
:bordered="false"
|
||||
:column-resizable="true">
|
||||
<!-- 连接用户 -->
|
||||
<template #username="{ record }">
|
||||
{{ record.username }}
|
||||
|
||||
@@ -83,12 +83,14 @@
|
||||
<a-table v-model:selected-keys="selectedKeys"
|
||||
row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:row-selection="rowSelection"
|
||||
:columns="tableColumns"
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 操作用户 -->
|
||||
|
||||
@@ -17,14 +17,15 @@
|
||||
@on-selected="clickGroup" />
|
||||
<a-divider direction="vertical" />
|
||||
<!-- 主机表格 -->
|
||||
<a-table class="group-main-hosts"
|
||||
row-key="id"
|
||||
<a-table row-key="id"
|
||||
class="group-main-hosts table-resize"
|
||||
:sticky-header="true"
|
||||
:loading="loading"
|
||||
:columns="hostColumns"
|
||||
:data="selectedGroupHosts"
|
||||
:pagination="false"
|
||||
:bordered="false">
|
||||
:bordered="false"
|
||||
:column-resizable="true">
|
||||
<!-- 空状态 -->
|
||||
<template #empty>
|
||||
<a-empty style="margin: 32px 0;" description="当前分组内无主机" />
|
||||
|
||||
@@ -8,14 +8,15 @@
|
||||
<!-- 主机身份表格 -->
|
||||
<a-table v-model:selected-keys="selectedKeys"
|
||||
row-key="id"
|
||||
class="host-identity-main-table"
|
||||
class="table-resize host-identity-main-table"
|
||||
:columns="hostIdentityColumns"
|
||||
:row-selection="rowSelection"
|
||||
row-class="pointer"
|
||||
:sticky-header="true"
|
||||
:data="hostIdentities"
|
||||
:sticky-header="true"
|
||||
:pagination="false"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
@row-click="clickRow">
|
||||
<!-- 类型 -->
|
||||
<template #type="{ record }">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<!-- 主机密钥表格 -->
|
||||
<a-table v-model:selected-keys="selectedKeys"
|
||||
row-key="id"
|
||||
class="host-key-main-table"
|
||||
class="table-resize host-key-main-table"
|
||||
:columns="hostKeyColumns"
|
||||
:row-selection="rowSelection"
|
||||
row-class="pointer"
|
||||
@@ -16,6 +16,7 @@
|
||||
:data="hostKeys"
|
||||
:pagination="false"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
@row-click="clickRow" />
|
||||
</grant-layout>
|
||||
</template>
|
||||
|
||||
@@ -111,12 +111,14 @@
|
||||
<a-table v-model:selected-keys="selectedKeys"
|
||||
row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="tableColumns"
|
||||
:row-selection="rowSelection"
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 类型 -->
|
||||
|
||||
@@ -94,12 +94,14 @@
|
||||
<a-table v-model:selected-keys="selectedKeys"
|
||||
row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="tableColumns"
|
||||
:row-selection="rowSelection"
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 操作 -->
|
||||
|
||||
@@ -230,7 +230,7 @@
|
||||
<a-button v-for="type in record.types"
|
||||
:key="type"
|
||||
size="mini"
|
||||
@click="openNewRoute({ name: 'terminal', query: { connect: record.id, type} })">
|
||||
@click="openNewRoute({ name: 'terminal', query: { connect: record.id, type }})">
|
||||
{{ type }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
|
||||
@@ -146,12 +146,14 @@
|
||||
<a-table v-model:selected-keys="selectedKeys"
|
||||
row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="tableColumns"
|
||||
:row-selection="rowSelection"
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 主机信息 -->
|
||||
@@ -275,7 +277,7 @@
|
||||
<a-button v-for="type in record.types"
|
||||
:key="type"
|
||||
size="mini"
|
||||
@click="openNewRoute({ name: 'terminal', query: { connect: record.id, type} })">
|
||||
@click="openNewRoute({ name: 'terminal', query: { connect: record.id, type }})">
|
||||
{{ type }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
|
||||
@@ -13,11 +13,13 @@
|
||||
<div class="card-body">
|
||||
<!-- 表格 -->
|
||||
<a-table row-key="id"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="batchExecColumns"
|
||||
:data="data.exec?.execLogList || []"
|
||||
:pagination="false"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
:scroll="{ y: 258 }">
|
||||
<!-- 空状态 -->
|
||||
<template #empty>
|
||||
|
||||
@@ -13,11 +13,13 @@
|
||||
<div class="card-body">
|
||||
<!-- 表格 -->
|
||||
<a-table row-key="id"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="terminalLogColumns"
|
||||
:data="data.terminal?.terminalConnectList || []"
|
||||
:pagination="false"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
:scroll="{ y: 258 }">
|
||||
<!-- 空状态 -->
|
||||
<template #empty>
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<a-table row-key="id"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="userLoginColumns"
|
||||
:data="data.infra?.loginHistoryList || []"
|
||||
:pagination="false"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
:scroll="{ y: 388 }">
|
||||
<!-- 登录设备 -->
|
||||
<template #content="{ record }">
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
<!-- table -->
|
||||
<a-table row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="hostColumns"
|
||||
:data="row.hosts"
|
||||
:expandable="expandable"
|
||||
:scroll="{ y: '100%' }"
|
||||
:pagination="false"
|
||||
:bordered="false">
|
||||
:bordered="false"
|
||||
:column-resizable="true">
|
||||
<!-- 执行主机 -->
|
||||
<template #hostName="{ record }">
|
||||
<span class="table-cell-value span-blue">
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
<a-table v-model:selected-keys="selectedKeys"
|
||||
row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="tableColumns"
|
||||
:row-selection="rowSelection"
|
||||
@@ -113,14 +114,15 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)"
|
||||
@expand="loadExecHost">
|
||||
<!-- 展开表格 -->
|
||||
<template #expand-row="{ record }">
|
||||
<exec-command-host-log-table :row="record"
|
||||
@view-command="s => emits('viewCommand', s)"
|
||||
@view-params="s => emits('viewParams', s)"
|
||||
@view-command="(s: any) => emits('viewCommand', s)"
|
||||
@view-params="(s: any) => emits('viewParams', s)"
|
||||
@refresh-host="refreshExecHost" />
|
||||
</template>
|
||||
<!-- 执行命令 -->
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
<!-- table -->
|
||||
<a-table row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="hostColumns"
|
||||
:data="row.hosts"
|
||||
:expandable="expandable"
|
||||
:scroll="{ y: '100%' }"
|
||||
:pagination="false"
|
||||
:bordered="false">
|
||||
:bordered="false"
|
||||
:column-resizable="true">
|
||||
<!-- 执行主机 -->
|
||||
<template #hostName="{ record }">
|
||||
<span class="table-cell-value span-blue">
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
<a-table v-model:selected-keys="selectedKeys"
|
||||
row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="tableColumns"
|
||||
:row-selection="rowSelection"
|
||||
@@ -104,6 +105,7 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)"
|
||||
@expand="loadExecHost">
|
||||
|
||||
@@ -89,12 +89,14 @@
|
||||
<a-table v-model:selected-keys="selectedKeys"
|
||||
row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="tableColumns"
|
||||
:row-selection="rowSelection"
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- cron -->
|
||||
|
||||
@@ -76,12 +76,14 @@
|
||||
<a-table v-model:selected-keys="selectedKeys"
|
||||
row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="tableColumns"
|
||||
:row-selection="rowSelection"
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 模板命令 -->
|
||||
|
||||
@@ -106,12 +106,14 @@
|
||||
<a-table v-model:selected-keys="selectedKeys"
|
||||
row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="tableColumns"
|
||||
:row-selection="rowSelection"
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 上传路径 -->
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
ok-text="清理"
|
||||
:ok-button-props="{ disabled: loading }"
|
||||
:cancel-button-props="{ disabled: loading }"
|
||||
:on-before-ok="handlerOk"
|
||||
:on-before-ok="handleOk"
|
||||
@close="handleClose">
|
||||
<a-spin class="full" :loading="loading">
|
||||
<a-form :model="formModel"
|
||||
@@ -23,12 +23,13 @@
|
||||
placeholder="请选择处理状态"
|
||||
allow-clear />
|
||||
</a-form-item>
|
||||
<!-- 告警主机 -->
|
||||
<a-form-item field="hostId" label="告警主机">
|
||||
<host-selector v-model="formModel.hostId"
|
||||
placeholder="请选择告警主机"
|
||||
hide-button
|
||||
allow-clear />
|
||||
<!-- 告警来源 -->
|
||||
<a-form-item field="agentKey" label="告警来源">
|
||||
<!-- 选择告警来源 -->
|
||||
<monitor-host-selector v-if="sourceType === AlarmSourceType.HOST"
|
||||
v-model="formModel.agentKey"
|
||||
placeholder="请选择告警来源"
|
||||
allow-clear />
|
||||
</a-form-item>
|
||||
<!-- 告警级别 -->
|
||||
<a-form-item field="alarmLevel" label="告警级别">
|
||||
@@ -58,7 +59,7 @@
|
||||
allow-clear />
|
||||
</a-form-item>
|
||||
<!-- 数据集 -->
|
||||
<a-form-item field="metricsId" label="数据集">
|
||||
<a-form-item field="metricsMeasurement" label="数据集">
|
||||
<a-select v-model="formModel.metricsMeasurement"
|
||||
:options="toOptions(MetricsMeasurementKey)"
|
||||
placeholder="数据集"
|
||||
@@ -85,12 +86,6 @@
|
||||
hide-button
|
||||
allow-clear />
|
||||
</a-form-item>
|
||||
<!-- agentKey -->
|
||||
<a-form-item field="agentKey" label="agentKey">
|
||||
<a-input v-model="formModel.agentKey"
|
||||
placeholder="请输入agentKey"
|
||||
allow-clear />
|
||||
</a-form-item>
|
||||
<!-- 告警时间 -->
|
||||
<a-form-item field="createTimeRange" label="告警时间">
|
||||
<a-range-picker v-model="formModel.createTimeRange"
|
||||
@@ -118,21 +113,25 @@
|
||||
import useVisible from '@/hooks/visible';
|
||||
import { Message, Modal } from '@arco-design/web-vue';
|
||||
import { useDictStore } from '@/store';
|
||||
import { maxClearLimit, HandleStatusKey, AlarmLevelKey, MetricsMeasurementKey, FalseAlarmKey } from '../types/const';
|
||||
import { maxClearLimit, HandleStatusKey, AlarmLevelKey, MetricsMeasurementKey, FalseAlarmKey, AlarmSourceType } from '../types/const';
|
||||
import { assignOmitRecord } from '@/utils';
|
||||
import UserSelector from '@/components/user/user/selector/index.vue';
|
||||
import HostSelector from '@/components/asset/host/selector/index.vue';
|
||||
import MonitorMetricsSelector from '@/components/monitor/metrics/selector/index.vue';
|
||||
import AlarmPolicySelector from '@/components/monitor/alarm-policy/selector/index.vue';
|
||||
import MonitorHostSelector from '@/components/monitor/host/selector/index.vue';
|
||||
|
||||
const { toOptions } = useDictStore();
|
||||
const { visible, setVisible } = useVisible();
|
||||
const { loading, setLoading } = useLoading();
|
||||
|
||||
const props = defineProps<{
|
||||
sourceType: string;
|
||||
}>();
|
||||
|
||||
const defaultForm = (): AlarmEventQueryRequest => {
|
||||
return {
|
||||
id: undefined,
|
||||
hostId: undefined,
|
||||
sourceType: undefined,
|
||||
agentKey: undefined,
|
||||
policyId: undefined,
|
||||
metricsId: undefined,
|
||||
@@ -160,7 +159,7 @@
|
||||
defineExpose({ open });
|
||||
|
||||
// 确定
|
||||
const handlerOk = async () => {
|
||||
const handleOk = async () => {
|
||||
if (!formModel.value.limit) {
|
||||
Message.error('请输入数量限制');
|
||||
return false;
|
||||
@@ -170,7 +169,7 @@
|
||||
// 获取总数量
|
||||
const { data } = await getAlarmEventCount(formModel.value);
|
||||
if (data) {
|
||||
// 清理
|
||||
// 清空
|
||||
doClear(data);
|
||||
} else {
|
||||
// 无数据
|
||||
@@ -195,9 +194,7 @@
|
||||
const { data } = await clearMonitorAlarmEvent(formModel.value);
|
||||
Message.success(`已成功清理 ${data} 条数据`);
|
||||
emits('clear');
|
||||
// 清空
|
||||
setVisible(false);
|
||||
handlerClear();
|
||||
handleClose();
|
||||
} catch (e) {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
@@ -208,11 +205,12 @@
|
||||
|
||||
// 关闭
|
||||
const handleClose = () => {
|
||||
handlerClear();
|
||||
handleClear();
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
// 清空
|
||||
const handlerClear = () => {
|
||||
const handleClear = () => {
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
ok-text="处理"
|
||||
:ok-button-props="{ disabled: loading }"
|
||||
:cancel-button-props="{ disabled: loading }"
|
||||
:on-before-ok="handlerOk"
|
||||
:on-before-ok="handleOk"
|
||||
@close="handleClose">
|
||||
<a-spin class="full" :loading="loading">
|
||||
<a-form ref="formRef"
|
||||
@@ -90,7 +90,7 @@
|
||||
defineExpose({ open });
|
||||
|
||||
// 确定
|
||||
const handlerOk = async () => {
|
||||
const handleOk = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
// 验证参数
|
||||
@@ -102,8 +102,7 @@
|
||||
await handleAlarmEvent(formModel.value);
|
||||
Message.success('已处理');
|
||||
emits('handled', { ...formModel.value });
|
||||
// 清空
|
||||
handlerClear();
|
||||
handleClose();
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
@@ -114,13 +113,13 @@
|
||||
|
||||
// 关闭
|
||||
const handleClose = () => {
|
||||
handlerClear();
|
||||
handleClear();
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
// 清空
|
||||
const handlerClear = () => {
|
||||
const handleClear = () => {
|
||||
setLoading(false);
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<a-button v-if="showClearButton"
|
||||
v-permission="['monitor:alarm-event:management:clear']"
|
||||
status="danger"
|
||||
@click="$emit('openClear', formModel)">
|
||||
@click="openClear">
|
||||
清理
|
||||
<template #icon>
|
||||
<icon-close />
|
||||
@@ -26,7 +26,7 @@
|
||||
<a-button v-permission="['monitor:alarm-event:handle']"
|
||||
type="primary"
|
||||
:disabled="selectedKeys.length === 0"
|
||||
@click="$emit('openHandle', selectedKeys)">
|
||||
@click="openHandle(selectedKeys)">
|
||||
处理告警
|
||||
<template #icon>
|
||||
<icon-play-arrow-fill />
|
||||
@@ -65,32 +65,36 @@
|
||||
<a-table v-model:selected-keys="selectedKeys"
|
||||
row-key="id"
|
||||
ref="tableRef"
|
||||
class="table-resize"
|
||||
:loading="loading"
|
||||
:columns="tableColumns"
|
||||
:row-selection="rowSelection"
|
||||
:data="tableData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:column-resizable="true"
|
||||
:scroll="{ x: 'auto' }"
|
||||
@page-change="(page: number) => $emit('query', page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => $emit('query', 1, size)">
|
||||
<!-- 主机信息 -->
|
||||
<template #hostInfo="{ record }">
|
||||
<!-- 来源信息 -->
|
||||
<template #sourceInfo="{ record }">
|
||||
<div class="info-wrapper">
|
||||
<div class="info-item">
|
||||
<!-- 主机名称 -->
|
||||
<div v-if="record.sourceType === AlarmSourceType.HOST && record.sourceInfo?.name" class="info-item">
|
||||
<span class="info-label">主机名称</span>
|
||||
<span class="info-value text-copy text-ellipsis"
|
||||
:title="record.hostName"
|
||||
@click="copy(record.hostName, true)">
|
||||
{{ record.hostName }}
|
||||
:title="record.sourceInfo.name"
|
||||
@click="copy(record.sourceInfo.name, true)">
|
||||
{{ record.sourceInfo.name }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<!-- 主机地址 -->
|
||||
<div v-if="record.sourceType === AlarmSourceType.HOST && record.sourceInfo?.address" class="info-item">
|
||||
<span class="info-label">主机地址</span>
|
||||
<span class="info-value span-blue text-copy text-ellipsis"
|
||||
:title="record.hostAddress"
|
||||
@click="copy(record.hostAddress, true)">
|
||||
{{ record.hostAddress }}
|
||||
:title="record.sourceInfo.address"
|
||||
@click="copy(record.sourceInfo.address, true)">
|
||||
{{ record.sourceInfo.address }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -147,7 +151,7 @@
|
||||
<a-button v-permission="['monitor:alarm-event:handle']"
|
||||
type="text"
|
||||
size="mini"
|
||||
@click="$emit('openHandle', [record.id])">
|
||||
@click="openHandle([record.id])">
|
||||
处理
|
||||
</a-button>
|
||||
<!-- 更多 -->
|
||||
@@ -171,6 +175,13 @@
|
||||
</div>
|
||||
</template>
|
||||
</a-table>
|
||||
<!-- 处理模态框-->
|
||||
<alarm-event-handle-modal ref="handleModal"
|
||||
@handled="alarmHandled" />
|
||||
<!-- 清理模态框-->
|
||||
<alarm-event-clear-modal ref="clearModal"
|
||||
:source-type="sourceType"
|
||||
@clear="emits('reload')" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
@@ -181,28 +192,33 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { PaginationProps } from '@arco-design/web-vue';
|
||||
import type { MetricsQueryResponse } from '@/api/monitor/metrics';
|
||||
import type { AlarmEventQueryRequest, AlarmEventQueryResponse, AlarmEventHandleRequest } from '@/api/monitor/alarm-event';
|
||||
import { h, ref } from 'vue';
|
||||
import { batchDeleteAlarmEvent, setAlarmEventFalse } from '@/api/monitor/alarm-event';
|
||||
import { Message, Modal, Space, Tag, type PaginationProps } from '@arco-design/web-vue';
|
||||
import { Message, Modal, Space, Tag } from '@arco-design/web-vue';
|
||||
import {
|
||||
FalseAlarm,
|
||||
HandleStatusKey,
|
||||
FalseAlarmKey,
|
||||
MetricsMeasurementKey,
|
||||
AlarmLevelKey,
|
||||
TriggerConditionKey
|
||||
} from '@/views/monitor/alarm-event/types/const';
|
||||
TriggerConditionKey,
|
||||
AlarmSourceType
|
||||
} from '../types/const';
|
||||
import { useRowSelection, useTableColumns } from '@/hooks/table';
|
||||
import { copy } from '@/hooks/copy';
|
||||
import { useQueryOrder, DESC } from '@/hooks/query-order';
|
||||
import { useDictStore, useCacheStore, useUserStore } from '@/store';
|
||||
import { MetricsUnit, MetricUnitFormatter } from '@/utils/metrics';
|
||||
import TableAdjust from '@/components/app/table-adjust/index.vue';
|
||||
import AlarmEventClearModal from './alarm-event-clear-modal.vue';
|
||||
import AlarmEventHandleModal from './alarm-event-handle-modal.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
tableName: string;
|
||||
sourceType: string;
|
||||
columns: any[];
|
||||
tableData: AlarmEventQueryResponse[];
|
||||
loading: boolean;
|
||||
@@ -212,25 +228,38 @@
|
||||
}>();
|
||||
|
||||
const emits = defineEmits<{
|
||||
openHandle: [ids: number[]];
|
||||
openClear: [formData: AlarmEventQueryRequest];
|
||||
reload: [];
|
||||
setLoading: [loading: boolean];
|
||||
query: [page?: number, pageSize?: number];
|
||||
}>();
|
||||
|
||||
const rowSelection = useRowSelection();
|
||||
const userStore = useUserStore();
|
||||
const cacheStore = useCacheStore();
|
||||
const queryOrder = useQueryOrder(props.tableName, DESC);
|
||||
const { tableColumns, columnsHook } = useTableColumns(props.tableName, props.columns);
|
||||
const { monitorMetrics } = useCacheStore();
|
||||
const { getDictValue } = useDictStore();
|
||||
|
||||
const handleModal = ref();
|
||||
const clearModal = ref();
|
||||
const selectedKeys = ref<Array<number>>([]);
|
||||
|
||||
// 告警处理回调
|
||||
const alarmHandled = (request: Required<AlarmEventHandleRequest>) => {
|
||||
props.tableData.filter(s => (request.idList || []).includes(s.id)).forEach(s => {
|
||||
s.handleTime = request.handleTime;
|
||||
s.handleStatus = request.handleStatus;
|
||||
s.handleRemark = request.handleRemark;
|
||||
s.handleUserId = userStore.id as number;
|
||||
s.handleUsername = userStore.username as string;
|
||||
});
|
||||
selectedKeys.value = [];
|
||||
};
|
||||
|
||||
// 获取指标名称
|
||||
const getMetricsField = (metricsId: number, field: string) => {
|
||||
return (monitorMetrics as Array<MetricsQueryResponse> || []).find(m => m.id === metricsId)?.[field];
|
||||
};
|
||||
return (cacheStore.monitorMetrics as Array<MetricsQueryResponse> || []).find(m => m.id === metricsId)?.[field];
|
||||
};
|
||||
|
||||
// 提取标签
|
||||
const extraTags = (record: AlarmEventQueryResponse) => {
|
||||
@@ -303,19 +332,15 @@
|
||||
});
|
||||
};
|
||||
|
||||
// 告警处理回调
|
||||
const alarmHandled = (request: Required<AlarmEventHandleRequest>) => {
|
||||
props.tableData.filter(s => (request.idList || []).includes(s.id)).forEach(s => {
|
||||
s.handleTime = request.handleTime;
|
||||
s.handleStatus = request.handleStatus;
|
||||
s.handleRemark = request.handleRemark;
|
||||
s.handleUserId = userStore.id as number;
|
||||
s.handleUsername = userStore.username as string;
|
||||
});
|
||||
selectedKeys.value = [];
|
||||
// 打开处理
|
||||
const openHandle = (idList: Array<number>) => {
|
||||
handleModal.value.open(idList);
|
||||
};
|
||||
|
||||
defineExpose({ alarmHandled });
|
||||
// 打开清理
|
||||
const openClear = () => {
|
||||
clearModal.value.open(props.formModel);
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@@ -13,12 +13,13 @@
|
||||
placeholder="请选择处理状态"
|
||||
allow-clear />
|
||||
</a-form-item>
|
||||
<!-- 告警主机 -->
|
||||
<a-form-item field="hostId" label="告警主机">
|
||||
<host-selector v-model="formModel.hostId"
|
||||
placeholder="请选择告警主机"
|
||||
hide-button
|
||||
allow-clear />
|
||||
<!-- 告警来源 -->
|
||||
<a-form-item field="agentKey" label="告警来源">
|
||||
<!-- 选择告警来源 -->
|
||||
<monitor-host-selector v-if="sourceType === AlarmSourceType.HOST"
|
||||
v-model="formModel.agentKey"
|
||||
placeholder="请选择告警来源"
|
||||
allow-clear />
|
||||
</a-form-item>
|
||||
<!-- 告警级别 -->
|
||||
<a-form-item field="alarmLevel" label="告警级别">
|
||||
@@ -75,12 +76,6 @@
|
||||
hide-button
|
||||
allow-clear />
|
||||
</a-form-item>
|
||||
<!-- agentKey -->
|
||||
<a-form-item field="agentKey" label="agentKey">
|
||||
<a-input v-model="formModel.agentKey"
|
||||
placeholder="请输入agentKey"
|
||||
allow-clear />
|
||||
</a-form-item>
|
||||
<!-- 告警时间 -->
|
||||
<a-form-item field="createTimeRange" label="告警时间">
|
||||
<a-range-picker v-model="formModel.createTimeRange"
|
||||
@@ -92,7 +87,7 @@
|
||||
</query-header>
|
||||
</a-card>
|
||||
<!-- 表格 -->
|
||||
<alarm-event-table-base ref="eventTable"
|
||||
<alarm-event-table-base :source-type="sourceType"
|
||||
:table-name="TableName"
|
||||
:columns="columns"
|
||||
:table-data="tableRenderData"
|
||||
@@ -100,9 +95,8 @@
|
||||
:form-model="formModel"
|
||||
:pagination="pagination"
|
||||
:show-clear-button="true"
|
||||
@open-handle="emits('openHandle', $event)"
|
||||
@open-clear="emits('openClear', formModel)"
|
||||
@set-loading="setLoading"
|
||||
@reload="reload"
|
||||
@query="fetchTableData" />
|
||||
</template>
|
||||
|
||||
@@ -113,25 +107,26 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { AlarmEventQueryRequest, AlarmEventQueryResponse, AlarmEventHandleRequest } from '@/api/monitor/alarm-event';
|
||||
import type { AlarmEventQueryRequest, AlarmEventQueryResponse } from '@/api/monitor/alarm-event';
|
||||
import { reactive, ref, onMounted } from 'vue';
|
||||
import { getAlarmEventPage } from '@/api/monitor/alarm-event';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import columns from '../types/table.columns';
|
||||
import { TableName, FalseAlarm, HandleStatusKey, FalseAlarmKey, MetricsMeasurementKey, AlarmLevelKey } from '../types/const';
|
||||
import { TableName, FalseAlarm, HandleStatusKey, FalseAlarmKey, MetricsMeasurementKey, AlarmLevelKey, AlarmSourceType } from '../types/const';
|
||||
import { useTablePagination } from '@/hooks/table';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useDictStore } from '@/store';
|
||||
import { useDictStore, useUserStore } from '@/store';
|
||||
import { useQueryOrder, DESC } from '@/hooks/query-order';
|
||||
import UserSelector from '@/components/user/user/selector/index.vue';
|
||||
import HostSelector from '@/components/asset/host/selector/index.vue';
|
||||
import MonitorMetricsSelector from '@/components/monitor/metrics/selector/index.vue';
|
||||
import AlarmPolicySelector from '@/components/monitor/alarm-policy/selector/index.vue';
|
||||
import AlarmEventTableBase from './alarm-event-table-base.vue';
|
||||
import MonitorHostSelector from '@/components/monitor/host/selector/index.vue';
|
||||
|
||||
const emits = defineEmits(['openHandle', 'openClear']);
|
||||
const props = defineProps<{
|
||||
sourceType: string;
|
||||
}>();
|
||||
|
||||
const eventTable = ref();
|
||||
const pagination = useTablePagination();
|
||||
const { toOptions } = useDictStore();
|
||||
const { loading, setLoading } = useLoading();
|
||||
@@ -139,8 +134,8 @@
|
||||
const tableRenderData = ref<Array<AlarmEventQueryResponse>>([]);
|
||||
const formModel = reactive<AlarmEventQueryRequest>({
|
||||
id: undefined,
|
||||
sourceType: props.sourceType,
|
||||
agentKey: undefined,
|
||||
hostId: undefined,
|
||||
policyId: undefined,
|
||||
metricsId: undefined,
|
||||
metricsMeasurement: undefined,
|
||||
@@ -158,12 +153,7 @@
|
||||
fetchTableData();
|
||||
};
|
||||
|
||||
// 告警处理回调
|
||||
const alarmHandled = (request: Required<AlarmEventHandleRequest>) => {
|
||||
eventTable.value.alarmHandled(request);
|
||||
};
|
||||
|
||||
defineExpose({ reload, alarmHandled });
|
||||
defineExpose({ reload });
|
||||
|
||||
// 加载数据
|
||||
const doFetchTableData = async (request: AlarmEventQueryRequest) => {
|
||||
@@ -186,10 +176,17 @@
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
const key = useRoute().query.key as string;
|
||||
const route = useRoute();
|
||||
const key = route.query.key as string;
|
||||
if (key) {
|
||||
formModel.id = Number.parseInt(key);
|
||||
}
|
||||
// 当前用户
|
||||
const action = route.query.action as string;
|
||||
if (action === 'self') {
|
||||
formModel.handleUserId = useUserStore().id;
|
||||
}
|
||||
// 查询数据
|
||||
fetchTableData();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
<template>
|
||||
<div class="layout-container" v-if="render">
|
||||
<!-- 列表-表格 -->
|
||||
<alarm-event-table ref="table"
|
||||
@open-handle="(e: any) => handleModal.open(e)"
|
||||
@open-clear="(e: any) => clearModal.open(e)" />
|
||||
<!-- 处理模态框-->
|
||||
<alarm-event-handle-modal ref="handleModal"
|
||||
@handled="(e: any) => table.alarmHandled(e)" />
|
||||
<!-- 清理模态框-->
|
||||
<alarm-event-clear-modal ref="clearModal"
|
||||
@clear="() => table.reload()" />
|
||||
<alarm-event-table :source-type="AlarmSourceType.HOST" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -22,20 +14,18 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, onBeforeMount } from 'vue';
|
||||
import { useDictStore, useCacheStore } from '@/store';
|
||||
import { dictKeys } from './types/const';
|
||||
import { dictKeys, AlarmSourceType } from './types/const';
|
||||
import AlarmEventTable from './components/alarm-event-table.vue';
|
||||
import AlarmEventClearModal from './components/alarm-event-clear-modal.vue';
|
||||
import AlarmEventHandleModal from './components/alarm-event-handle-modal.vue';
|
||||
|
||||
const render = ref(false);
|
||||
const table = ref();
|
||||
const handleModal = ref();
|
||||
const clearModal = ref();
|
||||
|
||||
onBeforeMount(async () => {
|
||||
const cacheStore = useCacheStore();
|
||||
// 加载告警策略
|
||||
await cacheStore.loadMonitorAlarmPolicy();
|
||||
// 加载指标列表
|
||||
await cacheStore.loadMonitorMetricsList();
|
||||
// 加载字典值
|
||||
const dictStore = useDictStore();
|
||||
await dictStore.loadKeys(dictKeys);
|
||||
render.value = true;
|
||||
|
||||
@@ -11,6 +11,12 @@ export const FalseAlarm = {
|
||||
FALSE: 0,
|
||||
};
|
||||
|
||||
// 告警来源类型
|
||||
export const AlarmSourceType = {
|
||||
HOST: 'HOST',
|
||||
UPTIME: 'UPTIME',
|
||||
};
|
||||
|
||||
// 告警条件 字典项
|
||||
export const TriggerConditionKey = 'alarmTriggerCondition';
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user