0

I am new to go, I am trying to get 3 functions to return them as follows

  1. function 1 - To return memory usage of the system
  2. function 2 - To return disk usage of the system
  3. function 3 - To return CPU usage of the system

So far I am able to do this much only (PS: trying not to use any libs)

func getCPUTrack() (idle, total uint64) {
    contents, err := ioutil.ReadFile("/proc/stat")
    if err != nil {
        return
    }
    lines := strings.Split(string(contents), "\n")
    for _, line := range lines {
        fields := strings.Fields(line)
        if fields[0] == "cpu" {
            numFields := len(fields)
            for i := 1; i < numFields; i++ {
                val, err := strconv.ParseUint(fields[i], 10, 64)
                if err != nil {
                    fmt.Println("Error: ", i, fields[i], err)
                }
                total += val // tally up all the numbers to get total ticks
                if i == 4 {  // idle is the 5th field in the cpu line
                    idle = val
                }
            }
            return
        }
    }
    return
}

idle0, total0 := getCPUTrack()
    time.Sleep(3 * time.Second)
    idle1, total1 := getCPUTrack()

    idleTicks := float64(idle1 - idle0)
    totalTicks := float64(total1 - total0)
    cpuUsage := 100 * (totalTicks - idleTicks) / totalTicks

    fmt.Printf("CPU usage is %f%% [busy: %f, total: %f]\n", cpuUsage, totalTicks-idleTicks, totalTicks)

Can anyone help me with this? Thanks

Anna P
  • 41
  • 1
  • 7
  • For disk usage, see [How do I get a block device's size correctly in go?](https://stackoverflow.com/questions/46558824/how-do-i-get-a-block-devices-size-correctly-in-go) – icza Aug 22 '22 at 19:45
  • For memory (RAM) info, read the `/proc/meminfo` file. – icza Aug 22 '22 at 19:46

1 Answers1

0

There is a pretty cool library you can use Go-osstat, or see in detail how it is implemented so you can build your own.

I've developed a client that uses this library and runs in the background sending Memory and CPU usage metrics

package main

import (
    "fmt"
    "os"
    "time"

    "github.com/mackerelio/go-osstat/cpu"
    "github.com/mackerelio/go-osstat/memory"
)

const (
    memoryMetric = "memory"
    cpuMetric    = "cpu"
    retries      = 10
)

type client struct {
    packageName     string
    memoryIteration int
    cpuIteration    int
    OSClient        OSClient
}

type Client interface {
    EmitMetrics()
}

type osClient struct{}

type OSClient interface {
    GetMemory() (*memory.Stats, error)
    GetCPU() (*cpu.Stats, error)
}

func (osc osClient) GetMemory() (*memory.Stats, error) { return memory.Get() }

func (osc osClient) GetCPU() (*cpu.Stats, error) { return cpu.Get() }

func NewClient(packageName string, memoryIteration, cpuIteration int) Client {
    return newClient(packageName, memoryIteration, cpuIteration, osClient{})
}

func newClient(packageName string, memoryIteration, cpuIteration int, osclient OSClient) Client {
    return &client{
        packageName:     packageName,
        memoryIteration: memoryIteration,
        cpuIteration:    cpuIteration,
        OSClient:        osclient,
    }
}

func (c *client) EmitMetrics() {
    protectFromPanic := func(metric string) {
        if r := recover(); r != nil {
            fmt.Printf(fmt.Sprintf("Recover from fail sending %s metrics for %s", metric, c.packageName), zap.Any("recover", r))
        }
    }
    c.sendMemoryMetrics(protectFromPanic)
    c.sendCPUMetrics(protectFromPanic)
}

func (c *client) sendMemoryMetrics(f func(string)) {
    count := 0
    go func() {
        defer func() {
            f(memoryMetric)
        }()
        for {
            memory, err := c.OSClient.GetMemory()
            if err != nil {
                fmt.Fprintf(os.Stderr, "%s\n", err)
                count++
                if count == retries {
                    return
                }
            } else {
                count = 0
                EmitMemoryMetrics(c.packageName, memory.Total, memory.Used, memory.Cached, memory.Free)
                time.Sleep(time.Duration(c.memoryIteration) * time.Millisecond)
            }
        }
    }()
}

func (c *client) sendCPUMetrics(f func(string)) {
    go func() {
        defer func() {
            f(cpuMetric)
        }()
        for {
            before, err := c.OSClient.GetCPU()
            if err != nil {
                fmt.Fprintf(os.Stderr, "%s\n", err)

                return
            }
            time.Sleep(time.Duration(c.cpuIteration) * time.Millisecond)
            after, err := c.OSClient.GetCPU()
            if err != nil {
                fmt.Fprintf(os.Stderr, "%s\n", err)

                return
            }
            total := float64(after.Total - before.Total)
            EmitCPUMetrics(c.packageName,
                total,
                float64(after.User-before.User)/total*100,
                float64(after.System-before.System)/total*100,
                float64(after.Idle-before.Idle)/total*100)
        }
    }()
}
  • what is `EmitMemoryMetrics` and `zap` it is undefined – Anna P Aug 23 '22 at 17:29
  • Hey @AnnaP! EmitMemoryMetrics is a function that you should implement that will send logs or the memory and cpu metrics you've just gotten in the lines above to your software of choice (Datadog, AWS Cloudwatch, etc...). Zap is a SUPER useful golang library for logging (https://github.com/uber-go/zap) – Bruno Giulianetti Aug 30 '22 at 19:25