mirror of
https://github.com/bcicen/ctop.git
synced 2024-08-30 18:23:19 +00:00
Merge pull request #35 from f1yegor/feature/more-stats
add pids, IO stat
This commit is contained in:
commit
ab1ccb3cd8
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ctop
|
||||||
|
.idea
|
@ -12,7 +12,7 @@ type CompactHeader struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewCompactHeader() *CompactHeader {
|
func NewCompactHeader() *CompactHeader {
|
||||||
fields := []string{"", "NAME", "CID", "CPU", "MEM", "NET RX/TX"}
|
fields := []string{"", "NAME", "CID", "CPU", "MEM", "NET RX/TX", "IO Read/Write", "Pids"}
|
||||||
ch := &CompactHeader{}
|
ch := &CompactHeader{}
|
||||||
ch.Height = 2
|
ch.Height = 2
|
||||||
for _, f := range fields {
|
for _, f := range fields {
|
||||||
@ -27,7 +27,7 @@ func (ch *CompactHeader) GetHeight() int {
|
|||||||
|
|
||||||
func (ch *CompactHeader) SetWidth(w int) {
|
func (ch *CompactHeader) SetWidth(w int) {
|
||||||
x := ch.X
|
x := ch.X
|
||||||
autoWidth := calcWidth(w, 5)
|
autoWidth := calcWidth(w, 7)
|
||||||
for n, col := range ch.pars {
|
for n, col := range ch.pars {
|
||||||
// set status column to static width
|
// set status column to static width
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
|
@ -15,6 +15,8 @@ type Compact struct {
|
|||||||
Cpu *GaugeCol
|
Cpu *GaugeCol
|
||||||
Memory *GaugeCol
|
Memory *GaugeCol
|
||||||
Net *TextCol
|
Net *TextCol
|
||||||
|
IO *TextCol
|
||||||
|
Pids *TextCol
|
||||||
X, Y int
|
X, Y int
|
||||||
Width int
|
Width int
|
||||||
Height int
|
Height int
|
||||||
@ -32,6 +34,8 @@ func NewCompact(id string) *Compact {
|
|||||||
Cpu: NewGaugeCol(),
|
Cpu: NewGaugeCol(),
|
||||||
Memory: NewGaugeCol(),
|
Memory: NewGaugeCol(),
|
||||||
Net: NewTextCol("-"),
|
Net: NewTextCol("-"),
|
||||||
|
IO: NewTextCol("-"),
|
||||||
|
Pids: NewTextCol("-"),
|
||||||
X: 1,
|
X: 1,
|
||||||
Height: 1,
|
Height: 1,
|
||||||
}
|
}
|
||||||
@ -59,6 +63,8 @@ func (row *Compact) SetMetrics(m metrics.Metrics) {
|
|||||||
row.SetCPU(m.CPUUtil)
|
row.SetCPU(m.CPUUtil)
|
||||||
row.SetNet(m.NetRx, m.NetTx)
|
row.SetNet(m.NetRx, m.NetTx)
|
||||||
row.SetMem(m.MemUsage, m.MemLimit, m.MemPercent)
|
row.SetMem(m.MemUsage, m.MemLimit, m.MemPercent)
|
||||||
|
row.SetIO(m.IOBytesRead, m.IOBytesWrite)
|
||||||
|
row.SetPids(m.Pids)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set gauges, counters to default unread values
|
// Set gauges, counters to default unread values
|
||||||
@ -66,6 +72,8 @@ func (row *Compact) Reset() {
|
|||||||
row.Cpu.Reset()
|
row.Cpu.Reset()
|
||||||
row.Memory.Reset()
|
row.Memory.Reset()
|
||||||
row.Net.Reset()
|
row.Net.Reset()
|
||||||
|
row.IO.Reset()
|
||||||
|
row.Pids.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (row *Compact) GetHeight() int {
|
func (row *Compact) GetHeight() int {
|
||||||
@ -91,7 +99,7 @@ func (row *Compact) SetWidth(width int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
x := row.X
|
x := row.X
|
||||||
autoWidth := calcWidth(width, 5)
|
autoWidth := calcWidth(width, 7)
|
||||||
for n, col := range row.all() {
|
for n, col := range row.all() {
|
||||||
// set status column to static width
|
// set status column to static width
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
@ -116,7 +124,8 @@ func (row *Compact) Buffer() ui.Buffer {
|
|||||||
buf.Merge(row.Cpu.Buffer())
|
buf.Merge(row.Cpu.Buffer())
|
||||||
buf.Merge(row.Memory.Buffer())
|
buf.Merge(row.Memory.Buffer())
|
||||||
buf.Merge(row.Net.Buffer())
|
buf.Merge(row.Net.Buffer())
|
||||||
|
buf.Merge(row.IO.Buffer())
|
||||||
|
buf.Merge(row.Pids.Buffer())
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,5 +137,7 @@ func (row *Compact) all() []ui.GridBufferer {
|
|||||||
row.Cpu,
|
row.Cpu,
|
||||||
row.Memory,
|
row.Memory,
|
||||||
row.Net,
|
row.Net,
|
||||||
|
row.IO,
|
||||||
|
row.Pids,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,16 @@ func (row *Compact) SetNet(rx int64, tx int64) {
|
|||||||
row.Net.Set(label)
|
row.Net.Set(label)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (row *Compact) SetIO(read int64, write int64) {
|
||||||
|
label := fmt.Sprintf("%s / %s", cwidgets.ByteFormat(read), cwidgets.ByteFormat(write))
|
||||||
|
row.IO.Set(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (row *Compact) SetPids(val int) {
|
||||||
|
label := fmt.Sprintf("%s", strconv.Itoa(val))
|
||||||
|
row.Pids.Set(label)
|
||||||
|
}
|
||||||
|
|
||||||
func (row *Compact) SetCPU(val int) {
|
func (row *Compact) SetCPU(val int) {
|
||||||
row.Cpu.BarColor = colorScale(val)
|
row.Cpu.BarColor = colorScale(val)
|
||||||
row.Cpu.Label = fmt.Sprintf("%s%%", strconv.Itoa(val))
|
row.Cpu.Label = fmt.Sprintf("%s%%", strconv.Itoa(val))
|
||||||
|
51
cwidgets/expanded/io.go
Normal file
51
cwidgets/expanded/io.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package expanded
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/bcicen/ctop/cwidgets"
|
||||||
|
ui "github.com/gizak/termui"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IO struct {
|
||||||
|
*ui.Sparklines
|
||||||
|
readHist *DiffHist
|
||||||
|
writeHist *DiffHist
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIO() *IO {
|
||||||
|
io := &IO{ui.NewSparklines(), NewDiffHist(60), NewDiffHist(60)}
|
||||||
|
io.BorderLabel = "IO"
|
||||||
|
io.Height = 6
|
||||||
|
io.Width = colWidth[0]
|
||||||
|
io.X = 0
|
||||||
|
io.Y = 24
|
||||||
|
|
||||||
|
read := ui.NewSparkline()
|
||||||
|
read.Title = "read"
|
||||||
|
read.Height = 1
|
||||||
|
read.Data = io.readHist.Data
|
||||||
|
read.LineColor = ui.ColorGreen
|
||||||
|
|
||||||
|
write := ui.NewSparkline()
|
||||||
|
write.Title = "write"
|
||||||
|
write.Height = 1
|
||||||
|
write.Data = io.writeHist.Data
|
||||||
|
write.LineColor = ui.ColorYellow
|
||||||
|
|
||||||
|
io.Lines = []ui.Sparkline{read, write}
|
||||||
|
return io
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *IO) Update(read int64, write int64) {
|
||||||
|
var rate string
|
||||||
|
|
||||||
|
w.readHist.Append(int(read))
|
||||||
|
rate = strings.ToLower(cwidgets.ByteFormatInt(w.readHist.Val))
|
||||||
|
w.Lines[0].Title = fmt.Sprintf("read [%s/s]", rate)
|
||||||
|
|
||||||
|
w.writeHist.Append(int(write))
|
||||||
|
rate = strings.ToLower(cwidgets.ByteFormatInt(w.writeHist.Val))
|
||||||
|
w.Lines[1].Title = fmt.Sprintf("write [%s/s]", rate)
|
||||||
|
}
|
@ -17,6 +17,7 @@ type Expanded struct {
|
|||||||
Net *Net
|
Net *Net
|
||||||
Cpu *Cpu
|
Cpu *Cpu
|
||||||
Mem *Mem
|
Mem *Mem
|
||||||
|
IO *IO
|
||||||
Width int
|
Width int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ func NewExpanded(id string) *Expanded {
|
|||||||
Net: NewNet(),
|
Net: NewNet(),
|
||||||
Cpu: NewCpu(),
|
Cpu: NewCpu(),
|
||||||
Mem: NewMem(),
|
Mem: NewMem(),
|
||||||
|
IO: NewIO(),
|
||||||
Width: ui.TermWidth(),
|
Width: ui.TermWidth(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,6 +47,7 @@ func (e *Expanded) SetMetrics(m metrics.Metrics) {
|
|||||||
e.Cpu.Update(m.CPUUtil)
|
e.Cpu.Update(m.CPUUtil)
|
||||||
e.Net.Update(m.NetRx, m.NetTx)
|
e.Net.Update(m.NetRx, m.NetTx)
|
||||||
e.Mem.Update(int(m.MemUsage), int(m.MemLimit))
|
e.Mem.Update(int(m.MemUsage), int(m.MemLimit))
|
||||||
|
e.IO.Update(m.IOBytesRead, m.IOBytesWrite)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Expanded) Align() {
|
func (e *Expanded) Align() {
|
||||||
@ -74,6 +77,7 @@ func (e *Expanded) Buffer() ui.Buffer {
|
|||||||
buf.Merge(e.Cpu.Buffer())
|
buf.Merge(e.Cpu.Buffer())
|
||||||
buf.Merge(e.Mem.Buffer())
|
buf.Merge(e.Mem.Buffer())
|
||||||
buf.Merge(e.Net.Buffer())
|
buf.Merge(e.Net.Buffer())
|
||||||
|
buf.Merge(e.IO.Buffer())
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +87,7 @@ func (e *Expanded) all() []ui.GridBufferer {
|
|||||||
e.Cpu,
|
e.Cpu,
|
||||||
e.Mem,
|
e.Mem,
|
||||||
e.Net,
|
e.Net,
|
||||||
|
e.IO,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ func (c *Docker) Start() {
|
|||||||
c.ReadCPU(s)
|
c.ReadCPU(s)
|
||||||
c.ReadMem(s)
|
c.ReadMem(s)
|
||||||
c.ReadNet(s)
|
c.ReadNet(s)
|
||||||
|
c.ReadIO(s)
|
||||||
c.stream <- c.Metrics
|
c.stream <- c.Metrics
|
||||||
}
|
}
|
||||||
log.Infof("collector stopped for container: %s", c.id)
|
log.Infof("collector stopped for container: %s", c.id)
|
||||||
@ -79,6 +80,7 @@ func (c *Docker) ReadCPU(stats *api.Stats) {
|
|||||||
c.CPUUtil = round((cpudiff / syscpudiff * 100) * ncpus)
|
c.CPUUtil = round((cpudiff / syscpudiff * 100) * ncpus)
|
||||||
c.lastCpu = total
|
c.lastCpu = total
|
||||||
c.lastSysCpu = system
|
c.lastSysCpu = system
|
||||||
|
c.Pids = int(stats.PidsStats.Current)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Docker) ReadMem(stats *api.Stats) {
|
func (c *Docker) ReadMem(stats *api.Stats) {
|
||||||
@ -95,3 +97,16 @@ func (c *Docker) ReadNet(stats *api.Stats) {
|
|||||||
}
|
}
|
||||||
c.NetRx, c.NetTx = rx, tx
|
c.NetRx, c.NetTx = rx, tx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Docker) ReadIO(stats *api.Stats) {
|
||||||
|
var read, write int64
|
||||||
|
for _, blk := range stats.BlkioStats.IOServiceBytesRecursive {
|
||||||
|
if blk.Op == "Read" {
|
||||||
|
read = int64(blk.Value)
|
||||||
|
}
|
||||||
|
if blk.Op == "Write" {
|
||||||
|
write = int64(blk.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.IOBytesRead, c.IOBytesWrite = read, write
|
||||||
|
}
|
||||||
|
@ -9,21 +9,27 @@ import (
|
|||||||
var log = logging.Init()
|
var log = logging.Init()
|
||||||
|
|
||||||
type Metrics struct {
|
type Metrics struct {
|
||||||
CPUUtil int
|
CPUUtil int
|
||||||
NetTx int64
|
NetTx int64
|
||||||
NetRx int64
|
NetRx int64
|
||||||
MemLimit int64
|
MemLimit int64
|
||||||
MemPercent int
|
MemPercent int
|
||||||
MemUsage int64
|
MemUsage int64
|
||||||
|
IOBytesRead int64
|
||||||
|
IOBytesWrite int64
|
||||||
|
Pids int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMetrics() Metrics {
|
func NewMetrics() Metrics {
|
||||||
return Metrics{
|
return Metrics{
|
||||||
CPUUtil: -1,
|
CPUUtil: -1,
|
||||||
NetTx: -1,
|
NetTx: -1,
|
||||||
NetRx: -1,
|
NetRx: -1,
|
||||||
MemUsage: -1,
|
MemUsage: -1,
|
||||||
MemPercent: -1,
|
MemPercent: -1,
|
||||||
|
IOBytesRead: -1,
|
||||||
|
IOBytesWrite: -1,
|
||||||
|
Pids: -1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
sort.go
11
sort.go
@ -53,6 +53,15 @@ var Sorters = map[string]sortMethod{
|
|||||||
}
|
}
|
||||||
return sum1 > sum2
|
return sum1 > sum2
|
||||||
},
|
},
|
||||||
|
"io": func(c1, c2 *Container) bool {
|
||||||
|
sum1 := sumIO(c1)
|
||||||
|
sum2 := sumIO(c2)
|
||||||
|
// Use secondary sort method if equal values
|
||||||
|
if sum1 == sum2 {
|
||||||
|
return nameSorter(c1, c2)
|
||||||
|
}
|
||||||
|
return sum1 > sum2
|
||||||
|
},
|
||||||
"state": func(c1, c2 *Container) bool {
|
"state": func(c1, c2 *Container) bool {
|
||||||
// Use secondary sort method if equal values
|
// Use secondary sort method if equal values
|
||||||
c1state := c1.GetMeta("state")
|
c1state := c1.GetMeta("state")
|
||||||
@ -101,3 +110,5 @@ func (a Containers) Filter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sumNet(c *Container) int64 { return c.NetRx + c.NetTx }
|
func sumNet(c *Container) int64 { return c.NetRx + c.NetTx }
|
||||||
|
|
||||||
|
func sumIO(c *Container) int64 { return c.IOBytesRead + c.IOBytesWrite }
|
||||||
|
Loading…
Reference in New Issue
Block a user