From 1a615ed9fd6428885e2a37a6bbf2022c83e6889c Mon Sep 17 00:00:00 2001 From: Bradley Cicenas Date: Fri, 20 Jan 2017 12:41:26 +0000 Subject: [PATCH] refactor container collector into subpackage --- collector/docker.go | 84 +++++++++++++++++++++++++++++++++++++++++++++ collector/main.go | 23 +++++++++++++ container.go | 36 ++++--------------- containermap.go | 16 +++++++-- reader.go | 72 -------------------------------------- 5 files changed, 126 insertions(+), 105 deletions(-) create mode 100644 collector/docker.go create mode 100644 collector/main.go delete mode 100644 reader.go diff --git a/collector/docker.go b/collector/docker.go new file mode 100644 index 0000000..42c3284 --- /dev/null +++ b/collector/docker.go @@ -0,0 +1,84 @@ +package collector + +import ( + api "github.com/fsouza/go-dockerclient" +) + +// Docker collector +type Docker struct { + Metrics + stream chan Metrics + done chan bool + lastCpu float64 + lastSysCpu float64 +} + +func NewDocker(client *api.Client, id string) *Docker { + c := &Docker{ + Metrics{}, + make(chan Metrics), + make(chan bool), + 0, + 0, + } + + stats := make(chan *api.Stats) + + go func() { + opts := api.StatsOptions{ + ID: id, + Stats: stats, + Stream: true, + Done: c.done, + } + client.Stats(opts) + }() + + go func() { + for s := range stats { + c.ReadCPU(s) + c.ReadMem(s) + c.ReadNet(s) + c.stream <- c.Metrics + } + }() + + return c +} + +func (c *Docker) Stream() chan Metrics { + return c.stream +} + +// Stop collector +func (c *Docker) Stop() { + c.done <- true +} + +func (c *Docker) ReadCPU(stats *api.Stats) { + ncpus := float64(len(stats.CPUStats.CPUUsage.PercpuUsage)) + total := float64(stats.CPUStats.CPUUsage.TotalUsage) + system := float64(stats.CPUStats.SystemCPUUsage) + + cpudiff := total - c.lastCpu + syscpudiff := system - c.lastSysCpu + + c.CPUUtil = round((cpudiff / syscpudiff * 100) * ncpus) + c.lastCpu = total + c.lastSysCpu = system +} + +func (c *Docker) ReadMem(stats *api.Stats) { + c.MemUsage = int64(stats.MemoryStats.Usage) + c.MemLimit = int64(stats.MemoryStats.Limit) + c.MemPercent = round((float64(c.MemUsage) / float64(c.MemLimit)) * 100) +} + +func (c *Docker) ReadNet(stats *api.Stats) { + var rx, tx int64 + for _, network := range stats.Networks { + rx += int64(network.RxBytes) + tx += int64(network.TxBytes) + } + c.NetRx, c.NetTx = rx, tx +} diff --git a/collector/main.go b/collector/main.go new file mode 100644 index 0000000..bda71d2 --- /dev/null +++ b/collector/main.go @@ -0,0 +1,23 @@ +package collector + +import ( + "math" +) + +type Metrics struct { + CPUUtil int + NetTx int64 + NetRx int64 + MemLimit int64 + MemPercent int + MemUsage int64 +} + +type Collector interface { + Stream() chan Metrics + Stop() +} + +func round(num float64) int { + return int(num + math.Copysign(0.5, num)) +} diff --git a/container.go b/container.go index c0e7d2f..1c16c0c 100644 --- a/container.go +++ b/container.go @@ -1,30 +1,17 @@ package main import ( - "strings" - + "github.com/bcicen/ctop/collector" "github.com/bcicen/ctop/widgets" - "github.com/fsouza/go-dockerclient" ) type Container struct { id string name string done chan bool + metrics collector.Metrics + collect collector.Collector widgets widgets.ContainerWidgets - metrics *MetricsReader -} - -func NewContainer(c docker.APIContainers) *Container { - id := c.ID[:12] - name := strings.Replace(c.Names[0], "/", "", 1) // use primary container name - return &Container{ - id: id, - name: name, - done: make(chan bool), - widgets: widgets.NewCompact(id, name), - metrics: NewMetricsReader(), - } } func (c *Container) Expand() { @@ -35,21 +22,10 @@ func (c *Container) Collapse() { c.widgets = widgets.NewCompact(c.id, c.name) } -func (c *Container) Collect(client *docker.Client) { - stats := make(chan *docker.Stats) - +func (c *Container) Collect() { go func() { - opts := docker.StatsOptions{ - ID: c.id, - Stats: stats, - Stream: true, - Done: c.done, - } - client.Stats(opts) - }() - - go func() { - for metrics := range c.metrics.Read(stats) { + for metrics := range c.collect.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) diff --git a/containermap.go b/containermap.go index 7e05201..68a76ce 100644 --- a/containermap.go +++ b/containermap.go @@ -2,7 +2,10 @@ package main import ( "sort" + "strings" + "github.com/bcicen/ctop/collector" + "github.com/bcicen/ctop/widgets" "github.com/fsouza/go-dockerclient" ) @@ -30,7 +33,7 @@ type ContainerMap struct { } func (cm *ContainerMap) Refresh() { - var id string + var id, name string opts := docker.ListContainersOptions{ Filters: filters, } @@ -41,8 +44,15 @@ func (cm *ContainerMap) Refresh() { for _, c := range containers { id = c.ID[:12] if _, ok := cm.containers[id]; ok == false { - cm.containers[id] = NewContainer(c) - cm.containers[id].Collect(cm.client) + name = strings.Replace(c.Names[0], "/", "", 1) // use primary container name + cm.containers[id] = &Container{ + id: id, + name: name, + done: make(chan bool), + collect: collector.NewDocker(cm.client, id), + widgets: widgets.NewCompact(id, name), + } + cm.containers[id].Collect() } } } diff --git a/reader.go b/reader.go deleted file mode 100644 index 5479b10..0000000 --- a/reader.go +++ /dev/null @@ -1,72 +0,0 @@ -package main - -import ( - "math" - - "github.com/fsouza/go-dockerclient" -) - -type Metrics struct { - CPUUtil int - NetTx int64 - NetRx int64 - MemLimit int64 - MemPercent int - MemUsage int64 -} - -type MetricsReader struct { - Metrics - lastCpu float64 - lastSysCpu float64 -} - -func NewMetricsReader() *MetricsReader { - return &MetricsReader{} -} - -func (m *MetricsReader) Read(statsCh chan *docker.Stats) chan Metrics { - stream := make(chan Metrics) - - go func() { - for s := range statsCh { - m.ReadCPU(s) - m.ReadMem(s) - m.ReadNet(s) - stream <- m.Metrics - } - }() - - return stream -} - -func (m *MetricsReader) ReadCPU(stats *docker.Stats) { - ncpus := float64(len(stats.CPUStats.CPUUsage.PercpuUsage)) - total := float64(stats.CPUStats.CPUUsage.TotalUsage) - system := float64(stats.CPUStats.SystemCPUUsage) - - cpudiff := total - m.lastCpu - syscpudiff := system - m.lastSysCpu - m.CPUUtil = round((cpudiff / syscpudiff * 100) * ncpus) - m.lastCpu = total - m.lastSysCpu = system -} - -func (m *MetricsReader) ReadMem(stats *docker.Stats) { - m.MemUsage = int64(stats.MemoryStats.Usage) - m.MemLimit = int64(stats.MemoryStats.Limit) - m.MemPercent = round((float64(m.MemUsage) / float64(m.MemLimit)) * 100) -} - -func (m *MetricsReader) ReadNet(stats *docker.Stats) { - var rx, tx int64 - for _, network := range stats.Networks { - rx += int64(network.RxBytes) - tx += int64(network.TxBytes) - } - m.NetRx, m.NetTx = rx, tx -} - -func round(num float64) int { - return int(num + math.Copysign(0.5, num)) -}