-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgostatgrab.go
429 lines (389 loc) · 12.3 KB
/
gostatgrab.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
// Copyright 2012 Scott Dunlop. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gostatgrab
/*
#cgo pkg-config: libstatgrab
#include <statgrab.h>
static sg_disk_io_stats* disk_stats_ref(sg_disk_io_stats* ptr, int idx) {
return &ptr[idx];
}
static sg_fs_stats* fs_stats_ref(sg_fs_stats* ptr, int idx) {
return &ptr[idx];
}
static sg_process_stats* process_stats_ref(sg_process_stats* ptr, int idx) {
return &ptr[idx];
}
static sg_network_io_stats* network_stats_ref(sg_network_io_stats* ptr, int idx) {
return &ptr[idx];
}
*/
import "C"
import (
"time"
)
func init() {
if C.sg_init() != 0 {
panic(getError())
}
// if C.sg_drop_privileges() != 0 {
// panic(getError())
// }
}
func getError() error {
return &Error{int(C.sg_get_error_errno())}
}
type Error struct {
Errno int
}
func (err *Error) Error() string {
return C.GoString(C.sg_str_error(C.sg_error(err.Errno)))
}
// Shutdown ensures that any descriptors opened when gostatgrab was imported
// are properly closed.
func Shutdown() error {
if C.sg_shutdown() != 0 {
return getError()
}
return nil
}
// GetCpuStats extracts the current CPU info from the system as ticks, see sg_get_cpu_stats(3).
func GetCpuStats() (*CpuStats, error) {
c := C.sg_get_cpu_stats()
if c == nil {
return nil, getError()
}
return &CpuStats{
int64(c.user),
int64(c.kernel),
int64(c.idle),
int64(c.iowait),
int64(c.swap),
int64(c.nice),
int64(c.total),
time.Duration(time.Duration(c.systime) * time.Second)}, nil
// WARNING: modern unixes only; will horribly confuse your PDP.
}
// GetCpuStatsDiff is like GetCpuStats, but only returns ticks since the last call, see sg_get_cpu_stats_diff(3).
func GetCpuStatsDiff() (*CpuStats, error) {
c := C.sg_get_cpu_stats_diff()
if c == nil {
return nil, getError()
}
return &CpuStats{
int64(c.user),
int64(c.kernel),
int64(c.idle),
int64(c.iowait),
int64(c.swap),
int64(c.nice),
int64(c.total),
time.Duration(time.Duration(c.systime) * time.Second)}, nil
// WARNING: modern unixes only; will horribly confuse your PDP.
}
type CpuStats struct {
User int64 // number of ticks spent in user state
Kernel int64 // number of ticks spent in kernel state
Idle int64 // number of ticks spent in idle state
Iowait int64 // number of ticks spent in iowait state
Swap int64 // number of ticks spent in swap state
Nice int64 // number of ticks spent in nice state
Total int64 // total number of ticks spent
Systime time.Duration // time since the last call to this API
}
// GetCpuPercents extracts the current CPU info from the system as percentages, see sg_get_cpu_percents(3).
func GetCpuPercents() (*CpuPercents, error) {
c := C.sg_get_cpu_percents()
if c == nil {
return nil, getError()
}
return &CpuPercents{
float32(c.user),
float32(c.kernel),
float32(c.idle),
float32(c.iowait),
float32(c.swap),
float32(c.nice),
time.Duration(int64(c.time_taken)) * time.Second}, nil
// WARNING: modern unixes only; will horribly confuse your PDP.
}
type CpuPercents struct {
User float32 // percentage of time spent in user state
Kernel float32 // percentage of time spent in kernel state
Idle float32 // percentage of time spent in idle state
Iowait float32 // percentage of time spent in iowait state
Swap float32 // percentage of time spent in swap state
Nice float32 // percentage of time spent in nice state
Systime time.Duration // time since the last call to this API
}
// GetDiskIoStats returns information about I/O transfers since boot for all disks, see sg_get_disk_io_stats(3).
func GetDiskIoStats() ([]*DiskIoStats, error) {
var ct C.int
c := C.sg_get_disk_io_stats(&ct)
if c == nil {
return nil, getError()
}
return asDiskIoStatsArray(c, int(ct)), nil
}
// GetDiskIoStatsDiff returns information about I/O transfers the last call for all disks, see sg_get_disk_io_stats_diff(3).
func GetDiskIoStatsDiff() ([]*DiskIoStats, error) {
var ct C.int
c := C.sg_get_disk_io_stats_diff(&ct)
if c == nil {
return nil, getError()
}
return asDiskIoStatsArray(c, int(ct)), nil
}
func asDiskIoStatsArray(d *C.sg_disk_io_stats, ct int) []*DiskIoStats {
r := make([]*DiskIoStats, ct)
for i := 0; i < ct; i++ {
cc := C.disk_stats_ref(d, C.int(i))
r[i] = &DiskIoStats{
C.GoString(cc.disk_name),
uint64(cc.read_bytes),
uint64(cc.write_bytes),
time.Duration(time.Duration(cc.systime) * time.Second)}
}
return r
}
type DiskIoStats struct {
DiskName string
ReadBytes uint64
WriteBytes uint64
Systime time.Duration // time since the last call to this API
}
// GetMemStats returns capacity and usage information about system memory, see sg_get_mem_stats(3).
func GetMemStats() (*MemStats, error) {
c := C.sg_get_mem_stats()
if c == nil {
return nil, getError()
}
return &MemStats{
int64(c.total),
int64(c.free),
int64(c.used),
int64(c.cache)}, nil
}
type MemStats struct {
Total int64
Free int64
Used int64
Cache int64
}
// GetSwapStats returns capacity and usage information about system swap, see sg_get_swap_stats(3).
func GetSwapStats() (*SwapStats, error) {
c := C.sg_get_swap_stats()
if c == nil {
return nil, getError()
}
return &SwapStats{
int64(c.total),
int64(c.free),
int64(c.used)}, nil
}
type SwapStats struct {
Total int64
Free int64
Used int64
}
// GetFsStats returns information about mounted filesystems; see sg_get_fs_stats(3).
func GetFsStats() ([]*FsStats, error) {
var ct C.int
c := C.sg_get_fs_stats(&ct)
if c == nil {
return nil, getError()
}
return asFsStatsArray(c, int(ct)), nil
}
func asFsStatsArray(d *C.sg_fs_stats, ct int) []*FsStats {
r := make([]*FsStats, ct)
for i := 0; i < ct; i++ {
cc := C.fs_stats_ref(d, C.int(i))
r[i] = &FsStats{
C.GoString(cc.device_name),
C.GoString(cc.fs_type),
C.GoString(cc.mnt_point),
int64(cc.size),
int64(cc.used),
int64(cc.avail),
int64(cc.total_inodes),
int64(cc.used_inodes),
int64(cc.free_inodes),
int64(cc.avail_inodes),
int64(cc.io_size),
int64(cc.block_size),
int64(cc.total_blocks),
int64(cc.free_blocks),
int64(cc.used_blocks),
int64(cc.avail_blocks)}
}
return r
}
type FsStats struct {
DeviceName string // the name of the device, as mounted
FsType string // the filesystem type (frequently misreported as "ext2" in Linux)
MntPoint string // where the filesystem is mounted
Size int64 // the size of the filesystem in bytes
Used int64 // the number of bytes used in the filesystem
Avail int64 // the number of bytes available for use
TotalInodes int64 // the number of inodes in the filesystem
UsedInodes int64 // the number of inodes used by the filesystem
FreeInodes int64 // the number of free inodes, may be different from avail.
AvailInodes int64 // the number of inodes available for use
IoSize int64 // the optimal size of a block for I/O
BlockSize int64 // the size of a block in the filesystem
TotalBlocks int64 // the total number of blocks in the filesystem
FreeBlocks int64 // the number of blocks unused in the filesystem
UsedBlocks int64 // the number of blocks used in the filesystem
AvailBlocks int64 // the number of blocks available to the filesystem
}
// GetHostInfo returns host identifying information; see sg_get_host_info(3).
func GetHostInfo() (*HostInfo, error) {
c := C.sg_get_host_info()
if c == nil {
return nil, getError()
}
return &HostInfo{
C.GoString(c.os_name),
C.GoString(c.os_release),
C.GoString(c.os_version),
C.GoString(c.platform),
C.GoString(c.hostname),
time.Duration(c.uptime) * time.Second}, nil
}
type HostInfo struct {
OsName string // equivalent to "uname -s"
OsRelease string // equivalent to "uname -r"
OsVersion string // equivalent to "uname -v"
Platform string // equivalent to "uname -m"
Hostname string // equivalent to "hostname"
Uptime time.Duration // time since last boot
}
// GetProcessStats returns process information similar to that found in ps(1); see sg_get_process_stats.
func GetProcessStats() ([]*ProcessStats, error) {
var ct C.int
c := C.sg_get_process_stats(&ct)
if c == nil {
return nil, getError()
}
return asProcessStatsArray(c, int(ct)), nil
}
func asProcessStatsArray(d *C.sg_process_stats, ct int) []*ProcessStats {
r := make([]*ProcessStats, ct)
for i := 0; i < ct; i++ {
cc := C.process_stats_ref(d, C.int(i))
r[i] = &ProcessStats{
C.GoString(cc.process_name),
C.GoString(cc.proctitle),
int64(cc.pid),
int64(cc.parent),
int64(cc.pgid),
int64(cc.uid),
int64(cc.euid),
int64(cc.gid),
int64(cc.egid),
uint64(cc.proc_size),
uint64(cc.proc_resident),
time.Duration(cc.time_spent) * time.Second,
float32(cc.cpu_percent),
int(cc.nice),
ProcessState(cc.state)}
}
return r
}
type ProcessStats struct {
ProcessName string // the name of the command
ProcessTitle string // the cmdline of the command (process-controlled)
Pid int64 // the process id
Parent int64 // the parent process id
Pgid int64 // the process group leader id
Uid int64 // the user id
Euid int64 // the effective user id
Gid int64 // the group id
Egid int64 // the efffective group id
ProcSize uint64 // the process size in bytes
ProcResident uint64 // the size of the process in memory in bytes
TimeSpent time.Duration // time spent in running state
CpuPercent float32 // current cpu percentage utilized by the process
Nice int // the "niceness" of the process, see nice(1) and/or nice(2)
State ProcessState // the state of the process, see ProcessState
}
type ProcessState int
var (
Running = ProcessState(0) // the process is currently running
Sleeping = ProcessState(1) // the process is sleeping, waiting for an event
Stopped = ProcessState(2) // the process was stopped and must be resumed
Zombie = ProcessState(3) // the process is defunct and needs parent cleanup
UnknownState = ProcessState(4) // the process state is not understood by statgrab
)
// GetProcessCount returns summary counts of processes in various states; see sg_get_process_count(3)
func GetProcessCount() (*ProcessCount, error) {
c := C.sg_get_process_count()
if c == nil {
return nil, getError()
}
return &ProcessCount{
int(c.total),
int(c.running),
int(c.sleeping),
int(c.stopped),
int(c.zombie)}, nil
}
type ProcessCount struct {
Total int // total number of processes in the system
Running int // number of processes that are Running
Sleeping int // number of processes that are Sleeping
Stopped int // number of processes that are Stopped
Zombie int // number of processes that are Zombies
}
// GetNetworkIoStats returns information about I/O transfers since boot for all networks, see sg_get_network_io_stats(3).
func GetNetworkIoStats() ([]*NetworkIoStats, error) {
var ct C.int
c := C.sg_get_network_io_stats(&ct)
if c == nil {
return nil, getError()
}
return asNetworkIoStatsArray(c, int(ct)), nil
}
// GetNetworkIoStatsDiff returns information about I/O transfers the last call for all networks, see sg_get_network_io_stats_diff(3).
func GetNetworkIoStatsDiff() ([]*NetworkIoStats, error) {
var ct C.int
c := C.sg_get_network_io_stats_diff(&ct)
if c == nil {
return nil, getError()
}
return asNetworkIoStatsArray(c, int(ct)), nil
}
func asNetworkIoStatsArray(d *C.sg_network_io_stats, ct int) []*NetworkIoStats {
r := make([]*NetworkIoStats, ct)
for i := 0; i < ct; i++ {
cc := C.network_stats_ref(d, C.int(i))
r[i] = &NetworkIoStats{
C.GoString(cc.interface_name),
uint64(cc.rx),
uint64(cc.tx),
uint64(cc.ipackets),
uint64(cc.opackets),
uint64(cc.ierrors),
uint64(cc.oerrors),
uint64(cc.collisions),
time.Duration(time.Duration(cc.systime) * time.Second)}
}
return r
}
type NetworkIoStats struct {
InterfaceName string
ReadBytes uint64
WriteBytes uint64
ReadPackets uint64
WritePackets uint64
ReadErrors uint64
WriteErrors uint64
Collisions uint64
Systime time.Duration // time since the last call to this API
}
//TODO sg_get_load_stats
//TODO sg_get_page_stats
//TODO sg_get_user_stats
//TODO sg_get_network_iface_stats
//TODO: thread-safety by massive mutex