Files
monitor/agent-windows/main.go
2025-12-07 18:15:50 +08:00

1257 lines
32 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.
//go:build windows
// +build windows
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io"
"log"
stdnet "net"
"net/http"
"os"
"os/exec"
"runtime"
"sort"
"strconv"
"strings"
"sync"
"time"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/mem"
"github.com/shirou/gopsutil/net"
"github.com/shirou/gopsutil/process"
"golang.org/x/text/encoding/simplifiedchinese"
)
// 只在Windows平台下导入wmi包
// Config Agent配置
type Config struct {
ServerURL string `json:"server_url"`
ID string `json:"id"` // Agent唯一标识自动生成
Name string `json:"name"` // Agent显示名称
Token string `json:"token"` // 设备认证令牌
Interval string `json:"interval"` // 采集间隔
Debug bool `json:"debug"` // 调试模式
APIPort int `json:"api_port"` // API端口
}
// NetworkInterfaceMetrics 网卡监控指标
type NetworkInterfaceMetrics struct {
BytesSent uint64 `json:"bytes_sent"` // 发送速率 (bytes/s)
BytesReceived uint64 `json:"bytes_received"` // 接收速率 (bytes/s)
TxBytes uint64 `json:"tx_bytes"` // 累计发送字节数
RxBytes uint64 `json:"rx_bytes"` // 累计接收字节数
}
// DiskMetrics 磁盘监控指标
type DiskMetrics struct {
UsedPercent float64 `json:"used_percent"` // 使用率百分比
Total uint64 `json:"total"` // 总容量 (bytes)
}
// ProcessMetrics 进程监控指标
type ProcessMetrics struct {
Name string `json:"name"` // 进程名
Username string `json:"username"` // 用户名
PID int32 `json:"pid"` // 进程ID
CPU float64 `json:"cpu"` // CPU使用率
Memory float64 `json:"memory"` // 内存使用率
Path string `json:"path"` // 路径
Cmdline string `json:"cmdline"` // 命令行
Ports []int `json:"ports"` // 占用端口
}
// DiskDetailMetrics 磁盘详细信息
type DiskDetailMetrics struct {
ID string `json:"id"` // 磁盘唯一ID数字序列
Path string `json:"path"` // 设备路径
Status string `json:"status"` // 设备状态
Type string `json:"type"` // 设备类型
SizeGB float64 `json:"size_gb"` // 设备大小(GB)
Model string `json:"model"` // 设备型号
Vendor string `json:"vendor"` // 设备厂商
InterfaceType string `json:"interface_type"` // 接口类型
FileSystem string `json:"file_system"` // 文件系统
DiskUUID string `json:"disk_uuid"` // 磁盘UUID
Description string `json:"description"` // 设备描述
}
// LogEntry 系统日志条目
type LogEntry struct {
Sequence int `json:"sequence"` // 日志序号
Source string `json:"source"` // 来源
Time time.Time `json:"time"` // 发生时间
Message string `json:"message"` // 内容
}
// OSInfo 操作系统信息
type OSInfo struct {
Name string `json:"name"` // 操作系统名称
Version string `json:"version"` // 操作系统版本
Arch string `json:"arch"` // 系统架构
Fullname string `json:"fullname"` // 完整名称Name+Version
}
// CPUInfo CPU详细信息
type CPUInfo struct {
Model string `json:"model"` // CPU型号
Cores int `json:"cores"` // 核心数
Threads int `json:"threads"` // 线程数
MaxFreq float64 `json:"max_freq"` // 最大频率 (MHz)
MinFreq float64 `json:"min_freq"` // 最小频率 (MHz)
AvgFreq float64 `json:"avg_freq"` // 平均频率 (MHz)
Usage float64 `json:"usage"` // 当前使用率
}
// MemoryInfo 内存详细信息
type MemoryInfo struct {
Total uint64 `json:"total"` // 总容量 (bytes)
Used uint64 `json:"used"` // 已使用 (bytes)
Free uint64 `json:"free"` // 空闲 (bytes)
UsedPercent float64 `json:"used_percent"` // 使用率百分比
}
// NetworkHardwareInfo 网卡硬件信息
type NetworkHardwareInfo struct {
ID string `json:"id"` // 网卡唯一ID数字序列
Name string `json:"name"` // 网卡名称
MAC string `json:"mac"` // MAC地址
IPAddresses []string `json:"ip_addresses"` // IP地址列表
MTU int `json:"mtu"` // MTU值
Speed int `json:"speed"` // 网卡速度 (Mbps)
Up bool `json:"up"` // 是否启用
}
// HardwareMetrics 硬件信息指标
type HardwareMetrics struct {
OS OSInfo `json:"os"` // 操作系统信息
CPU CPUInfo `json:"cpu"` // CPU信息
Memory MemoryInfo `json:"memory"` // 内存信息
DiskDetails []DiskDetailMetrics `json:"disk_details"` // 磁盘硬件信息
NetworkCards []NetworkHardwareInfo `json:"network_cards"` // 网卡硬件信息
}
// Metrics 监控指标
type Metrics struct {
CPU float64 `json:"cpu"`
CPUHz float64 `json:"cpu_hz"` // CPU频率 (MHz)
Memory float64 `json:"memory"`
Disk map[string]DiskMetrics `json:"disk"`
DiskDetails []DiskDetailMetrics `json:"disk_details"` // 磁盘详细信息
Network map[string]NetworkInterfaceMetrics `json:"network"`
Processes []ProcessMetrics `json:"processes"` // 进程信息
Logs []LogEntry `json:"logs"` // 系统日志
RxTotal uint64 `json:"rx_total"` // 所有网卡累计接收字节数总和
TxTotal uint64 `json:"tx_total"` // 所有网卡累计发送字节数总和
RxRate uint64 `json:"rx_rate"` // 所有网卡实时接收速率总和 (bytes/s)
TxRate uint64 `json:"tx_rate"` // 所有网卡实时发送速率总和 (bytes/s)
// 设备信息字段
AgentID string `json:"agent_id"` // Agent唯一标识
Name string `json:"name"` // 设备名称
IP string `json:"ip"` // 设备IP地址
// 硬件信息
Hardware HardwareMetrics `json:"hardware"` // 硬件详细信息
}
// 全局配置
var config Config
// 保存解析后的时间间隔
var parsedInterval time.Duration
// 命令行参数
var (
// 日志文件路径
logFile string
)
// 保存上一次网络流量采集的数据
type NetworkStats struct {
BytesSent uint64
BytesReceived uint64
}
var (
lastNetworkStats = make(map[string]NetworkStats)
lastCollectTime time.Time
)
// 保存采集到的数据点
var metricsBuffer []*Metrics
var metricsBufferMutex sync.Mutex
// 初始化互斥锁
func init() {
metricsBuffer = make([]*Metrics, 0)
}
// getLocalIP 获取本机IP地址
func getLocalIP() string {
// 获取所有网络接口
interfaces, err := stdnet.Interfaces()
if err != nil {
log.Printf("Failed to get network interfaces: %v", err)
return ""
}
// 遍历网络接口查找非回环、UP状态的IP
for _, iface := range interfaces {
// 跳过回环接口和非UP状态的接口
if iface.Flags&stdnet.FlagLoopback != 0 || iface.Flags&stdnet.FlagUp == 0 {
continue
}
// 获取接口的IP地址
addresses, err := iface.Addrs()
if err != nil {
log.Printf("Failed to get addresses for interface %s: %v", iface.Name, err)
continue
}
// 遍历地址并返回IPv4地址
for _, addr := range addresses {
var ip stdnet.IP
switch v := addr.(type) {
case *stdnet.IPNet:
ip = v.IP
case *stdnet.IPAddr:
ip = v.IP
}
// 跳过IPv6地址和回环地址
if ip == nil || ip.IsLoopback() || ip.To4() == nil {
continue
}
return ip.String()
}
}
// 如果找不到合适的IP尝试另一种方法
conn, err := stdnet.Dial("udp", "8.8.8.8:80")
if err != nil {
log.Printf("Failed to dial UDP: %v", err)
return ""
}
defer conn.Close()
localAddr := conn.LocalAddr().(*stdnet.UDPAddr)
return localAddr.IP.String()
}
// 初始化配置
func initConfig() {
// 默认配置
config = Config{
ServerURL: "http://localhost:8080/api",
ID: "", // 自动生成
Name: "", // 自动生成或从配置读取
Token: "", // 设备认证令牌,从配置或环境变量读取
Interval: "10s",
Debug: false, // 默认非调试模式
APIPort: 8081, // 默认API端口8081
}
// 读取配置文件
readConfigFile()
// 从环境变量读取配置(优先级高于配置文件)
loadFromEnv()
// 生成或确保ID存在
ensureAgentID()
// 确保名称存在
ensureAgentName()
// 保存配置到文件(如果有修改)
saveConfigFile()
// 解析时间间隔
var err error
parsedInterval, err = time.ParseDuration(config.Interval)
if err != nil {
log.Printf("Failed to parse interval: %v, using default 10s", err)
parsedInterval = 10 * time.Second
}
// 打印配置信息
if config.Debug {
log.Printf("Agent ID: %s, Name: %s, Debug: %v, API Port: %d", config.ID, config.Name, config.Debug, config.APIPort)
} else {
log.Printf("Agent ID: %s, Name: %s", config.ID, config.Name)
}
}
// 从环境变量读取配置
func loadFromEnv() {
if serverURL := os.Getenv("AGENT_SERVER_URL"); serverURL != "" {
config.ServerURL = serverURL
}
if id := os.Getenv("AGENT_ID"); id != "" {
config.ID = id
}
if name := os.Getenv("AGENT_NAME"); name != "" {
config.Name = name
}
if token := os.Getenv("AGENT_TOKEN"); token != "" {
config.Token = token
}
if intervalStr := os.Getenv("AGENT_INTERVAL"); intervalStr != "" {
config.Interval = intervalStr
}
if debugStr := os.Getenv("AGENT_DEBUG"); debugStr != "" {
debug, err := strconv.ParseBool(debugStr)
if err == nil {
config.Debug = debug
}
}
if apiPortStr := os.Getenv("AGENT_API_PORT"); apiPortStr != "" {
apiPort, err := strconv.Atoi(apiPortStr)
if err == nil && apiPort > 0 {
config.APIPort = apiPort
}
}
}
// 确保Agent ID存在不存在则生成
func ensureAgentID() {
if config.ID != "" {
return
}
// 使用时间戳和进程ID生成唯一ID
config.ID = fmt.Sprintf("agent-%d-%d", time.Now().UnixNano(), os.Getpid())
log.Printf("Generated new Agent ID: %s", config.ID)
}
// 确保Agent名称存在不存在则生成
func ensureAgentName() {
if config.Name != "" {
return
}
// 尝试获取主机名作为默认名称
hostname, err := os.Hostname()
if err != nil {
// 如果获取主机名失败使用ID的前8位作为默认名称
hostname = fmt.Sprintf("Agent-%s", config.ID[:8])
}
config.Name = hostname
log.Printf("Generated new Agent Name: %s", config.Name)
}
// 保存配置到文件
func saveConfigFile() {
// 获取配置文件路径,默认./agent.json可通过环境变量指定
configFile := os.Getenv("AGENT_CONFIG_FILE")
if configFile == "" {
configFile = "./agent.json"
}
// 将配置转换为JSON
jsonData, err := json.MarshalIndent(config, "", " ")
if err != nil {
log.Printf("Failed to marshal config: %v", err)
return
}
// 保存配置到文件
if err := os.WriteFile(configFile, jsonData, 0644); err != nil {
log.Printf("Failed to save config to file: %v", err)
return
}
log.Printf("Config saved to %s", configFile)
}
// 初始化日志配置
func initLogging() error {
// 默认日志输出到标准输出
var output io.Writer = os.Stdout
// 如果指定了日志文件,则输出到文件
if logFile != "" {
// 处理日志文件路径
logFilePath := logFile
// 创建日志文件
file, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return fmt.Errorf("failed to open log file: %v", err)
}
output = file
}
// 配置日志输出格式
log.SetOutput(output)
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
return nil
}
// 读取配置文件
func readConfigFile() {
// 获取配置文件路径,默认./agent.json可通过环境变量指定
configFile := os.Getenv("AGENT_CONFIG_FILE")
if configFile == "" {
configFile = "./agent.json"
}
// 检查配置文件是否存在
if _, err := os.Stat(configFile); os.IsNotExist(err) {
log.Printf("Config file %s not found, using default config", configFile)
return
}
// 读取配置文件
content, err := os.ReadFile(configFile)
if err != nil {
log.Printf("Failed to read config file %s: %v, using default config", configFile, err)
return
}
// 解析配置文件
var fileConfig Config
if err := json.Unmarshal(content, &fileConfig); err != nil {
log.Printf("Failed to parse config file %s: %v, using default config", configFile, err)
return
}
// 合并配置:所有字段都从配置文件覆盖,除了空字符串
if fileConfig.ServerURL != "" {
config.ServerURL = fileConfig.ServerURL
}
if fileConfig.ID != "" {
config.ID = fileConfig.ID
}
if fileConfig.Name != "" {
config.Name = fileConfig.Name
}
if fileConfig.Token != "" {
config.Token = fileConfig.Token
}
if fileConfig.Interval != "" {
config.Interval = fileConfig.Interval
}
// 对于bool类型总是从配置文件覆盖
config.Debug = fileConfig.Debug
// 对于int类型如果配置文件中的值大于0则使用配置文件中的值否则使用默认值
if fileConfig.APIPort > 0 {
config.APIPort = fileConfig.APIPort
}
log.Printf("Config loaded from %s", configFile)
}
// 采集CPU使用率和频率
func collectCPU() (float64, float64, error) {
// 采集CPU使用率
percentages, err := cpu.Percent(0, false)
if err != nil {
return 0, 0, err
}
// Windows环境下CPU频率获取方式不同暂时返回0
return percentages[0], 0, nil
}
// 采集内存使用率
func collectMemory() (float64, error) {
vm, err := mem.VirtualMemory()
if err != nil {
return 0, err
}
return vm.UsedPercent, nil
}
// 采集磁盘使用率和总容量
func collectDisk() (map[string]DiskMetrics, error) {
// 获取系统所有挂载点
partitions, err := disk.Partitions(false)
if err != nil {
return nil, err
}
// 初始化返回值
diskMetricsMap := make(map[string]DiskMetrics)
// 遍历所有挂载点,采集磁盘使用率和总容量
for _, partition := range partitions {
// 获取磁盘使用率
usage, err := disk.Usage(partition.Mountpoint)
if err != nil {
log.Printf("Failed to collect disk usage for %s: %v", partition.Mountpoint, err)
continue
}
// 创建磁盘指标
diskMetrics := DiskMetrics{
UsedPercent: usage.UsedPercent,
Total: usage.Total,
}
// 将指标添加到map中使用挂载点作为键
diskMetricsMap[partition.Mountpoint] = diskMetrics
}
return diskMetricsMap, nil
}
// 采集磁盘详细信息
func collectDiskDetails() ([]DiskDetailMetrics, error) {
// 获取系统所有挂载点
partitions, err := disk.Partitions(true)
if err != nil {
return nil, err
}
// 初始化返回值
diskDetails := make([]DiskDetailMetrics, 0)
// 遍历所有挂载点,采集磁盘详细信息
for i, partition := range partitions {
// 获取磁盘使用率
usage, err := disk.Usage(partition.Mountpoint)
if err != nil {
log.Printf("Failed to collect disk usage for %s: %v", partition.Mountpoint, err)
continue
}
// 创建磁盘详细信息
diskDetail := DiskDetailMetrics{
ID: fmt.Sprintf("%d", i+1),
Path: partition.Mountpoint,
Status: "active",
Type: "disk",
SizeGB: float64(usage.Total) / (1024 * 1024 * 1024),
Model: "",
Vendor: "",
InterfaceType: "",
FileSystem: partition.Fstype,
DiskUUID: "",
Description: fmt.Sprintf("Disk partition %s", partition.Mountpoint),
}
// 将磁盘详细信息添加到切片中
diskDetails = append(diskDetails, diskDetail)
}
return diskDetails, nil
}
// 采集网络流量
func collectNetwork() (map[string]NetworkInterfaceMetrics, uint64, uint64, uint64, uint64, error) {
// 获取当前时间
currentTime := time.Now()
// 获取网络接口列表
interfaces, err := net.Interfaces()
if err != nil {
return nil, 0, 0, 0, 0, err
}
// 初始化返回值
networkMetrics := make(map[string]NetworkInterfaceMetrics)
var rxTotal, txTotal, rxRate, txRate uint64
// 遍历所有网络接口,采集网络流量
for _, iface := range interfaces {
// 跳过回环接口
if strings.Contains(strings.ToLower(iface.Name), "loopback") || strings.Contains(strings.ToLower(iface.Name), "lo") {
continue
}
// 获取网络接口统计信息
stats, err := net.IOCounters(true)
if err != nil {
log.Printf("Failed to collect network stats for %s: %v", iface.Name, err)
continue
}
// 查找当前接口的统计信息
var interfaceStats net.IOCountersStat
found := false
for _, stat := range stats {
if stat.Name == iface.Name {
interfaceStats = stat
found = true
break
}
}
if !found {
continue
}
// 计算时间差
timeDiff := currentTime.Sub(lastCollectTime)
if timeDiff <= 0 {
timeDiff = time.Second
}
// 获取上一次采集的数据
lastStats, exists := lastNetworkStats[iface.Name]
// 计算发送和接收速率
var bytesSent, bytesReceived uint64
if exists {
bytesSent = uint64(float64(interfaceStats.BytesSent-lastStats.BytesSent) / timeDiff.Seconds())
bytesReceived = uint64(float64(interfaceStats.BytesRecv-lastStats.BytesReceived) / timeDiff.Seconds())
}
// 创建网络指标
interfaceMetrics := NetworkInterfaceMetrics{
BytesSent: bytesSent,
BytesReceived: bytesReceived,
TxBytes: interfaceStats.BytesSent,
RxBytes: interfaceStats.BytesRecv,
}
// 将指标添加到map中
networkMetrics[iface.Name] = interfaceMetrics
// 更新上一次采集的数据
lastNetworkStats[iface.Name] = NetworkStats{
BytesSent: interfaceStats.BytesSent,
BytesReceived: interfaceStats.BytesRecv,
}
// 累加总流量
rxTotal += interfaceStats.BytesRecv
txTotal += interfaceStats.BytesSent
rxRate += bytesReceived
txRate += bytesSent
}
// 更新上一次采集时间
lastCollectTime = currentTime
return networkMetrics, rxTotal, txTotal, rxRate, txRate, nil
}
// 采集进程信息
func collectProcessMetrics() ([]ProcessMetrics, error) {
// 获取所有进程
processes, err := process.Processes()
if err != nil {
return nil, err
}
// 初始化返回值
processMetrics := make([]ProcessMetrics, 0)
// 遍历所有进程,采集进程信息
for _, p := range processes {
// 获取进程名称
name, err := p.Name()
if err != nil {
continue
}
// 获取进程用户名
username, err := p.Username()
if err != nil {
username = ""
}
// 获取进程CPU使用率
cpu, err := p.CPUPercent()
if err != nil {
cpu = 0
}
// 获取进程内存使用率
mem, err := p.MemoryPercent()
if err != nil {
mem = 0
}
// 获取进程路径
path, err := p.Exe()
if err != nil {
path = ""
}
// 获取进程命令行
cmdline, err := p.Cmdline()
if err != nil {
cmdline = ""
}
// 获取进程占用的端口
connections, err := p.Connections()
if err != nil {
continue
}
// 提取端口号
ports := make([]int, 0)
for _, conn := range connections {
ports = append(ports, int(conn.Laddr.Port))
}
// 去重并排序端口号
sort.Ints(ports)
uniquePorts := make([]int, 0)
prevPort := -1
for _, port := range ports {
if port != prevPort {
uniquePorts = append(uniquePorts, port)
prevPort = port
}
}
// 创建进程指标
pm := ProcessMetrics{
Name: name,
Username: username,
PID: p.Pid,
CPU: cpu,
Memory: float64(mem),
Path: path,
Cmdline: cmdline,
Ports: uniquePorts,
}
// 将指标添加到切片中
processMetrics = append(processMetrics, pm)
}
return processMetrics, nil
}
// 采集系统日志
func collectLogs() ([]LogEntry, error) {
// Windows系统日志采集需要特殊处理这里返回空切片
return []LogEntry{}, nil
}
// 采集操作系统信息
func collectOSInfo() (OSInfo, error) {
// 默认值
name := "Windows"
version := "Unknown"
arch := "Unknown"
fullname := "Windows"
// 先获取架构信息
if runtime.GOARCH == "amd64" {
arch = "64-bit"
} else if runtime.GOARCH == "386" {
arch = "32-bit"
}
// 使用wmic命令获取详细的Windows版本信息包括版本类型和版本号
cmd := exec.Command("cmd.exe", "/c", "wmic os get Caption, Version, OSArchitecture /format:list")
output, err := cmd.Output()
if err == nil {
// 处理GBK编码输出
decodedOutput, err := simplifiedchinese.GBK.NewDecoder().Bytes(output)
if err != nil {
// 解码失败时使用原始字符串
decodedOutput = output
}
outputStr := string(decodedOutput)
// 解析wmic命令输出
lines := strings.Split(outputStr, "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if line == "" {
continue
}
// 解析Caption完整名称例如Microsoft Windows 10 Pro
if strings.HasPrefix(line, "Caption=") {
fullname = strings.TrimPrefix(line, "Caption=")
}
// 解析Version版本号例如10.0.19045
if strings.HasPrefix(line, "Version=") {
version = strings.TrimPrefix(line, "Version=")
}
// 解析OSArchitecture架构例如64-bit
if strings.HasPrefix(line, "OSArchitecture=") {
arch = strings.TrimPrefix(line, "OSArchitecture=")
}
}
} else {
// 如果wmic命令失败使用ver命令作为备选
cmd := exec.Command("cmd.exe", "/c", "ver")
output, err := cmd.Output()
if err == nil {
// 处理GBK编码输出
decodedOutput, err := simplifiedchinese.GBK.NewDecoder().Bytes(output)
if err != nil {
// 解码失败时使用原始字符串
decodedOutput = output
}
outputStr := string(decodedOutput)
// 提取版本号
versionStart := strings.Index(outputStr, "[Version ")
if versionStart > 0 {
versionStart += 9
versionEnd := strings.Index(outputStr[versionStart:], "]")
if versionEnd > 0 {
version = outputStr[versionStart : versionStart+versionEnd]
}
}
// 构建完整名称
fullname = fmt.Sprintf("Windows %s", version)
}
}
return OSInfo{
Name: name,
Version: version,
Arch: arch,
Fullname: fullname,
}, nil
}
// 采集CPU详细信息
func collectCPUInfo() (CPUInfo, error) {
// 获取CPU信息
cpus, err := cpu.Info()
if err != nil {
return CPUInfo{}, err
}
// 获取CPU使用率
usage, err := cpu.Percent(0, false)
if err != nil {
usage = []float64{0}
}
// Windows环境下CPU信息
cpuInfo := CPUInfo{
Model: cpus[0].ModelName,
Cores: int(cpus[0].Cores),
Threads: 0, // Windows环境下可能不支持Threads字段
MaxFreq: 0, // Windows环境下频率获取方式不同
MinFreq: 0,
AvgFreq: 0,
Usage: usage[0],
}
return cpuInfo, nil
}
// 采集内存详细信息
func collectMemoryInfo() (MemoryInfo, error) {
// 获取内存信息
mem, err := mem.VirtualMemory()
if err != nil {
return MemoryInfo{}, err
}
// 创建内存详细信息
return MemoryInfo{
Total: mem.Total,
Used: mem.Used,
Free: mem.Free,
UsedPercent: mem.UsedPercent,
}, nil
}
// 采集网卡硬件信息
func collectNetworkHardware() ([]NetworkHardwareInfo, error) {
// 获取网络接口列表
interfaces, err := net.Interfaces()
if err != nil {
return nil, err
}
// 初始化返回值
networkCards := make([]NetworkHardwareInfo, 0)
// 获取所有IP地址
allAddrs, err := stdnet.InterfaceAddrs()
if err != nil {
allAddrs = []stdnet.Addr{}
}
// 遍历所有网络接口,采集网卡硬件信息
for i, iface := range interfaces {
// 跳过回环接口
if strings.Contains(strings.ToLower(iface.Name), "loopback") || strings.Contains(strings.ToLower(iface.Name), "lo") {
continue
}
// 提取IP地址
ipAddresses := make([]string, 0)
for _, addr := range allAddrs {
if ipnet, ok := addr.(*stdnet.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
ipAddresses = append(ipAddresses, ipnet.IP.String())
}
}
}
// 创建网卡硬件信息
networkCard := NetworkHardwareInfo{
ID: fmt.Sprintf("%d", i+1),
Name: iface.Name,
MAC: iface.HardwareAddr,
IPAddresses: ipAddresses,
MTU: iface.MTU,
Speed: 0, // 在Windows上net.Interface没有Speed字段
Up: true, // Windows环境下接口状态判断方式不同
}
// 将网卡硬件信息添加到切片中
networkCards = append(networkCards, networkCard)
}
return networkCards, nil
}
// 采集指标
func collectMetrics() (*Metrics, error) {
metrics := &Metrics{}
// 初始化Network字段为非nil避免空指针问题
metrics.Network = make(map[string]NetworkInterfaceMetrics)
// 设置设备信息
metrics.AgentID = config.ID
metrics.Name = config.Name
// 尝试获取本机IP地址
metrics.IP = getLocalIP()
// 采集CPU使用率和频率
cpuUsage, cpuHz, err := collectCPU()
if err != nil {
// CPU采集失败时使用0值
log.Printf("Failed to collect CPU metrics: %v, using 0 values", err)
cpuUsage = 0
cpuHz = 0
}
metrics.CPU = cpuUsage
metrics.CPUHz = cpuHz
// 采集内存使用率
memoryUsage, err := collectMemory()
if err != nil {
// 内存采集失败时使用0值
log.Printf("Failed to collect memory metrics: %v, using 0 value", err)
memoryUsage = 0
}
metrics.Memory = memoryUsage
// 采集磁盘使用率和总容量
diskMetricsMap, err := collectDisk()
if err != nil {
// 磁盘采集失败时使用空map
log.Printf("Failed to collect disk metrics: %v, using empty map", err)
diskMetricsMap = make(map[string]DiskMetrics)
}
metrics.Disk = diskMetricsMap
// 采集磁盘详细信息
diskDetails, err := collectDiskDetails()
if err != nil {
// 磁盘详细信息采集失败时使用空切片
log.Printf("Failed to collect disk details: %v, using empty slice", err)
diskDetails = make([]DiskDetailMetrics, 0)
}
metrics.DiskDetails = diskDetails
// 采集进程信息
processes, err := collectProcessMetrics()
if err != nil {
// 进程信息采集失败时使用空切片
log.Printf("Failed to collect process metrics: %v, using empty slice", err)
processes = make([]ProcessMetrics, 0)
}
metrics.Processes = processes
// 采集网络流量
networkMetrics, rxTotal, txTotal, rxRate, txRate, err := collectNetwork()
if err != nil {
// 网络采集失败时使用0值
log.Printf("Failed to collect network metrics: %v, using 0 values", err)
networkMetrics = make(map[string]NetworkInterfaceMetrics)
rxTotal, txTotal, rxRate, txRate = 0, 0, 0, 0
}
// 直接使用采集到的网卡流量
metrics.Network = networkMetrics
metrics.RxTotal = rxTotal
metrics.TxTotal = txTotal
metrics.RxRate = rxRate
metrics.TxRate = txRate
// 采集系统日志
logs, err := collectLogs()
if err != nil {
// 日志采集失败时使用空切片
log.Printf("Failed to collect logs: %v, using empty slice", err)
logs = make([]LogEntry, 0)
}
metrics.Logs = logs
// 采集硬件信息
// 采集操作系统信息
osInfo, err := collectOSInfo()
if err != nil {
log.Printf("Failed to collect OS info: %v", err)
}
// 采集CPU详细信息
cpuInfo, err := collectCPUInfo()
if err != nil {
log.Printf("Failed to collect CPU info: %v", err)
}
// 采集内存详细信息
memoryInfo, err := collectMemoryInfo()
if err != nil {
log.Printf("Failed to collect memory info: %v", err)
}
// 采集网卡硬件信息
networkCards, err := collectNetworkHardware()
if err != nil {
log.Printf("Failed to collect network hardware info: %v", err)
networkCards = make([]NetworkHardwareInfo, 0)
}
// 设置硬件信息
metrics.Hardware = HardwareMetrics{
OS: osInfo,
CPU: cpuInfo,
Memory: memoryInfo,
DiskDetails: diskDetails,
NetworkCards: networkCards,
}
return metrics, nil
}
// 发送指标到服务器
func sendMetrics(metricsList []*Metrics) error {
// 创建HTTP客户端
client := &http.Client{
Timeout: 10 * time.Second,
}
// 将指标转换为JSON
jsonData, err := json.Marshal(metricsList)
if err != nil {
return err
}
// 创建请求
req, err := http.NewRequest("POST", fmt.Sprintf("%s/metrics/", config.ServerURL), bytes.NewBuffer(jsonData))
if err != nil {
return err
}
// 设置请求头
req.Header.Set("Content-Type", "application/json")
// 设置Agent名称
req.Header.Set("X-Agent-Name", config.Name)
// 设置设备认证令牌
req.Header.Set("X-Device-Token", config.Token)
log.Printf("Sending %d metrics to server: %s", len(metricsList), config.ServerURL)
// 发送请求
resp, err := client.Do(req)
if err != nil {
log.Printf("Failed to send metrics: %v", err)
return err
}
defer resp.Body.Close()
// 检查响应状态码
if resp.StatusCode != http.StatusOK {
log.Printf("Server returned status code %d", resp.StatusCode)
return fmt.Errorf("server returned status code %d", resp.StatusCode)
}
log.Printf("Successfully sent %d metrics to server", len(metricsList))
return nil
}
// 启动HTTP服务器
func startHTTPServer() {
// 指标查询端点
http.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) {
if config.Debug {
log.Printf("API Request: %s %s", r.Method, r.URL.Path)
}
metrics, err := collectMetrics()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 设置响应头
w.Header().Set("Content-Type", "application/json")
// 返回JSON响应
json.NewEncoder(w).Encode(metrics)
})
// 健康检查端点
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
if config.Debug {
log.Printf("API Request: %s %s", r.Method, r.URL.Path)
}
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"status": "ok",
"agent_id": config.ID,
})
})
// 获取配置端点
http.HandleFunc("/config", func(w http.ResponseWriter, r *http.Request) {
if config.Debug {
log.Printf("API Request: %s %s", r.Method, r.URL.Path)
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(config)
})
// 获取状态端点
http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
if config.Debug {
log.Printf("API Request: %s %s", r.Method, r.URL.Path)
}
// 采集当前状态
cpu, cpuHz, _ := collectCPU()
memory, _ := collectMemory()
disk, _ := collectDisk()
status := map[string]interface{}{
"status": "running",
"agent_id": config.ID,
"name": config.Name,
"debug": config.Debug,
"interval": config.Interval,
"cpu": cpu,
"cpu_hz": cpuHz,
"memory": memory,
"disk": disk,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(status)
})
// 立即采集和发送指标端点
http.HandleFunc("/collect", func(w http.ResponseWriter, r *http.Request) {
if config.Debug {
log.Printf("API Request: %s %s", r.Method, r.URL.Path)
}
go collectAndSendMetrics()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"status": "ok",
"message": "Metrics collection triggered",
})
})
// 启动服务器
addr := fmt.Sprintf(":%d", config.APIPort)
log.Printf("Starting HTTP server on %s", addr)
if err := http.ListenAndServe(addr, nil); err != nil {
log.Fatalf("Failed to start HTTP server: %v", err)
}
}
// 采集并发送指标
func collectAndSendMetrics() {
// 采集指标
metrics, err := collectMetrics()
if err != nil {
log.Printf("Failed to collect metrics: %v", err)
return
}
// 将指标添加到缓冲区
metricsBufferMutex.Lock()
metricsBuffer = append(metricsBuffer, metrics)
metricsBufferMutex.Unlock()
// 如果缓冲区已满,发送指标到服务器
metricsBufferMutex.Lock()
if len(metricsBuffer) >= 10 {
// 复制缓冲区
sendMetricsList := make([]*Metrics, len(metricsBuffer))
copy(sendMetricsList, metricsBuffer)
// 清空缓冲区
metricsBuffer = make([]*Metrics, 0)
metricsBufferMutex.Unlock()
// 发送指标
if err := sendMetrics(sendMetricsList); err != nil {
log.Printf("Failed to send metrics: %v", err)
}
} else {
metricsBufferMutex.Unlock()
}
}
func main() {
// 解析命令行参数
flag.StringVar(&logFile, "log-file", "", "Path to log file")
flag.StringVar(&logFile, "l", "", "Path to log file - shorthand")
flag.Parse()
// 初始化日志
if err := initLogging(); err != nil {
log.Fatalf("Failed to initialize logging: %v", err)
}
// 初始化配置
initConfig()
// 启动HTTP服务器
go startHTTPServer()
// 采集初始指标
collectAndSendMetrics()
// 创建定时器,定期采集指标
ticker := time.NewTicker(parsedInterval)
defer ticker.Stop()
// 主循环
log.Printf("Agent started successfully, collecting metrics every %s", config.Interval)
for {
select {
case <-ticker.C:
// 定期采集指标
collectAndSendMetrics()
}
}
}