mirror of
https://github.com/bcicen/ctop.git
synced 2025-12-06 15:16:41 +08:00
Merge branch 'refactor-widgets'
This commit is contained in:
8
Makefile
8
Makefile
@@ -11,9 +11,6 @@ build:
|
|||||||
go mod download
|
go mod download
|
||||||
CGO_ENABLED=0 go build -tags release -ldflags $(LD_FLAGS) -o ctop
|
CGO_ENABLED=0 go build -tags release -ldflags $(LD_FLAGS) -o ctop
|
||||||
|
|
||||||
build-dev:
|
|
||||||
go build -ldflags "-w -X main.version=$(VERSION)-dev -X main.build=$(BUILD) -extldflags=$(EXT_LD_FLAGS)"
|
|
||||||
|
|
||||||
build-all:
|
build-all:
|
||||||
mkdir -p _build
|
mkdir -p _build
|
||||||
GOOS=darwin GOARCH=amd64 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-darwin-amd64
|
GOOS=darwin GOARCH=amd64 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-darwin-amd64
|
||||||
@@ -23,6 +20,11 @@ build-all:
|
|||||||
GOOS=windows GOARCH=amd64 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-windows-amd64
|
GOOS=windows GOARCH=amd64 go build -tags release -ldflags $(LD_FLAGS) -o _build/ctop-$(VERSION)-windows-amd64
|
||||||
cd _build; sha256sum * > sha256sums.txt
|
cd _build; sha256sum * > sha256sums.txt
|
||||||
|
|
||||||
|
run-dev:
|
||||||
|
rm -f ctop.sock ctop
|
||||||
|
go build -ldflags $(LD_FLAGS) -o ctop
|
||||||
|
CTOP_DEBUG=1 ./ctop
|
||||||
|
|
||||||
image:
|
image:
|
||||||
docker build -t ctop -f Dockerfile .
|
docker build -t ctop -f Dockerfile .
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ const (
|
|||||||
type Container struct {
|
type Container struct {
|
||||||
models.Metrics
|
models.Metrics
|
||||||
Id string
|
Id string
|
||||||
Meta map[string]string
|
Meta models.Meta
|
||||||
Widgets *compact.Compact
|
Widgets *compact.CompactRow
|
||||||
Display bool // display this container in compact view
|
Display bool // display this container in compact view
|
||||||
updater cwidgets.WidgetUpdater
|
updater cwidgets.WidgetUpdater
|
||||||
collector collector.Collector
|
collector collector.Collector
|
||||||
@@ -30,11 +30,11 @@ type Container struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func New(id string, collector collector.Collector, manager manager.Manager) *Container {
|
func New(id string, collector collector.Collector, manager manager.Manager) *Container {
|
||||||
widgets := compact.NewCompact(id)
|
widgets := compact.NewCompactRow()
|
||||||
return &Container{
|
return &Container{
|
||||||
Metrics: models.NewMetrics(),
|
Metrics: models.NewMetrics(),
|
||||||
Id: id,
|
Id: id,
|
||||||
Meta: make(map[string]string),
|
Meta: models.NewMeta("id", id),
|
||||||
Widgets: widgets,
|
Widgets: widgets,
|
||||||
updater: widgets,
|
updater: widgets,
|
||||||
collector: collector,
|
collector: collector,
|
||||||
@@ -44,21 +44,16 @@ func New(id string, collector collector.Collector, manager manager.Manager) *Con
|
|||||||
|
|
||||||
func (c *Container) SetUpdater(u cwidgets.WidgetUpdater) {
|
func (c *Container) SetUpdater(u cwidgets.WidgetUpdater) {
|
||||||
c.updater = u
|
c.updater = u
|
||||||
for k, v := range c.Meta {
|
c.updater.SetMeta(c.Meta)
|
||||||
c.updater.SetMeta(k, v)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) SetMeta(k, v string) {
|
func (c *Container) SetMeta(k, v string) {
|
||||||
c.Meta[k] = v
|
c.Meta[k] = v
|
||||||
c.updater.SetMeta(k, v)
|
c.updater.SetMeta(c.Meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) GetMeta(k string) string {
|
func (c *Container) GetMeta(k string) string {
|
||||||
if v, ok := c.Meta[k]; ok {
|
return c.Meta.Get(k)
|
||||||
return v
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) SetState(s string) {
|
func (c *Container) SetState(s string) {
|
||||||
|
|||||||
@@ -1,21 +1,59 @@
|
|||||||
package compact
|
package compact
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/bcicen/ctop/cwidgets"
|
||||||
|
"github.com/bcicen/ctop/models"
|
||||||
ui "github.com/gizak/termui"
|
ui "github.com/gizak/termui"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GaugeCol struct {
|
type CPUCol struct {
|
||||||
*ui.Gauge
|
*GaugeCol
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGaugeCol() *GaugeCol {
|
func NewCPUCol() CompactCol {
|
||||||
g := ui.NewGauge()
|
return &CPUCol{NewGaugeCol("CPU")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *CPUCol) SetMetrics(m models.Metrics) {
|
||||||
|
val := m.CPUUtil
|
||||||
|
w.BarColor = colorScale(val)
|
||||||
|
w.Label = fmt.Sprintf("%d%%", val)
|
||||||
|
|
||||||
|
if val > 100 {
|
||||||
|
val = 100
|
||||||
|
}
|
||||||
|
w.Percent = val
|
||||||
|
}
|
||||||
|
|
||||||
|
type MemCol struct {
|
||||||
|
*GaugeCol
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMemCol() CompactCol {
|
||||||
|
return &MemCol{NewGaugeCol("MEM")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *MemCol) SetMetrics(m models.Metrics) {
|
||||||
|
w.BarColor = ui.ThemeAttr("gauge.bar.bg")
|
||||||
|
w.Label = fmt.Sprintf("%s / %s", cwidgets.ByteFormat(m.MemUsage), cwidgets.ByteFormat(m.MemLimit))
|
||||||
|
w.Percent = m.MemPercent
|
||||||
|
}
|
||||||
|
|
||||||
|
type GaugeCol struct {
|
||||||
|
*ui.Gauge
|
||||||
|
header string
|
||||||
|
fWidth int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGaugeCol(header string) *GaugeCol {
|
||||||
|
g := &GaugeCol{ui.NewGauge(), header, 0}
|
||||||
g.Height = 1
|
g.Height = 1
|
||||||
g.Border = false
|
g.Border = false
|
||||||
g.Percent = 0
|
|
||||||
g.PaddingBottom = 0
|
g.PaddingBottom = 0
|
||||||
g.Label = "-"
|
g.Reset()
|
||||||
return &GaugeCol{g}
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *GaugeCol) Reset() {
|
func (w *GaugeCol) Reset() {
|
||||||
@@ -23,11 +61,30 @@ func (w *GaugeCol) Reset() {
|
|||||||
w.Percent = 0
|
w.Percent = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *GaugeCol) Buffer() ui.Buffer {
|
||||||
|
// if bar would not otherwise be visible, set a minimum
|
||||||
|
// percentage value and low-contrast color for structure
|
||||||
|
if w.Percent < 5 {
|
||||||
|
w.Percent = 5
|
||||||
|
w.BarColor = ui.ColorBlack
|
||||||
|
}
|
||||||
|
|
||||||
|
return w.Gauge.Buffer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GaugeCol implements CompactCol
|
||||||
|
func (w *GaugeCol) SetMeta(models.Meta) {}
|
||||||
|
func (w *GaugeCol) SetMetrics(models.Metrics) {}
|
||||||
|
func (w *GaugeCol) Header() string { return w.header }
|
||||||
|
func (w *GaugeCol) FixedWidth() int { return w.fWidth }
|
||||||
|
|
||||||
|
// GaugeCol implements CompactCol
|
||||||
func (w *GaugeCol) Highlight() {
|
func (w *GaugeCol) Highlight() {
|
||||||
w.Bg = ui.ThemeAttr("par.text.fg")
|
w.Bg = ui.ThemeAttr("par.text.fg")
|
||||||
w.PercentColor = ui.ThemeAttr("par.text.hi")
|
w.PercentColor = ui.ThemeAttr("par.text.hi")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GaugeCol implements CompactCol
|
||||||
func (w *GaugeCol) UnHighlight() {
|
func (w *GaugeCol) UnHighlight() {
|
||||||
w.Bg = ui.ThemeAttr("par.text.bg")
|
w.Bg = ui.ThemeAttr("par.text.bg")
|
||||||
w.PercentColor = ui.ThemeAttr("par.text.bg")
|
w.PercentColor = ui.ThemeAttr("par.text.bg")
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import (
|
|||||||
ui "github.com/gizak/termui"
|
ui "github.com/gizak/termui"
|
||||||
)
|
)
|
||||||
|
|
||||||
var header *CompactHeader
|
|
||||||
|
|
||||||
type CompactGrid struct {
|
type CompactGrid struct {
|
||||||
ui.GridBufferer
|
ui.GridBufferer
|
||||||
Rows []ui.GridBufferer
|
header *CompactHeader
|
||||||
|
cols []CompactCol // reference columns
|
||||||
|
Rows []RowBufferer
|
||||||
X, Y int
|
X, Y int
|
||||||
Width int
|
Width int
|
||||||
Height int
|
Height int
|
||||||
@@ -16,8 +16,13 @@ type CompactGrid struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewCompactGrid() *CompactGrid {
|
func NewCompactGrid() *CompactGrid {
|
||||||
header = NewCompactHeader() // init column header
|
cg := &CompactGrid{header: NewCompactHeader()}
|
||||||
return &CompactGrid{}
|
for _, wFn := range allCols {
|
||||||
|
w := wFn()
|
||||||
|
cg.cols = append(cg.cols, w)
|
||||||
|
cg.header.addFieldPar(w.Header())
|
||||||
|
}
|
||||||
|
return cg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cg *CompactGrid) Align() {
|
func (cg *CompactGrid) Align() {
|
||||||
@@ -28,22 +33,47 @@ func (cg *CompactGrid) Align() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update row ypos, width recursively
|
// update row ypos, width recursively
|
||||||
|
colWidths := cg.calcWidths()
|
||||||
for _, r := range cg.pageRows() {
|
for _, r := range cg.pageRows() {
|
||||||
r.SetY(y)
|
r.SetY(y)
|
||||||
y += r.GetHeight()
|
y += r.GetHeight()
|
||||||
r.SetWidth(cg.Width)
|
r.SetWidths(cg.Width, colWidths)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cg *CompactGrid) Clear() { cg.Rows = []ui.GridBufferer{} }
|
func (cg *CompactGrid) Clear() { cg.Rows = []RowBufferer{} }
|
||||||
func (cg *CompactGrid) GetHeight() int { return len(cg.Rows) + header.Height }
|
func (cg *CompactGrid) GetHeight() int { return len(cg.Rows) + cg.header.Height }
|
||||||
func (cg *CompactGrid) SetX(x int) { cg.X = x }
|
func (cg *CompactGrid) SetX(x int) { cg.X = x }
|
||||||
func (cg *CompactGrid) SetY(y int) { cg.Y = y }
|
func (cg *CompactGrid) SetY(y int) { cg.Y = y }
|
||||||
func (cg *CompactGrid) SetWidth(w int) { cg.Width = w }
|
func (cg *CompactGrid) SetWidth(w int) { cg.Width = w }
|
||||||
func (cg *CompactGrid) MaxRows() int { return ui.TermHeight() - header.Height - cg.Y }
|
func (cg *CompactGrid) MaxRows() int { return ui.TermHeight() - cg.header.Height - cg.Y }
|
||||||
|
|
||||||
func (cg *CompactGrid) pageRows() (rows []ui.GridBufferer) {
|
// calculate and return per-column width
|
||||||
rows = append(rows, header)
|
func (cg *CompactGrid) calcWidths() []int {
|
||||||
|
var autoCols int
|
||||||
|
width := cg.Width
|
||||||
|
colWidths := make([]int, len(cg.cols))
|
||||||
|
|
||||||
|
for n, w := range cg.cols {
|
||||||
|
colWidths[n] = w.FixedWidth()
|
||||||
|
width -= w.FixedWidth()
|
||||||
|
if w.FixedWidth() == 0 {
|
||||||
|
autoCols++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spacing := colSpacing * len(cg.cols)
|
||||||
|
autoWidth := (width - spacing) / autoCols
|
||||||
|
for n, val := range colWidths {
|
||||||
|
if val == 0 {
|
||||||
|
colWidths[n] = autoWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return colWidths
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cg *CompactGrid) pageRows() (rows []RowBufferer) {
|
||||||
|
rows = append(rows, cg.header)
|
||||||
rows = append(rows, cg.Rows[cg.Offset:]...)
|
rows = append(rows, cg.Rows[cg.Offset:]...)
|
||||||
return rows
|
return rows
|
||||||
}
|
}
|
||||||
@@ -56,6 +86,6 @@ func (cg *CompactGrid) Buffer() ui.Buffer {
|
|||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cg *CompactGrid) AddRows(rows ...ui.GridBufferer) {
|
func (cg *CompactGrid) AddRows(rows ...RowBufferer) {
|
||||||
cg.Rows = append(cg.Rows, rows...)
|
cg.Rows = append(cg.Rows, rows...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,63 +8,52 @@ type CompactHeader struct {
|
|||||||
X, Y int
|
X, Y int
|
||||||
Width int
|
Width int
|
||||||
Height int
|
Height int
|
||||||
|
cols []CompactCol
|
||||||
|
widths []int
|
||||||
pars []*ui.Par
|
pars []*ui.Par
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCompactHeader() *CompactHeader {
|
func NewCompactHeader() *CompactHeader {
|
||||||
fields := []string{"", "NAME", "CID", "CPU", "MEM", "NET RX/TX", "IO R/W", "PIDS"}
|
return &CompactHeader{Height: 2}
|
||||||
ch := &CompactHeader{}
|
}
|
||||||
ch.Height = 2
|
|
||||||
for _, f := range fields {
|
func (row *CompactHeader) GetHeight() int {
|
||||||
ch.addFieldPar(f)
|
return row.Height
|
||||||
|
}
|
||||||
|
|
||||||
|
func (row *CompactHeader) SetWidths(totalWidth int, widths []int) {
|
||||||
|
x := row.X
|
||||||
|
|
||||||
|
for n, w := range row.pars {
|
||||||
|
w.SetX(x)
|
||||||
|
w.SetWidth(widths[n])
|
||||||
|
x += widths[n] + colSpacing
|
||||||
}
|
}
|
||||||
return ch
|
row.Width = totalWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch *CompactHeader) GetHeight() int {
|
func (row *CompactHeader) SetX(x int) {
|
||||||
return ch.Height
|
row.X = x
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch *CompactHeader) SetWidth(w int) {
|
func (row *CompactHeader) SetY(y int) {
|
||||||
x := ch.X
|
for _, p := range row.pars {
|
||||||
autoWidth := calcWidth(w)
|
|
||||||
for n, col := range ch.pars {
|
|
||||||
// set column to static width
|
|
||||||
if colWidths[n] != 0 {
|
|
||||||
col.SetX(x)
|
|
||||||
col.SetWidth(colWidths[n])
|
|
||||||
x += colWidths[n]
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
col.SetX(x)
|
|
||||||
col.SetWidth(autoWidth)
|
|
||||||
x += autoWidth + colSpacing
|
|
||||||
}
|
|
||||||
ch.Width = w
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *CompactHeader) SetX(x int) {
|
|
||||||
ch.X = x
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ch *CompactHeader) SetY(y int) {
|
|
||||||
for _, p := range ch.pars {
|
|
||||||
p.SetY(y)
|
p.SetY(y)
|
||||||
}
|
}
|
||||||
ch.Y = y
|
row.Y = y
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch *CompactHeader) Buffer() ui.Buffer {
|
func (row *CompactHeader) Buffer() ui.Buffer {
|
||||||
buf := ui.NewBuffer()
|
buf := ui.NewBuffer()
|
||||||
for _, p := range ch.pars {
|
for _, p := range row.pars {
|
||||||
buf.Merge(p.Buffer())
|
buf.Merge(p.Buffer())
|
||||||
}
|
}
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch *CompactHeader) addFieldPar(s string) {
|
func (row *CompactHeader) addFieldPar(s string) {
|
||||||
p := ui.NewPar(s)
|
p := ui.NewPar(s)
|
||||||
p.Height = ch.Height
|
p.Height = row.Height
|
||||||
p.Border = false
|
p.Border = false
|
||||||
ch.pars = append(ch.pars, p)
|
row.pars = append(row.pars, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,195 +0,0 @@
|
|||||||
package compact
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/bcicen/ctop/config"
|
|
||||||
"github.com/bcicen/ctop/logging"
|
|
||||||
"github.com/bcicen/ctop/models"
|
|
||||||
ui "github.com/gizak/termui"
|
|
||||||
)
|
|
||||||
|
|
||||||
var log = logging.Init()
|
|
||||||
|
|
||||||
type Compact struct {
|
|
||||||
Status *Status
|
|
||||||
Name *TextCol
|
|
||||||
Cid *TextCol
|
|
||||||
Cpu *GaugeCol
|
|
||||||
Mem *GaugeCol
|
|
||||||
Net *TextCol
|
|
||||||
IO *TextCol
|
|
||||||
Pids *TextCol
|
|
||||||
Bg *RowBg
|
|
||||||
X, Y int
|
|
||||||
Width int
|
|
||||||
Height int
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCompact(id string) *Compact {
|
|
||||||
// truncate container id
|
|
||||||
if len(id) > 12 {
|
|
||||||
id = id[:12]
|
|
||||||
}
|
|
||||||
row := &Compact{
|
|
||||||
Status: NewStatus(),
|
|
||||||
Name: NewTextCol("-"),
|
|
||||||
Cid: NewTextCol(id),
|
|
||||||
Cpu: NewGaugeCol(),
|
|
||||||
Mem: NewGaugeCol(),
|
|
||||||
Net: NewTextCol("-"),
|
|
||||||
IO: NewTextCol("-"),
|
|
||||||
Pids: NewTextCol("-"),
|
|
||||||
Bg: NewRowBg(),
|
|
||||||
X: 1,
|
|
||||||
Height: 1,
|
|
||||||
}
|
|
||||||
return row
|
|
||||||
}
|
|
||||||
|
|
||||||
//func (row *Compact) ToggleExpand() {
|
|
||||||
//if row.Height == 1 {
|
|
||||||
//row.Height = 4
|
|
||||||
//} else {
|
|
||||||
//row.Height = 1
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
|
|
||||||
func (row *Compact) SetMeta(k, v string) {
|
|
||||||
switch k {
|
|
||||||
case "name":
|
|
||||||
row.Name.Set(v)
|
|
||||||
case "state":
|
|
||||||
row.Status.Set(v)
|
|
||||||
case "health":
|
|
||||||
row.Status.SetHealth(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (row *Compact) SetMetrics(m models.Metrics) {
|
|
||||||
row.SetCPU(m.CPUUtil)
|
|
||||||
row.SetNet(m.NetRx, m.NetTx)
|
|
||||||
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
|
|
||||||
func (row *Compact) Reset() {
|
|
||||||
row.Cpu.Reset()
|
|
||||||
row.Mem.Reset()
|
|
||||||
row.Net.Reset()
|
|
||||||
row.IO.Reset()
|
|
||||||
row.Pids.Reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (row *Compact) GetHeight() int {
|
|
||||||
return row.Height
|
|
||||||
}
|
|
||||||
|
|
||||||
func (row *Compact) SetX(x int) {
|
|
||||||
row.X = x
|
|
||||||
}
|
|
||||||
|
|
||||||
func (row *Compact) SetY(y int) {
|
|
||||||
if y == row.Y {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
row.Bg.Y = y
|
|
||||||
for _, col := range row.all() {
|
|
||||||
col.SetY(y)
|
|
||||||
}
|
|
||||||
row.Y = y
|
|
||||||
}
|
|
||||||
|
|
||||||
func (row *Compact) SetWidth(width int) {
|
|
||||||
if width == row.Width {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
x := row.X
|
|
||||||
|
|
||||||
row.Bg.SetX(x + colWidths[0] + 1)
|
|
||||||
row.Bg.SetWidth(width)
|
|
||||||
|
|
||||||
autoWidth := calcWidth(width)
|
|
||||||
for n, col := range row.all() {
|
|
||||||
if colWidths[n] != 0 {
|
|
||||||
col.SetX(x)
|
|
||||||
col.SetWidth(colWidths[n])
|
|
||||||
x += colWidths[n]
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
col.SetX(x)
|
|
||||||
col.SetWidth(autoWidth)
|
|
||||||
x += autoWidth + colSpacing
|
|
||||||
}
|
|
||||||
row.Width = width
|
|
||||||
}
|
|
||||||
|
|
||||||
func (row *Compact) Buffer() ui.Buffer {
|
|
||||||
buf := ui.NewBuffer()
|
|
||||||
|
|
||||||
buf.Merge(row.Bg.Buffer())
|
|
||||||
buf.Merge(row.Status.Buffer())
|
|
||||||
buf.Merge(row.Name.Buffer())
|
|
||||||
buf.Merge(row.Cid.Buffer())
|
|
||||||
buf.Merge(row.Cpu.Buffer())
|
|
||||||
buf.Merge(row.Mem.Buffer())
|
|
||||||
buf.Merge(row.Net.Buffer())
|
|
||||||
buf.Merge(row.IO.Buffer())
|
|
||||||
buf.Merge(row.Pids.Buffer())
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
func (row *Compact) all() []ui.GridBufferer {
|
|
||||||
return []ui.GridBufferer{
|
|
||||||
row.Status,
|
|
||||||
row.Name,
|
|
||||||
row.Cid,
|
|
||||||
row.Cpu,
|
|
||||||
row.Mem,
|
|
||||||
row.Net,
|
|
||||||
row.IO,
|
|
||||||
row.Pids,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (row *Compact) Highlight() {
|
|
||||||
row.Name.Highlight()
|
|
||||||
if config.GetSwitchVal("fullRowCursor") {
|
|
||||||
row.Bg.Highlight()
|
|
||||||
row.Cid.Highlight()
|
|
||||||
row.Cpu.Highlight()
|
|
||||||
row.Mem.Highlight()
|
|
||||||
row.Net.Highlight()
|
|
||||||
row.IO.Highlight()
|
|
||||||
row.Pids.Highlight()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (row *Compact) UnHighlight() {
|
|
||||||
row.Name.UnHighlight()
|
|
||||||
if config.GetSwitchVal("fullRowCursor") {
|
|
||||||
row.Bg.UnHighlight()
|
|
||||||
row.Cid.UnHighlight()
|
|
||||||
row.Cpu.UnHighlight()
|
|
||||||
row.Mem.UnHighlight()
|
|
||||||
row.Net.UnHighlight()
|
|
||||||
row.IO.UnHighlight()
|
|
||||||
row.Pids.UnHighlight()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type RowBg struct {
|
|
||||||
*ui.Par
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRowBg() *RowBg {
|
|
||||||
bg := ui.NewPar("")
|
|
||||||
bg.Height = 1
|
|
||||||
bg.Border = false
|
|
||||||
bg.Bg = ui.ThemeAttr("par.text.bg")
|
|
||||||
return &RowBg{bg}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *RowBg) Highlight() { w.Bg = ui.ThemeAttr("par.text.fg") }
|
|
||||||
func (w *RowBg) UnHighlight() { w.Bg = ui.ThemeAttr("par.text.bg") }
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package compact
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/bcicen/ctop/cwidgets"
|
|
||||||
ui "github.com/gizak/termui"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (row *Compact) SetNet(rx int64, tx int64) {
|
|
||||||
label := fmt.Sprintf("%s / %s", cwidgets.ByteFormat(rx), cwidgets.ByteFormat(tx))
|
|
||||||
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 := strconv.Itoa(val)
|
|
||||||
row.Pids.Set(label)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (row *Compact) SetCPU(val int) {
|
|
||||||
row.Cpu.BarColor = colorScale(val)
|
|
||||||
row.Cpu.Label = fmt.Sprintf("%s%%", strconv.Itoa(val))
|
|
||||||
if val < 5 {
|
|
||||||
val = 5
|
|
||||||
row.Cpu.BarColor = ui.ThemeAttr("gauge.bar.bg")
|
|
||||||
}
|
|
||||||
if val > 100 {
|
|
||||||
val = 100
|
|
||||||
}
|
|
||||||
row.Cpu.Percent = val
|
|
||||||
}
|
|
||||||
|
|
||||||
func (row *Compact) SetMem(val int64, limit int64, percent int) {
|
|
||||||
row.Mem.Label = fmt.Sprintf("%s / %s", cwidgets.ByteFormat(val), cwidgets.ByteFormat(limit))
|
|
||||||
if percent < 5 {
|
|
||||||
percent = 5
|
|
||||||
row.Mem.BarColor = ui.ColorBlack
|
|
||||||
} else {
|
|
||||||
row.Mem.BarColor = ui.ThemeAttr("gauge.bar.bg")
|
|
||||||
}
|
|
||||||
row.Mem.Percent = percent
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package compact
|
package compact
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/bcicen/ctop/models"
|
||||||
ui "github.com/gizak/termui"
|
ui "github.com/gizak/termui"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,14 +18,14 @@ type Status struct {
|
|||||||
health []ui.Cell
|
health []ui.Cell
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStatus() *Status {
|
func NewStatus() CompactCol {
|
||||||
s := &Status{
|
s := &Status{
|
||||||
Block: ui.NewBlock(),
|
Block: ui.NewBlock(),
|
||||||
health: []ui.Cell{{Ch: ' '}},
|
health: []ui.Cell{{Ch: ' '}},
|
||||||
}
|
}
|
||||||
s.Height = 1
|
s.Height = 1
|
||||||
s.Border = false
|
s.Border = false
|
||||||
s.Set("")
|
s.setState("")
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +44,20 @@ func (s *Status) Buffer() ui.Buffer {
|
|||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Status) Set(val string) {
|
func (s *Status) SetMeta(m models.Meta) {
|
||||||
|
s.setState(m.Get("state"))
|
||||||
|
s.setHealth(m.Get("health"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status implements CompactCol
|
||||||
|
func (s *Status) Reset() {}
|
||||||
|
func (s *Status) SetMetrics(models.Metrics) {}
|
||||||
|
func (s *Status) Highlight() {}
|
||||||
|
func (s *Status) UnHighlight() {}
|
||||||
|
func (s *Status) Header() string { return "" }
|
||||||
|
func (s *Status) FixedWidth() int { return 3 }
|
||||||
|
|
||||||
|
func (s *Status) setState(val string) {
|
||||||
// defaults
|
// defaults
|
||||||
text := mark
|
text := mark
|
||||||
color := ui.ColorDefault
|
color := ui.ColorDefault
|
||||||
@@ -60,21 +74,21 @@ func (s *Status) Set(val string) {
|
|||||||
s.status = ui.TextCells(text, color, ui.ColorDefault)
|
s.status = ui.TextCells(text, color, ui.ColorDefault)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Status) SetHealth(val string) {
|
func (s *Status) setHealth(val string) {
|
||||||
if val == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
color := ui.ColorDefault
|
color := ui.ColorDefault
|
||||||
mark := healthMark
|
mark := healthMark
|
||||||
|
|
||||||
switch val {
|
switch val {
|
||||||
|
case "":
|
||||||
|
return
|
||||||
case "healthy":
|
case "healthy":
|
||||||
color = ui.ThemeAttr("status.ok")
|
color = ui.ThemeAttr("status.ok")
|
||||||
case "unhealthy":
|
case "unhealthy":
|
||||||
color = ui.ThemeAttr("status.danger")
|
color = ui.ThemeAttr("status.danger")
|
||||||
case "starting":
|
case "starting":
|
||||||
color = ui.ThemeAttr("status.warn")
|
color = ui.ThemeAttr("status.warn")
|
||||||
|
default:
|
||||||
|
log.Warningf("unknown health state string: \"%v\"", val)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.health = ui.TextCells(mark, color, ui.ColorDefault)
|
s.health = ui.TextCells(mark, color, ui.ColorDefault)
|
||||||
|
|||||||
@@ -1,19 +1,93 @@
|
|||||||
package compact
|
package compact
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/bcicen/ctop/cwidgets"
|
||||||
|
"github.com/bcicen/ctop/models"
|
||||||
ui "github.com/gizak/termui"
|
ui "github.com/gizak/termui"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TextCol struct {
|
type NameCol struct {
|
||||||
*ui.Par
|
*TextCol
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTextCol(s string) *TextCol {
|
func NewNameCol() CompactCol {
|
||||||
p := ui.NewPar(s)
|
return &NameCol{NewTextCol("NAME")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *NameCol) SetMeta(m models.Meta) {
|
||||||
|
w.Text = m.Get("name")
|
||||||
|
// truncate container id
|
||||||
|
if len(w.Text) > 12 {
|
||||||
|
w.Text = w.Text[:12]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type CIDCol struct {
|
||||||
|
*TextCol
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCIDCol() CompactCol {
|
||||||
|
return &CIDCol{NewTextCol("CID")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *CIDCol) SetMeta(m models.Meta) {
|
||||||
|
w.Text = m.Get("id")
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetCol struct {
|
||||||
|
*TextCol
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNetCol() CompactCol {
|
||||||
|
return &NetCol{NewTextCol("NET RX/TX")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *NetCol) SetMetrics(m models.Metrics) {
|
||||||
|
label := fmt.Sprintf("%s / %s", cwidgets.ByteFormat(m.NetRx), cwidgets.ByteFormat(m.NetTx))
|
||||||
|
w.Text = label
|
||||||
|
}
|
||||||
|
|
||||||
|
type IOCol struct {
|
||||||
|
*TextCol
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIOCol() CompactCol {
|
||||||
|
return &IOCol{NewTextCol("IO R/W")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *IOCol) SetMetrics(m models.Metrics) {
|
||||||
|
label := fmt.Sprintf("%s / %s", cwidgets.ByteFormat(m.IOBytesRead), cwidgets.ByteFormat(m.IOBytesWrite))
|
||||||
|
w.Text = label
|
||||||
|
}
|
||||||
|
|
||||||
|
type PIDCol struct {
|
||||||
|
*TextCol
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPIDCol() CompactCol {
|
||||||
|
w := &PIDCol{NewTextCol("PIDS")}
|
||||||
|
w.fWidth = 4
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *PIDCol) SetMetrics(m models.Metrics) {
|
||||||
|
w.Text = fmt.Sprintf("%d", m.Pids)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextCol struct {
|
||||||
|
*ui.Par
|
||||||
|
header string
|
||||||
|
fWidth int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTextCol(header string) *TextCol {
|
||||||
|
p := ui.NewPar("-")
|
||||||
p.Border = false
|
p.Border = false
|
||||||
p.Height = 1
|
p.Height = 1
|
||||||
p.Width = 20
|
p.Width = 20
|
||||||
return &TextCol{p}
|
return &TextCol{p, header, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *TextCol) Highlight() {
|
func (w *TextCol) Highlight() {
|
||||||
@@ -28,10 +102,8 @@ func (w *TextCol) UnHighlight() {
|
|||||||
w.TextBgColor = ui.ThemeAttr("par.text.bg")
|
w.TextBgColor = ui.ThemeAttr("par.text.bg")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *TextCol) Reset() {
|
func (w *TextCol) Reset() { w.Text = "-" }
|
||||||
w.Text = "-"
|
func (w *TextCol) SetMeta(models.Meta) {}
|
||||||
}
|
func (w *TextCol) SetMetrics(models.Metrics) {}
|
||||||
|
func (w *TextCol) Header() string { return w.header }
|
||||||
func (w *TextCol) Set(s string) {
|
func (w *TextCol) FixedWidth() int { return w.fWidth }
|
||||||
w.Text = s
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -22,19 +22,6 @@ var colWidths = []int{
|
|||||||
4, // pids
|
4, // pids
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate per-column width, given total width
|
|
||||||
func calcWidth(width int) int {
|
|
||||||
spacing := colSpacing * len(colWidths)
|
|
||||||
var staticCols int
|
|
||||||
for _, w := range colWidths {
|
|
||||||
width -= w
|
|
||||||
if w == 0 {
|
|
||||||
staticCols++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (width - spacing) / staticCols
|
|
||||||
}
|
|
||||||
|
|
||||||
func centerParText(p *ui.Par) {
|
func centerParText(p *ui.Par) {
|
||||||
var text string
|
var text string
|
||||||
var padding string
|
var padding string
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ import (
|
|||||||
var log = logging.Init()
|
var log = logging.Init()
|
||||||
|
|
||||||
type WidgetUpdater interface {
|
type WidgetUpdater interface {
|
||||||
SetMeta(string, string)
|
SetMeta(models.Meta)
|
||||||
SetMetrics(models.Metrics)
|
SetMetrics(models.Metrics)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,12 +55,14 @@ func (e *Single) Down() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Single) SetWidth(w int) { e.Width = w }
|
func (e *Single) SetWidth(w int) { e.Width = w }
|
||||||
func (e *Single) SetMeta(k, v string) {
|
func (e *Single) SetMeta(m models.Meta) {
|
||||||
|
for k, v := range m {
|
||||||
if k == "[ENV-VAR]" {
|
if k == "[ENV-VAR]" {
|
||||||
e.Env.Set(k, v)
|
e.Env.Set(k, v)
|
||||||
} else {
|
} else {
|
||||||
e.Info.Set(k, v)
|
e.Info.Set(k, v)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Single) SetMetrics(m models.Metrics) {
|
func (e *Single) SetMetrics(m models.Metrics) {
|
||||||
|
|||||||
@@ -7,6 +7,33 @@ type Log struct {
|
|||||||
Message string
|
Message string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Meta map[string]string
|
||||||
|
|
||||||
|
// NewMeta returns an initialized Meta map.
|
||||||
|
// An optional series of key, values may be provided to populate the map prior to returning
|
||||||
|
func NewMeta(kvs ...string) Meta {
|
||||||
|
m := make(Meta)
|
||||||
|
|
||||||
|
var k string
|
||||||
|
for i := 0; i < len(kvs)-1; i++ {
|
||||||
|
if k == "" {
|
||||||
|
k = kvs[i]
|
||||||
|
} else {
|
||||||
|
m[k] = kvs[i]
|
||||||
|
k = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Meta) Get(k string) string {
|
||||||
|
if s, ok := m[k]; ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
type Metrics struct {
|
type Metrics struct {
|
||||||
CPUUtil int
|
CPUUtil int
|
||||||
NetTx int64
|
NetTx int64
|
||||||
|
|||||||
Reference in New Issue
Block a user