Coletando métricas utilizando Go

Num projeto pessoal, me deparei com a necessidade de coletar métricas, tais como uso da CPU, uso do disco, uso da memória, etc. Além disso, em ambientes com uso intensivo dos recursos, essa coleta deve impactar o menos possível no desempenho geral do sistema. A primeira opção, portanto, é utilizar C. Porém, resolvi dar uma chance à linguagem Go, do Google. Tendo uma comunidade bastante ativa, devido a idade da linguagem, não foi difícil achar um pacote que colete essas métricas, o gopsutil. Esse pacote é baseado no psutil, feito em Python.

O uso deste pacote é bastante simples, e a documentação pode ser obtida aqui.

Por exemplo, para pegar informações relativas a CPU:

package main

import (
"fmt"
"github.com/shirou/gopsutil/cpu"
)

func main() {
cpuInfo, _ := cpu.Info()
fmt.Printf("%v", cpuInfo)
}

O código acima, que importa o pacote gopsutil/cpu, resulta na imagem abaixo, que mostra uma série de informações sobre a CPU, por núcleo.

Imagem de um terminal mostrando um array na linguagem Go, com informações como vendorId, physicalId, modelName, mhz, cacheSize e outros. Cada item do array é uma thread da CPU

Para pegar informações específicas, como por exemplo, a de um núcleo específico da CPU, é só fazer isso (resto do código fica igual):

fmt.Printf("%v", cpuInfo[0])

Terminal do linux mostrando a execução do programa, mostrando um dos itens do array da imagem anterior, com cpu, vendorId, family, physicalId, coreId, cores, modelName, mhz, cacheSize, etc.

E por fim, pegar um campo específico, tal como o “ModelName”:

fmt.Printf("%v", cpuInfo[0].ModelName)

Terminal mostrando a execução do programa go run getCpu.go, que retorna "Intel Core i3-4005U CPU @ 1.70GHz"

Uma função bastante útil é o percentual em uso:

fmt.Printf("%v", cpu.Percent(time.Duration(1) * time.Second, false))

 

Essa função possui dois parâmetros, o intervalo de tempo no qual será observado, e se a consulta será por núcleo. Se o intervalo for igual a 0, a função calculará relativo a última execução dessa função (e portanto, na primeira execução, o resultado será 0, que deverá ser descartado). Para exemplificar o segundo parâmetro, primeiro vou mostrar a execução quando o parâmetro é false. Como pode-se ver, é um único resultado, que é a média de uso de todos as threads da CPU:

Terminal mostrando a execução de go run getCPU.go, que retorna 2.7499999, que é o uso da CPU.

Já quando o parâmetro é true, o resultado de cada thread é mostrado:

Terminal mostrando o programa go run getCPU.go, que retorna 4 itens em um array, que é o uso da CPU por thread.

 

As outras funções relativas a CPU podem ser obtidas aqui: https://godoc.org/github.com/shirou/gopsutil/cpu

Só pra mostrar outras funções desse pacote, uma métrica que eu considero interessante é o load, que mostra quantos processos estão enfileirados, esperando por recursos. Seu uso é bastante intuitivo:

package main

import (
    "fmt"
    "github.com/shirou/gopsutil/load"
)

func main() {
    loadInfo, _ := load.Avg()

    fmt.Println("Load 1 min:",loadInfo.Load1)
    fmt.Println("Load 5 min:",loadInfo.Load5)
    fmt.Println("Load 15 min:",loadInfo.Load15)
}

Terminal mostrando a execução do programa go run getLoad.go, que retorna as métricas do load average do Linux: Load 1 min: 0.44 Load 5 min: 0.63 Load 15 min: 0.73

Esse pacote, simples e efetivo, não funciona somente no ambiente Linux. A ideia do mantenedor é que as funções funcionem em Unix-like, Windows, FreeBDS e outros.