93 lines
1.6 KiB
Go
93 lines
1.6 KiB
Go
|
|
package memory
|
||
|
|
|
||
|
|
import (
|
||
|
|
"bufio"
|
||
|
|
"os"
|
||
|
|
"strconv"
|
||
|
|
"strings"
|
||
|
|
|
||
|
|
"bugs.watch/agent/internal/aggregate"
|
||
|
|
)
|
||
|
|
|
||
|
|
type Stats struct {
|
||
|
|
TotalKB uint64
|
||
|
|
AvailableKB uint64
|
||
|
|
}
|
||
|
|
|
||
|
|
// Read reads MemTotal and MemAvailable from /proc/meminfo.
|
||
|
|
// Values are in KB.
|
||
|
|
func Read() (Stats, error) {
|
||
|
|
f, err := os.Open("/proc/meminfo")
|
||
|
|
if err != nil {
|
||
|
|
return Stats{}, err
|
||
|
|
}
|
||
|
|
defer f.Close()
|
||
|
|
|
||
|
|
var total uint64
|
||
|
|
var available uint64
|
||
|
|
|
||
|
|
scanner := bufio.NewScanner(f)
|
||
|
|
for scanner.Scan() {
|
||
|
|
line := scanner.Text()
|
||
|
|
|
||
|
|
if strings.HasPrefix(line, "MemTotal:") {
|
||
|
|
fields := strings.Fields(line)
|
||
|
|
if len(fields) >= 2 {
|
||
|
|
if v, err := strconv.ParseUint(fields[1], 10, 64); err == nil {
|
||
|
|
total = v
|
||
|
|
}
|
||
|
|
}
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
if strings.HasPrefix(line, "MemAvailable:") {
|
||
|
|
fields := strings.Fields(line)
|
||
|
|
if len(fields) >= 2 {
|
||
|
|
if v, err := strconv.ParseUint(fields[1], 10, 64); err == nil {
|
||
|
|
available = v
|
||
|
|
}
|
||
|
|
}
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := scanner.Err(); err != nil {
|
||
|
|
return Stats{}, err
|
||
|
|
}
|
||
|
|
|
||
|
|
return Stats{
|
||
|
|
TotalKB: total,
|
||
|
|
AvailableKB: available,
|
||
|
|
}, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// UsedPercent returns used memory percentage based on MemTotal and MemAvailable.
|
||
|
|
func UsedPercent(s Stats) float64 {
|
||
|
|
if s.TotalKB == 0 {
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
|
||
|
|
used := s.TotalKB - s.AvailableKB
|
||
|
|
return (float64(used) / float64(s.TotalKB)) * 100.0
|
||
|
|
}
|
||
|
|
|
||
|
|
// Collector implements a stateless memory usage collector.
|
||
|
|
type Collector struct{}
|
||
|
|
|
||
|
|
func New() *Collector {
|
||
|
|
return &Collector{}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Collector) Name() string {
|
||
|
|
return "memory"
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Collector) Collect(window *aggregate.Window) {
|
||
|
|
stats, err := Read()
|
||
|
|
if err != nil {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
window.AddMemory(UsedPercent(stats))
|
||
|
|
}
|