feat(alert-center): 添加飞书Webhook通知渠道 + 告警引擎实时通知
- 后端: NotifyChannel 模型新增 feishu 类型, FeishuWebhookConfig - 后端: TestNotifyChannel 真实发送飞书测试消息(文本格式) - 后端: 告警引擎触发/恢复时自动发送飞书通知(sendFeishuAlert/sendFeishuRecovery) - 后端: AlertEngine 新增 tcp_time_wait/tcp_close_wait/service_process 指标检测 - 后端: NetworkStatModel 新增 TCPCloseWait 字段 - 后端: QuickSetupRules 一键创建6条告警规则(CPU/内存/磁盘/TIME_WAIT/CLOSE_WAIT/进程) - 后端: 注册 /alerts/quick-setup 路由 - 前端: AlertChannelDialog 新增飞书类型选项 - 前端: helpers 新增 getChannelIcon/getChannelTypeLabel 支持 feishu/dingtalk/wechat
This commit is contained in:
1 parent
7bc5169e8f
commit
5333f6f04a
30 files changed
+2406
-1001
No files matched your search
@@ -0,0 +1,76 @@
|
||||
// Package collector — Swap 采集器
|
||||
// 从 /proc/meminfo 读取 SwapTotal / SwapFree
|
||||
// 仅当系统有 swap 分区时返回有效数据
|
||||
//
|
||||
// 署名 Logan.Li
|
||||
package collector
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"ezops/agent/model"
|
||||
)
|
||||
|
||||
// SwapCollector 交换分区采集器
|
||||
type SwapCollector struct{}
|
||||
|
||||
// NewSwapCollector 创建 Swap 采集器
|
||||
func NewSwapCollector() *SwapCollector {
|
||||
return &SwapCollector{}
|
||||
}
|
||||
|
||||
// Collect 读取 swap 指标
|
||||
func (s *SwapCollector) Collect() (*model.SwapStat, error) {
|
||||
f, err := os.Open("/proc/meminfo")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var swapTotal, swapFree uint64
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 2 {
|
||||
continue
|
||||
}
|
||||
// Line format: "SwapTotal: 0 kB"
|
||||
key := strings.TrimSuffix(fields[0], ":")
|
||||
switch key {
|
||||
case "SwapTotal":
|
||||
swapTotal, _ = parseUint64(fields[1])
|
||||
case "SwapFree":
|
||||
swapFree, _ = parseUint64(fields[1])
|
||||
}
|
||||
}
|
||||
|
||||
// No swap configured — return nil (caller should omit from report)
|
||||
if swapTotal == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
used := swapTotal - swapFree
|
||||
stat := &model.SwapStat{
|
||||
TotalGB: float64(swapTotal) / (1024.0 * 1024.0),
|
||||
UsedGB: float64(used) / (1024.0 * 1024.0),
|
||||
}
|
||||
if swapTotal > 0 {
|
||||
stat.UsagePercent = float64(used) / float64(swapTotal) * 100.0
|
||||
}
|
||||
return stat, nil
|
||||
}
|
||||
|
||||
// parseUint64 parses a uint64 or returns 0
|
||||
func parseUint64(s string) (uint64, error) {
|
||||
var v uint64
|
||||
for _, c := range s {
|
||||
if c < '0' || c > '9' {
|
||||
break
|
||||
}
|
||||
v = v*10 + uint64(c-'0')
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
Reference in new issue
Block a user