refactor container collector into subpackage

This commit is contained in:
Bradley Cicenas 2017-01-20 12:41:26 +00:00
parent 9a87c269aa
commit 1a615ed9fd
5 changed files with 126 additions and 105 deletions

84
collector/docker.go Normal file
View File

@ -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
}

23
collector/main.go Normal file
View File

@ -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))
}

View File

@ -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)

View File

@ -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()
}
}
}

View File

@ -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))
}