135 lines
2.9 KiB
Go
135 lines
2.9 KiB
Go
|
package node
|
||
|
|
||
|
import (
|
||
|
"github.com/rosti-cz/node-api/common"
|
||
|
|
||
|
"github.com/shirou/gopsutil/cpu"
|
||
|
"github.com/shirou/gopsutil/disk"
|
||
|
"github.com/shirou/gopsutil/load"
|
||
|
"github.com/shirou/gopsutil/mem"
|
||
|
)
|
||
|
|
||
|
const history = 72 * 3600 / 300 // 3 days, one record every five minutes
|
||
|
|
||
|
func init() {
|
||
|
db := common.GetDBConnection()
|
||
|
db.AutoMigrate(PerformanceLog{})
|
||
|
}
|
||
|
|
||
|
// Log creates a record for all important metrics used as
|
||
|
func Log() error {
|
||
|
performanceLog := PerformanceLog{}
|
||
|
|
||
|
// Load
|
||
|
loadStats, err := load.Avg()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
performanceLog.Load1 = loadStats.Load1
|
||
|
performanceLog.Load5 = loadStats.Load5
|
||
|
performanceLog.Load15 = loadStats.Load15
|
||
|
|
||
|
// Memory
|
||
|
memoryStat, err := mem.VirtualMemory()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
performanceLog.Memory = memoryStat.UsedPercent / 100.0
|
||
|
|
||
|
// Disk space
|
||
|
diskUsage, err := disk.Usage("/srv")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
performanceLog.DiskSpaceUsage = diskUsage.UsedPercent / 100.0
|
||
|
|
||
|
// Save
|
||
|
db := common.GetDBConnection()
|
||
|
err = db.Create(&performanceLog).Error
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// and clean
|
||
|
// we have to use this stupid approach because DELETE doesn't support ORDER BY and LIMIT
|
||
|
toDeleteLogs := []PerformanceLog{}
|
||
|
err = db.Order("id DESC").Limit("99").Offset(history).Find(&toDeleteLogs).Error
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
for _, toDeleteLog := range toDeleteLogs {
|
||
|
err = db.Delete(&toDeleteLog).Error
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Index returns number from 0 to 1 where 0 means least loaded and 1 maximally loaded.
|
||
|
// It uses history of last 72 hours
|
||
|
func index() (*Node, error) {
|
||
|
node := Node{
|
||
|
Index: 1.0,
|
||
|
}
|
||
|
|
||
|
// Number of CPUs
|
||
|
cpus, err := cpu.Counts(true)
|
||
|
if err != nil {
|
||
|
return &node, err
|
||
|
}
|
||
|
|
||
|
db := common.GetDBConnection()
|
||
|
|
||
|
logs := []PerformanceLog{}
|
||
|
|
||
|
err = db.Find(&logs).Error
|
||
|
if err != nil {
|
||
|
return &node, err
|
||
|
}
|
||
|
|
||
|
var totalLoad1 float64
|
||
|
var totalLoad5 float64
|
||
|
var totalLoad15 float64
|
||
|
var totalDiskSpaceUsage float64
|
||
|
var totalMemory float64
|
||
|
|
||
|
// If there is no record we have to wait until it is, until then the server is "full"
|
||
|
if len(logs) == 0 {
|
||
|
return &node, nil
|
||
|
}
|
||
|
|
||
|
for _, log := range logs {
|
||
|
totalLoad1 += log.Load1
|
||
|
totalLoad5 += log.Load5
|
||
|
totalLoad15 += log.Load15
|
||
|
totalDiskSpaceUsage += log.DiskSpaceUsage
|
||
|
totalMemory += log.Memory
|
||
|
}
|
||
|
|
||
|
node.Load1Index = totalLoad1 / float64(len(logs)) / float64(cpus)
|
||
|
node.Load5Index = totalLoad5 / float64(len(logs)) / float64(cpus)
|
||
|
node.Load15Index = totalLoad15 / float64(len(logs)) / float64(cpus)
|
||
|
node.MemoryIndex = totalMemory / float64(len(logs))
|
||
|
node.DiskSpaceIndex = totalDiskSpaceUsage / float64(len(logs))
|
||
|
|
||
|
var indexes []float64
|
||
|
indexes = append(indexes, node.Load5Index)
|
||
|
indexes = append(indexes, node.MemoryIndex)
|
||
|
indexes = append(indexes, node.DiskSpaceIndex)
|
||
|
|
||
|
finalIndex := float64(0)
|
||
|
for _, index := range indexes {
|
||
|
if index > finalIndex {
|
||
|
finalIndex = index
|
||
|
}
|
||
|
}
|
||
|
|
||
|
node.Index = finalIndex
|
||
|
|
||
|
return &node, nil
|
||
|
}
|