docs: update README, API reference, dev-log, project structure with Agent monitoring + quick-alarm + latest fixes
- README.md: React 19, default pwd 123456, Docker Compose deploy, correct module list - api-reference.md: add Agent monitoring section (report/latest/rules/quick-setup/alerts/tasks/kline) - dev-log.md: new entry documenting hostname/IP fix, system collector, offline detection, quick alarm - project-structure.md: add agent/ directory, dev-log.md link, React 19
This commit is contained in:
1 parent
c51d0b8b8b
commit
4e3f8cb306
20 files changed
+1315
-1344
No files matched your search
@@ -95,36 +95,74 @@ func (e *AlertEngine) checkResourceAlerts() {
|
||||
}
|
||||
}
|
||||
|
||||
// 检查主机离线(超过 3 分钟无上报)— 内置规则,无需手动创建
|
||||
// 检查主机离线(超过 3 分钟无上报)— 内置规则,无需手动创建。
|
||||
// 以 servers 表为中心:遍历所有服务器,检查其 IP 上是否有 Agent 在最近 3 分钟内上报。
|
||||
// 如果同一 IP 下有多个 Agent hostname,只要有一个在活跃上报,该服务器就算在线。
|
||||
func (e *AlertEngine) checkOfflineAlerts() {
|
||||
offlineThreshold := 3 * time.Minute
|
||||
|
||||
// 查所有曾上报的主机
|
||||
var hostnames []string
|
||||
e.db.Model(&models.AgentReport{}).Distinct("hostname").Pluck("hostname", &hostnames)
|
||||
// 获取所有已登记的主机(去重 IP)
|
||||
var servers []models.Server
|
||||
e.db.Select("ip, hostname").Group("ip").Find(&servers)
|
||||
|
||||
for _, hostname := range hostnames {
|
||||
var report models.AgentReport
|
||||
e.db.Where("hostname = ?", hostname).Order("id DESC").First(&report)
|
||||
if report.ID == 0 {
|
||||
// 收集所有 agent_reports 中活跃上报的主机名(最近 3 分钟内有上报)
|
||||
threeMinAgo := time.Now().Add(-offlineThreshold)
|
||||
|
||||
var activeHostnames []string
|
||||
e.db.Model(&models.AgentReport{}).
|
||||
Where("report_time >= ?", threeMinAgo).
|
||||
Distinct("hostname").
|
||||
Pluck("hostname", &activeHostnames)
|
||||
|
||||
// 对于每个已登记的服务器,检查是否有活跃 Agent
|
||||
for _, s := range servers {
|
||||
if s.IP == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
isOffline := time.Since(report.ReportTime) > offlineThreshold
|
||||
// 检查该 IP 对应的服务器是否有活跃 Agent 上报
|
||||
hasActiveAgent := false
|
||||
for _, h := range activeHostnames {
|
||||
// 通过 hostname 精确匹配或 servers 表 IP 匹配
|
||||
if h == s.Hostname {
|
||||
hasActiveAgent = true
|
||||
break
|
||||
}
|
||||
// 检查该 hostname 的最新上报——其源 IP 是否匹配此 server IP
|
||||
// (通过 servers 表中查找 hostname 对应的 IP)
|
||||
var matchedServer models.Server
|
||||
e.db.Where("hostname = ?", h).First(&matchedServer)
|
||||
if matchedServer.ID > 0 && matchedServer.IP == s.IP {
|
||||
hasActiveAgent = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否有未恢复的离线告警
|
||||
if hasActiveAgent {
|
||||
continue // 有活跃 Agent,在线
|
||||
}
|
||||
|
||||
// 该服务器离线:检查是否已有未恢复的离线告警
|
||||
var existing models.AgentAlert
|
||||
e.db.Where("hostname = ? AND metric = ? AND resolved = ?",
|
||||
hostname, "offline", false).First(&existing)
|
||||
s.Hostname, "offline", false).First(&existing)
|
||||
|
||||
if existing.ID == 0 {
|
||||
// 获取最后一次上报时间计算离线时长
|
||||
var lastReport models.AgentReport
|
||||
e.db.Order("id DESC").First(&lastReport)
|
||||
offlineMinutes := 3.0
|
||||
if lastReport.ID > 0 {
|
||||
offlineMinutes = time.Since(lastReport.ReportTime).Minutes()
|
||||
}
|
||||
|
||||
if isOffline && existing.ID == 0 {
|
||||
alert := models.AgentAlert{
|
||||
RuleName: "主机离线",
|
||||
Hostname: hostname,
|
||||
Hostname: s.Hostname,
|
||||
Metric: "offline",
|
||||
Severity: "critical",
|
||||
Message: fmt.Sprintf("主机 %s 已超过 3 分钟无数据上报,可能已离线", hostname),
|
||||
Value: time.Since(report.ReportTime).Minutes(),
|
||||
Message: fmt.Sprintf("主机 %s (%s) 已超过 3 分钟无数据上报,可能已离线", s.Hostname, s.IP),
|
||||
Value: offlineMinutes,
|
||||
Threshold: 3,
|
||||
}
|
||||
e.db.Create(&alert)
|
||||
|
||||
Reference in new issue
Block a user