Files
pika/pkg/agent/collector/disk.go
T
2026-08-12 18:59:29 +08:00

125 lines
2.9 KiB
Go

package collector
import (
"strings"
"github.com/pika-monitor/pika/internal/protocol"
"github.com/pika-monitor/pika/pkg/agent/config"
"github.com/shirou/gopsutil/v4/disk"
)
// 不以 /dev/ 开头但仍是真实存储的文件系统类型
var realFSTypes = map[string]bool{
"nfs": true,
"nfs4": true,
"cifs": true,
"smbfs": true,
"zfs": true,
"glusterfs": true,
"cephfs": true,
}
// DiskCollector 磁盘监控采集器
type DiskCollector struct {
config *config.Config
}
// NewDiskCollector 创建磁盘采集器
func NewDiskCollector(cfg *config.Config) *DiskCollector {
return &DiskCollector{
config: cfg,
}
}
// isRealDisk 判断是否为真实存储设备
func isRealDisk(device, fstype string) bool {
// Windows 盘符
if len(device) == 2 && device[1] == ':' {
return true
}
// Unix 块设备
if strings.HasPrefix(device, "/dev/") {
return true
}
// 网络/集群存储
return realFSTypes[fstype]
}
// macOS APFS 容器内与数据卷共享物理空间的系统辅助卷
var macosSystemVolumes = map[string]bool{
"Preboot": true,
"VM": true,
"Update": true,
"xarts": true,
"iSCPreboot": true,
"Hardware": true,
}
// isMacOSRedundant 判断是否为 macOS APFS 冗余系统卷
func isMacOSRedundant(mountPoint, fstype string) bool {
if fstype != "apfs" {
return false
}
const prefix = "/System/Volumes/"
if !strings.HasPrefix(mountPoint, prefix) {
return false
}
volumeName := strings.TrimPrefix(mountPoint, prefix)
return macosSystemVolumes[volumeName]
}
// Collect 采集磁盘数据
// 只采集配置的 DiskInclude 白名单中的挂载点
func (d *DiskCollector) Collect() ([]protocol.DiskData, error) {
partitions, err := disk.Partitions(false)
if err != nil {
return nil, err
}
var diskDataList []protocol.DiskData
for _, partition := range partitions {
// 跳过虚拟文件系统
if !isRealDisk(partition.Device, partition.Fstype) {
continue
}
// 跳过 macOS APFS 冗余系统卷(与 Data 共享物理空间)
if isMacOSRedundant(partition.Mountpoint, partition.Fstype) {
continue
}
// 检查是否在白名单中
if !d.config.ShouldIncludeDiskMountPoint(partition.Mountpoint) {
continue
}
// 获取动态使用情况
usage, err := disk.Usage(partition.Mountpoint)
if err != nil {
continue // 跳过无法访问的分区
}
// 跳过容量为 0 的分区
if usage.Total == 0 {
continue
}
diskDataList = append(diskDataList, protocol.DiskData{
MountPoint: partition.Mountpoint,
Device: partition.Device,
Fstype: partition.Fstype,
Total: usage.Total,
Used: usage.Used,
Free: usage.Free,
UsagePercent: usage.UsedPercent,
})
}
// 所有白名单分区均采集失败时,返回空列表表示异常
if len(diskDataList) == 0 {
return nil, nil
}
return diskDataList, nil
}