github.com/mattyr/nomad@v0.3.3-0.20160919021406-3485a065154a/client/stats/host.go (about) 1 package stats 2 3 import ( 4 "math" 5 "runtime" 6 "time" 7 8 "github.com/shirou/gopsutil/cpu" 9 "github.com/shirou/gopsutil/disk" 10 "github.com/shirou/gopsutil/host" 11 "github.com/shirou/gopsutil/mem" 12 13 shelpers "github.com/hashicorp/nomad/helper/stats" 14 ) 15 16 // HostStats represents resource usage stats of the host running a Nomad client 17 type HostStats struct { 18 Memory *MemoryStats 19 CPU []*CPUStats 20 DiskStats []*DiskStats 21 Uptime uint64 22 Timestamp int64 23 CPUTicksConsumed float64 24 } 25 26 // MemoryStats represnts stats related to virtual memory usage 27 type MemoryStats struct { 28 Total uint64 29 Available uint64 30 Used uint64 31 Free uint64 32 } 33 34 // CPUStats represents stats related to cpu usage 35 type CPUStats struct { 36 CPU string 37 User float64 38 System float64 39 Idle float64 40 Total float64 41 } 42 43 // DiskStats represents stats related to disk usage 44 type DiskStats struct { 45 Device string 46 Mountpoint string 47 Size uint64 48 Used uint64 49 Available uint64 50 UsedPercent float64 51 InodesUsedPercent float64 52 } 53 54 // HostStatsCollector collects host resource usage stats 55 type HostStatsCollector struct { 56 clkSpeed float64 57 numCores int 58 statsCalculator map[string]*HostCpuStatsCalculator 59 } 60 61 // NewHostStatsCollector returns a HostStatsCollector 62 func NewHostStatsCollector() *HostStatsCollector { 63 numCores := runtime.NumCPU() 64 statsCalculator := make(map[string]*HostCpuStatsCalculator) 65 collector := &HostStatsCollector{ 66 statsCalculator: statsCalculator, 67 numCores: numCores, 68 } 69 return collector 70 } 71 72 // Collect collects stats related to resource usage of a host 73 func (h *HostStatsCollector) Collect() (*HostStats, error) { 74 hs := &HostStats{Timestamp: time.Now().UTC().UnixNano()} 75 memStats, err := mem.VirtualMemory() 76 if err != nil { 77 return nil, err 78 } 79 hs.Memory = &MemoryStats{ 80 Total: memStats.Total, 81 Available: memStats.Available, 82 Used: memStats.Used, 83 Free: memStats.Free, 84 } 85 86 ticksConsumed := 0.0 87 cpuStats, err := cpu.Times(true) 88 if err != nil { 89 return nil, err 90 } 91 cs := make([]*CPUStats, len(cpuStats)) 92 for idx, cpuStat := range cpuStats { 93 percentCalculator, ok := h.statsCalculator[cpuStat.CPU] 94 if !ok { 95 percentCalculator = NewHostCpuStatsCalculator() 96 h.statsCalculator[cpuStat.CPU] = percentCalculator 97 } 98 idle, user, system, total := percentCalculator.Calculate(cpuStat) 99 cs[idx] = &CPUStats{ 100 CPU: cpuStat.CPU, 101 User: user, 102 System: system, 103 Idle: idle, 104 Total: total, 105 } 106 ticksConsumed += (total / 100) * (shelpers.TotalTicksAvailable() / float64(len(cpuStats))) 107 } 108 hs.CPU = cs 109 hs.CPUTicksConsumed = ticksConsumed 110 111 partitions, err := disk.Partitions(false) 112 if err != nil { 113 return nil, err 114 } 115 var diskStats []*DiskStats 116 for _, partition := range partitions { 117 usage, err := disk.Usage(partition.Mountpoint) 118 if err != nil { 119 return nil, err 120 } 121 ds := DiskStats{ 122 Device: partition.Device, 123 Mountpoint: partition.Mountpoint, 124 Size: usage.Total, 125 Used: usage.Used, 126 Available: usage.Free, 127 UsedPercent: usage.UsedPercent, 128 InodesUsedPercent: usage.InodesUsedPercent, 129 } 130 if math.IsNaN(ds.UsedPercent) { 131 ds.UsedPercent = 0.0 132 } 133 if math.IsNaN(ds.InodesUsedPercent) { 134 ds.InodesUsedPercent = 0.0 135 } 136 diskStats = append(diskStats, &ds) 137 } 138 hs.DiskStats = diskStats 139 140 uptime, err := host.Uptime() 141 if err != nil { 142 return nil, err 143 } 144 hs.Uptime = uptime 145 146 return hs, nil 147 } 148 149 // HostCpuStatsCalculator calculates cpu usage percentages 150 type HostCpuStatsCalculator struct { 151 prevIdle float64 152 prevUser float64 153 prevSystem float64 154 prevBusy float64 155 prevTotal float64 156 } 157 158 // NewHostCpuStatsCalculator returns a HostCpuStatsCalculator 159 func NewHostCpuStatsCalculator() *HostCpuStatsCalculator { 160 return &HostCpuStatsCalculator{} 161 } 162 163 // Calculate calculates the current cpu usage percentages 164 func (h *HostCpuStatsCalculator) Calculate(times cpu.TimesStat) (idle float64, user float64, system float64, total float64) { 165 currentIdle := times.Idle 166 currentUser := times.User 167 currentSystem := times.System 168 currentTotal := times.Total() 169 170 deltaTotal := currentTotal - h.prevTotal 171 idle = ((currentIdle - h.prevIdle) / deltaTotal) * 100 172 user = ((currentUser - h.prevUser) / deltaTotal) * 100 173 system = ((currentSystem - h.prevSystem) / deltaTotal) * 100 174 175 currentBusy := times.User + times.System + times.Nice + times.Iowait + times.Irq + 176 times.Softirq + times.Steal + times.Guest + times.GuestNice + times.Stolen 177 178 total = ((currentBusy - h.prevBusy) / deltaTotal) * 100 179 180 h.prevIdle = currentIdle 181 h.prevUser = currentUser 182 h.prevSystem = currentSystem 183 h.prevTotal = currentTotal 184 h.prevBusy = currentBusy 185 186 return 187 }