telegraf/plugins/system/system.go

337 lines
9.0 KiB
Go

package system
import (
"fmt"
gonet "net"
"strings"
dc "github.com/fsouza/go-dockerclient"
"github.com/influxdb/tivan/plugins"
"github.com/influxdb/tivan/plugins/system/ps/common"
"github.com/influxdb/tivan/plugins/system/ps/cpu"
"github.com/influxdb/tivan/plugins/system/ps/disk"
"github.com/influxdb/tivan/plugins/system/ps/docker"
"github.com/influxdb/tivan/plugins/system/ps/load"
"github.com/influxdb/tivan/plugins/system/ps/mem"
"github.com/influxdb/tivan/plugins/system/ps/net"
)
type DockerContainerStat struct {
Id string
Name string
Command string
CPU *cpu.CPUTimesStat
Mem *docker.CgroupMemStat
}
type PS interface {
LoadAvg() (*load.LoadAvgStat, error)
CPUTimes() ([]cpu.CPUTimesStat, error)
DiskUsage() ([]*disk.DiskUsageStat, error)
NetIO() ([]net.NetIOCountersStat, error)
DiskIO() (map[string]disk.DiskIOCountersStat, error)
VMStat() (*mem.VirtualMemoryStat, error)
SwapStat() (*mem.SwapMemoryStat, error)
DockerStat() ([]*DockerContainerStat, error)
}
type SystemStats struct {
ps PS
}
func (s *SystemStats) add(acc plugins.Accumulator,
name string, val float64, tags map[string]string) {
if val >= 0 {
acc.Add(name, val, tags)
}
}
func (s *SystemStats) Gather(acc plugins.Accumulator) error {
lv, err := s.ps.LoadAvg()
if err != nil {
return err
}
acc.Add("system.load1", lv.Load1, nil)
acc.Add("system.load5", lv.Load5, nil)
acc.Add("system.load15", lv.Load15, nil)
times, err := s.ps.CPUTimes()
if err != nil {
return fmt.Errorf("error getting CPU info: %s", err)
}
for _, cts := range times {
tags := map[string]string{
"cpu": cts.CPU,
}
s.add(acc, "cpu.user", cts.User, tags)
s.add(acc, "cpu.system", cts.System, tags)
s.add(acc, "cpu.idle", cts.Idle, tags)
s.add(acc, "cpu.nice", cts.Nice, tags)
s.add(acc, "cpu.iowait", cts.Iowait, tags)
s.add(acc, "cpu.irq", cts.Irq, tags)
s.add(acc, "cpu.softirq", cts.Softirq, tags)
s.add(acc, "cpu.steal", cts.Steal, tags)
s.add(acc, "cpu.guest", cts.Guest, tags)
s.add(acc, "cpu.guestNice", cts.GuestNice, tags)
s.add(acc, "cpu.stolen", cts.Stolen, tags)
}
disks, err := s.ps.DiskUsage()
if err != nil {
return fmt.Errorf("error getting disk usage info: %s", err)
}
for _, du := range disks {
tags := map[string]string{
"path": du.Path,
}
acc.Add("disk.total", du.Total, tags)
acc.Add("disk.free", du.Free, tags)
acc.Add("disk.used", du.Total-du.Free, tags)
acc.Add("disk.inodes_total", du.InodesTotal, tags)
acc.Add("disk.inodes_free", du.InodesFree, tags)
acc.Add("disk.inodes_used", du.InodesTotal-du.InodesFree, tags)
}
diskio, err := s.ps.DiskIO()
if err != nil {
return fmt.Errorf("error getting disk io info: %s", err)
}
for _, io := range diskio {
tags := map[string]string{
"name": io.Name,
"serial": io.SerialNumber,
}
acc.Add("io.reads", io.ReadCount, tags)
acc.Add("io.writes", io.WriteCount, tags)
acc.Add("io.read_bytes", io.ReadBytes, tags)
acc.Add("io.write_bytes", io.WriteBytes, tags)
acc.Add("io.read_time", io.ReadTime, tags)
acc.Add("io.write_time", io.WriteTime, tags)
acc.Add("io.io_time", io.IoTime, tags)
}
netio, err := s.ps.NetIO()
if err != nil {
return fmt.Errorf("error getting net io info: %s", err)
}
for _, io := range netio {
tags := map[string]string{
"interface": io.Name,
}
acc.Add("net.bytes_sent", io.BytesSent, tags)
acc.Add("net.bytes_recv", io.BytesRecv, tags)
acc.Add("net.packets_sent", io.PacketsSent, tags)
acc.Add("net.packets_recv", io.PacketsRecv, tags)
acc.Add("net.err_in", io.Errin, tags)
acc.Add("net.err_out", io.Errout, tags)
acc.Add("net.drop_in", io.Dropin, tags)
acc.Add("net.drop_out", io.Dropout, tags)
}
vm, err := s.ps.VMStat()
if err != nil {
return fmt.Errorf("error getting virtual memory info: %s", err)
}
vmtags := map[string]string(nil)
acc.Add("mem.total", vm.Total, vmtags)
acc.Add("mem.available", vm.Available, vmtags)
acc.Add("mem.used", vm.Used, vmtags)
acc.Add("mem.used_prec", vm.UsedPercent, vmtags)
acc.Add("mem.free", vm.Free, vmtags)
acc.Add("mem.active", vm.Active, vmtags)
acc.Add("mem.inactive", vm.Inactive, vmtags)
acc.Add("mem.buffers", vm.Buffers, vmtags)
acc.Add("mem.cached", vm.Cached, vmtags)
acc.Add("mem.wired", vm.Wired, vmtags)
acc.Add("mem.shared", vm.Shared, vmtags)
swap, err := s.ps.SwapStat()
if err != nil {
return fmt.Errorf("error getting swap memory info: %s", err)
}
swaptags := map[string]string(nil)
acc.Add("swap.total", swap.Total, swaptags)
acc.Add("swap.used", swap.Used, swaptags)
acc.Add("swap.free", swap.Free, swaptags)
acc.Add("swap.used_perc", swap.UsedPercent, swaptags)
acc.Add("swap.swap_in", swap.Sin, swaptags)
acc.Add("swap.swap_out", swap.Sout, swaptags)
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,
}
cts := cont.CPU
acc.Add("docker.user", cts.User, tags)
acc.Add("docker.system", cts.System, tags)
acc.Add("docker.idle", cts.Idle, tags)
acc.Add("docker.nice", cts.Nice, tags)
acc.Add("docker.iowait", cts.Iowait, tags)
acc.Add("docker.irq", cts.Irq, tags)
acc.Add("docker.softirq", cts.Softirq, tags)
acc.Add("docker.steal", cts.Steal, tags)
acc.Add("docker.guest", cts.Guest, tags)
acc.Add("docker.guestNice", cts.GuestNice, tags)
acc.Add("docker.stolen", cts.Stolen, tags)
acc.Add("docker.cache", cont.Mem.Cache, tags)
acc.Add("docker.rss", cont.Mem.RSS, tags)
acc.Add("docker.rss_huge", cont.Mem.RSSHuge, tags)
acc.Add("docker.mapped_file", cont.Mem.MappedFile, tags)
acc.Add("docker.swap_in", cont.Mem.Pgpgin, tags)
acc.Add("docker.swap_out", cont.Mem.Pgpgout, tags)
acc.Add("docker.page_fault", cont.Mem.Pgfault, tags)
acc.Add("docker.page_major_fault", cont.Mem.Pgmajfault, tags)
acc.Add("docker.inactive_anon", cont.Mem.InactiveAnon, tags)
acc.Add("docker.active_anon", cont.Mem.ActiveAnon, tags)
acc.Add("docker.inactive_file", cont.Mem.InactiveFile, tags)
acc.Add("docker.active_file", cont.Mem.ActiveFile, tags)
acc.Add("docker.unevictable", cont.Mem.Unevictable, tags)
acc.Add("docker.memory_limit", cont.Mem.HierarchicalMemoryLimit, tags)
acc.Add("docker.total_cache", cont.Mem.TotalCache, tags)
acc.Add("docker.total_rss", cont.Mem.TotalRSS, tags)
acc.Add("docker.total_rss_huge", cont.Mem.TotalRSSHuge, tags)
acc.Add("docker.total_mapped_file", cont.Mem.TotalMappedFile, tags)
acc.Add("docker.total_swap_in", cont.Mem.TotalPgpgIn, tags)
acc.Add("docker.total_swap_out", cont.Mem.TotalPgpgOut, tags)
acc.Add("docker.total_page_fault", cont.Mem.TotalPgFault, tags)
acc.Add("docker.total_page_major_fault", cont.Mem.TotalPgMajFault, tags)
acc.Add("docker.total_inactive_anon", cont.Mem.TotalInactiveAnon, tags)
acc.Add("docker.total_active_anon", cont.Mem.TotalActiveAnon, tags)
acc.Add("docker.total_inactive_file", cont.Mem.TotalInactiveFile, tags)
acc.Add("docker.total_active_file", cont.Mem.TotalActiveFile, tags)
acc.Add("docker.total_unevictable", cont.Mem.TotalUnevictable, tags)
}
return nil
}
type systemPS struct {
dockerClient *dc.Client
}
func (s *systemPS) LoadAvg() (*load.LoadAvgStat, error) {
return load.LoadAvg()
}
func (s *systemPS) CPUTimes() ([]cpu.CPUTimesStat, error) {
return cpu.CPUTimes(true)
}
func (s *systemPS) DiskUsage() ([]*disk.DiskUsageStat, error) {
parts, err := disk.DiskPartitions(true)
if err != nil {
return nil, err
}
var usage []*disk.DiskUsageStat
for _, p := range parts {
du, err := disk.DiskUsage(p.Mountpoint)
if err != nil {
return nil, err
}
usage = append(usage, du)
}
return usage, nil
}
func (s *systemPS) NetIO() ([]net.NetIOCountersStat, error) {
return net.NetIOCounters(true)
}
func (s *systemPS) DiskIO() (map[string]disk.DiskIOCountersStat, error) {
m, err := disk.DiskIOCounters()
if err == common.NotImplementedError {
return nil, nil
}
return m, err
}
func (s *systemPS) VMStat() (*mem.VirtualMemoryStat, error) {
return mem.VirtualMemory()
}
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{}
list, err := s.dockerClient.ListContainers(opts)
if err != nil {
if _, ok := err.(*gonet.OpError); ok {
return nil, nil
}
return nil, err
}
var stats []*DockerContainerStat
for _, cont := range list {
ctu, err := docker.CgroupCPUDocker(cont.ID)
if err != nil {
return nil, err
}
mem, err := docker.CgroupMemDocker(cont.ID)
if err != nil {
return nil, err
}
name := strings.Join(cont.Names, " ")
stats = append(stats, &DockerContainerStat{
Id: cont.ID,
Name: name,
Command: cont.Command,
CPU: ctu,
Mem: mem,
})
}
return stats, nil
}
func init() {
plugins.Add("system", func() plugins.Plugin {
return &SystemStats{ps: &systemPS{}}
})
}