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  }