diff --git a/container.go b/container.go index fb960b6..d1f7c6b 100644 --- a/container.go +++ b/container.go @@ -36,7 +36,7 @@ func (c *Container) Expand() { var curWidgets widgets.ContainerWidgets curWidgets = c.widgets - c.widgets = widgets.NewExpanded(c.ShortID(), c.ShortName()) + c.widgets = widgets.NewExpanded(c.ShortID(), c.name) c.widgets.Render(0, 0) c.widgets = curWidgets } diff --git a/containermap.go b/containermap.go index e76735e..9951be2 100644 --- a/containermap.go +++ b/containermap.go @@ -12,32 +12,37 @@ import ( var lock = sync.RWMutex{} -type ContainerMap struct { +type ContainerSource interface { + All() []*Container + Get(string) (*Container, bool) +} + +type DockerContainerSource struct { client *docker.Client containers Containers collectors map[string]metrics.Collector needsRefresh map[string]int // container IDs requiring refresh } -func NewContainerMap() *ContainerMap { +func NewDockerContainerSource() *DockerContainerSource { // init docker client client, err := docker.NewClient(config.GetVal("dockerHost")) if err != nil { panic(err) } - cm := &ContainerMap{ + cm := &DockerContainerSource{ client: client, collectors: make(map[string]metrics.Collector), needsRefresh: make(map[string]int), } cm.refreshAll() - go cm.UpdateLoop() + go cm.Loop() go cm.watchEvents() return cm } // Docker events watcher -func (cm *ContainerMap) watchEvents() { +func (cm *DockerContainerSource) watchEvents() { log.Info("docker event listener starting") events := make(chan *docker.APIEvents) cm.client.AddEventListener(events) @@ -52,16 +57,16 @@ func (cm *ContainerMap) watchEvents() { cm.needsRefresh[e.ID] = 1 case "destroy": log.Debugf("handling docker event: action=%s id=%s", e.Action, e.ID) - cm.DelByID(e.ID) + cm.delByID(e.ID) } } } -func (cm *ContainerMap) refresh(id string) { +func (cm *DockerContainerSource) refresh(id string) { insp := cm.inspect(id) // remove container if no longer exists if insp == nil { - cm.DelByID(id) + cm.delByID(id) return } @@ -91,7 +96,7 @@ func (cm *ContainerMap) refresh(id string) { } } -func (cm *ContainerMap) inspect(id string) *docker.Container { +func (cm *DockerContainerSource) inspect(id string) *docker.Container { c, err := cm.client.InspectContainer(id) if err != nil { if _, ok := err.(*docker.NoSuchContainer); ok == false { @@ -101,7 +106,8 @@ func (cm *ContainerMap) inspect(id string) *docker.Container { return c } -func (cm *ContainerMap) refreshAll() { +// Mark all container IDs for refresh +func (cm *DockerContainerSource) refreshAll() { opts := docker.ListContainersOptions{All: true} allContainers, err := cm.client.ListContainers(opts) if err != nil { @@ -113,7 +119,7 @@ func (cm *ContainerMap) refreshAll() { } } -func (cm *ContainerMap) UpdateLoop() { +func (cm *DockerContainerSource) Loop() { for { switch { case len(cm.needsRefresh) > 0: @@ -126,13 +132,13 @@ func (cm *ContainerMap) UpdateLoop() { delete(cm.needsRefresh, id) } default: - time.Sleep(1 * time.Second) + time.Sleep(3 * time.Second) } } } // Get a single container, by ID -func (cm *ContainerMap) Get(id string) (*Container, bool) { +func (cm *DockerContainerSource) Get(id string) (*Container, bool) { for _, c := range cm.containers { if c.id == id { return c, true @@ -142,17 +148,17 @@ func (cm *ContainerMap) Get(id string) (*Container, bool) { } // Remove containers by ID -func (cm *ContainerMap) DelByID(id string) { +func (cm *DockerContainerSource) delByID(id string) { for n, c := range cm.containers { if c.id == id { - cm.Del(n) + cm.del(n) return } } } // Remove one or more containers by index -func (cm *ContainerMap) Del(idx ...int) { +func (cm *DockerContainerSource) del(idx ...int) { lock.Lock() defer lock.Unlock() for _, i := range idx { @@ -162,7 +168,7 @@ func (cm *ContainerMap) Del(idx ...int) { } // Return array of all containers, sorted by field -func (cm *ContainerMap) All() []*Container { +func (cm *DockerContainerSource) All() []*Container { sort.Sort(cm.containers) return cm.containers } diff --git a/grid.go b/grid.go index 318fdd2..cf5ce06 100644 --- a/grid.go +++ b/grid.go @@ -16,16 +16,16 @@ func maxRows() int { type Grid struct { cursorID string // id of currently selected container - cmap *ContainerMap + cSource ContainerSource containers Containers // sorted slice of containers header *widgets.CTopHeader } func NewGrid() *Grid { - cmap := NewContainerMap() + cs := NewDockerContainerSource() g := &Grid{ - cmap: cmap, - containers: cmap.All(), + cSource: cs, + containers: cs.All(), header: widgets.NewCTopHeader(), } return g @@ -125,7 +125,7 @@ func (g *Grid) ExpandView() { ui.Clear() ui.DefaultEvtStream.ResetHandlers() defer ui.DefaultEvtStream.ResetHandlers() - container, _ := g.cmap.Get(g.cursorID) + container, _ := g.cSource.Get(g.cursorID) container.Expand() } @@ -187,7 +187,7 @@ func Display(g *Grid) bool { }) ui.Handle("/timer/1s", func(e ui.Event) { - g.containers = g.cmap.All() // refresh containers for current sort order + g.containers = g.cSource.All() // refresh containers for current sort order g.redrawRows() }) diff --git a/sort.go b/sort.go index bcc9a45..7cc31d4 100644 --- a/sort.go +++ b/sort.go @@ -16,32 +16,40 @@ 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 { return nameSorter(c1, c2) } - return c1.metrics.CPUUtil < c2.metrics.CPUUtil + return c1.metrics.CPUUtil > c2.metrics.CPUUtil }, "mem": func(c1, c2 *Container) bool { + // Use secondary sort method if equal values if c1.metrics.MemUsage == c2.metrics.MemUsage { return nameSorter(c1, c2) } - return c1.metrics.MemUsage < c2.metrics.MemUsage + return c1.metrics.MemUsage > c2.metrics.MemUsage }, "mem %": func(c1, c2 *Container) bool { + // Use secondary sort method if equal values if c1.metrics.MemPercent == c2.metrics.MemPercent { return nameSorter(c1, c2) } - return c1.metrics.MemPercent < c2.metrics.MemPercent + return c1.metrics.MemPercent > c2.metrics.MemPercent }, "net": func(c1, c2 *Container) bool { sum1 := sumNet(c1) sum2 := sumNet(c2) + // Use secondary sort method if equal values if sum1 == sum2 { return nameSorter(c1, c2) } - return sum1 < sum2 + return sum1 > sum2 }, "state": func(c1, c2 *Container) bool { + // Use secondary sort method if equal values + if c1.state == c2.state { + return nameSorter(c1, c2) + } if c1.state == "running" { return true } diff --git a/widgets/compact.go b/widgets/compact.go index 8663f20..0db1900 100644 --- a/widgets/compact.go +++ b/widgets/compact.go @@ -287,5 +287,6 @@ func slimGauge() *ui.Gauge { g.PaddingBottom = 0 g.BarColor = ui.ColorGreen g.Label = "-" + g.Bg = ui.ColorBlack return g }