Files
ITWorx Pulse release export bd774932d5
Public source validation / validate (push) Failing after 3m8s
Publish ITWorx Pulse source
2026-09-03 02:09:19 +02:00

72 lines
1.9 KiB
Go

package hostcollect
import (
"fmt"
"strings"
"github.com/itworx/pulse/internal/host"
)
// parseMeminfo converts /proc/meminfo into bytes.
//
// meminfo is kB based ("MemTotal: 16316420 kB"), where kB means KiB, and a handful of
// counters carry no unit at all. Treating either as bytes is the classic off-by-1024
// bug, so the unit is read per line instead of assumed.
func parseMeminfo(data []byte) (host.RawMemory, error) {
values := make(map[string]uint64, 8)
for _, line := range lines(data) {
key, rest, found := strings.Cut(line, ":")
if !found {
continue
}
fields := strings.Fields(rest)
if len(fields) == 0 {
continue
}
amount, ok := parseUint(fields[0])
if !ok {
continue
}
if len(fields) > 1 && strings.EqualFold(fields[1], "kB") {
const kib = 1024
if amount > (1<<64-1)/kib {
continue
}
amount *= kib
}
values[strings.TrimSpace(key)] = amount
}
total := values["MemTotal"]
if total == 0 {
return host.RawMemory{}, errNoMemTotal
}
available, ok := values["MemAvailable"]
if !ok {
// Kernels before 3.14 have no MemAvailable. The traditional approximation is
// free plus the reclaimable page cache; it is an estimate, never above total.
available = values["MemFree"] + values["Buffers"] + values["Cached"] + values["SReclaimable"]
}
if available > total {
available = total
}
memory := host.RawMemory{TotalBytes: total, AvailableBytes: available}
swapTotal := values["SwapTotal"]
if swapTotal > 0 {
swapFree := values["SwapFree"]
if swapFree > swapTotal {
swapFree = swapTotal
}
memory.SwapTotalBytes = swapTotal
memory.SwapUsedBytes = swapTotal - swapFree
}
return memory, nil
}
func (c *Collector) memory() (host.RawMemory, error) {
data, err := readLimited(c.procPath("meminfo"), maxFileBytes)
if err != nil {
return host.RawMemory{}, fmt.Errorf("hostcollect: read meminfo: %w", err)
}
return parseMeminfo(data)
}