mirror of
https://github.com/bcicen/ctop.git
synced 2024-08-30 18:23:19 +00:00
refactor widgets, add wrapper structs
This commit is contained in:
parent
9f5cd42b73
commit
56be64367b
76
container.go
76
container.go
@ -1,61 +1,69 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/bcicen/ctop/cwidgets"
|
||||
"github.com/bcicen/ctop/cwidgets/compact"
|
||||
"github.com/bcicen/ctop/metrics"
|
||||
)
|
||||
|
||||
// Metrics and metadata representing a container
|
||||
type Container struct {
|
||||
id string
|
||||
name string
|
||||
state string
|
||||
metrics metrics.Metrics
|
||||
widgets cwidgets.ContainerWidgets
|
||||
metrics.Metrics
|
||||
Id string
|
||||
Name string
|
||||
State string
|
||||
Meta map[string]string
|
||||
Updates chan [2]string
|
||||
Widgets *compact.Compact
|
||||
collector metrics.Collector
|
||||
}
|
||||
|
||||
func NewContainer(id, name string) *Container {
|
||||
c := &Container{
|
||||
id: id,
|
||||
name: name,
|
||||
metrics: metrics.NewMetrics(),
|
||||
func NewContainer(id, name string, collector metrics.Collector) *Container {
|
||||
return &Container{
|
||||
Metrics: metrics.NewMetrics(),
|
||||
Id: id,
|
||||
Name: name,
|
||||
Meta: make(map[string]string),
|
||||
Updates: make(chan [2]string),
|
||||
Widgets: compact.NewCompact(id, name),
|
||||
collector: collector,
|
||||
}
|
||||
c.widgets = compact.NewCompact(c.ShortID(), c.ShortName(), c.state)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Container) ShortID() string {
|
||||
return c.id[:12]
|
||||
func (c *Container) GetMeta(k string) string {
|
||||
if v, ok := c.Meta[k]; ok {
|
||||
return v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c *Container) ShortName() string {
|
||||
return strings.Replace(c.name, "/", "", 1) // use primary container name
|
||||
func (c *Container) SetMeta(k, v string) {
|
||||
c.Meta[k] = v
|
||||
c.Updates <- [2]string{k, v}
|
||||
}
|
||||
|
||||
func (c *Container) SetState(s string) {
|
||||
c.state = s
|
||||
c.widgets.SetStatus(s)
|
||||
}
|
||||
|
||||
// Set metrics to zero state, clear widget gauges
|
||||
func (c *Container) reset() {
|
||||
c.metrics = metrics.Metrics{}
|
||||
c.widgets.Reset()
|
||||
c.State = s
|
||||
c.Widgets.Status.Set(s)
|
||||
// start collector, if needed
|
||||
if c.State == "running" && !c.collector.Running() {
|
||||
c.collector.Start()
|
||||
c.Read(c.collector.Stream())
|
||||
}
|
||||
// stop collector, if needed
|
||||
if c.State != "running" && c.collector.Running() {
|
||||
c.collector.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
// Read metric stream, updating widgets
|
||||
func (c *Container) Read(stream chan metrics.Metrics) {
|
||||
go func() {
|
||||
for metrics := range stream {
|
||||
c.metrics = metrics
|
||||
c.widgets.SetCPU(metrics.CPUUtil)
|
||||
c.widgets.SetMem(metrics.MemUsage, metrics.MemLimit, metrics.MemPercent)
|
||||
c.widgets.SetNet(metrics.NetRx, metrics.NetTx)
|
||||
c.Metrics = metrics
|
||||
c.Widgets.SetMetrics(metrics)
|
||||
}
|
||||
log.Infof("reader stopped for container: %s", c.id)
|
||||
c.reset()
|
||||
log.Infof("reader stopped for container: %s", c.Id)
|
||||
c.Widgets.Reset()
|
||||
}()
|
||||
log.Infof("reader started for container: %s", c.id)
|
||||
log.Infof("reader started for container: %s", c.Id)
|
||||
}
|
||||
|
25
cwidgets/compact/gauge.go
Normal file
25
cwidgets/compact/gauge.go
Normal file
@ -0,0 +1,25 @@
|
||||
package compact
|
||||
|
||||
import (
|
||||
ui "github.com/gizak/termui"
|
||||
)
|
||||
|
||||
type GaugeCol struct {
|
||||
*ui.Gauge
|
||||
}
|
||||
|
||||
func NewGaugeCol() *GaugeCol {
|
||||
g := ui.NewGauge()
|
||||
g.Height = 1
|
||||
g.Border = false
|
||||
g.Percent = 0
|
||||
g.PaddingBottom = 0
|
||||
g.BarColor = ui.ColorGreen
|
||||
g.Label = "-"
|
||||
return &GaugeCol{g}
|
||||
}
|
||||
|
||||
func (w *GaugeCol) Reset() {
|
||||
w.Label = "-"
|
||||
w.Percent = 0
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
package compact
|
||||
|
||||
import (
|
||||
"github.com/bcicen/ctop/cwidgets"
|
||||
ui "github.com/gizak/termui"
|
||||
)
|
||||
|
||||
type CompactGrid struct {
|
||||
ui.GridBufferer
|
||||
Rows []cwidgets.ContainerWidgets
|
||||
Rows []*Compact // rows to render
|
||||
X, Y int
|
||||
Width int
|
||||
Height int
|
||||
@ -21,31 +20,37 @@ func NewCompactGrid() *CompactGrid {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CompactGrid) Align() {
|
||||
func (cg *CompactGrid) Align() {
|
||||
// Update y recursively
|
||||
c.header.SetY(c.Y)
|
||||
y := c.Y + 1
|
||||
for n, r := range c.Rows {
|
||||
cg.header.SetY(cg.Y)
|
||||
y := cg.Y + 1
|
||||
for n, r := range cg.Rows {
|
||||
r.SetY(y + n)
|
||||
}
|
||||
// Update width recursively
|
||||
c.header.SetWidth(c.Width)
|
||||
for _, r := range c.Rows {
|
||||
r.SetWidth(c.Width)
|
||||
cg.header.SetWidth(cg.Width)
|
||||
for _, r := range cg.Rows {
|
||||
r.SetWidth(cg.Width)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CompactGrid) Clear() { c.Rows = []cwidgets.ContainerWidgets{} }
|
||||
func (c *CompactGrid) GetHeight() int { return len(c.Rows) }
|
||||
func (c *CompactGrid) SetX(x int) { c.X = x }
|
||||
func (c *CompactGrid) SetY(y int) { c.Y = y }
|
||||
func (c *CompactGrid) SetWidth(w int) { c.Width = w }
|
||||
func (cg *CompactGrid) Clear() { cg.Rows = []*Compact{} }
|
||||
func (cg *CompactGrid) GetHeight() int { return len(cg.Rows) }
|
||||
func (cg *CompactGrid) SetX(x int) { cg.X = x }
|
||||
func (cg *CompactGrid) SetY(y int) { cg.Y = y }
|
||||
func (cg *CompactGrid) SetWidth(w int) { cg.Width = w }
|
||||
|
||||
func (c *CompactGrid) Buffer() ui.Buffer {
|
||||
func (cg *CompactGrid) Buffer() ui.Buffer {
|
||||
buf := ui.NewBuffer()
|
||||
buf.Merge(c.header.Buffer())
|
||||
for _, r := range c.Rows {
|
||||
buf.Merge(cg.header.Buffer())
|
||||
for _, r := range cg.Rows {
|
||||
buf.Merge(r.Buffer())
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
func (cg *CompactGrid) AddRows(rows ...*Compact) {
|
||||
for _, r := range rows {
|
||||
cg.Rows = append(cg.Rows, r)
|
||||
}
|
||||
}
|
||||
|
@ -5,50 +5,53 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/bcicen/ctop/cwidgets"
|
||||
"github.com/bcicen/ctop/logging"
|
||||
"github.com/bcicen/ctop/metrics"
|
||||
ui "github.com/gizak/termui"
|
||||
)
|
||||
|
||||
var log = logging.Init()
|
||||
|
||||
const (
|
||||
mark = string('\u25C9')
|
||||
vBar = string('\u25AE')
|
||||
colSpacing = 1
|
||||
statusWidth = 3
|
||||
colSpacing = 1
|
||||
)
|
||||
|
||||
type Compact struct {
|
||||
Status *ui.Par
|
||||
Name *ui.Par
|
||||
Cid *ui.Par
|
||||
Cpu *ui.Gauge
|
||||
Memory *ui.Gauge
|
||||
Net *ui.Par
|
||||
Status *Status
|
||||
Name *TextCol
|
||||
Cid *TextCol
|
||||
Cpu *GaugeCol
|
||||
Memory *GaugeCol
|
||||
Net *TextCol
|
||||
X, Y int
|
||||
Width int
|
||||
Height int
|
||||
}
|
||||
|
||||
func NewCompact(id, name, status string) *Compact {
|
||||
func NewCompact(id, name string) *Compact {
|
||||
row := &Compact{
|
||||
Status: slimPar(mark),
|
||||
Name: slimPar(name),
|
||||
Cid: slimPar(id),
|
||||
Cpu: slimGauge(),
|
||||
Memory: slimGauge(),
|
||||
Net: slimPar("-"),
|
||||
Status: NewStatus(),
|
||||
Name: NewTextCol(name),
|
||||
Cid: NewTextCol(id),
|
||||
Cpu: NewGaugeCol(),
|
||||
Memory: NewGaugeCol(),
|
||||
Net: NewTextCol("-"),
|
||||
Height: 1,
|
||||
}
|
||||
row.Reset()
|
||||
row.SetStatus(status)
|
||||
return row
|
||||
}
|
||||
|
||||
func (row *Compact) SetMetrics(m metrics.Metrics) {
|
||||
row.SetCPU(m.CPUUtil)
|
||||
row.SetNet(m.NetRx, m.NetTx)
|
||||
row.SetMem(m.MemUsage, m.MemLimit, m.MemPercent)
|
||||
}
|
||||
|
||||
// Set gauges, counters to default unread values
|
||||
func (row *Compact) Reset() {
|
||||
row.Cpu.Percent = 0
|
||||
row.Cpu.Label = "-"
|
||||
row.Memory.Percent = 0
|
||||
row.Memory.Label = "-"
|
||||
row.Net.Text = "-"
|
||||
row.Cpu.Reset()
|
||||
row.Memory.Reset()
|
||||
row.Net.Reset()
|
||||
}
|
||||
|
||||
func (row *Compact) all() []ui.GridBufferer {
|
||||
@ -115,24 +118,9 @@ func (row *Compact) UnHighlight() {
|
||||
row.Name.TextBgColor = ui.ColorDefault
|
||||
}
|
||||
|
||||
func (row *Compact) SetStatus(val string) {
|
||||
switch val {
|
||||
case "running":
|
||||
row.Status.Text = mark
|
||||
row.Status.TextFgColor = ui.ColorGreen
|
||||
case "exited":
|
||||
row.Status.Text = mark
|
||||
row.Status.TextFgColor = ui.ColorRed
|
||||
case "paused":
|
||||
row.Status.Text = fmt.Sprintf("%s%s", vBar, vBar)
|
||||
row.Status.TextFgColor = ui.ColorDefault
|
||||
case "created":
|
||||
row.Status.Text = mark
|
||||
row.Status.TextFgColor = ui.ColorDefault
|
||||
default:
|
||||
row.Status.Text = mark
|
||||
row.Status.TextFgColor = ui.ColorRed
|
||||
}
|
||||
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) SetCPU(val int) {
|
||||
@ -145,10 +133,6 @@ func (row *Compact) SetCPU(val int) {
|
||||
row.Cpu.Percent = val
|
||||
}
|
||||
|
||||
func (row *Compact) SetNet(rx int64, tx int64) {
|
||||
row.Net.Text = fmt.Sprintf("%s / %s", cwidgets.ByteFormat(rx), cwidgets.ByteFormat(tx))
|
||||
}
|
||||
|
||||
func (row *Compact) SetMem(val int64, limit int64, percent int) {
|
||||
row.Memory.Label = fmt.Sprintf("%s / %s", cwidgets.ByteFormat(val), cwidgets.ByteFormat(limit))
|
||||
if percent < 5 {
|
||||
|
63
cwidgets/compact/text.go
Normal file
63
cwidgets/compact/text.go
Normal file
@ -0,0 +1,63 @@
|
||||
package compact
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
ui "github.com/gizak/termui"
|
||||
)
|
||||
|
||||
const (
|
||||
mark = string('\u25C9')
|
||||
vBar = string('\u25AE')
|
||||
statusWidth = 3
|
||||
)
|
||||
|
||||
type TextCol struct {
|
||||
*ui.Par
|
||||
}
|
||||
|
||||
func NewTextCol(s string) *TextCol {
|
||||
p := ui.NewPar(s)
|
||||
p.Border = false
|
||||
p.Height = 1
|
||||
p.Width = 20
|
||||
return &TextCol{p}
|
||||
}
|
||||
|
||||
func (w *TextCol) Reset() {
|
||||
w.Text = "-"
|
||||
}
|
||||
|
||||
func (w *TextCol) Set(s string) {
|
||||
w.Text = s
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
*ui.Par
|
||||
}
|
||||
|
||||
func NewStatus() *Status {
|
||||
p := ui.NewPar(mark)
|
||||
p.Border = false
|
||||
p.Height = 1
|
||||
p.Width = statusWidth
|
||||
return &Status{p}
|
||||
}
|
||||
|
||||
func (s *Status) Set(val string) {
|
||||
// defaults
|
||||
text := mark
|
||||
color := ui.ColorDefault
|
||||
|
||||
switch val {
|
||||
case "running":
|
||||
color = ui.ColorGreen
|
||||
case "exited":
|
||||
color = ui.ColorRed
|
||||
case "paused":
|
||||
text = fmt.Sprintf("%s%s", vBar, vBar)
|
||||
}
|
||||
|
||||
s.Text = text
|
||||
s.TextFgColor = color
|
||||
}
|
@ -14,32 +14,14 @@ func calcWidth(width, items int) int {
|
||||
}
|
||||
|
||||
func slimHeaderPar(s string) *ui.Par {
|
||||
p := slimPar(s)
|
||||
p := ui.NewPar(s)
|
||||
p.Y = 2
|
||||
p.Height = 2
|
||||
return p
|
||||
}
|
||||
|
||||
func slimPar(s string) *ui.Par {
|
||||
p := ui.NewPar(s)
|
||||
p.Border = false
|
||||
p.Height = 1
|
||||
p.Width = 20
|
||||
p.TextFgColor = ui.ColorWhite
|
||||
p.Border = false
|
||||
return p
|
||||
}
|
||||
|
||||
func slimGauge() *ui.Gauge {
|
||||
g := ui.NewGauge()
|
||||
g.Height = 1
|
||||
g.Border = false
|
||||
g.Percent = 0
|
||||
g.PaddingBottom = 0
|
||||
g.BarColor = ui.ColorGreen
|
||||
g.Label = "-"
|
||||
return g
|
||||
}
|
||||
|
||||
func centerParText(p *ui.Par) {
|
||||
var text string
|
||||
var padding string
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
var log = logging.Init()
|
||||
|
||||
type ContainerWidgets interface {
|
||||
Reset()
|
||||
Buffer() ui.Buffer
|
||||
Highlight()
|
||||
UnHighlight()
|
||||
|
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -20,7 +21,6 @@ type ContainerSource interface {
|
||||
type DockerContainerSource struct {
|
||||
client *docker.Client
|
||||
containers Containers
|
||||
collectors map[string]metrics.Collector
|
||||
needsRefresh map[string]int // container IDs requiring refresh
|
||||
}
|
||||
|
||||
@ -32,7 +32,6 @@ func NewDockerContainerSource() *DockerContainerSource {
|
||||
}
|
||||
cm := &DockerContainerSource{
|
||||
client: client,
|
||||
collectors: make(map[string]metrics.Collector),
|
||||
needsRefresh: make(map[string]int),
|
||||
}
|
||||
cm.refreshAll()
|
||||
@ -73,27 +72,16 @@ func (cm *DockerContainerSource) refresh(id string) {
|
||||
c, ok := cm.Get(id)
|
||||
// append container struct for new containers
|
||||
if !ok {
|
||||
c = NewContainer(id, insp.Name)
|
||||
// create collector
|
||||
collector := metrics.NewDocker(cm.client, id)
|
||||
// create container
|
||||
c = NewContainer(shortID(id), shortName(insp.Name), collector)
|
||||
lock.Lock()
|
||||
cm.containers = append(cm.containers, c)
|
||||
lock.Unlock()
|
||||
// create collector
|
||||
if _, ok := cm.collectors[id]; ok == false {
|
||||
cm.collectors[id] = metrics.NewDocker(cm.client, id)
|
||||
}
|
||||
}
|
||||
|
||||
c.SetState(insp.State.Status)
|
||||
|
||||
// start collector if needed
|
||||
if c.state == "running" && !cm.collectors[c.id].Running() {
|
||||
cm.collectors[c.id].Start()
|
||||
c.Read(cm.collectors[c.id].Stream())
|
||||
}
|
||||
// stop collector if needed
|
||||
if c.state != "running" && cm.collectors[c.id].Running() {
|
||||
cm.collectors[c.id].Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (cm *DockerContainerSource) inspect(id string) *docker.Container {
|
||||
@ -140,7 +128,7 @@ func (cm *DockerContainerSource) Loop() {
|
||||
// Get a single container, by ID
|
||||
func (cm *DockerContainerSource) Get(id string) (*Container, bool) {
|
||||
for _, c := range cm.containers {
|
||||
if c.id == id {
|
||||
if c.Id == id {
|
||||
return c, true
|
||||
}
|
||||
}
|
||||
@ -150,7 +138,7 @@ func (cm *DockerContainerSource) Get(id string) (*Container, bool) {
|
||||
// Remove containers by ID
|
||||
func (cm *DockerContainerSource) delByID(id string) {
|
||||
for n, c := range cm.containers {
|
||||
if c.id == id {
|
||||
if c.Id == id {
|
||||
cm.del(n)
|
||||
return
|
||||
}
|
||||
@ -172,3 +160,13 @@ func (cm *DockerContainerSource) All() []*Container {
|
||||
sort.Sort(cm.containers)
|
||||
return cm.containers
|
||||
}
|
||||
|
||||
// truncate container id
|
||||
func shortID(id string) string {
|
||||
return id[:12]
|
||||
}
|
||||
|
||||
// use primary container name
|
||||
func shortName(name string) string {
|
||||
return strings.Replace(name, "/", "", 1)
|
||||
}
|
||||
|
29
grid.go
29
grid.go
@ -35,15 +35,15 @@ func NewGrid() *Grid {
|
||||
// Set an initial cursor position, if possible
|
||||
func (g *Grid) cursorReset() {
|
||||
if len(g.containers) > 0 {
|
||||
g.cursorID = g.containers[0].id
|
||||
g.containers[0].widgets.Highlight()
|
||||
g.cursorID = g.containers[0].Id
|
||||
g.containers[0].Widgets.Highlight()
|
||||
}
|
||||
}
|
||||
|
||||
// Return current cursor index
|
||||
func (g *Grid) cursorIdx() int {
|
||||
for n, c := range g.containers {
|
||||
if c.id == g.cursorID {
|
||||
if c.Id == g.cursorID {
|
||||
return n
|
||||
}
|
||||
}
|
||||
@ -59,9 +59,9 @@ func (g *Grid) cursorUp() {
|
||||
active := g.containers[idx]
|
||||
next := g.containers[idx-1]
|
||||
|
||||
active.widgets.UnHighlight()
|
||||
g.cursorID = next.id
|
||||
next.widgets.Highlight()
|
||||
active.Widgets.UnHighlight()
|
||||
g.cursorID = next.Id
|
||||
next.Widgets.Highlight()
|
||||
|
||||
ui.Render(cGrid)
|
||||
}
|
||||
@ -78,9 +78,9 @@ func (g *Grid) cursorDown() {
|
||||
active := g.containers[idx]
|
||||
next := g.containers[idx+1]
|
||||
|
||||
active.widgets.UnHighlight()
|
||||
g.cursorID = next.id
|
||||
next.widgets.Highlight()
|
||||
active.Widgets.UnHighlight()
|
||||
g.cursorID = next.Id
|
||||
next.Widgets.Highlight()
|
||||
ui.Render(cGrid)
|
||||
}
|
||||
|
||||
@ -93,7 +93,6 @@ func (g *Grid) redrawRows() {
|
||||
if config.GetSwitchVal("enableHeader") {
|
||||
g.header.SetCount(len(g.containers))
|
||||
g.header.SetFilter(config.GetVal("filterStr"))
|
||||
g.header.Render()
|
||||
y += g.header.Height()
|
||||
}
|
||||
cGrid.SetY(y)
|
||||
@ -104,8 +103,8 @@ func (g *Grid) redrawRows() {
|
||||
if n >= max {
|
||||
break
|
||||
}
|
||||
cGrid.Rows = append(cGrid.Rows, c.widgets)
|
||||
if c.id == g.cursorID {
|
||||
cGrid.AddRows(c.Widgets)
|
||||
if c.Id == g.cursorID {
|
||||
cursorVisible = true
|
||||
}
|
||||
}
|
||||
@ -125,9 +124,9 @@ func (g *Grid) redrawRows() {
|
||||
// Log current container and widget state
|
||||
func (g *Grid) dumpContainer() {
|
||||
c, _ := g.cSource.Get(g.cursorID)
|
||||
msg := fmt.Sprintf("logging state for container: %s\n", c.ShortID())
|
||||
msg += fmt.Sprintf("id = %s\nname = %s\nstate = %s\n", c.id, c.name, c.state)
|
||||
msg += inspect(&c.metrics)
|
||||
msg := fmt.Sprintf("logging state for container: %s\n", c.Id)
|
||||
msg += fmt.Sprintf("Id = %s\nname = %s\nstate = %s\n", c.Id, c.Name, c.State)
|
||||
msg += inspect(&c.Metrics)
|
||||
log.Infof(msg)
|
||||
}
|
||||
|
||||
|
10
main.go
10
main.go
@ -1,6 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/bcicen/ctop/config"
|
||||
"github.com/bcicen/ctop/logging"
|
||||
ui "github.com/gizak/termui"
|
||||
@ -9,6 +12,13 @@ import (
|
||||
var log *logging.CTopLogger
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ui.Clear()
|
||||
fmt.Printf("panic: %s", r)
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
config.Init()
|
||||
log = logging.Init()
|
||||
if config.GetSwitchVal("loggingEnabled") {
|
||||
|
@ -13,13 +13,10 @@ import (
|
||||
|
||||
type MockContainerSource struct {
|
||||
containers Containers
|
||||
collectors map[string]metrics.Collector
|
||||
}
|
||||
|
||||
func NewMockContainerSource() *MockContainerSource {
|
||||
cs := &MockContainerSource{
|
||||
collectors: make(map[string]metrics.Collector),
|
||||
}
|
||||
cs := &MockContainerSource{}
|
||||
cs.Init()
|
||||
go cs.Loop()
|
||||
return cs
|
||||
@ -27,15 +24,15 @@ func NewMockContainerSource() *MockContainerSource {
|
||||
|
||||
// Create Mock containers
|
||||
func (cs *MockContainerSource) Init() {
|
||||
total := 10
|
||||
total := 40
|
||||
rand.Seed(int64(time.Now().Nanosecond()))
|
||||
|
||||
for i := 0; i < total; i++ {
|
||||
c := NewContainer(makeID(), makeName())
|
||||
collector := metrics.NewMock()
|
||||
c := NewContainer(makeID(), makeName(), collector)
|
||||
lock.Lock()
|
||||
cs.containers = append(cs.containers, c)
|
||||
lock.Unlock()
|
||||
cs.collectors[c.id] = metrics.NewMock()
|
||||
|
||||
c.SetState(makeState())
|
||||
}
|
||||
@ -45,26 +42,10 @@ func (cs *MockContainerSource) Init() {
|
||||
func (cs *MockContainerSource) Loop() {
|
||||
iter := 0
|
||||
for {
|
||||
for _, c := range cs.containers {
|
||||
// Change state for random container
|
||||
if iter%5 == 0 {
|
||||
randC := cs.containers[rand.Intn(len(cs.containers))]
|
||||
randC.SetState(makeState())
|
||||
}
|
||||
|
||||
isCollecting := cs.collectors[c.id].Running()
|
||||
//log.Infof("id=%s state=%s collector=%t", c.id, c.state, isCollecting)
|
||||
|
||||
// start collector if needed
|
||||
if c.state == "running" && !isCollecting {
|
||||
cs.collectors[c.id].Start()
|
||||
c.Read(cs.collectors[c.id].Stream())
|
||||
}
|
||||
// stop collector if needed
|
||||
if c.state != "running" && isCollecting {
|
||||
cs.collectors[c.id].Stop()
|
||||
}
|
||||
|
||||
// Change state for random container
|
||||
if iter%5 == 0 {
|
||||
randC := cs.containers[rand.Intn(len(cs.containers))]
|
||||
randC.SetState(makeState())
|
||||
}
|
||||
iter++
|
||||
time.Sleep(3 * time.Second)
|
||||
@ -74,7 +55,7 @@ func (cs *MockContainerSource) Loop() {
|
||||
// Get a single container, by ID
|
||||
func (cs *MockContainerSource) Get(id string) (*Container, bool) {
|
||||
for _, c := range cs.containers {
|
||||
if c.id == id {
|
||||
if c.Id == id {
|
||||
return c, true
|
||||
}
|
||||
}
|
||||
@ -84,7 +65,7 @@ func (cs *MockContainerSource) Get(id string) (*Container, bool) {
|
||||
// Remove containers by ID
|
||||
func (cs *MockContainerSource) delByID(id string) {
|
||||
for n, c := range cs.containers {
|
||||
if c.id == id {
|
||||
if c.Id == id {
|
||||
cs.del(n)
|
||||
return
|
||||
}
|
||||
@ -112,7 +93,7 @@ func makeID() string {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return strings.Replace(u.String(), "-", "", -1)
|
||||
return strings.Replace(u.String(), "-", "", -1)[:12]
|
||||
}
|
||||
|
||||
func makeName() string {
|
||||
|
26
sort.go
26
sort.go
@ -16,32 +16,32 @@ var stateMap = map[string]int{
|
||||
"created": 0,
|
||||
}
|
||||
|
||||
var idSorter = func(c1, c2 *Container) bool { return c1.id < c2.id }
|
||||
var nameSorter = func(c1, c2 *Container) bool { return c1.name < c2.name }
|
||||
var idSorter = func(c1, c2 *Container) bool { return c1.Id < c2.Id }
|
||||
var nameSorter = func(c1, c2 *Container) bool { return c1.Name < c2.Name }
|
||||
|
||||
var Sorters = map[string]sortMethod{
|
||||
"id": idSorter,
|
||||
"name": nameSorter,
|
||||
"cpu": func(c1, c2 *Container) bool {
|
||||
// Use secondary sort method if equal values
|
||||
if c1.metrics.CPUUtil == c2.metrics.CPUUtil {
|
||||
if c1.CPUUtil == c2.CPUUtil {
|
||||
return nameSorter(c1, c2)
|
||||
}
|
||||
return c1.metrics.CPUUtil > c2.metrics.CPUUtil
|
||||
return c1.CPUUtil > c2.CPUUtil
|
||||
},
|
||||
"mem": func(c1, c2 *Container) bool {
|
||||
// Use secondary sort method if equal values
|
||||
if c1.metrics.MemUsage == c2.metrics.MemUsage {
|
||||
if c1.MemUsage == c2.MemUsage {
|
||||
return nameSorter(c1, c2)
|
||||
}
|
||||
return c1.metrics.MemUsage > c2.metrics.MemUsage
|
||||
return c1.MemUsage > c2.MemUsage
|
||||
},
|
||||
"mem %": func(c1, c2 *Container) bool {
|
||||
// Use secondary sort method if equal values
|
||||
if c1.metrics.MemPercent == c2.metrics.MemPercent {
|
||||
if c1.MemPercent == c2.MemPercent {
|
||||
return nameSorter(c1, c2)
|
||||
}
|
||||
return c1.metrics.MemPercent > c2.metrics.MemPercent
|
||||
return c1.MemPercent > c2.MemPercent
|
||||
},
|
||||
"net": func(c1, c2 *Container) bool {
|
||||
sum1 := sumNet(c1)
|
||||
@ -54,10 +54,10 @@ var Sorters = map[string]sortMethod{
|
||||
},
|
||||
"state": func(c1, c2 *Container) bool {
|
||||
// Use secondary sort method if equal values
|
||||
if c1.state == c2.state {
|
||||
if c1.State == c2.State {
|
||||
return nameSorter(c1, c2)
|
||||
}
|
||||
return stateMap[c1.state] > stateMap[c2.state]
|
||||
return stateMap[c1.State] > stateMap[c2.State]
|
||||
},
|
||||
}
|
||||
|
||||
@ -86,11 +86,11 @@ func (a Containers) Filter() (filtered []*Container) {
|
||||
|
||||
for _, c := range a {
|
||||
// Apply name filter
|
||||
if re.FindAllString(c.name, 1) == nil {
|
||||
if re.FindAllString(c.Name, 1) == nil {
|
||||
continue
|
||||
}
|
||||
// Apply state filter
|
||||
if !config.GetSwitchVal("allContainers") && c.state != "running" {
|
||||
if !config.GetSwitchVal("allContainers") && c.State != "running" {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, c)
|
||||
@ -99,4 +99,4 @@ func (a Containers) Filter() (filtered []*Container) {
|
||||
return filtered
|
||||
}
|
||||
|
||||
func sumNet(c *Container) int64 { return c.metrics.NetRx + c.metrics.NetTx }
|
||||
func sumNet(c *Container) int64 { return c.NetRx + c.NetTx }
|
||||
|
Loading…
Reference in New Issue
Block a user