Browse Source

fix: disk statistics issue #1119

Jacky 3 weeks ago
parent
commit
2734da5e09
3 changed files with 73 additions and 55 deletions
  1. 11 55
      internal/analytic/disk.go
  2. 30 0
      internal/analytic/memory.go
  3. 32 0
      internal/analytic/types.go

+ 11 - 55
internal/analytic/stat.go → internal/analytic/disk.go

@@ -2,65 +2,13 @@ package analytic
 
 import (
 	"fmt"
-	"math"
 
 	"github.com/dustin/go-humanize"
 	"github.com/pkg/errors"
 	"github.com/shirou/gopsutil/v4/disk"
-	"github.com/shirou/gopsutil/v4/mem"
 	"github.com/spf13/cast"
 )
 
-type MemStat struct {
-	Total       string  `json:"total"`
-	Used        string  `json:"used"`
-	Cached      string  `json:"cached"`
-	Free        string  `json:"free"`
-	SwapUsed    string  `json:"swap_used"`
-	SwapTotal   string  `json:"swap_total"`
-	SwapCached  string  `json:"swap_cached"`
-	SwapPercent float64 `json:"swap_percent"`
-	Pressure    float64 `json:"pressure"`
-}
-
-type PartitionStat struct {
-	Mountpoint string  `json:"mountpoint"`
-	Device     string  `json:"device"`
-	Fstype     string  `json:"fstype"`
-	Total      string  `json:"total"`
-	Used       string  `json:"used"`
-	Free       string  `json:"free"`
-	Percentage float64 `json:"percentage"`
-}
-
-type DiskStat struct {
-	Total      string          `json:"total"`
-	Used       string          `json:"used"`
-	Percentage float64         `json:"percentage"`
-	Writes     Usage[uint64]   `json:"writes"`
-	Reads      Usage[uint64]   `json:"reads"`
-	Partitions []PartitionStat `json:"partitions"`
-}
-
-func GetMemoryStat() (MemStat, error) {
-	memoryStat, err := mem.VirtualMemory()
-	if err != nil {
-		return MemStat{}, errors.Wrap(err, "error analytic getMemoryStat")
-	}
-	return MemStat{
-		Total:      humanize.Bytes(memoryStat.Total),
-		Used:       humanize.Bytes(memoryStat.Used),
-		Cached:     humanize.Bytes(memoryStat.Cached),
-		Free:       humanize.Bytes(memoryStat.Free),
-		SwapUsed:   humanize.Bytes(memoryStat.SwapTotal - memoryStat.SwapFree),
-		SwapTotal:  humanize.Bytes(memoryStat.SwapTotal),
-		SwapCached: humanize.Bytes(memoryStat.SwapCached),
-		SwapPercent: cast.ToFloat64(fmt.Sprintf("%.2f",
-			100*float64(memoryStat.SwapTotal-memoryStat.SwapFree)/math.Max(float64(memoryStat.SwapTotal), 1))),
-		Pressure: cast.ToFloat64(fmt.Sprintf("%.2f", memoryStat.UsedPercent)),
-	}, nil
-}
-
 func GetDiskStat() (DiskStat, error) {
 	// Get all partitions
 	partitions, err := disk.Partitions(false)
@@ -71,6 +19,8 @@ func GetDiskStat() (DiskStat, error) {
 	var totalSize uint64
 	var totalUsed uint64
 	var partitionStats []PartitionStat
+	// Track partitions to avoid double counting same partition with multiple mount points
+	partitionUsage := make(map[string]*disk.UsageStat)
 
 	// Get usage for each partition
 	for _, partition := range partitions {
@@ -85,6 +35,7 @@ func GetDiskStat() (DiskStat, error) {
 			continue
 		}
 
+		// Create partition stat for display purposes
 		partitionStat := PartitionStat{
 			Mountpoint: partition.Mountpoint,
 			Device:     partition.Device,
@@ -94,10 +45,15 @@ func GetDiskStat() (DiskStat, error) {
 			Free:       humanize.Bytes(usage.Free),
 			Percentage: cast.ToFloat64(fmt.Sprintf("%.2f", usage.UsedPercent)),
 		}
-
 		partitionStats = append(partitionStats, partitionStat)
-		totalSize += usage.Total
-		totalUsed += usage.Used
+
+		// Only count each partition device once for total calculation
+		// This handles cases where same partition is mounted multiple times (e.g., bind mounts, overlayfs)
+		if _, exists := partitionUsage[partition.Device]; !exists {
+			partitionUsage[partition.Device] = usage
+			totalSize += usage.Total
+			totalUsed += usage.Used
+		}
 	}
 
 	// Calculate overall percentage

+ 30 - 0
internal/analytic/memory.go

@@ -0,0 +1,30 @@
+package analytic
+
+import (
+	"fmt"
+	"math"
+
+	"github.com/dustin/go-humanize"
+	"github.com/pkg/errors"
+	"github.com/shirou/gopsutil/v4/mem"
+	"github.com/spf13/cast"
+)
+
+func GetMemoryStat() (MemStat, error) {
+	memoryStat, err := mem.VirtualMemory()
+	if err != nil {
+		return MemStat{}, errors.Wrap(err, "error analytic getMemoryStat")
+	}
+	return MemStat{
+		Total:      humanize.Bytes(memoryStat.Total),
+		Used:       humanize.Bytes(memoryStat.Used),
+		Cached:     humanize.Bytes(memoryStat.Cached),
+		Free:       humanize.Bytes(memoryStat.Free),
+		SwapUsed:   humanize.Bytes(memoryStat.SwapTotal - memoryStat.SwapFree),
+		SwapTotal:  humanize.Bytes(memoryStat.SwapTotal),
+		SwapCached: humanize.Bytes(memoryStat.SwapCached),
+		SwapPercent: cast.ToFloat64(fmt.Sprintf("%.2f",
+			100*float64(memoryStat.SwapTotal-memoryStat.SwapFree)/math.Max(float64(memoryStat.SwapTotal), 1))),
+		Pressure: cast.ToFloat64(fmt.Sprintf("%.2f", memoryStat.UsedPercent)),
+	}, nil
+}

+ 32 - 0
internal/analytic/types.go

@@ -0,0 +1,32 @@
+package analytic
+
+type MemStat struct {
+	Total       string  `json:"total"`
+	Used        string  `json:"used"`
+	Cached      string  `json:"cached"`
+	Free        string  `json:"free"`
+	SwapUsed    string  `json:"swap_used"`
+	SwapTotal   string  `json:"swap_total"`
+	SwapCached  string  `json:"swap_cached"`
+	SwapPercent float64 `json:"swap_percent"`
+	Pressure    float64 `json:"pressure"`
+}
+
+type PartitionStat struct {
+	Mountpoint string  `json:"mountpoint"`
+	Device     string  `json:"device"`
+	Fstype     string  `json:"fstype"`
+	Total      string  `json:"total"`
+	Used       string  `json:"used"`
+	Free       string  `json:"free"`
+	Percentage float64 `json:"percentage"`
+}
+
+type DiskStat struct {
+	Total      string          `json:"total"`
+	Used       string          `json:"used"`
+	Percentage float64         `json:"percentage"`
+	Writes     Usage[uint64]   `json:"writes"`
+	Reads      Usage[uint64]   `json:"reads"`
+	Partitions []PartitionStat `json:"partitions"`
+}