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:
1 parent
092d0e4b9e
commit
471353e3d7
190 files changed
+16640
-3484
No files matched your search
@@ -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)
|
||||
|
||||
|
||||
Reference in new issue
Block a user