1
0
mirror of https://github.com/cjbassi/gotop.git synced 2025-04-27 13:48:54 +08:00
gotop/src/widgets/disk.go

169 lines
4.1 KiB
Go
Raw Normal View History

2018-02-18 23:25:02 -08:00
package widgets
import (
"fmt"
"log"
2018-05-21 16:02:31 -07:00
"sort"
"strings"
2018-02-18 23:25:02 -08:00
"time"
2018-05-10 21:23:20 -07:00
"github.com/cjbassi/gotop/src/utils"
2018-03-29 15:48:43 -07:00
ui "github.com/cjbassi/termui"
2018-03-03 17:05:52 -08:00
psDisk "github.com/shirou/gopsutil/disk"
2018-02-18 23:25:02 -08:00
)
2018-05-21 16:02:31 -07:00
type Partition struct {
Device string
Mount string
TotalRead uint64
TotalWrite uint64
CurRead string
CurWrite string
UsedPercent int
Free string
}
2018-02-18 23:25:02 -08:00
type Disk struct {
2018-05-21 16:02:31 -07:00
*ui.Table
interval time.Duration
Partitions map[string]*Partition
2018-02-18 23:25:02 -08:00
}
func NewDisk() *Disk {
2018-03-27 14:27:23 -07:00
self := &Disk{
2018-05-21 16:02:31 -07:00
Table: ui.NewTable(),
interval: time.Second,
Partitions: make(map[string]*Partition),
2018-03-03 17:05:52 -08:00
}
2018-03-27 14:27:23 -07:00
self.Label = "Disk Usage"
2018-05-21 16:02:31 -07:00
self.Header = []string{"Disk", "Mount", "Used", "Free", "R/s", "W/s"}
self.Gap = 2
self.ColResizer = self.ColResize
2018-02-18 23:25:02 -08:00
2018-04-12 20:00:34 -07:00
self.update()
2018-02-18 23:25:02 -08:00
go func() {
ticker := time.NewTicker(self.interval)
2018-02-18 23:25:02 -08:00
for range ticker.C {
2018-03-27 14:27:23 -07:00
self.update()
2018-02-18 23:25:02 -08:00
}
}()
2018-03-27 14:27:23 -07:00
return self
2018-02-18 23:25:02 -08:00
}
2018-03-27 14:27:23 -07:00
func (self *Disk) update() {
Partitions, err := psDisk.Partitions(false)
if err != nil {
log.Printf("failed to get disk partitions from gopsutil: %v", err)
}
2018-05-21 16:02:31 -07:00
// add partition if it's new
for _, Part := range Partitions {
2018-12-03 10:55:39 +01:00
// don't show loop devices
2018-12-09 22:04:43 -08:00
if strings.HasPrefix(Part.Device, "/dev/loop") {
2018-12-03 10:55:39 +01:00
continue
}
// don't show docker container filesystems
if strings.HasPrefix(Part.Mountpoint, "/var/lib/docker/") {
continue
}
// check if partition doesn't already exist in our list
if _, ok := self.Partitions[Part.Device]; !ok {
self.Partitions[Part.Device] = &Partition{
Device: Part.Device,
2018-12-04 21:53:53 -08:00
Mount: Part.Mountpoint,
2018-05-21 16:02:31 -07:00
}
}
}
// delete a partition if it no longer exists
todelete := []string{}
for key := range self.Partitions {
2018-05-21 16:02:31 -07:00
exists := false
for _, Part := range Partitions {
if key == Part.Device {
2018-05-21 16:02:31 -07:00
exists = true
break
}
}
if !exists {
todelete = append(todelete, key)
}
}
for _, val := range todelete {
delete(self.Partitions, val)
}
// updates partition info
for _, Part := range self.Partitions {
usage, err := psDisk.Usage(Part.Mount)
if err != nil {
2018-12-04 22:34:45 -08:00
log.Printf("failed to get partition usage statistics from gopsutil: %v. Part: %v", err, Part)
continue
}
2018-05-21 16:02:31 -07:00
Part.UsedPercent = int(usage.UsedPercent)
Free, Mag := utils.ConvertBytes(usage.Free)
Part.Free = fmt.Sprintf("%3d%s", uint64(Free), Mag)
ret, err := psDisk.IOCounters(Part.Device)
if err != nil {
2018-12-04 22:34:45 -08:00
log.Printf("failed to get partition read/write info from gopsutil: %v. Part: %v", err, Part)
continue
}
2018-05-21 16:02:31 -07:00
data := ret[Part.Device]
curRead, curWrite := data.ReadBytes, data.WriteBytes
if Part.TotalRead != 0 { // if this isn't the first update
readRecent := curRead - Part.TotalRead
writeRecent := curWrite - Part.TotalWrite
readFloat, unitRead := utils.ConvertBytes(readRecent)
writeFloat, unitWrite := utils.ConvertBytes(writeRecent)
readRecent, writeRecent = uint64(readFloat), uint64(writeFloat)
Part.CurRead = fmt.Sprintf("%d%s", readRecent, unitRead)
Part.CurWrite = fmt.Sprintf("%d%s", writeRecent, unitWrite)
} else {
Part.CurRead = fmt.Sprintf("%d%s", 0, "B")
Part.CurWrite = fmt.Sprintf("%d%s", 0, "B")
}
Part.TotalRead, Part.TotalWrite = curRead, curWrite
}
// converts self.Partitions into self.Rows which is a [][]String
sortedPartitions := []string{}
for seriesName := range self.Partitions {
sortedPartitions = append(sortedPartitions, seriesName)
}
sort.Strings(sortedPartitions)
self.Rows = make([][]string, len(self.Partitions))
for i, key := range sortedPartitions {
Part := self.Partitions[key]
self.Rows[i] = make([]string, 6)
2018-12-10 11:20:32 -08:00
self.Rows[i][0] = strings.Replace(strings.Replace(Part.Device, "/dev/", "", -1), "mapper/", "", -1)
2018-05-21 16:02:31 -07:00
self.Rows[i][1] = Part.Mount
self.Rows[i][2] = fmt.Sprintf("%d%%", Part.UsedPercent)
self.Rows[i][3] = Part.Free
self.Rows[i][4] = Part.CurRead
self.Rows[i][5] = Part.CurWrite
}
}
// ColResize overrides the default ColResize in the termui table.
func (self *Disk) ColResize() {
self.ColWidths = []int{
4,
utils.Max(5, self.X-33),
4, 5, 5, 5,
}
self.CellXPos = []int{}
cur := 1
for _, w := range self.ColWidths {
self.CellXPos = append(self.CellXPos, cur)
cur += w
cur += self.Gap
}
2018-02-18 23:25:02 -08:00
}