in metric/memory/memory_linux.go [28:88]
func get(rootfs resolve.Resolver) (Memory, error) {
table, err := ParseMeminfo(rootfs)
if err != nil {
return Memory{}, fmt.Errorf("error fetching meminfo: %w", err)
}
memData := Memory{}
var free, cached uint64
var ok bool
if total, ok := table["MemTotal"]; ok {
memData.Total = opt.UintWith(total)
}
if free, ok = table["MemFree"]; ok {
memData.Free = opt.UintWith(free)
}
if cached, ok = table["Cached"]; ok {
memData.Cached = opt.UintWith(cached)
}
// overlook parsing issues here
// On the very small chance some of these don't exist,
// It's not the end of the world
buffers := table["Buffers"]
if memAvail, ok := table["MemAvailable"]; ok {
// MemAvailable is in /proc/meminfo (kernel 3.14+)
memData.Actual.Free = opt.UintWith(memAvail)
} else {
// in the future we may want to find another way to do this.
// "MemAvailable" and other more derivied metrics
// Are very relative, and can be unhelpful in cerntain workloads
// We may want to find a way to more clearly express to users
// where a certain value is coming from and what it represents
// The use of `cached` here is particularly concerning,
// as under certain intense DB server workloads, the cached memory can be quite large
// and give the impression that we've passed memory usage watermark
memData.Actual.Free = opt.UintWith(free + buffers + cached)
}
memData.Used.Bytes = opt.UintWith(memData.Total.ValueOr(0) - memData.Free.ValueOr(0))
memData.Actual.Used.Bytes = opt.UintWith(memData.Total.ValueOr(0) - memData.Actual.Free.ValueOr(0))
// Populate swap data
swapTotal, okST := table["SwapTotal"]
if okST {
memData.Swap.Total = opt.UintWith(swapTotal)
}
swapFree, okSF := table["SwapFree"]
if okSF {
memData.Swap.Free = opt.UintWith(swapFree)
}
if okSF && okST {
memData.Swap.Used.Bytes = opt.UintWith(swapTotal - swapFree)
}
return memData, nil
}