feat: 监控告警体系统一重构 + 自动化任务调度引擎 + 监控大屏拆分

告警中心
- 新增统一告警(alert_unified)、监控告警规则(monitor_alert_rule)、指标目录(alert_metric_catalog)
- 通知策略与消息分发(alert_notify_policy/dispatch/message)、静默规则
- 告警引擎按阈值/SNMP 拆分(alert_engine_monitor/snmp)

监控采集
- SNMP 常量/模板与历史指标(snmp templates/constants、snmp_metrics_history、snmp_collect)
- 中间件监控 Redis 采集与种子(middleware_monitor_redis/seed)
- 站点探测 pkg(siteprobe) + 站点视图(site_view)

自动化任务
- cron 调度器(cronscheduler)、脚本运行器(scriptrunner)、系统任务(systask)及运行记录(cron_job_run、system_task)

审计与凭证
- 审计设置(audit_setting) + 历史清理(auditcleaner)

前端
- 监控页面(host/middleware/site/snmp)拆分为子模块并大屏化
- 告警中心多 Tab(规则/指标目录/通知策略/静默)、任务管理组件重构、Agent CLI Markdown 渲染
- 移除旧脚本卡片/详情/日志组件,统一为 ScriptTable/ScriptCodeEditor/TerminalOutput

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
LoganandClaude committed 2026-07-01 23:44:45 +08:00
1 parent 092d0e4b9e
commit 471353e3d7
190 files changed
+16640 -3484

No files matched your search

+70 -6
View File
@@ -335,18 +335,82 @@ func (h *AgentHandler) GetLatestReports(c *gin.Context) {
})
}
// parseFlexibleTime 解析前端传入的时间(ISO / datetime-local) // Logan.Li
func parseFlexibleTime(s string) (time.Time, error) {
s = strings.TrimSpace(s)
layouts := []string{
time.RFC3339,
"2006-01-02T15:04:05Z07:00",
"2006-01-02 15:04:05",
"2006-01-02T15:04",
"2006-01-02 15:04",
}
for _, layout := range layouts {
if t, err := time.ParseInLocation(layout, s, time.Local); err == nil {
return t, nil
}
}
return time.Time{}, fmt.Errorf("无法解析时间: %s", s)
}
// resolveHostHistoryRange 解析历史查询时间范围(minutes / hours / start+end) // Logan.Li
func resolveHostHistoryRange(c *gin.Context) (since, until time.Time, err error) {
until = time.Now()
if startStr := strings.TrimSpace(c.Query("start")); startStr != "" {
endStr := strings.TrimSpace(c.Query("end"))
if endStr == "" {
return since, until, fmt.Errorf("自定义范围缺少 end 参数")
}
since, err = parseFlexibleTime(startStr)
if err != nil {
return since, until, err
}
until, err = parseFlexibleTime(endStr)
if err != nil {
return since, until, err
}
if until.Before(since) {
since, until = until, since
}
return since, until, nil
}
if minStr := strings.TrimSpace(c.Query("minutes")); minStr != "" {
mins, _ := strconv.Atoi(minStr)
if mins <= 0 {
mins = 60
}
if mins > 43200 {
mins = 43200
}
since = until.Add(-time.Duration(mins) * time.Minute)
return since, until, nil
}
hours := 1
if v := strings.TrimSpace(c.Query("hours")); v != "" {
hours, _ = strconv.Atoi(v)
if hours <= 0 {
hours = 1
}
if hours > 720 {
hours = 720
}
}
since = until.Add(-time.Duration(hours) * time.Hour)
return since, until, nil
}
// GetHostHistory 获取指定主机的历史指标
// GET /api/v1/agent/history/:hostname?hours=1
// GET /api/v1/agent/history/:hostname?minutes=60 | ?hours=1 | ?start=&end=
func (h *AgentHandler) GetHostHistory(c *gin.Context) {
hostname := c.Param("hostname")
hours := 1
if v := c.Query("hours"); v != "" {
fmt.Sscanf(v, "%d", &hours)
since, until, err := resolveHostHistoryRange(c)
if err != nil {
c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: err.Error()})
return
}
since := time.Now().Add(-time.Duration(hours) * time.Hour)
var reports []model.AgentReport
h.db.Where("hostname = ? AND report_time >= ?", hostname, since).
h.db.Where("hostname = ? AND report_time >= ? AND report_time <= ?", hostname, since, until).
Order("report_time ASC").
Find(&reports)