You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go脚本获取磁盘IO返回异常设备名及空值问题求助

磁盘I/O获取脚本返回空值,设备名日志异常问题

我正在开发一个Go脚本,用于获取磁盘I/O操作数据,但遇到了脚本返回空值的异常问题。为排查问题,我添加了fmt.Print(deviceName)来检查发现的设备,得到如下日志:

/dev/dm-02023/11/09 16:49:47 IOCounters for /dev/dm-0 not found
/dev/sda22023/11/09 16:49:47 IOCounters for /dev/sda2 not found
/dev/sda12023/11/09 16:49:47 IOCounters for /dev/sda1 not found

令我困惑的是,日志中出现了异常的设备名(比如/dev/dm-02023),请问有人能解释这些设备名出现的原因吗?以及如何准确获取磁盘I/O操作数据?

我的Go代码如下:

package disk

import (
    "fmt"
    "log"

    "github.com/shirou/gopsutil/disk"
)

func GetAllDiskIO() (string, error) {
    diskPartitions, err := disk.Partitions(false)
    if err != nil {
        return "", fmt.Errorf("error during request: %v", err)
    }

    var result string

    for _, partition := range diskPartitions {
        deviceName := partition.Device

        diskIO, err := disk.IOCounters(deviceName)
        if err != nil {
            log.Printf("error during request for %s: %v", deviceName, err)
            continue
        }

        if counters, ok := diskIO[deviceName]; ok {
            result += fmt.Sprintf("%s: Read Count: %d, Write Count: %d; ", deviceName, counters.ReadCount, counters.WriteCount)
        } else {
            log.Printf("IOCounters for %s not found", deviceName)
        }
    }

    return result, nil
}

是否有人遇到过类似问题?或者对这些异常设备名的成因有见解?恳请指导如何改进脚本以准确捕获磁盘I/O操作数据!


异常设备名的成因

你看到的/dev/dm-02023这类异常名称,根本原因是fmt.Print(deviceName)没有加换行符。fmt.Print会直接输出内容到标准输出,而后面的log.Printf会输出带时间戳的日志,两者没有分隔,导致设备名和日志的时间戳直接拼接在一起,看起来像是设备名异常。比如/dev/dm-0加上2023/11/09...就变成了/dev/dm-02023...,并非设备名本身有问题。

无法获取I/O数据的原因及解决方案

1. disk.Partitions(false)参数限制

调用disk.Partitions(false)时,参数false仅返回挂载了文件系统的分区,但IOCounters通常需要的是磁盘设备(如/dev/sda)而非分区(如/dev/sda1),部分逻辑卷或未挂载设备也会被过滤,导致后续查找不到对应I/O数据。

解决办法:

  • 若需要磁盘级别的I/O数据,直接调用disk.IOCounters()(不带参数)获取所有设备的统计;
  • 若需基于分区查询,先将分区路径转换为对应磁盘设备(比如从/dev/sda1提取/dev/sda),再去I/O结果中匹配。

2. IOCounters返回键名的匹配问题

当传入单个设备名调用disk.IOCounters(deviceName)时,返回的map键名可能不含/dev/前缀(比如系统内部用sda而非/dev/sda),导致用完整路径deviceName查找时命中失败。

解决办法:

  • 调用无参的disk.IOCounters()获取全量数据,遍历结果时自行过滤需要的设备;
  • 对设备名做前缀处理,比如去掉/dev/后再与map键匹配。

3. 改进后的代码示例

package disk

import (
    "fmt"
    "log"
    "strings"

    "github.com/shirou/gopsutil/disk"
)

func GetAllDiskIO() (string, error) {
    // 获取所有磁盘设备的I/O统计数据
    diskIO, err := disk.IOCounters()
    if err != nil {
        return "", fmt.Errorf("error getting I/O counters: %v", err)
    }

    var result string
    for device, counters := range diskIO {
        // 过滤掉不需要的设备(如loop虚拟设备),可根据需求调整
        if !strings.HasPrefix(device, "sd") && !strings.HasPrefix(device, "dm-") {
            continue
        }
        // 补充/dev/前缀,让输出更直观
        fullDevice := "/dev/" + device
        result += fmt.Sprintf("%s: Read Count: %d, Write Count: %d; ", fullDevice, counters.ReadCount, counters.WriteCount)
    }

    return result, nil
}

4. 日志输出修正

之前的fmt.Print(deviceName)导致日志拼接混淆,建议替换为带换行和时间戳的日志输出:

log.Printf("Checking device: %s", deviceName)

内容的提问来源于stack exchange,提问作者kekw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 18:20:01