328 lines
8.4 KiB
Go
328 lines
8.4 KiB
Go
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
|
|
}
|