Home > Blockchain >  Extracting memory and swap info from /proc/meminfo in Golang
Extracting memory and swap info from /proc/meminfo in Golang

Time:12-16

I'd like to extract the values for MemTotal, MemFree, MemAvailable, SwapTotal and SwapFree from /proc/meminfo in Golang. The closest I've gotten so far, is to use fmt.Sscanf() which will give me the values I want one at a time, but I'm also getting many lines with zeros for output. Here's the code I'm using:

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    f, e := os.Open("/proc/meminfo")
    if e != nil {
        panic(e)
    }
    defer f.Close()
    s := bufio.NewScanner(f)
    for s.Scan() {
        var n int
        fmt.Sscanf(s.Text(), "MemFree: %d kB", &n)
        fmt.Println(n)
    }
}

Which gives me the following results:

0
11260616
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0

So the first question, is there a way to limit the results to the one value (non-zero) I'm after? Or, is there a better way to approach this altogether?

My /proc/meminfo file looks like this:

MemTotal:       16314336 kB
MemFree:        11268004 kB
MemAvailable:   13955820 kB
Buffers:          330284 kB
Cached:          2536848 kB
SwapCached:            0 kB
Active:          1259348 kB
Inactive:        3183140 kB
Active(anon):       4272 kB
Inactive(anon):  1578028 kB
Active(file):    1255076 kB
Inactive(file):  1605112 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:       4194304 kB
SwapFree:        4194304 kB
Dirty:                96 kB
Writeback:             0 kB
AnonPages:       1411704 kB
Mapped:           594408 kB
Shmem:              6940 kB
KReclaimable:     151936 kB
Slab:             253384 kB
SReclaimable:     151936 kB
SUnreclaim:       101448 kB
KernelStack:       17184 kB
PageTables:        25060 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:    12351472 kB
Committed_AS:    6092984 kB
VmallocTotal:   34359738367 kB
VmallocUsed:       40828 kB
VmallocChunk:          0 kB
Percpu:             5696 kB
AnonHugePages:    720896 kB
ShmemHugePages:        0 kB
ShmemPmdMapped:        0 kB
FileHugePages:         0 kB
FilePmdMapped:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB
DirectMap4k:      230400 kB
DirectMap2M:    11235328 kB
DirectMap1G:    14680064 kB

CodePudding user response:

Note, s.Scan() reads the input line by line. If a line does not match the format string given to fmt.Sscanf, your program outputs 0 as var n int is declared inside the loop. My suggestion is to check the first result returned by fmt.Sscanf`, i.e., the number of items matched. So, if first result is 1 you have a match and you can output the value. See working example here: https://go.dev/play/p/RtBKusGg8wV

EDIT: I tried to stay as close as possible to your code. There may be further issues as the unit of measurement used may vary according to the man pages. It may be good enough for your use case, however, if the the values in question on your systems are always output in "kB".

CodePudding user response:

I'd like to extract the values for MemTotal, MemFree, MemAvailable, SwapTotal and SwapFree from /proc/meminfo in Golang.

When I look at the values you provided from /proc/meminfo I think of a map: key/value pairs using items from the first column as keys and items from the second column as values.

To keep it simple, you could use map[string]string initially to collect, then convert where needed later to a specific type.

From there, you could use the comma ok idiom to check whether values are available for the specific data you'd like to retrieve.

If you didn't care about the specific values, you just wanted anything that was non-zero you could filter key/value pairs before you put them in the map: assert that they're not zero. I'd recommend explicitly trim spaces before any comparisons that you may make.

EDIT: Note, I ran into issues using other approaches and eventually switched to using a bufio.Scanner to process the file I was working with (also in the /proc filesystem).

  • Related