fix: 磁盘采集支持多硬盘,修复只采集系统盘的问题

- 默认采集所有真实存储设备而非仅根分区
- 通过设备路径白名单识别真实磁盘(块设备/网络存储)
- 排除 tmpfs、proc、cgroup 等虚拟文件系统
- 排除 macOS APFS 冗余系统卷(Preboot/VM/Update 等)
This commit is contained in:
yumusb committed 2026-04-30 14:37:58 +08:00
1 parent 47c9a515a2
commit cfde75e21e
2 files changed
+69 -13

No files matched your search

+63 -5
View File
@@ -1,11 +1,24 @@
package collector
import (
"strings"
"github.com/dushixiang/pika/internal/protocol"
"github.com/dushixiang/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
@@ -18,6 +31,43 @@ func NewDiskCollector(cfg *config.Config) *DiskCollector {
}
}
// 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) {
@@ -28,6 +78,16 @@ func (d *DiskCollector) Collect() ([]protocol.DiskData, error) {
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
@@ -39,12 +99,12 @@ func (d *DiskCollector) Collect() ([]protocol.DiskData, error) {
continue // 跳过无法访问的分区
}
// 跳过容量为 0 的分区(可能是虚拟文件系统)
// 跳过容量为 0 的分区
if usage.Total == 0 {
continue
}
diskData := protocol.DiskData{
diskDataList = append(diskDataList, protocol.DiskData{
MountPoint: partition.Mountpoint,
Device: partition.Device,
Fstype: partition.Fstype,
@@ -52,9 +112,7 @@ func (d *DiskCollector) Collect() ([]protocol.DiskData, error) {
Used: usage.Used,
Free: usage.Free,
UsagePercent: usage.UsedPercent,
}
diskDataList = append(diskDataList, diskData)
})
}
// 所有白名单分区均采集失败时,返回空列表表示异常
+6 -8
View File
@@ -388,23 +388,21 @@ func (c *Config) ShouldExcludeNetworkInterface(interfaceName string) bool {
}
// GetDiskInclude 获取磁盘包含的挂载点列表(白名单)
// 如果配置为空,返回默认的根分区匹配规则
// Linux/macOS: ["/"]
// Windows: ["C:"]
// 返回 nil 表示未配置白名单,采集所有挂载点
func (c *Config) GetDiskInclude() []string {
if len(c.Collector.DiskInclude) == 0 {
if runtime.GOOS == "windows" {
return []string{"C:"}
}
return []string{"/"}
return nil
}
return c.Collector.DiskInclude
}
// ShouldIncludeDiskMountPoint 检查挂载点是否应该被采集
// 只有在 DiskInclude 白名单中的挂载点才会被采集
// 未配置白名单时采集所有挂载点
func (c *Config) ShouldIncludeDiskMountPoint(mountPoint string) bool {
includeMounts := c.GetDiskInclude()
if len(includeMounts) == 0 {
return true // 未配置白名单,采集所有
}
for _, mount := range includeMounts {
if mountPoint == mount {
return true