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:
attacker committed 2026-06-18 16:11:13 +00:00
1 parent c51d0b8b8b
commit 4e3f8cb306
20 files changed
+1315 -1344

No files matched your search

+69
View File
@@ -0,0 +1,69 @@
// Package collector 实现 AIOps Agent 系统静态信息采集。
// 仅在 Agent 启动时执行一次,采集 OS 版本、内核版本等信息。
//
// 署名 Logan.Li
package collector
import (
"bufio"
"os"
"strings"
)
// SystemInfo 包含系统静态信息(Agent 版本通过编译时注入,非运行时采集)
type SystemInfo struct {
OSVersion string // OS 发行版版本 (如 "Ubuntu 22.04.4 LTS")
Kernel string // 内核版本 (如 "Linux 6.8.0-90-generic")
}
// CollectSystem 采集系统静态信息。
// 从 /etc/os-release 和 /proc/version 读取(Linux 特定)。
// 非 Linux 系统返回空值,不报错。
func CollectSystem() SystemInfo {
info := SystemInfo{}
// 读取 /etc/os-release 获取 PRETTY_NAME
info.OSVersion = readOSRelease()
// 读取 /proc/version 获取内核版本
info.Kernel = readProcVersion()
return info
}
// readOSRelease 从 /etc/os-release 提取 PRETTY_NAME
func readOSRelease() string {
f, err := os.Open("/etc/os-release")
if err != nil {
return ""
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "PRETTY_NAME=") {
// 去除前缀和引号: PRETTY_NAME="Ubuntu 22.04.4 LTS"
val := strings.TrimPrefix(line, "PRETTY_NAME=")
val = strings.Trim(val, `"`)
return val
}
}
return ""
}
// readProcVersion 从 /proc/version 提取内核版本
func readProcVersion() string {
data, err := os.ReadFile("/proc/version")
if err != nil {
return ""
}
// 格式: Linux version 6.8.0-90-generic (...) ...
line := strings.TrimSpace(string(data))
// 提取 "Linux version X.Y.Z-..."
parts := strings.Fields(line)
if len(parts) >= 3 && parts[0] == "Linux" && parts[1] == "version" {
return parts[2]
}
return ""
}
+53
View File
@@ -10,6 +10,7 @@ import (
"context"
"flag"
"log"
"net"
"os"
"os/signal"
"syscall"
@@ -68,6 +69,17 @@ func main() {
diskIOCollector := collector.NewDiskIOCollector()
rep := reporter.New(*server, *token, logger)
// 采集系统静态信息(OS/内核),仅在启动时执行一次
sysInfo := collector.CollectSystem()
logger.Printf("系统信息: OS=%q Kernel=%q", sysInfo.OSVersion, sysInfo.Kernel)
// 探测本机主 IP(用于后端匹配 servers 表)
localIP := detectLocalIP()
logger.Printf("探测本机 IP: %s", localIP)
// 系统信息上报计数器:前 3 次上报携带系统信息,确保后端至少收到一次
sysReportCount := 0
// 初始化任务执行器与任务客户端(与 reporter 复用相同的 server/token/hostname)
taskExecutor := task.New(logger)
taskClient := task.NewClient(*server, *token, hostname, logger)
@@ -83,10 +95,20 @@ func main() {
collectAndReport := func() {
report := &model.Report{
Hostname: hostname,
IP: localIP,
Timestamp: time.Now().UTC().Format(time.RFC3339),
AgentVersion: version,
}
// 前 3 次上报携带系统信息
if sysReportCount < 3 && (sysInfo.OSVersion != "" || sysInfo.Kernel != "") {
report.System = &model.SystemStat{
OSVersion: sysInfo.OSVersion,
Kernel: sysInfo.Kernel,
}
sysReportCount++
}
if stat, err := cpuCollector.Collect(); err != nil {
logger.Printf("CPU 采集异常: %v", err)
} else {
@@ -209,3 +231,34 @@ func maskToken(token string) string {
}
return token[:4] + "****"
}
// detectLocalIP 探测本机主 IP 地址。
// 通过 UDP 连接到公网地址(不实际发包),获取系统路由选择的本机 IP。
// 如果失败,回退到遍历网卡查找非 loopback 的 IPv4 地址。
func detectLocalIP() string {
// 方法1:通过 UDP "连接" 到公网 DNS 获取出口 IP
conn, err := net.Dial("udp", "8.8.8.8:53")
if err == nil {
defer conn.Close()
if addr, ok := conn.LocalAddr().(*net.UDPAddr); ok && addr.IP != nil {
return addr.IP.String()
}
}
// 方法2:遍历网卡
ifaces, err := net.Interfaces()
if err == nil {
for _, iface := range ifaces {
if iface.Flags&net.FlagLoopback != 0 || iface.Flags&net.FlagUp == 0 {
continue
}
addrs, _ := iface.Addrs()
for _, addr := range addrs {
if ipnet, ok := addr.(*net.IPNet); ok && ipnet.IP.To4() != nil {
return ipnet.IP.String()
}
}
}
}
return "unknown"
}
+11 -9
View File
@@ -6,15 +6,17 @@ package model
// Report 为单次采集周期的完整上报报文
type Report struct {
Hostname string `json:"hostname"` // 主机名
Timestamp string `json:"timestamp"` // RFC3339 格式的 UTC 时间戳
AgentVersion string `json:"agent_version"` // Agent 版本号
CPU CPUStat `json:"cpu"` // CPU 指标
Memory MemoryStat `json:"memory"` // 内存指标
Disks []DiskStat `json:"disks"` // 磁盘指标列表
Ports []PortStat `json:"ports"` // 监听端口列表
Network NetworkStat `json:"network"` // 网络指标
DiskIO DiskIOStat `json:"disk_io"` // 磁盘 IO 指标
Hostname string `json:"hostname"` // 主机名
IP string `json:"ip,omitempty"` // 本机 IP(Agent 启动时探测)
Timestamp string `json:"timestamp"` // RFC3339 格式的 UTC 时间戳
AgentVersion string `json:"agent_version"` // Agent 版本号
CPU CPUStat `json:"cpu"` // CPU 指标
Memory MemoryStat `json:"memory"` // 内存指标
Disks []DiskStat `json:"disks"` // 磁盘指标列表
Ports []PortStat `json:"ports"` // 监听端口列表
Network NetworkStat `json:"network"` // 网络指标
DiskIO DiskIOStat `json:"disk_io"` // 磁盘 IO
System *SystemStat `json:"system,omitempty"` // 系统信息(首次采集后携带)
}
// CPUStat CPU 相关指标