package collect import ( "bufio" "bytes" "os" "strconv" "strings" ) type Memory struct { Total uint64 `json:"total"` Available uint64 `json:"available"` Used uint64 `json:"used"` // Total - Available SwapTotal uint64 `json:"swap_total"` SwapUsed uint64 `json:"swap_used"` ARCSize uint64 `json:"arc_size"` ARCMax uint64 `json:"arc_max"` } func ReadMemory() (Memory, error) { b, err := os.ReadFile("/proc/meminfo") if err != nil { return Memory{}, err } m := parseMeminfo(b) if ab, err := os.ReadFile("/proc/spl/kstat/zfs/arcstats"); err == nil { m.ARCSize, m.ARCMax = parseArcstats(ab) } return m, nil } func parseMeminfo(b []byte) Memory { kv := map[string]uint64{} sc := bufio.NewScanner(bytes.NewReader(b)) for sc.Scan() { f := strings.Fields(sc.Text()) if len(f) < 2 { continue } n, err := strconv.ParseUint(f[1], 10, 64) if err != nil { continue } kv[strings.TrimSuffix(f[0], ":")] = n * 1024 } m := Memory{ Total: kv["MemTotal"], Available: kv["MemAvailable"], SwapTotal: kv["SwapTotal"], } m.Used = m.Total - m.Available m.SwapUsed = m.SwapTotal - kv["SwapFree"] return m } // parseArcstats picks "size" and "c_max" from the kstat table (name type data). func parseArcstats(b []byte) (size, max uint64) { sc := bufio.NewScanner(bytes.NewReader(b)) for sc.Scan() { f := strings.Fields(sc.Text()) if len(f) != 3 { continue } n, err := strconv.ParseUint(f[2], 10, 64) if err != nil { continue } switch f[0] { case "size": size = n case "c_max": max = n } } return }