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

+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"
}