Introduction of gopsutil to acquire information such as CPU and memory

Go Advent Calendar 2015 ` _ is a 16-day.

The Python psutil that, there is a library to obtain information, such as CPU and memory. Sessaku gopsutil began trying to port this psutil to golang.

Gopsutil has the following features.

  • It works on Linux / Darwin / FreeBSD / Windows
    • Of course, the correspondence situation is quite different
  • It is (almost) implemented in pure golang. Therefore, cross-compiling is easy
    • Almost, I use cgo only for darwin's CPU utilization. If cgo is not used, simply implemented will be returned.
  • You can also retrieve information not found in psutil
    • It is the information of docker (cgroup), virtualization situation, and adds functions as you like

Gopsutil has continued to develop daily since over a year and a half, and now thanks to the star of github exceeding 800 more.

Also,

It is used as a library from software such as.

How to use

Usage is written in README, but it is as follows. github.com/shirou/gopsutil/mem to import, etc., simply call the method that is placed in the package.

import (
    "fmt"

    "github.com/shirou/gopsutil/mem"
)

func main() {
    v, _ := mem.VirtualMemory()

 // structが返ってきます。
    fmt.Printf("Total: %v, Free:%v, UsedPercent:%f%%\n", v.Total, v.Free, v.UsedPercent)

 // PrintするとJSON形式の結果が返ってきます
    fmt.Println(v)
}

When you do this, it looks something like this.

Total: 3179569152, Free:284233728, UsedPercent:84.508194%

{"total":3179569152,"available":492572672,"used":2895335424,"usedPercent":84.50819439828305, (以下省略)}

You can get it as a struct, so please customize it as you like. Or, if you print it you can treat it as JSON.

Information that can be obtained

I can get quite a lot of information, but I will introduce some of them.

  • CPU
    • CPU utilization, CPU hardware information
  • Memory
    • Memory usage rate, swap usage rate
  • Disk
    • Partition information, I / O, disk utilization, disk serial number
  • Host
    • Host name, start time, OS, virtualization method,
    • Login user information
  • Load
    • Load 1, 5, 15
  • Process
    • PID and state of each process, boot process name, memory, CPU usage etc.
  • Docker
    • Container internal CPU usage, memory usage, etc.

If there is demand, if it is within the range not to destroy the existing API, I think that I will increase it more and more.

contents

Gopsutil is doing a lot of very dirty things. First of all, cgo can not be used because it is making a big principle of going with pure go. Also, Linux / BSD / Windows has a very different method.

Linux
File base such as proc file system
FreeBSD / Darwin
Sysctl
Windows
DLL and WMI

These are cpu_darwin.go are separated by file name, such as.

Linux

Basically it's text file base so it's pretty easy.

And thinks Ya, or different information can take, depending on the version of Linux, in the interior of the container /sys such as it is necessary to be replacing the path, since it could not be used is different from the small point.

In addition, user information is /var/run/utmp でバイナリ(utmp構造体)で格納されていますので、ちゃんとparseしてあげる必要があります。このあたりは2015年6月のGoConで 公開 was (not announced).

FreeBSD / Darwin

BSD systems are sysctl You can get a variety of information on the command. sysctl vm.stats.vm.v_page_size it is or take a page size.

However, only information in text format can be acquired with the sysctl command. Since such information of Proc structure is not hitting from the command, syscall.Syscall6 Strike, such as using. (As an aside, since only Linux code comes out with godoc, you need to read the source code if you want to know other than Linux)

mib := []int32{CTLKern, KernProc, KernProcProc, 0}
miblen := uint64(len(mib))

// まずlengthを0にして叩き、必要となるバッファ量を得る
length := uint64(0)
_, _, err := syscall.Syscall6(
    syscall.SYS___SYSCTL,
    uintptr(unsafe.Pointer(&mib[0])),
    uintptr(miblen),
    0,
    uintptr(unsafe.Pointer(&length)),
    0,
    0)

// 必要な情報を得る
buf := make([]byte, length)
_, _, err = syscall.Syscall6(
    syscall.SYS___SYSCTL,
    uintptr(unsafe.Pointer(&mib[0])),
    uintptr(miblen),
    uintptr(unsafe.Pointer(&buf[0])),
    uintptr(unsafe.Pointer(&length)),
    0,
    0)

However, Darwin is sysctl information to get in is also the place that gave up so much less compared to FreeBSD.

Windows

We are calling the DLL to get the information.

procGetDiskFreeSpaceExW := modkernel32.NewProc("GetDiskFreeSpaceExW")

diskret, _, err := procGetDiskFreeSpaceExW.Call(
     uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))),
     uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
     uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
     uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)))

It is like that. However, because indeed this is various painful, github.com/StackExchange/wmi the use we try to hit the WMI.

type Win32_Processor struct {
    LoadPercentage            *uint16
    Family                    uint16
    Manufacturer              string
    Name                      string
    NumberOfLogicalProcessors uint32
    ProcessorId               *string
    Stepping                  *string
    MaxClockSpeed             uint32
}

func get() {
    var dst []Win32_Processor
    q := wmi.CreateQuery(&dst, "")
    err := wmi.Query(q, &dst)
    if err != nil {
        return ret, err
    }
    fmt.Println(dst)
}

Performance

Although it is not measured, since it is easy to call external commands, etc., performance should not be so much. Running at a tremendous high frequency will put load on the host side. I think that you can cash the point appropriately on the side you use.

Summary

To obtain information, such as CPU and memory of the host gopsutil was introduced.

It was about time I started using go, it was not long before I got to use go, and since I got knowledge about various platforms later, I do not feel unity. I am thinking that I want to do it properly ...

If you want to get information on the system with go, I would appreciate it if you remember gopsutil. In addition, we will wait for PR from time to time.