Feat[linux]: sysinfo
This commit is contained in:
parent
c7eafdbc52
commit
2e58f576ff
1
go.mod
1
go.mod
@ -3,6 +3,7 @@ module git.tcp.direct/kayos/common
|
|||||||
go 1.19
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8
|
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8
|
||||||
inet.af/netaddr v0.0.0-20220811202034-502d2d690317
|
inet.af/netaddr v0.0.0-20220811202034-502d2d690317
|
||||||
|
2
go.sum
2
go.sum
@ -1,3 +1,5 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
|
github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
108
linux/sysinfo.go
Normal file
108
linux/sysinfo.go
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
|
package linux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
some interesting information on RAM, sysinfo, and /proc/meminfo
|
||||||
|
|
||||||
|
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773
|
||||||
|
- https://github.com/mmalecki/procps/blob/master/proc/sysinfo.c
|
||||||
|
|
||||||
|
in the second link we see that even procps is parsing /proc/meminfo to get the RAM information
|
||||||
|
i'd really like to avoid this, and I may end up estimating the available memory myself...
|
||||||
|
the whole idea of this package is to focus on system calls and not on parsing files
|
||||||
|
|
||||||
|
for now I'll just add a note to the RAMInfo struct definition.
|
||||||
|
|
||||||
|
tldr; sysinfo is a bit incomplete due to it's lack of available memory calculation
|
||||||
|
*/
|
||||||
|
|
||||||
|
// from https://man7.org/linux/man-pages/man2/sysinfo.2.html
|
||||||
|
/*
|
||||||
|
struct sysinfo {
|
||||||
|
long uptime; // Seconds since boot
|
||||||
|
unsigned long loads[3]; // 1, 5, and 15 minute load averages
|
||||||
|
unsigned long totalram; // Total usable main memory size
|
||||||
|
unsigned long freeram; // Available memory size
|
||||||
|
unsigned long sharedram; // Amount of shared memory
|
||||||
|
unsigned long bufferram; // Memory used by buffers
|
||||||
|
unsigned long totalswap; // Total swap space size
|
||||||
|
unsigned long freeswap; // Swap space still available
|
||||||
|
unsigned short procs; // Number of current processes
|
||||||
|
unsigned long totalhigh; // Total high memory size
|
||||||
|
unsigned long freehigh; // Available high memory size
|
||||||
|
unsigned int mem_unit; // Memory unit size in bytes
|
||||||
|
char _f[20-2*sizeof(long)-sizeof(int)]; // Padding to 64 bytes
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
type SystemInfo struct {
|
||||||
|
Uptime time.Duration
|
||||||
|
Loads [3]uint64
|
||||||
|
|
||||||
|
RAM RAMInfo
|
||||||
|
|
||||||
|
// Totalswap is the total amount of swap space available.
|
||||||
|
Totalswap uint64
|
||||||
|
// Freeswap is the amount of swap space still available.
|
||||||
|
Freeswap uint64
|
||||||
|
// Procs is the number of current processes.
|
||||||
|
Procs uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// RAMInfo is a struct that contains information about the running system's memory.
|
||||||
|
// Please see important notes in the struct definition.
|
||||||
|
type RAMInfo struct {
|
||||||
|
Total int64
|
||||||
|
// Free is the amount of memory that is not being used.
|
||||||
|
// This does not take into account memory that is being used for caching.
|
||||||
|
// For more information, see the comments at the top of this file.
|
||||||
|
Free int64
|
||||||
|
Used int64
|
||||||
|
Shared int64
|
||||||
|
Buffers int64
|
||||||
|
Cached int64
|
||||||
|
SwapTotal int64
|
||||||
|
SwapFree int64
|
||||||
|
|
||||||
|
// unit is the memory unit size multiple in bytes.
|
||||||
|
// It is used to calculate the above values when the struct is initialized.q
|
||||||
|
unit uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sysinfo returns a SystemInfo struct containing information about the running system.
|
||||||
|
// For memory, please see important notes in the RAMInfo struct definition and the top of this file.
|
||||||
|
func Sysinfo() (systemInfo *SystemInfo, err error) {
|
||||||
|
sysinf := syscall.Sysinfo_t{}
|
||||||
|
err = syscall.Sysinfo(&sysinf)
|
||||||
|
unit := uint64(sysinf.Unit)
|
||||||
|
return &SystemInfo{
|
||||||
|
Uptime: time.Duration(sysinf.Uptime) * time.Second,
|
||||||
|
Loads: [3]uint64{sysinf.Loads[0], sysinf.Loads[1], sysinf.Loads[2]},
|
||||||
|
RAM: RAMInfo{
|
||||||
|
Total: int64(sysinf.Totalram * unit),
|
||||||
|
Free: int64(sysinf.Freeram * unit),
|
||||||
|
Used: int64((sysinf.Totalram - sysinf.Freeram) * unit),
|
||||||
|
Shared: int64(sysinf.Sharedram * unit),
|
||||||
|
Buffers: int64(sysinf.Bufferram * unit),
|
||||||
|
Cached: int64((sysinf.Totalram - sysinf.Freeram - sysinf.Bufferram) * unit),
|
||||||
|
SwapTotal: int64(sysinf.Totalswap * unit),
|
||||||
|
SwapFree: int64(sysinf.Freeswap * unit),
|
||||||
|
unit: sysinf.Unit,
|
||||||
|
},
|
||||||
|
Totalswap: sysinf.Totalswap,
|
||||||
|
Freeswap: sysinf.Freeswap,
|
||||||
|
Procs: sysinf.Procs,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Uptime() (utime time.Duration, err error) {
|
||||||
|
var sysinf *SystemInfo
|
||||||
|
sysinf, err = Sysinfo()
|
||||||
|
return sysinf.Uptime, nil
|
||||||
|
}
|
87
linux/sysinfo_test.go
Normal file
87
linux/sysinfo_test.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
|
package linux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUptime(t *testing.T) {
|
||||||
|
f, err := os.Open("/proc/uptime")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to open /proc/uptime with error: %v", err)
|
||||||
|
}
|
||||||
|
buf, err := io.ReadAll(f)
|
||||||
|
|
||||||
|
// calling Uptime() here to try and get the same time as the file
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read /proc/uptime with error: %v", err)
|
||||||
|
}
|
||||||
|
t.Logf("read %d bytes from /proc/uptime: %s", len(buf), buf)
|
||||||
|
|
||||||
|
controlSeconds, err := strconv.ParseInt(string(buf[:strings.IndexByte(string(buf), '.')]), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to parse /proc/uptime with error: %e", err)
|
||||||
|
}
|
||||||
|
if controlSeconds < 1 {
|
||||||
|
t.Fatalf("failed to parse /proc/uptime")
|
||||||
|
}
|
||||||
|
uptimeCtrl := time.Duration(controlSeconds) * time.Second
|
||||||
|
t.Logf("control uptime: %v", uptimeCtrl)
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
uptime, err := Uptime()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to get uptime with error: %e", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if uptime < 1 {
|
||||||
|
t.Fatalf("failed to get uptime (zero value)")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("uptime: %v", uptime)
|
||||||
|
|
||||||
|
matching := uptime == uptimeCtrl
|
||||||
|
|
||||||
|
// if somehow the uptime is less than the control, which was called first
|
||||||
|
// then this has failed terribly.
|
||||||
|
// If it's greater, then it's possible we are within an acceptable tolerance.
|
||||||
|
|
||||||
|
if !matching && uptime < uptimeCtrl {
|
||||||
|
t.Fatalf("uptime does not match control uptime (uptime < uptimeCtrl)!!")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !matching {
|
||||||
|
t.Logf("no match, allowing for a 1 second tolerance...")
|
||||||
|
matching = uptime == uptimeCtrl+time.Second
|
||||||
|
if matching {
|
||||||
|
t.Logf("success! (uptime == uptimeCtrl+time.Second)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !matching {
|
||||||
|
t.Fatalf("uptime does not match control uptime: %v != %v", uptime, uptimeCtrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSysinfo(t *testing.T) {
|
||||||
|
si, err := Sysinfo()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to get sysinfo with error: %e", err)
|
||||||
|
}
|
||||||
|
if si == nil {
|
||||||
|
t.Fatalf("failed to get sysinfo (nil)")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("sysinfo: %s", spew.Sdump(si))
|
||||||
|
}
|
@ -49,7 +49,7 @@ const (
|
|||||||
// GetUname uses system calls to retrieve the same values as the uname linux command
|
// GetUname uses system calls to retrieve the same values as the uname linux command
|
||||||
func GetUname(unameFlags string) (un string, err error) {
|
func GetUname(unameFlags string) (un string, err error) {
|
||||||
ub := &syscall.Utsname{}
|
ub := &syscall.Utsname{}
|
||||||
_ = syscall.Uname(ub)
|
err = syscall.Uname(ub)
|
||||||
var targets []*[65]int8
|
var targets []*[65]int8
|
||||||
for _, n := range unameFlags {
|
for _, n := range unameFlags {
|
||||||
var flag = [1]string{string(n)}
|
var flag = [1]string{string(n)}
|
||||||
@ -76,7 +76,7 @@ func GetUname(unameFlags string) (un string, err error) {
|
|||||||
return "", errors.New("no valid uname targets in string")
|
return "", errors.New("no valid uname targets in string")
|
||||||
}
|
}
|
||||||
|
|
||||||
var uns []string
|
var uns = make([]string, len(targets))
|
||||||
for _, target := range targets {
|
for _, target := range targets {
|
||||||
var sub []string
|
var sub []string
|
||||||
for _, r := range target {
|
for _, r := range target {
|
||||||
|
Loading…
Reference in New Issue
Block a user