package producer import ( "github.com/mackerelio/go-osstat/memory" "github.com/mackerelio/go-osstat/loadavg" "github.com/mackerelio/go-osstat/network" "github.com/mackerelio/go-osstat/uptime" "github.com/mackerelio/go-osstat/cpu" "github.com/hako/durafmt" "amuz.es/src/infra/goutils/misc" "time" "go.uber.org/multierr" "sync" "runtime" ) type NetIOInfo struct { Name string `json:"name"` RxBytes uint64 `json:"rx_bytes"` TxBytes uint64 `json:"tx_bytes"` } type MemoryInfo struct { Total uint64 `json:"total_bytes"` Active uint64 `json:"active_bytes"` Cached uint64 `json:"cached_bytes"` Free uint64 `json:"free_bytes"` Inactive uint64 `json:"inactive_bytes"` SwapFree uint64 `json:"swap_free_bytes"` SwapTotal uint64 `json:"swap_total_bytes"` SwapUsed uint64 `json:"swap_used_bytes"` Used uint64 `json:"used_bytes"` } type LoadInfo struct { Avg1 float64 `json:"avg_1"` Avg5 float64 `json:"avg_5"` Avg15 float64 `json:"avg_15"` } type CPUInfo struct { Idle float64 `json:"idle"` Nice float64 `json:"nice"` System float64 `json:"system"` User float64 `json:"user"` } type OSMetricInfo struct { Memory MemoryInfo `json:"memory"` Load LoadInfo `json:"load"` NetIO map[string]NetIOInfo `json:"net_io"` Uptime time.Duration `json:"uptime"` CPU CPUInfo `json:"cpu"` Host string `json:"host"` At time.Time `json:"at"` } func (p *OSMetricInfo) MarshalUptime() (name string, tags []map[string]string, fields []map[string]interface{}) { name, tags, fields = "uptime", []map[string]string{ { "os": runtime.GOOS, }, }, []map[string]interface{}{ { "duration": p.Uptime, }, } return } func (p *OSMetricInfo) MarshalLoad() (name string, tags []map[string]string, fields []map[string]interface{}) { name, tags, fields = "load", []map[string]string{ { "os": runtime.GOOS, }, }, []map[string]interface{}{ { "avg_1": p.Load.Avg1, "avg_5": p.Load.Avg5, "avg_15": p.Load.Avg15, }, } return } func (p *OSMetricInfo) MarshalCPU() (name string, tags []map[string]string, fields []map[string]interface{}) { name, tags, fields = "cpu", []map[string]string{ { "os": runtime.GOOS, }, }, []map[string]interface{}{ { "idle": p.CPU.Idle, "nice": p.CPU.Nice, "system": p.CPU.System, "user": p.CPU.User, }, } return } func (p *OSMetricInfo) MarshalNetworks() (name string, tags []map[string]string, fields []map[string]interface{}) { name = "network" tags = make([]map[string]string, 0) fields = make([]map[string]interface{}, 0) for name, info := range p.NetIO { tags, fields = append(tags, map[string]string{ "os": runtime.GOOS, "name": name, }), append(fields, map[string]interface{}{ "rx_bytes": info.RxBytes, "tx_bytes": info.TxBytes, }) } return } func (p *OSMetricInfo) MarshalMemory() (name string, tags []map[string]string, fields []map[string]interface{}) { name, tags, fields = "memory", []map[string]string{ { "os": runtime.GOOS, }, }, []map[string]interface{}{ { "total_bytes": p.Memory.Total, "active_bytes": p.Memory.Active, "cached_bytes": p.Memory.Cached, "free_bytes": p.Memory.Free, "inactive_bytes": p.Memory.Inactive, "swap_free_bytes": p.Memory.SwapFree, "swap_total_bytes": p.Memory.SwapTotal, "swap_used_bytes": p.Memory.SwapUsed, "used_bytes": p.Memory.Used, }, } return } func (p *OSMetricInfo) Applier() (generator []OSMetricPointGen) { generator = append( generator, p.MarshalLoad, p.MarshalCPU, p.MarshalMemory, p.MarshalNetworks, p.MarshalUptime, ) return } func (p *osMetric) readMemoryStat(info *OSMetricInfo, errChan chan<- error, waiter *sync.WaitGroup) { memoryInfo, err := memory.Get() defer func() { defer waiter.Done() if panicErr := recover(); panicErr != nil { err = multierr.Append(err, panicErr.(error)) } if err != nil { p.logger.Error("unable to retrieve readMemoryStat: ", err) errChan <- err } }() if err != nil { return } p.logger.Debug("memory total: ", misc.FileSizeIEC(memoryInfo.Total)) p.logger.Debug("memory active: ", misc.FileSizeIEC(memoryInfo.Active)) p.logger.Debug("memory cached: ", misc.FileSizeIEC(memoryInfo.Cached)) p.logger.Debug("memory free: ", misc.FileSizeIEC(memoryInfo.Free)) p.logger.Debug("memory inactive: ", misc.FileSizeIEC(memoryInfo.Inactive)) p.logger.Debug("memory swapFree: ", misc.FileSizeIEC(memoryInfo.SwapFree)) p.logger.Debug("memory swapTotal: ", misc.FileSizeIEC(memoryInfo.SwapTotal)) p.logger.Debug("memory swapUsed: ", misc.FileSizeIEC(memoryInfo.SwapUsed)) p.logger.Debug("memory used: ", misc.FileSizeIEC(memoryInfo.Used)) info.Memory.Total = memoryInfo.Total info.Memory.Active = memoryInfo.Active info.Memory.Cached = memoryInfo.Cached info.Memory.Free = memoryInfo.Free info.Memory.Inactive = memoryInfo.Inactive info.Memory.SwapFree = memoryInfo.SwapFree info.Memory.SwapTotal = memoryInfo.SwapTotal info.Memory.SwapUsed = memoryInfo.SwapUsed info.Memory.Used = memoryInfo.Used return } func (p *osMetric) readLoadStat(info *OSMetricInfo, errChan chan<- error, waiter *sync.WaitGroup) { load, err := loadavg.Get() defer func() { defer waiter.Done() if panicErr := recover(); panicErr != nil { err = multierr.Append(err, panicErr.(error)) } if err != nil { p.logger.Error("unable to retrieve readLoadStat: ", err) errChan <- err } }() if err != nil { return } p.logger.Debugf("load Loadavg1: %f", load.Loadavg1) p.logger.Debugf("load Loadavg5: %f", load.Loadavg5) p.logger.Debugf("load Loadavg15: %f", load.Loadavg15) info.Load.Avg1 = load.Loadavg1 info.Load.Avg5 = load.Loadavg5 info.Load.Avg15 = load.Loadavg15 return } func (p *osMetric) readNetworkStat(info *OSMetricInfo, errChan chan<- error, waiter *sync.WaitGroup) { netios, err := network.Get() defer func() { defer waiter.Done() if panicErr := recover(); panicErr != nil { err = multierr.Append(err, panicErr.(error)) } if err != nil { p.logger.Error("unable to retrieve readNetworkStat: ", err) errChan <- err } }() if err != nil { return } netIoMap := make(map[string]NetIOInfo) for _, netio := range netios { p.logger.Debug("netio name: ", netio.Name) p.logger.Debug("netio rxBytes: ", misc.FileSizeIEC(netio.RxBytes)) p.logger.Debug("netio txBytes: ", misc.FileSizeIEC(netio.TxBytes)) netIoMap[netio.Name] = NetIOInfo{ Name: netio.Name, RxBytes: netio.RxBytes, TxBytes: netio.TxBytes, } } info.NetIO = netIoMap return } func (p *osMetric) readUptimeStat(info *OSMetricInfo, errChan chan<- error, waiter *sync.WaitGroup) { ut, err := uptime.Get() defer func() { defer waiter.Done() if panicErr := recover(); panicErr != nil { err = multierr.Append(err, panicErr.(error)) } if err != nil { p.logger.Error("unable to retrieve readUptimeStat: ", err) errChan <- err } }() if err != nil { return } p.logger.Debugf("readUptimeStat: %s", durafmt.Parse(ut).String()) info.Uptime = ut return } func (p *osMetric) readCpuStat(info *OSMetricInfo, errChan chan<- error, waiter *sync.WaitGroup) { ct, err := cpu.Get() defer func() { defer waiter.Done() if panicErr := recover(); panicErr != nil { err = multierr.Append(err, panicErr.(error)) } if err != nil { p.logger.Error("unable to retrieve readCpuStat: ", err) errChan <- err } }() if err != nil { return } p.logger.Debugf("readCpuStat: idle=%d", ct.Idle) p.logger.Debugf("readCpuStat: nice=%d", ct.Nice) p.logger.Debugf("readCpuStat: system=%d", ct.System) p.logger.Debugf("readCpuStat: total=%d", ct.Total) p.logger.Debugf("readCpuStat: user=%d", ct.User) p.logger.Debugf("readCpuStat: idle=%f%%", float64(ct.Idle*100)/float64(ct.Total)) p.logger.Debugf("readCpuStat: nice=%f%%", float64(ct.Nice*100)/float64(ct.Total)) p.logger.Debugf("readCpuStat: system=%f%%", float64(ct.System*100)/float64(ct.Total)) p.logger.Debugf("readCpuStat: user=%f%%", float64(ct.User*100)/float64(ct.Total)) info.CPU.Idle = float64(ct.Idle*100) / float64(ct.Total) info.CPU.Nice = float64(ct.Nice*100) / float64(ct.Total) info.CPU.System = float64(ct.System*100) / float64(ct.Total) info.CPU.User = float64(ct.User*100) / float64(ct.Total) return } func (p *osMetric) availableMetrics() (appliers []osMetricApplier) { appliers = append(appliers, p.readLoadStat, p.readMemoryStat, p.readCpuStat, p.readNetworkStat, p.readUptimeStat, ) return }