diff --git a/go.mod b/go.mod index 377029a..bf16155 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/gorilla/websocket v1.5.1 github.com/joho/godotenv v1.5.1 github.com/rivo/tview v0.0.0-20240505185119-ed116790de0f + github.com/shirou/gopsutil/v4 v4.24.6 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 github.com/swaggo/swag v1.16.3 @@ -38,6 +39,7 @@ require ( github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gdamore/encoding v1.0.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.4 // indirect github.com/go-openapi/spec v0.20.14 // indirect @@ -53,14 +55,19 @@ require ( github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect golang.org/x/arch v0.8.0 // indirect golang.org/x/crypto v0.23.0 // indirect golang.org/x/net v0.25.0 // indirect diff --git a/go.sum b/go.sum index 6f7cabd..326e564 100644 --- a/go.sum +++ b/go.sum @@ -54,6 +54,8 @@ github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= @@ -76,8 +78,9 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= @@ -107,6 +110,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -131,6 +136,8 @@ github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/rivo/tview v0.0.0-20240505185119-ed116790de0f h1:DAbaKhyPcZQp/TqlSdUd6Z445PkJb3bI0VccXg22oeg= github.com/rivo/tview v0.0.0-20240505185119-ed116790de0f/go.mod h1:02iFIz7K/A9jGCvrizLPvoqr4cEIx7q54RH5Qudkrss= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -144,6 +151,8 @@ github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil/v4 v4.24.6 h1:9qqCSYF2pgOU+t+NgJtp7Co5+5mHF/HyKBUckySQL64= +github.com/shirou/gopsutil/v4 v4.24.6/go.mod h1:aoebb2vxetJ/yIDZISmduFvVNPHqXQ9SEJwRXxkf0RA= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= @@ -170,12 +179,18 @@ github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+z github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/gopher-lua v0.0.0-20190514113301-1cd887cd7036/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zaffka/mongodb-boltdb-mock v0.0.0-20221014194232-b4bb03fbe3a0/go.mod h1:GsDD1qsG+86MeeCG7ndi6Ei3iGthKL3wQ7PTFigDfNY= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= @@ -206,7 +221,9 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -214,6 +231,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= @@ -238,7 +257,6 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/src/app/process.go b/src/app/process.go index 3f07ae2..3ddc017 100644 --- a/src/app/process.go +++ b/src/app/process.go @@ -5,8 +5,6 @@ import ( "context" "errors" "fmt" - "github.com/cakturk/go-netstat/netstat" - "github.com/f1bonacc1/process-compose/src/types" "io" "math/rand" "os" @@ -17,12 +15,16 @@ import ( "syscall" "time" + "github.com/cakturk/go-netstat/netstat" + "github.com/f1bonacc1/process-compose/src/types" + "github.com/f1bonacc1/process-compose/src/command" "github.com/f1bonacc1/process-compose/src/health" "github.com/f1bonacc1/process-compose/src/pclog" "github.com/fatih/color" "github.com/rs/zerolog/log" + puproc "github.com/shirou/gopsutil/v4/process" ) const ( @@ -455,10 +457,11 @@ func (p *Process) updateProcState() { p.procState.SystemTime = durationToString(dur) p.procState.Age = dur p.procState.Name = p.getName() + p.procState.Mem = p.getMemUsage() } p.procState.IsRunning = isRunning - } + func (p *Process) setStartTime(startTime time.Time) { p.timeMutex.Lock() defer p.timeMutex.Unlock() @@ -471,6 +474,26 @@ func (p *Process) getStartTime() time.Time { return p.startTime } +func (p *Process) getMemUsage() int64 { + if p.procConf.IsDaemon { + return 0 + } + proc, err := puproc.NewProcess(int32(p.procState.Pid)) + if err != nil { + log.Err(err).Msgf("Could not find process") + return -1 + } + meminfo, err := proc.MemoryInfo() + if err != nil { + log.Err(err). + Str("process", p.getName()). + Int("pid", p.procState.Pid). + Msg("Error retrieving memory stats") + return -1 + } + return int64(meminfo.RSS) +} + func (p *Process) handleInput(pipe io.WriteCloser) { reader := bufio.NewReader(os.Stdin) for { diff --git a/src/tui/proc-table.go b/src/tui/proc-table.go index f01d22a..6cd6709 100644 --- a/src/tui/proc-table.go +++ b/src/tui/proc-table.go @@ -21,6 +21,7 @@ type tableRowValues struct { ns string status string age string + mem string health string restarts string exitCode string @@ -101,6 +102,7 @@ func setRowValues(procTable *tview.Table, row int, rowVals tableRowValues) { procTable.SetCell(row, int(ProcessStateStatus), tview.NewTableCell(rowVals.status).SetAlign(tview.AlignLeft).SetExpansion(1).SetTextColor(rowVals.fgColor)) procTable.SetCell(row, int(ProcessStateAge), tview.NewTableCell(rowVals.age).SetAlign(tview.AlignLeft).SetExpansion(1).SetTextColor(rowVals.fgColor)) procTable.SetCell(row, int(ProcessStateHealth), tview.NewTableCell(rowVals.health).SetAlign(tview.AlignLeft).SetExpansion(1).SetTextColor(rowVals.fgColor)) + procTable.SetCell(row, int(ProcessStateMem), tview.NewTableCell(rowVals.mem).SetAlign(tview.AlignLeft).SetExpansion(1).SetTextColor(rowVals.fgColor)) procTable.SetCell(row, int(ProcessStateRestarts), tview.NewTableCell(rowVals.restarts).SetAlign(tview.AlignRight).SetExpansion(0).SetTextColor(rowVals.fgColor)) procTable.SetCell(row, int(ProcessStateExit), tview.NewTableCell(rowVals.exitCode).SetAlign(tview.AlignRight).SetExpansion(0).SetTextColor(rowVals.fgColor)) } @@ -132,6 +134,7 @@ func (pv *pcView) createProcTable() *tview.Table { ProcessStateStatus: "STATUS(S)", ProcessStateAge: "AGE(A)", ProcessStateHealth: "HEALTH(H)", + ProcessStateMem: "MEM(M)", ProcessStateRestarts: "RESTARTS(R)", ProcessStateExit: "EXIT CODE(E)", } @@ -157,6 +160,8 @@ func (pv *pcView) createProcTable() *tview.Table { pv.setTableSorter(ProcessStateAge) } else if event.Rune() == 'H' { pv.setTableSorter(ProcessStateHealth) + } else if event.Rune() == 'M' { + pv.setTableSorter(ProcessStateMem) } else if event.Rune() == 'R' { pv.setTableSorter(ProcessStateRestarts) } else if event.Rune() == 'E' { @@ -313,6 +318,32 @@ func (pv *pcView) getIconForState(state types.ProcessState) (string, tcell.Color } } +func byteCountIEC(b int64) string { + const mib = 1024 * 1024 + if b < mib { + return fmt.Sprintf("%.1f MiB", float64(b)/float64(mib)) + + } + const unit = 1024 + div, exp := int64(1024), 0 + for n := b / unit; n >= unit; n /= unit { + div *= unit + exp++ + } + return fmt.Sprintf("%.1f %ciB", + float64(b)/float64(div), "KMGTPE"[exp]) +} + +func getStrForMem(mem int64) string { + if mem < 0 { + return "unknown" + } + if mem == 0 { + return "-" + } + return byteCountIEC(mem) +} + func getStrForRestarts(restarts int) string { if restarts == 0 { return types.PlaceHolderValue @@ -346,6 +377,7 @@ func (pv *pcView) getTableRowValues(state types.ProcessState) tableRowValues { status: state.Status, age: state.SystemTime, health: state.Health, + mem: getStrForMem(state.Mem), restarts: getStrForRestarts(state.Restarts), exitCode: getStrForExitCode(state), } diff --git a/src/tui/proc-table_test.go b/src/tui/proc-table_test.go new file mode 100644 index 0000000..c071b74 --- /dev/null +++ b/src/tui/proc-table_test.go @@ -0,0 +1,66 @@ +package tui + +import ( + "testing" +) + +func TestMemToString(t *testing.T) { + type args struct { + mem int64 + } + tests := []struct { + name string + args args + want string + }{ + { + name: "negative", + args: args{ + mem: -1, + }, + want: "unknown", + }, + { + name: "zero", + args: args{ + mem: 0, + }, + want: "-", + }, + { + name: "bytes", + args: args{ + mem: 345, + }, + want: "0.0 MiB", + }, + { + name: "kilobytes", + args: args{ + mem: 1024 * 513, + }, + want: "0.5 MiB", + }, + { + name: "megabytes", + args: args{ + mem: 1024*1024*7 + 1024*513, + }, + want: "7.5 MiB", + }, + { + name: "gigabytes", + args: args{ + mem: 1024*1024*1024*4 + 1024*1024*740, + }, + want: "4.7 GiB", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getStrForMem(tt.args.mem); got != tt.want { + t.Errorf("getStrForMem() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/src/tui/procstate_sorter.go b/src/tui/procstate_sorter.go index e104104..473099a 100644 --- a/src/tui/procstate_sorter.go +++ b/src/tui/procstate_sorter.go @@ -18,8 +18,9 @@ const ( ProcessStateStatus ColumnID = 4 ProcessStateAge ColumnID = 5 ProcessStateHealth ColumnID = 6 - ProcessStateRestarts ColumnID = 7 - ProcessStateExit ColumnID = 8 + ProcessStateMem ColumnID = 7 + ProcessStateRestarts ColumnID = 8 + ProcessStateExit ColumnID = 9 ) var columnNames = map[ColumnID]string{ @@ -30,6 +31,7 @@ var columnNames = map[ColumnID]string{ ProcessStateStatus: "STATUS", ProcessStateAge: "AGE", ProcessStateHealth: "HEALTH", + ProcessStateMem: "MEM", ProcessStateRestarts: "RESTARTS", ProcessStateExit: "EXIT", } @@ -42,6 +44,7 @@ var columnIDs = map[string]ColumnID{ "STATUS": ProcessStateStatus, "AGE": ProcessStateAge, "HEALTH": ProcessStateHealth, + "MEM": ProcessStateMem, "RESTARTS": ProcessStateRestarts, "EXIT": ProcessStateExit, } @@ -148,6 +151,10 @@ func getSorter(sortBy ColumnID, states *types.ProcessesState) sortFn { return eci < ecj } } + case ProcessStateMem: + return func(i, j int) bool { + return states.States[i].Mem < states.States[j].Mem + } case ProcessStateName: fallthrough default: diff --git a/src/types/process.go b/src/types/process.go index a2af2d6..3c980be 100644 --- a/src/types/process.go +++ b/src/types/process.go @@ -76,6 +76,7 @@ func NewProcessState(proc *ProcessConfig) *ProcessState { Health: ProcessHealthUnknown, Restarts: 0, ExitCode: 0, + Mem: 0, Pid: 0, } if proc.Disabled { @@ -96,6 +97,7 @@ type ProcessState struct { Restarts int `json:"restarts"` ExitCode int `json:"exit_code"` Pid int `json:"pid"` + Mem int64 `json:"mem"` IsRunning bool }