Files
aiops/agent/collector/network.go
T
attacker f3a9e5e8d0 feat: 重构监控中心导航,新增资源监控4大模块
- 主菜单「监控告警」→「监控中心」
- 「告警中心」→「告警服务」移至链路追踪下方
- 新增资源监控 Tab 页(主机/中间件/SNMP/站点拨测)
- Agent 新增网络采集器(network)和磁盘IO采集器(diskio)
- 后端扩展 Agent 上报模型,支持 NetworkStat/DiskIOStat
- 前端 ServerTableRow 展示网络和磁盘IO实时指标
- WebSocket MetricsUpdate 推送扩展
2026-06-18 09:30:45 +00:00

172 lines
4.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package collector 提供服务器各项系统指标的采集能力。
// 本文件实现网络连接数、网卡流量等网络指标采集。
//
// 署名 Hermes (extended from Logan.Li pattern)
package collector
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"sync"
"time"
"ezops/agent/model"
)
// netSample 保存上一次的网络采样数据,用于计算速率
type netSample struct {
time time.Time
rxBytes uint64
txBytes uint64
}
// NetworkCollector 网络指标采集器
type NetworkCollector struct {
mu sync.Mutex
prev *netSample
}
// NewNetworkCollector 创建网络采集器
func NewNetworkCollector() *NetworkCollector {
return &NetworkCollector{}
}
// Collect 采集网络指标(并发连接数、TIME_WAIT、网卡 rx/tx B/s)
func (c *NetworkCollector) Collect() (model.NetworkStat, error) {
stat := model.NetworkStat{}
// 1. 采集 TCP 连接统计
if tcpStat, err := readSockStat(); err == nil {
stat.TCPEstablished = tcpStat.established
stat.TCPTimeWait = tcpStat.timeWait
stat.TCPTotal = tcpStat.total
}
// 2. 采集网卡流量(取所有非 lo 网卡合计)
curRx, curTx, nicName, err := readNetDevTotal()
if err != nil {
return stat, fmt.Errorf("读取网卡流量失败: %w", err)
}
stat.NicName = nicName
c.mu.Lock()
defer c.mu.Unlock()
now := time.Now()
cur := &netSample{time: now, rxBytes: curRx, txBytes: curTx}
if c.prev != nil && now.After(c.prev.time) {
elapsed := now.Sub(c.prev.time).Seconds()
if elapsed > 0 && cur.rxBytes >= c.prev.rxBytes && cur.txBytes >= c.prev.txBytes {
stat.NetRxBPS = float64(cur.rxBytes-c.prev.rxBytes) / elapsed
stat.NetTxBPS = float64(cur.txBytes-c.prev.txBytes) / elapsed
}
}
c.prev = cur
return stat, nil
}
// tcpSockStat 解析 /proc/net/sockstat 或 /proc/net/tcp 的结果
type tcpSockStat struct {
established int
timeWait int
total int
}
// readSockStat 从 /proc/net/sockstat 读取 TCP 连接统计
func readSockStat() (tcpSockStat, error) {
var result tcpSockStat
f, err := os.Open("/proc/net/sockstat")
if err != nil {
// Fallback: try /proc/net/sockstat6
return result, err
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
if !strings.HasPrefix(line, "TCP:") {
continue
}
// 格式: "TCP: inuse 123 orphan 0 tw 45 alloc 200 mem 30"
fields := strings.Fields(line)
for i, f := range fields {
switch f {
case "inuse":
if i+1 < len(fields) {
result.established, _ = strconv.Atoi(fields[i+1])
}
case "tw":
if i+1 < len(fields) {
result.timeWait, _ = strconv.Atoi(fields[i+1])
}
case "alloc":
if i+1 < len(fields) {
result.total, _ = strconv.Atoi(fields[i+1])
}
}
}
result.total = result.established // total = established count (inuse)
break
}
return result, scanner.Err()
}
// readNetDevTotal 读取 /proc/net/dev,取第一个非 lo 且活跃的物理网卡总流量
func readNetDevTotal() (rxBytes, txBytes uint64, nicName string, err error) {
f, err := os.Open("/proc/net/dev")
if err != nil {
return 0, 0, "", err
}
defer f.Close()
scanner := bufio.NewScanner(f)
// Skip header lines (first 2 lines)
lineNum := 0
for scanner.Scan() {
lineNum++
if lineNum <= 2 {
continue
}
line := strings.TrimSpace(scanner.Text())
parts := strings.SplitN(line, ":", 2)
if len(parts) != 2 {
continue
}
name := strings.TrimSpace(parts[0])
// Skip loopback and virtual interfaces
if name == "lo" || strings.HasPrefix(name, "veth") || strings.HasPrefix(name, "docker") ||
strings.HasPrefix(name, "br-") || strings.HasPrefix(name, "virbr") {
continue
}
fields := strings.Fields(parts[1])
if len(fields) < 10 {
continue
}
// fields[0]=rx_bytes, fields[8]=tx_bytes
rb, _ := strconv.ParseUint(fields[0], 10, 64)
tb, _ := strconv.ParseUint(fields[8], 10, 64)
if rb > 0 || tb > 0 {
nicName = name
rxBytes += rb
txBytes += tb
}
}
if nicName == "" {
return 0, 0, "eth0", nil
}
return rxBytes, txBytes, nicName, scanner.Err()
}