Refactor the docker plugin, use go-dockerclient throughout
fixes #503 fixes #463
This commit is contained in:
@@ -1,89 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
type DockerStats struct {
|
||||
ps PS
|
||||
}
|
||||
|
||||
func (_ *DockerStats) Description() string {
|
||||
return "Read metrics about docker containers"
|
||||
}
|
||||
|
||||
func (_ *DockerStats) SampleConfig() string { return "" }
|
||||
|
||||
func (s *DockerStats) Gather(acc inputs.Accumulator) error {
|
||||
containers, err := s.ps.DockerStat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting docker info: %s", err)
|
||||
}
|
||||
|
||||
for _, cont := range containers {
|
||||
tags := map[string]string{
|
||||
"id": cont.Id,
|
||||
"name": cont.Name,
|
||||
"command": cont.Command,
|
||||
}
|
||||
for k, v := range cont.Labels {
|
||||
tags[k] = v
|
||||
}
|
||||
|
||||
cts := cont.CPU
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"user": cts.User,
|
||||
"system": cts.System,
|
||||
"idle": cts.Idle,
|
||||
"nice": cts.Nice,
|
||||
"iowait": cts.Iowait,
|
||||
"irq": cts.Irq,
|
||||
"softirq": cts.Softirq,
|
||||
"steal": cts.Steal,
|
||||
"guest": cts.Guest,
|
||||
"guest_nice": cts.GuestNice,
|
||||
|
||||
"cache": cont.Mem.Cache,
|
||||
"rss": cont.Mem.RSS,
|
||||
"rss_huge": cont.Mem.RSSHuge,
|
||||
"mapped_file": cont.Mem.MappedFile,
|
||||
"swap_in": cont.Mem.Pgpgin,
|
||||
"swap_out": cont.Mem.Pgpgout,
|
||||
"page_fault": cont.Mem.Pgfault,
|
||||
"page_major_fault": cont.Mem.Pgmajfault,
|
||||
"inactive_anon": cont.Mem.InactiveAnon,
|
||||
"active_anon": cont.Mem.ActiveAnon,
|
||||
"inactive_file": cont.Mem.InactiveFile,
|
||||
"active_file": cont.Mem.ActiveFile,
|
||||
"unevictable": cont.Mem.Unevictable,
|
||||
"memory_limit": cont.Mem.HierarchicalMemoryLimit,
|
||||
"total_cache": cont.Mem.TotalCache,
|
||||
"total_rss": cont.Mem.TotalRSS,
|
||||
"total_rss_huge": cont.Mem.TotalRSSHuge,
|
||||
"total_mapped_file": cont.Mem.TotalMappedFile,
|
||||
"total_swap_in": cont.Mem.TotalPgpgIn,
|
||||
"total_swap_out": cont.Mem.TotalPgpgOut,
|
||||
"total_page_fault": cont.Mem.TotalPgFault,
|
||||
"total_page_major_fault": cont.Mem.TotalPgMajFault,
|
||||
"total_inactive_anon": cont.Mem.TotalInactiveAnon,
|
||||
"total_active_anon": cont.Mem.TotalActiveAnon,
|
||||
"total_inactive_file": cont.Mem.TotalInactiveFile,
|
||||
"total_active_file": cont.Mem.TotalActiveFile,
|
||||
"total_unevictable": cont.Mem.TotalUnevictable,
|
||||
}
|
||||
acc.AddFields("docker", fields, tags)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("docker", func() inputs.Input {
|
||||
return &DockerStats{ps: &systemPS{}}
|
||||
})
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
// +build linux
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
"github.com/shirou/gopsutil/cpu"
|
||||
"github.com/shirou/gopsutil/docker"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDockerStats_GenerateStats(t *testing.T) {
|
||||
var mps MockPS
|
||||
var acc testutil.Accumulator
|
||||
|
||||
ds := &DockerContainerStat{
|
||||
Name: "blah",
|
||||
CPU: &cpu.CPUTimesStat{
|
||||
CPU: "all",
|
||||
User: 3.1,
|
||||
System: 8.2,
|
||||
Idle: 80.1,
|
||||
Nice: 1.3,
|
||||
Iowait: 0.2,
|
||||
Irq: 0.1,
|
||||
Softirq: 0.11,
|
||||
Steal: 0.0001,
|
||||
Guest: 8.1,
|
||||
GuestNice: 0.324,
|
||||
},
|
||||
Mem: &docker.CgroupMemStat{
|
||||
ContainerID: "blah",
|
||||
Cache: 1,
|
||||
RSS: 2,
|
||||
RSSHuge: 3,
|
||||
MappedFile: 4,
|
||||
Pgpgin: 5,
|
||||
Pgpgout: 6,
|
||||
Pgfault: 7,
|
||||
Pgmajfault: 8,
|
||||
InactiveAnon: 9,
|
||||
ActiveAnon: 10,
|
||||
InactiveFile: 11,
|
||||
ActiveFile: 12,
|
||||
Unevictable: 13,
|
||||
HierarchicalMemoryLimit: 14,
|
||||
TotalCache: 15,
|
||||
TotalRSS: 16,
|
||||
TotalRSSHuge: 17,
|
||||
TotalMappedFile: 18,
|
||||
TotalPgpgIn: 19,
|
||||
TotalPgpgOut: 20,
|
||||
TotalPgFault: 21,
|
||||
TotalPgMajFault: 22,
|
||||
TotalInactiveAnon: 23,
|
||||
TotalActiveAnon: 24,
|
||||
TotalInactiveFile: 25,
|
||||
TotalActiveFile: 26,
|
||||
TotalUnevictable: 27,
|
||||
},
|
||||
}
|
||||
|
||||
mps.On("DockerStat").Return([]*DockerContainerStat{ds}, nil)
|
||||
|
||||
err := (&DockerStats{&mps}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
dockertags := map[string]string{
|
||||
"name": "blah",
|
||||
"id": "",
|
||||
"command": "",
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"user": 3.1,
|
||||
"system": 8.2,
|
||||
"idle": 80.1,
|
||||
"nice": 1.3,
|
||||
"iowait": 0.2,
|
||||
"irq": 0.1,
|
||||
"softirq": 0.11,
|
||||
"steal": 0.0001,
|
||||
"guest": 8.1,
|
||||
"guest_nice": 0.324,
|
||||
|
||||
"cache": uint64(1),
|
||||
"rss": uint64(2),
|
||||
"rss_huge": uint64(3),
|
||||
"mapped_file": uint64(4),
|
||||
"swap_in": uint64(5),
|
||||
"swap_out": uint64(6),
|
||||
"page_fault": uint64(7),
|
||||
"page_major_fault": uint64(8),
|
||||
"inactive_anon": uint64(9),
|
||||
"active_anon": uint64(10),
|
||||
"inactive_file": uint64(11),
|
||||
"active_file": uint64(12),
|
||||
"unevictable": uint64(13),
|
||||
"memory_limit": uint64(14),
|
||||
"total_cache": uint64(15),
|
||||
"total_rss": uint64(16),
|
||||
"total_rss_huge": uint64(17),
|
||||
"total_mapped_file": uint64(18),
|
||||
"total_swap_in": uint64(19),
|
||||
"total_swap_out": uint64(20),
|
||||
"total_page_fault": uint64(21),
|
||||
"total_page_major_fault": uint64(22),
|
||||
"total_inactive_anon": uint64(23),
|
||||
"total_active_anon": uint64(24),
|
||||
"total_inactive_file": uint64(25),
|
||||
"total_active_file": uint64(26),
|
||||
"total_unevictable": uint64(27),
|
||||
}
|
||||
|
||||
acc.AssertContainsTaggedFields(t, "docker", fields, dockertags)
|
||||
}
|
||||
@@ -87,15 +87,6 @@ func (m *MockPS) SwapStat() (*mem.SwapMemoryStat, error) {
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m *MockPS) DockerStat() ([]*DockerContainerStat, error) {
|
||||
ret := m.Called()
|
||||
|
||||
r0 := ret.Get(0).([]*DockerContainerStat)
|
||||
r1 := ret.Error(1)
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m *MockPS) NetConnections() ([]net.NetConnectionStat, error) {
|
||||
ret := m.Called()
|
||||
|
||||
|
||||
@@ -1,30 +1,17 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
gonet "net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/influxdata/telegraf/internal"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
|
||||
dc "github.com/fsouza/go-dockerclient"
|
||||
"github.com/shirou/gopsutil/cpu"
|
||||
"github.com/shirou/gopsutil/disk"
|
||||
"github.com/shirou/gopsutil/docker"
|
||||
"github.com/shirou/gopsutil/mem"
|
||||
"github.com/shirou/gopsutil/net"
|
||||
)
|
||||
|
||||
type DockerContainerStat struct {
|
||||
Id string
|
||||
Name string
|
||||
Command string
|
||||
Labels map[string]string
|
||||
CPU *cpu.CPUTimesStat
|
||||
Mem *docker.CgroupMemStat
|
||||
}
|
||||
|
||||
type PS interface {
|
||||
CPUTimes(perCPU, totalCPU bool) ([]cpu.CPUTimesStat, error)
|
||||
DiskUsage(mountPointFilter []string) ([]*disk.DiskUsageStat, error)
|
||||
@@ -33,7 +20,6 @@ type PS interface {
|
||||
DiskIO() (map[string]disk.DiskIOCountersStat, error)
|
||||
VMStat() (*mem.VirtualMemoryStat, error)
|
||||
SwapStat() (*mem.SwapMemoryStat, error)
|
||||
DockerStat() ([]*DockerContainerStat, error)
|
||||
NetConnections() ([]net.NetConnectionStat, error)
|
||||
}
|
||||
|
||||
@@ -44,9 +30,7 @@ func add(acc inputs.Accumulator,
|
||||
}
|
||||
}
|
||||
|
||||
type systemPS struct {
|
||||
dockerClient *dc.Client
|
||||
}
|
||||
type systemPS struct{}
|
||||
|
||||
func (s *systemPS) CPUTimes(perCPU, totalCPU bool) ([]cpu.CPUTimesStat, error) {
|
||||
var cpuTimes []cpu.CPUTimesStat
|
||||
@@ -133,52 +117,3 @@ func (s *systemPS) VMStat() (*mem.VirtualMemoryStat, error) {
|
||||
func (s *systemPS) SwapStat() (*mem.SwapMemoryStat, error) {
|
||||
return mem.SwapMemory()
|
||||
}
|
||||
|
||||
func (s *systemPS) DockerStat() ([]*DockerContainerStat, error) {
|
||||
if s.dockerClient == nil {
|
||||
c, err := dc.NewClient("unix:///var/run/docker.sock")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.dockerClient = c
|
||||
}
|
||||
|
||||
opts := dc.ListContainersOptions{}
|
||||
|
||||
containers, err := s.dockerClient.ListContainers(opts)
|
||||
if err != nil {
|
||||
if _, ok := err.(*gonet.OpError); ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var stats []*DockerContainerStat
|
||||
|
||||
for _, container := range containers {
|
||||
ctu, err := docker.CgroupCPUDocker(container.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mem, err := docker.CgroupMemDocker(container.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name := strings.Join(container.Names, " ")
|
||||
|
||||
stats = append(stats, &DockerContainerStat{
|
||||
Id: container.ID,
|
||||
Name: name,
|
||||
Command: container.Command,
|
||||
Labels: container.Labels,
|
||||
CPU: ctu,
|
||||
Mem: mem,
|
||||
})
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user