2016-05-09 15:55:19 +00:00
|
|
|
package stats
|
|
|
|
|
|
|
|
import (
|
2016-06-20 17:29:46 +00:00
|
|
|
"math"
|
2016-06-10 21:14:33 +00:00
|
|
|
"runtime"
|
2016-05-27 21:15:51 +00:00
|
|
|
"time"
|
|
|
|
|
2016-05-09 15:55:19 +00:00
|
|
|
"github.com/shirou/gopsutil/cpu"
|
2016-05-22 10:46:49 +00:00
|
|
|
"github.com/shirou/gopsutil/disk"
|
2016-05-22 09:36:12 +00:00
|
|
|
"github.com/shirou/gopsutil/host"
|
2016-05-09 15:55:19 +00:00
|
|
|
"github.com/shirou/gopsutil/mem"
|
2016-06-10 21:14:33 +00:00
|
|
|
|
|
|
|
shelpers "github.com/hashicorp/nomad/helper/stats"
|
2016-05-09 15:55:19 +00:00
|
|
|
)
|
|
|
|
|
2016-05-09 16:53:00 +00:00
|
|
|
// HostStats represents resource usage stats of the host running a Nomad client
|
2016-05-09 15:55:19 +00:00
|
|
|
type HostStats struct {
|
2016-06-10 21:14:33 +00:00
|
|
|
Memory *MemoryStats
|
|
|
|
CPU []*CPUStats
|
|
|
|
DiskStats []*DiskStats
|
|
|
|
Uptime uint64
|
|
|
|
Timestamp int64
|
|
|
|
CPUTicksConsumed float64
|
2016-05-09 15:55:19 +00:00
|
|
|
}
|
|
|
|
|
2016-05-09 16:53:00 +00:00
|
|
|
// MemoryStats represnts stats related to virtual memory usage
|
2016-05-09 15:55:19 +00:00
|
|
|
type MemoryStats struct {
|
|
|
|
Total uint64
|
|
|
|
Available uint64
|
|
|
|
Used uint64
|
|
|
|
Free uint64
|
|
|
|
}
|
|
|
|
|
2016-05-09 16:53:00 +00:00
|
|
|
// CPUStats represents stats related to cpu usage
|
2016-05-09 15:55:19 +00:00
|
|
|
type CPUStats struct {
|
|
|
|
CPU string
|
|
|
|
User float64
|
|
|
|
System float64
|
|
|
|
Idle float64
|
2016-05-22 09:04:27 +00:00
|
|
|
Total float64
|
2016-05-09 15:55:19 +00:00
|
|
|
}
|
|
|
|
|
2016-05-22 10:46:49 +00:00
|
|
|
// DiskStats represents stats related to disk usage
|
|
|
|
type DiskStats struct {
|
|
|
|
Device string
|
|
|
|
Mountpoint string
|
|
|
|
Size uint64
|
|
|
|
Used uint64
|
|
|
|
Available uint64
|
|
|
|
UsedPercent float64
|
|
|
|
InodesUsedPercent float64
|
|
|
|
}
|
|
|
|
|
2016-05-22 09:04:27 +00:00
|
|
|
// HostStatsCollector collects host resource usage stats
|
|
|
|
type HostStatsCollector struct {
|
2016-06-10 21:14:33 +00:00
|
|
|
clkSpeed float64
|
|
|
|
numCores int
|
2016-05-22 09:04:27 +00:00
|
|
|
statsCalculator map[string]*HostCpuStatsCalculator
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewHostStatsCollector returns a HostStatsCollector
|
2016-05-25 20:09:51 +00:00
|
|
|
func NewHostStatsCollector() *HostStatsCollector {
|
2016-06-10 21:14:33 +00:00
|
|
|
numCores := runtime.NumCPU()
|
2016-05-22 09:04:27 +00:00
|
|
|
statsCalculator := make(map[string]*HostCpuStatsCalculator)
|
2016-06-10 21:14:33 +00:00
|
|
|
collector := &HostStatsCollector{
|
|
|
|
statsCalculator: statsCalculator,
|
|
|
|
numCores: numCores,
|
|
|
|
}
|
|
|
|
return collector
|
2016-05-22 09:04:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Collect collects stats related to resource usage of a host
|
|
|
|
func (h *HostStatsCollector) Collect() (*HostStats, error) {
|
2016-05-27 21:15:51 +00:00
|
|
|
hs := &HostStats{Timestamp: time.Now().UTC().UnixNano()}
|
2016-08-07 06:00:00 +00:00
|
|
|
memStats, err := mem.VirtualMemory()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-08-11 01:53:33 +00:00
|
|
|
hs.Memory = &MemoryStats{
|
2016-08-07 06:00:00 +00:00
|
|
|
Total: memStats.Total,
|
|
|
|
Available: memStats.Available,
|
|
|
|
Used: memStats.Used,
|
|
|
|
Free: memStats.Free,
|
2016-05-09 15:55:19 +00:00
|
|
|
}
|
|
|
|
|
2016-06-10 21:14:33 +00:00
|
|
|
ticksConsumed := 0.0
|
2016-08-07 06:00:00 +00:00
|
|
|
cpuStats, err := cpu.Times(true)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
cs := make([]*CPUStats, len(cpuStats))
|
|
|
|
for idx, cpuStat := range cpuStats {
|
|
|
|
percentCalculator, ok := h.statsCalculator[cpuStat.CPU]
|
|
|
|
if !ok {
|
|
|
|
percentCalculator = NewHostCpuStatsCalculator()
|
|
|
|
h.statsCalculator[cpuStat.CPU] = percentCalculator
|
2016-05-22 09:04:27 +00:00
|
|
|
}
|
2016-08-07 06:00:00 +00:00
|
|
|
idle, user, system, total := percentCalculator.Calculate(cpuStat)
|
|
|
|
cs[idx] = &CPUStats{
|
|
|
|
CPU: cpuStat.CPU,
|
|
|
|
User: user,
|
|
|
|
System: system,
|
|
|
|
Idle: idle,
|
|
|
|
Total: total,
|
|
|
|
}
|
|
|
|
ticksConsumed += (total / 100) * (shelpers.TotalTicksAvailable() / float64(len(cpuStats)))
|
2016-05-09 15:55:19 +00:00
|
|
|
}
|
2016-08-07 06:00:00 +00:00
|
|
|
hs.CPU = cs
|
|
|
|
hs.CPUTicksConsumed = ticksConsumed
|
2016-05-09 15:55:19 +00:00
|
|
|
|
2016-08-07 06:00:00 +00:00
|
|
|
partitions, err := disk.Partitions(false)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var diskStats []*DiskStats
|
|
|
|
for _, partition := range partitions {
|
|
|
|
usage, err := disk.Usage(partition.Mountpoint)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2016-05-22 10:46:49 +00:00
|
|
|
}
|
2016-08-07 06:00:00 +00:00
|
|
|
ds := DiskStats{
|
|
|
|
Device: partition.Device,
|
|
|
|
Mountpoint: partition.Mountpoint,
|
|
|
|
Size: usage.Total,
|
|
|
|
Used: usage.Used,
|
|
|
|
Available: usage.Free,
|
|
|
|
UsedPercent: usage.UsedPercent,
|
|
|
|
InodesUsedPercent: usage.InodesUsedPercent,
|
|
|
|
}
|
|
|
|
if math.IsNaN(ds.UsedPercent) {
|
|
|
|
ds.UsedPercent = 0.0
|
|
|
|
}
|
|
|
|
if math.IsNaN(ds.InodesUsedPercent) {
|
|
|
|
ds.InodesUsedPercent = 0.0
|
|
|
|
}
|
|
|
|
diskStats = append(diskStats, &ds)
|
2016-05-09 15:55:19 +00:00
|
|
|
}
|
2016-08-07 06:00:00 +00:00
|
|
|
hs.DiskStats = diskStats
|
2016-05-22 10:46:49 +00:00
|
|
|
|
2016-08-07 06:00:00 +00:00
|
|
|
uptime, err := host.Uptime()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2016-05-22 09:36:12 +00:00
|
|
|
}
|
2016-08-07 06:00:00 +00:00
|
|
|
hs.Uptime = uptime
|
|
|
|
|
2016-05-09 15:55:19 +00:00
|
|
|
return hs, nil
|
|
|
|
}
|
2016-05-22 09:04:27 +00:00
|
|
|
|
|
|
|
// HostCpuStatsCalculator calculates cpu usage percentages
|
|
|
|
type HostCpuStatsCalculator struct {
|
|
|
|
prevIdle float64
|
|
|
|
prevUser float64
|
|
|
|
prevSystem float64
|
|
|
|
prevBusy float64
|
|
|
|
prevTotal float64
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewHostCpuStatsCalculator returns a HostCpuStatsCalculator
|
|
|
|
func NewHostCpuStatsCalculator() *HostCpuStatsCalculator {
|
|
|
|
return &HostCpuStatsCalculator{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate calculates the current cpu usage percentages
|
|
|
|
func (h *HostCpuStatsCalculator) Calculate(times cpu.TimesStat) (idle float64, user float64, system float64, total float64) {
|
|
|
|
currentIdle := times.Idle
|
|
|
|
currentUser := times.User
|
|
|
|
currentSystem := times.System
|
|
|
|
currentTotal := times.Total()
|
|
|
|
|
|
|
|
deltaTotal := currentTotal - h.prevTotal
|
|
|
|
idle = ((currentIdle - h.prevIdle) / deltaTotal) * 100
|
|
|
|
user = ((currentUser - h.prevUser) / deltaTotal) * 100
|
|
|
|
system = ((currentSystem - h.prevSystem) / deltaTotal) * 100
|
|
|
|
|
|
|
|
currentBusy := times.User + times.System + times.Nice + times.Iowait + times.Irq +
|
|
|
|
times.Softirq + times.Steal + times.Guest + times.GuestNice + times.Stolen
|
|
|
|
|
|
|
|
total = ((currentBusy - h.prevBusy) / deltaTotal) * 100
|
|
|
|
|
|
|
|
h.prevIdle = currentIdle
|
|
|
|
h.prevUser = currentUser
|
|
|
|
h.prevSystem = currentSystem
|
|
|
|
h.prevTotal = currentTotal
|
|
|
|
h.prevBusy = currentBusy
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|