Skip to content

Commit 80e09a6

Browse files
committed
fix(analytic): disk analytic issue #1062
1 parent 205101c commit 80e09a6

File tree

3 files changed

+154
-12
lines changed

3 files changed

+154
-12
lines changed

app/src/api/analytic.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,23 @@ export interface MemStat {
5959
pressure: number
6060
}
6161

62+
export interface PartitionStat {
63+
mountpoint: string
64+
device: string
65+
fstype: string
66+
total: string
67+
used: string
68+
free: string
69+
percentage: number
70+
}
71+
6272
export interface DiskStat {
6373
total: string
6474
used: string
6575
percentage: number
6676
writes: Usage
6777
reads: Usage
78+
partitions: PartitionStat[]
6879
}
6980

7081
export interface LoadStat {

internal/analytic/stat.go

Lines changed: 94 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ package analytic
22

33
import (
44
"fmt"
5+
"math"
6+
57
"github.com/dustin/go-humanize"
68
"github.com/pkg/errors"
79
"github.com/shirou/gopsutil/v4/disk"
810
"github.com/shirou/gopsutil/v4/mem"
911
"github.com/spf13/cast"
10-
"math"
1112
)
1213

1314
type MemStat struct {
@@ -22,12 +23,23 @@ type MemStat struct {
2223
Pressure float64 `json:"pressure"`
2324
}
2425

26+
type PartitionStat struct {
27+
Mountpoint string `json:"mountpoint"`
28+
Device string `json:"device"`
29+
Fstype string `json:"fstype"`
30+
Total string `json:"total"`
31+
Used string `json:"used"`
32+
Free string `json:"free"`
33+
Percentage float64 `json:"percentage"`
34+
}
35+
2536
type DiskStat struct {
26-
Total string `json:"total"`
27-
Used string `json:"used"`
28-
Percentage float64 `json:"percentage"`
29-
Writes Usage[uint64] `json:"writes"`
30-
Reads Usage[uint64] `json:"reads"`
37+
Total string `json:"total"`
38+
Used string `json:"used"`
39+
Percentage float64 `json:"percentage"`
40+
Writes Usage[uint64] `json:"writes"`
41+
Reads Usage[uint64] `json:"reads"`
42+
Partitions []PartitionStat `json:"partitions"`
3143
}
3244

3345
func GetMemoryStat() (MemStat, error) {
@@ -50,17 +62,87 @@ func GetMemoryStat() (MemStat, error) {
5062
}
5163

5264
func GetDiskStat() (DiskStat, error) {
53-
diskUsage, err := disk.Usage(".")
54-
65+
// Get all partitions
66+
partitions, err := disk.Partitions(false)
5567
if err != nil {
56-
return DiskStat{}, errors.Wrap(err, "error analytic getDiskStat")
68+
return DiskStat{}, errors.Wrap(err, "error analytic getDiskStat - getting partitions")
69+
}
70+
71+
var totalSize uint64
72+
var totalUsed uint64
73+
var partitionStats []PartitionStat
74+
75+
// Get usage for each partition
76+
for _, partition := range partitions {
77+
usage, err := disk.Usage(partition.Mountpoint)
78+
if err != nil {
79+
// Skip partitions that can't be accessed
80+
continue
81+
}
82+
83+
// Skip virtual filesystems and special filesystems
84+
if isVirtualFilesystem(partition.Fstype) {
85+
continue
86+
}
87+
88+
partitionStat := PartitionStat{
89+
Mountpoint: partition.Mountpoint,
90+
Device: partition.Device,
91+
Fstype: partition.Fstype,
92+
Total: humanize.Bytes(usage.Total),
93+
Used: humanize.Bytes(usage.Used),
94+
Free: humanize.Bytes(usage.Free),
95+
Percentage: cast.ToFloat64(fmt.Sprintf("%.2f", usage.UsedPercent)),
96+
}
97+
98+
partitionStats = append(partitionStats, partitionStat)
99+
totalSize += usage.Total
100+
totalUsed += usage.Used
101+
}
102+
103+
// Calculate overall percentage
104+
var overallPercentage float64
105+
if totalSize > 0 {
106+
overallPercentage = cast.ToFloat64(fmt.Sprintf("%.2f", float64(totalUsed)/float64(totalSize)*100))
57107
}
58108

59109
return DiskStat{
60-
Used: humanize.Bytes(diskUsage.Used),
61-
Total: humanize.Bytes(diskUsage.Total),
62-
Percentage: cast.ToFloat64(fmt.Sprintf("%.2f", diskUsage.UsedPercent)),
110+
Used: humanize.Bytes(totalUsed),
111+
Total: humanize.Bytes(totalSize),
112+
Percentage: overallPercentage,
63113
Writes: DiskWriteRecord[len(DiskWriteRecord)-1],
64114
Reads: DiskReadRecord[len(DiskReadRecord)-1],
115+
Partitions: partitionStats,
65116
}, nil
66117
}
118+
119+
// isVirtualFilesystem checks if the filesystem type is virtual
120+
func isVirtualFilesystem(fstype string) bool {
121+
virtualFSTypes := map[string]bool{
122+
"proc": true,
123+
"sysfs": true,
124+
"devfs": true,
125+
"devpts": true,
126+
"tmpfs": true,
127+
"debugfs": true,
128+
"securityfs": true,
129+
"cgroup": true,
130+
"cgroup2": true,
131+
"pstore": true,
132+
"bpf": true,
133+
"tracefs": true,
134+
"hugetlbfs": true,
135+
"mqueue": true,
136+
"overlay": true,
137+
"autofs": true,
138+
"binfmt_misc": true,
139+
"configfs": true,
140+
"fusectl": true,
141+
"rpc_pipefs": true,
142+
"selinuxfs": true,
143+
"systemd-1": true,
144+
"none": true,
145+
}
146+
147+
return virtualFSTypes[fstype]
148+
}

internal/analytic/stat_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package analytic
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestGetDiskStat(t *testing.T) {
10+
diskStat, err := GetDiskStat()
11+
12+
// Test that the function doesn't return an error
13+
assert.NoError(t, err)
14+
15+
// Test that partitions are populated
16+
assert.NotEmpty(t, diskStat.Partitions)
17+
18+
// Test that overall stats are calculated
19+
assert.NotEmpty(t, diskStat.Total)
20+
assert.NotEmpty(t, diskStat.Used)
21+
assert.GreaterOrEqual(t, diskStat.Percentage, 0.0)
22+
assert.LessOrEqual(t, diskStat.Percentage, 100.0)
23+
24+
// Test each partition has required fields
25+
for _, partition := range diskStat.Partitions {
26+
assert.NotEmpty(t, partition.Mountpoint)
27+
assert.NotEmpty(t, partition.Device)
28+
assert.NotEmpty(t, partition.Fstype)
29+
assert.NotEmpty(t, partition.Total)
30+
assert.NotEmpty(t, partition.Used)
31+
assert.NotEmpty(t, partition.Free)
32+
assert.GreaterOrEqual(t, partition.Percentage, 0.0)
33+
assert.LessOrEqual(t, partition.Percentage, 100.0)
34+
}
35+
}
36+
37+
func TestIsVirtualFilesystem(t *testing.T) {
38+
// Test virtual filesystems
39+
assert.True(t, isVirtualFilesystem("proc"))
40+
assert.True(t, isVirtualFilesystem("sysfs"))
41+
assert.True(t, isVirtualFilesystem("tmpfs"))
42+
assert.True(t, isVirtualFilesystem("devpts"))
43+
44+
// Test real filesystems
45+
assert.False(t, isVirtualFilesystem("ext4"))
46+
assert.False(t, isVirtualFilesystem("xfs"))
47+
assert.False(t, isVirtualFilesystem("ntfs"))
48+
assert.False(t, isVirtualFilesystem("fat32"))
49+
}

0 commit comments

Comments
 (0)