hostutil: query stats with context, update gopsutil, refactor tests (#7769)

* hostutil: query stats with context, update gopsutil, refactor tests

* go mod vendor

* minor comment wording
This commit is contained in:
Calvin Leung Huang 2019-11-01 10:12:22 -07:00 committed by GitHub
parent f8032e7cc1
commit 14aac1123b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 570 additions and 509 deletions

5
go.mod
View file

@ -14,6 +14,7 @@ require (
github.com/Azure/go-autorest v11.7.1+incompatible
github.com/NYTimes/gziphandler v1.1.1
github.com/SAP/go-hdb v0.14.1
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af // indirect
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190620160927-9418d7b0cd0f
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5
@ -41,6 +42,7 @@ require (
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
github.com/go-errors/errors v1.0.1
github.com/go-ldap/ldap v3.0.2+incompatible
github.com/go-ole/go-ole v1.2.1 // indirect
github.com/go-sql-driver/mysql v1.4.1
github.com/go-test/deep v1.0.2
github.com/gocql/gocql v0.0.0-20190402132108-0e1d5de854df
@ -119,7 +121,8 @@ require (
github.com/ryanuber/columnize v2.1.0+incompatible
github.com/ryanuber/go-glob v1.0.0
github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec
github.com/shirou/gopsutil v0.0.0-20190731134726-d80c43f9c984
github.com/shirou/gopsutil v2.19.9+incompatible
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect
github.com/stretchr/testify v1.3.0
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect

2
go.sum
View file

@ -591,6 +591,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUt
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shirou/gopsutil v0.0.0-20190731134726-d80c43f9c984 h1:wsZAb4P8F7uQSwsnxE1gk9AHCcc5U0wvyDzcLwFY0Eo=
github.com/shirou/gopsutil v0.0.0-20190731134726-d80c43f9c984/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
github.com/shirou/gopsutil v2.19.9+incompatible h1:IrPVlK4nfwW10DF7pW+7YJKws9NkgNzWozwwWv9FsgY=
github.com/shirou/gopsutil v2.19.9+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 h1:udFKJ0aHUL60LboW/A+DfgoHVedieIzIXE8uylPue0U=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=

View file

@ -3,6 +3,7 @@
package hostutil
import (
"context"
"fmt"
"time"
@ -39,29 +40,29 @@ type HostInfo struct {
// The function does a best-effort capture on the most information possible,
// continuing on capture errors encountered and appending them to a resulting
// multierror.Error that gets returned at the end.
func CollectHostInfo() (*HostInfo, error) {
func CollectHostInfo(ctx context.Context) (*HostInfo, error) {
var retErr *multierror.Error
info := &HostInfo{Timestamp: time.Now().UTC()}
if h, err := host.Info(); err != nil {
if h, err := host.InfoWithContext(ctx); err != nil {
retErr = multierror.Append(retErr, &HostInfoError{"host", err})
} else {
info.Host = h
}
if v, err := mem.VirtualMemory(); err != nil {
if v, err := mem.VirtualMemoryWithContext(ctx); err != nil {
retErr = multierror.Append(retErr, &HostInfoError{"memory", err})
} else {
info.Memory = v
}
parts, err := disk.Partitions(false)
parts, err := disk.PartitionsWithContext(ctx, false)
if err != nil {
retErr = multierror.Append(retErr, &HostInfoError{"disk", err})
} else {
var usage []*disk.UsageStat
for i, part := range parts {
u, err := disk.Usage(part.Mountpoint)
u, err := disk.UsageWithContext(ctx, part.Mountpoint)
if err != nil {
retErr = multierror.Append(retErr, &HostInfoError{fmt.Sprintf("disk.%d", i), err})
continue
@ -72,13 +73,13 @@ func CollectHostInfo() (*HostInfo, error) {
info.Disk = usage
}
if c, err := cpu.Info(); err != nil {
if c, err := cpu.InfoWithContext(ctx); err != nil {
retErr = multierror.Append(retErr, &HostInfoError{"cpu", err})
} else {
info.CPU = c
}
t, err := cpu.Times(true)
t, err := cpu.TimesWithContext(ctx, true)
if err != nil {
retErr = multierror.Append(retErr, &HostInfoError{"cpu_times", err})
} else {

View file

@ -1,30 +1,60 @@
package hostutil
import (
"context"
"strings"
"testing"
"github.com/hashicorp/errwrap"
)
func TestCollectHostInfo(t *testing.T) {
info, err := CollectHostInfo()
if err != nil {
info, err := CollectHostInfo(context.Background())
if err != nil && !errwrap.ContainsType(err, new(HostInfoError)) {
t.Fatal(err)
}
// Get all the possible HostInfoError errors and check for the resulting
// stat if the package is able to fetch it for the platform we're testing
// on.
errs := errwrap.GetAllType(err, new(HostInfoError))
if info.Timestamp.IsZero() {
t.Fatal("expected non-zero Timestamp")
}
if info.CPU == nil {
if !checkErrTypeExists(errs, "cpu") && info.CPU == nil {
t.Fatal("expected non-nil CPU value")
}
if info.CPUTimes == nil {
if !checkErrTypeExists(errs, "cpu_times") && info.CPUTimes == nil {
t.Fatal("expected non-nil CPUTimes value")
}
if info.Disk == nil {
if !checkErrTypeExists(errs, "disk") && info.Disk == nil {
t.Fatal("expected non-nil Disk value")
}
if info.Host == nil {
if !checkErrTypeExists(errs, "host") && info.Host == nil {
t.Fatal("expected non-nil Host value")
}
if info.Memory == nil {
if !checkErrTypeExists(errs, "memory") && info.Memory == nil {
t.Fatal("expected non-nil Memory value")
}
}
// checkErrTypeExists is a helper that checks whether an particular
// HostInfoError.Type exists within a set of errors.
func checkErrTypeExists(errs []error, errType string) bool {
for _, e := range errs {
err, ok := e.(*HostInfoError)
if !ok {
return false
}
// This is mainly for disk error since the type string can contain an
// index for the disk.
parts := strings.SplitN(err.Type, ".", 2)
if parts[0] == errType {
return true
}
}
return false
}

View file

@ -2518,7 +2518,7 @@ func (b *SystemBackend) handleMetrics(ctx context.Context, req *logical.Request,
// returned by the collection method will be returned as response warnings.
func (b *SystemBackend) handleHostInfo(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
resp := &logical.Response{}
info, err := hostutil.CollectHostInfo()
info, err := hostutil.CollectHostInfo(ctx)
if err != nil {
// If the error is a HostInfoError, we return them as response warnings
if errs, ok := err.(*multierror.Error); ok {

View file

@ -5,7 +5,6 @@ package cpu
import (
"context"
"fmt"
"runtime"
"unsafe"
"github.com/StackExchange/wmi"
@ -13,12 +12,18 @@ import (
"golang.org/x/sys/windows"
)
var (
procGetActiveProcessorCount = common.Modkernel32.NewProc("GetActiveProcessorCount")
procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo")
)
type Win32_Processor struct {
LoadPercentage *uint16
Family uint16
Manufacturer string
Name string
NumberOfLogicalProcessors uint32
NumberOfCores uint32
ProcessorID *string
Stepping *string
MaxClockSpeed uint32
@ -201,6 +206,50 @@ func perfInfo() ([]win32_SystemProcessorPerformanceInformation, error) {
return resultBuffer, nil
}
func CountsWithContext(ctx context.Context, logical bool) (int, error) {
return runtime.NumCPU(), nil
// SystemInfo is an equivalent representation of SYSTEM_INFO in the Windows API.
// https://msdn.microsoft.com/en-us/library/ms724958%28VS.85%29.aspx?f=255&MSPPError=-2147217396
// https://github.com/elastic/go-windows/blob/bb1581babc04d5cb29a2bfa7a9ac6781c730c8dd/kernel32.go#L43
type systemInfo struct {
wProcessorArchitecture uint16
wReserved uint16
dwPageSize uint32
lpMinimumApplicationAddress uintptr
lpMaximumApplicationAddress uintptr
dwActiveProcessorMask uintptr
dwNumberOfProcessors uint32
dwProcessorType uint32
dwAllocationGranularity uint32
wProcessorLevel uint16
wProcessorRevision uint16
}
func CountsWithContext(ctx context.Context, logical bool) (int, error) {
if logical {
// https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_psutil_windows.c#L97
err := procGetActiveProcessorCount.Find()
if err == nil { // Win7+
ret, _, _ := procGetActiveProcessorCount.Call(uintptr(0xffff)) // ALL_PROCESSOR_GROUPS is 0xffff according to Rust's winapi lib https://docs.rs/winapi/*/x86_64-pc-windows-msvc/src/winapi/shared/ntdef.rs.html#120
if ret != 0 {
return int(ret), nil
}
}
var systemInfo systemInfo
_, _, err = procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&systemInfo)))
if systemInfo.dwNumberOfProcessors == 0 {
return 0, err
}
return int(systemInfo.dwNumberOfProcessors), nil
}
// physical cores https://github.com/giampaolo/psutil/blob/d01a9eaa35a8aadf6c519839e987a49d8be2d891/psutil/_psutil_windows.c#L499
// for the time being, try with unreliable and slow WMI call…
var dst []Win32_Processor
q := wmi.CreateQuery(&dst, "")
if err := common.WMIQueryWithContext(ctx, q, &dst); err != nil {
return 0, err
}
var count uint32
for _, d := range dst {
count += d.NumberOfCores
}
return int(count), nil
}

131
vendor/github.com/shirou/gopsutil/disk/disk_darwin.c generated vendored Normal file
View file

@ -0,0 +1,131 @@
// https://github.com/lufia/iostat/blob/9f7362b77ad333b26c01c99de52a11bdb650ded2/iostat_darwin.c
#include <stdint.h>
#include <CoreFoundation/CoreFoundation.h>
#include "disk_darwin.h"
#define IOKIT 1 /* to get io_name_t in device_types.h */
#include <IOKit/IOKitLib.h>
#include <IOKit/storage/IOBlockStorageDriver.h>
#include <IOKit/storage/IOMedia.h>
#include <IOKit/IOBSD.h>
#include <mach/mach_host.h>
static int getdrivestat(io_registry_entry_t d, DriveStats *stat);
static int fillstat(io_registry_entry_t d, DriveStats *stat);
int
readdrivestat(DriveStats a[], int n)
{
mach_port_t port;
CFMutableDictionaryRef match;
io_iterator_t drives;
io_registry_entry_t d;
kern_return_t status;
int na, rv;
IOMasterPort(bootstrap_port, &port);
match = IOServiceMatching("IOMedia");
CFDictionaryAddValue(match, CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
status = IOServiceGetMatchingServices(port, match, &drives);
if(status != KERN_SUCCESS)
return -1;
na = 0;
while(na < n && (d=IOIteratorNext(drives)) > 0){
rv = getdrivestat(d, &a[na]);
if(rv < 0)
return -1;
if(rv > 0)
na++;
IOObjectRelease(d);
}
IOObjectRelease(drives);
return na;
}
static int
getdrivestat(io_registry_entry_t d, DriveStats *stat)
{
io_registry_entry_t parent;
kern_return_t status;
CFDictionaryRef props;
CFStringRef name;
CFNumberRef num;
int rv;
memset(stat, 0, sizeof *stat);
status = IORegistryEntryGetParentEntry(d, kIOServicePlane, &parent);
if(status != KERN_SUCCESS)
return -1;
if(!IOObjectConformsTo(parent, "IOBlockStorageDriver")){
IOObjectRelease(parent);
return 0;
}
status = IORegistryEntryCreateCFProperties(d, (CFMutableDictionaryRef *)&props, kCFAllocatorDefault, kNilOptions);
if(status != KERN_SUCCESS){
IOObjectRelease(parent);
return -1;
}
name = (CFStringRef)CFDictionaryGetValue(props, CFSTR(kIOBSDNameKey));
CFStringGetCString(name, stat->name, NAMELEN, CFStringGetSystemEncoding());
num = (CFNumberRef)CFDictionaryGetValue(props, CFSTR(kIOMediaSizeKey));
CFNumberGetValue(num, kCFNumberSInt64Type, &stat->size);
num = (CFNumberRef)CFDictionaryGetValue(props, CFSTR(kIOMediaPreferredBlockSizeKey));
CFNumberGetValue(num, kCFNumberSInt64Type, &stat->blocksize);
CFRelease(props);
rv = fillstat(parent, stat);
IOObjectRelease(parent);
if(rv < 0)
return -1;
return 1;
}
static struct {
char *key;
size_t off;
} statstab[] = {
{kIOBlockStorageDriverStatisticsBytesReadKey, offsetof(DriveStats, read)},
{kIOBlockStorageDriverStatisticsBytesWrittenKey, offsetof(DriveStats, written)},
{kIOBlockStorageDriverStatisticsReadsKey, offsetof(DriveStats, nread)},
{kIOBlockStorageDriverStatisticsWritesKey, offsetof(DriveStats, nwrite)},
{kIOBlockStorageDriverStatisticsTotalReadTimeKey, offsetof(DriveStats, readtime)},
{kIOBlockStorageDriverStatisticsTotalWriteTimeKey, offsetof(DriveStats, writetime)},
{kIOBlockStorageDriverStatisticsLatentReadTimeKey, offsetof(DriveStats, readlat)},
{kIOBlockStorageDriverStatisticsLatentWriteTimeKey, offsetof(DriveStats, writelat)},
};
static int
fillstat(io_registry_entry_t d, DriveStats *stat)
{
CFDictionaryRef props, v;
CFNumberRef num;
kern_return_t status;
typeof(statstab[0]) *bp, *ep;
status = IORegistryEntryCreateCFProperties(d, (CFMutableDictionaryRef *)&props, kCFAllocatorDefault, kNilOptions);
if(status != KERN_SUCCESS)
return -1;
v = (CFDictionaryRef)CFDictionaryGetValue(props, CFSTR(kIOBlockStorageDriverStatisticsKey));
if(v == NULL){
CFRelease(props);
return -1;
}
ep = &statstab[sizeof(statstab)/sizeof(statstab[0])];
for(bp = &statstab[0]; bp < ep; bp++){
CFStringRef s;
s = CFStringCreateWithCString(kCFAllocatorDefault, bp->key, CFStringGetSystemEncoding());
num = (CFNumberRef)CFDictionaryGetValue(v, s);
if(num)
CFNumberGetValue(num, kCFNumberSInt64Type, ((char*)stat)+bp->off);
CFRelease(s);
}
CFRelease(props);
return 0;
}

View file

@ -1,164 +1,33 @@
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/storage/IOBlockStorageDriver.h>
#include <IOKit/storage/IOMedia.h>
#include <IOKit/IOBSD.h>
// https://github.com/lufia/iostat/blob/9f7362b77ad333b26c01c99de52a11bdb650ded2/iostat_darwin.h
typedef struct DriveStats DriveStats;
typedef struct CPUStats CPUStats;
// The iterator of all things disk. Allocated by StartIOCounterFetch, released
// by EndIOCounterFetch.
static io_iterator_t diskIter;
enum {
NDRIVE = 16,
NAMELEN = 31
};
// Begins fetching IO counters.
//
// Returns 1 if the fetch started successfully, false otherwise.
//
// If the fetch was started successfully, you must call EndIOCounterFetch once
// done to release resources.
int StartIOCounterFetch()
{
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching(kIOMediaClass),
&diskIter) != kIOReturnSuccess) {
return 0;
}
struct DriveStats {
char name[NAMELEN+1];
int64_t size;
int64_t blocksize;
return 1;
}
int64_t read;
int64_t written;
int64_t nread;
int64_t nwrite;
int64_t readtime;
int64_t writetime;
int64_t readlat;
int64_t writelat;
};
// Releases resources from fetching IO counters.
void EndIOCounterFetch()
{
IOObjectRelease(diskIter);
}
// The current disk entry of interest. Allocated by FetchNextDisk(), released by
// ReadDiskInfo().
static io_registry_entry_t diskEntry;
// The parent of diskEntry. Same lifetimes.
static io_registry_entry_t parentEntry;
// Fetches the next disk. Note that a disk entry is allocated, and will be held
// until it is processed and freed by ReadDiskInfo.
int FetchNextDisk()
{
while ((diskEntry = IOIteratorNext(diskIter)) != 0) {
// We are iterating IOMedia. We need to get the parent too (IOBSD).
if (IORegistryEntryGetParentEntry(diskEntry, kIOServicePlane, &parentEntry) != kIOReturnSuccess) {
// something is wrong...
IOObjectRelease(diskEntry);
continue;
}
if (!IOObjectConformsTo(parentEntry, "IOBlockStorageDriver")) {
// no use to us, try the next disk
IOObjectRelease(diskEntry);
IOObjectRelease(parentEntry);
continue;
}
// Got a disk OK.
return 1;
}
// No more disks.
return 0;
}
// Reads the current disk (from iteration) info into DiskInfo struct.
// Once done, all resources from the current iteration of reading are freed,
// ready for FetchNextDisk() to be called again.
int ReadDiskInfo(DiskInfo *info)
{
// Parent props. Allocated by us.
CFDictionaryRef parentProps = NULL;
// Disk props. Allocated by us.
CFDictionaryRef diskProps = NULL;
// Disk stats, fetched by us, but not allocated by us.
CFDictionaryRef stats = NULL;
if (IORegistryEntryCreateCFProperties(diskEntry, (CFMutableDictionaryRef *)&parentProps,
kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
{
// can't get parent props, give up
CFRelease(parentProps);
IOObjectRelease(diskEntry);
IOObjectRelease(parentEntry);
return -1;
}
if (IORegistryEntryCreateCFProperties(parentEntry, (CFMutableDictionaryRef *)&diskProps,
kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
{
// can't get disk props, give up
CFRelease(parentProps);
CFRelease(diskProps);
IOObjectRelease(diskEntry);
IOObjectRelease(parentEntry);
return -1;
}
// Start fetching
CFStringRef cfDiskName = (CFStringRef)CFDictionaryGetValue(parentProps, CFSTR(kIOBSDNameKey));
CFStringGetCString(cfDiskName, info->DiskName, MAX_DISK_NAME, CFStringGetSystemEncoding());
stats = (CFDictionaryRef)CFDictionaryGetValue( diskProps, CFSTR(kIOBlockStorageDriverStatisticsKey));
if (stats == NULL) {
// stat fetch failed...
CFRelease(parentProps);
CFRelease(diskProps);
IOObjectRelease(parentEntry);
IOObjectRelease(diskEntry);
return -1;
}
CFNumberRef cfnum;
if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) {
CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->Reads);
} else {
info->Reads = 0;
}
if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) {
CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->Writes);
} else {
info->Writes = 0;
}
if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) {
CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->ReadBytes);
} else {
info->ReadBytes = 0;
}
if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) {
CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->WriteBytes);
} else {
info->WriteBytes = 0;
}
if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey)))) {
CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->ReadTime);
} else {
info->ReadTime = 0;
}
if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) {
CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->WriteTime);
} else {
info->WriteTime = 0;
}
// note: read/write time are in ns, but we want ms.
info->ReadTime = info->ReadTime / 1000 / 1000;
info->WriteTime = info->WriteTime / 1000 / 1000;
CFRelease(parentProps);
CFRelease(diskProps);
IOObjectRelease(parentEntry);
IOObjectRelease(diskEntry);
return 0;
}
struct CPUStats {
natural_t user;
natural_t nice;
natural_t sys;
natural_t idle;
};
extern int readdrivestat(DriveStats a[], int n);
extern int readcpustat(CPUStats *cpu);

View file

@ -4,32 +4,15 @@
package disk
/*
#cgo LDFLAGS: -lobjc -framework Foundation -framework IOKit
#cgo LDFLAGS: -framework CoreFoundation -framework IOKit
#include <stdint.h>
// ### enough?
const int MAX_DISK_NAME = 100;
typedef struct
{
char DiskName[MAX_DISK_NAME];
int64_t Reads;
int64_t Writes;
int64_t ReadBytes;
int64_t WriteBytes;
int64_t ReadTime;
int64_t WriteTime;
} DiskInfo;
#include <CoreFoundation/CoreFoundation.h>
#include "disk_darwin.h"
*/
import "C"
import (
"context"
"errors"
"strings"
"unsafe"
"github.com/shirou/gopsutil/internal/common"
)
@ -39,57 +22,28 @@ func IOCounters(names ...string) (map[string]IOCountersStat, error) {
}
func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) {
if C.StartIOCounterFetch() == 0 {
return nil, errors.New("Unable to fetch disk list")
var buf [C.NDRIVE]C.DriveStats
n, err := C.readdrivestat(&buf[0], C.int(len(buf)))
if err != nil {
return nil, err
}
// Clean up when we are done.
defer C.EndIOCounterFetch()
ret := make(map[string]IOCountersStat, 0)
for {
res := C.FetchNextDisk()
if res == -1 {
return nil, errors.New("Unable to fetch disk information")
} else if res == 0 {
break // done
}
di := C.DiskInfo{}
if C.ReadDiskInfo((*C.DiskInfo)(unsafe.Pointer(&di))) == -1 {
return nil, errors.New("Unable to fetch disk properties")
}
// Used to only get the necessary part of the C string.
isRuneNull := func(r rune) bool {
return r == '\u0000'
}
// Map from the darwin-specific C struct to the Go type
//
// ### missing: IopsInProgress, WeightedIO, MergedReadCount,
// MergedWriteCount, SerialNumber
// IOKit can give us at least the serial number I think...
for i := 0; i < int(n); i++ {
d := IOCountersStat{
// Note: The Go type wants unsigned values, but CFNumberGetValue
// doesn't appear to be able to give us unsigned values. So, we
// cast, and hope for the best.
ReadBytes: uint64(di.ReadBytes),
WriteBytes: uint64(di.WriteBytes),
ReadCount: uint64(di.Reads),
WriteCount: uint64(di.Writes),
ReadTime: uint64(di.ReadTime),
WriteTime: uint64(di.WriteTime),
IoTime: uint64(di.ReadTime + di.WriteTime),
Name: strings.TrimFunc(C.GoStringN(&di.DiskName[0], C.MAX_DISK_NAME), isRuneNull),
ReadBytes: uint64(buf[i].read),
WriteBytes: uint64(buf[i].written),
ReadCount: uint64(buf[i].nread),
WriteCount: uint64(buf[i].nwrite),
ReadTime: uint64(buf[i].readtime / 1000 / 1000), // note: read/write time are in ns, but we want ms.
WriteTime: uint64(buf[i].writetime / 1000 / 1000),
IoTime: uint64((buf[i].readtime + buf[i].writetime) / 1000 / 1000),
Name: C.GoString(&buf[i].name[0]),
}
if len(names) > 0 && !common.StringsHas(names, d.Name) {
continue
}
ret[d.Name] = d
}
return ret, nil
}

View file

@ -244,7 +244,7 @@ func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, erro
}
fs, err := getFileSystems()
if err != nil && all {
if err != nil && !all {
return nil, err
}
@ -289,7 +289,7 @@ func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, erro
d = PartitionStat{
Device: device,
Mountpoint: mountPoint,
Mountpoint: unescapeFstab(mountPoint),
Fstype: fstype,
Opts: mountOpts,
}
@ -302,10 +302,9 @@ func PartitionsWithContext(ctx context.Context, all bool) ([]PartitionStat, erro
if strings.HasPrefix(d.Device, "/dev/mapper/") {
devpath, err := filepath.EvalSymlinks(d.Device)
if err != nil {
return nil, err
if err == nil {
d.Device = devpath
}
d.Device = devpath
}
// /dev/root is not the real device name

View file

@ -20,6 +20,7 @@ type InfoStat struct {
PlatformFamily string `json:"platformFamily"` // ex: debian, rhel
PlatformVersion string `json:"platformVersion"` // version of the complete OS
KernelVersion string `json:"kernelVersion"` // version of the OS kernel (if available)
KernelArch string `json:"kernelArch"` // native cpu architecture queried at runtime, as returned by `uname -m` or empty string in case of error
VirtualizationSystem string `json:"virtualizationSystem"`
VirtualizationRole string `json:"virtualizationRole"` // guest or host
HostID string `json:"hostid"` // ex: uuid

View file

@ -43,6 +43,11 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) {
ret.KernelVersion = kernelVersion
}
kernelArch, err := kernelArch()
if err == nil {
ret.KernelArch = kernelArch
}
platform, family, pver, err := PlatformInformation()
if err == nil {
ret.Platform = platform

View file

@ -50,6 +50,11 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) {
ret.KernelVersion = version
}
kernelArch, err := kernelArch()
if err == nil {
ret.KernelArch = kernelArch
}
system, role, err := Virtualization()
if err == nil {
ret.VirtualizationSystem = system

View file

@ -18,6 +18,7 @@ import (
"time"
"github.com/shirou/gopsutil/internal/common"
"golang.org/x/sys/unix"
)
type LSB struct {
@ -55,6 +56,11 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) {
ret.KernelVersion = kernelVersion
}
kernelArch, err := kernelArch()
if err == nil {
ret.KernelArch = kernelArch
}
system, role, err := Virtualization()
if err == nil {
ret.VirtualizationSystem = system
@ -369,19 +375,12 @@ func KernelVersion() (version string, err error) {
}
func KernelVersionWithContext(ctx context.Context) (version string, err error) {
filename := common.HostProc("sys/kernel/osrelease")
if common.PathExists(filename) {
contents, err := common.ReadLines(filename)
if err != nil {
return "", err
}
if len(contents) > 0 {
version = contents[0]
}
var utsname unix.Utsname
err = unix.Uname(&utsname)
if err != nil {
return "", err
}
return version, nil
return string(utsname.Release[:bytes.IndexByte(utsname.Release[:], 0)]), nil
}
func getSlackwareVersion(contents []string) string {

View file

@ -40,6 +40,11 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) {
ret.Hostname = hostname
}
kernelArch, err := kernelArch()
if err == nil {
ret.KernelArch = kernelArch
}
platform, family, version, err := PlatformInformation()
if err == nil {
ret.Platform = platform

15
vendor/github.com/shirou/gopsutil/host/host_posix.go generated vendored Normal file
View file

@ -0,0 +1,15 @@
// +build linux freebsd openbsd darwin solaris
package host
import (
"bytes"
"golang.org/x/sys/unix"
)
func kernelArch() (string, error) {
var utsname unix.Utsname
err := unix.Uname(&utsname)
return string(utsname.Machine[:bytes.IndexByte(utsname.Machine[:], 0)]), err
}

View file

@ -54,6 +54,11 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) {
result.PlatformVersion = fields[2]
}
kernelArch, err := kernelArch()
if err == nil {
result.KernelArch = kernelArch
}
// Find distribution name from /etc/release
fh, err := os.Open("/etc/release")
if err != nil {

View file

@ -24,6 +24,7 @@ var (
procGetSystemTimeAsFileTime = common.Modkernel32.NewProc("GetSystemTimeAsFileTime")
procGetTickCount32 = common.Modkernel32.NewProc("GetTickCount")
procGetTickCount64 = common.Modkernel32.NewProc("GetTickCount64")
procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo")
procRtlGetVersion = common.ModNt.NewProc("RtlGetVersion")
)
@ -42,6 +43,20 @@ type osVersionInfoExW struct {
wReserved uint8
}
type systemInfo struct {
wProcessorArchitecture uint16
wReserved uint16
dwPageSize uint32
lpMinimumApplicationAddress uintptr
lpMaximumApplicationAddress uintptr
dwActiveProcessorMask uintptr
dwNumberOfProcessors uint32
dwProcessorType uint32
dwAllocationGranularity uint32
wProcessorLevel uint16
wProcessorRevision uint16
}
type msAcpi_ThermalZoneTemperature struct {
Active bool
CriticalTripPoint uint32
@ -77,7 +92,14 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) {
}
{
boot, err := BootTime()
kernelArch, err := kernelArch()
if err == nil {
ret.KernelArch = kernelArch
}
}
{
boot, err := BootTimeWithContext(ctx)
if err == nil {
ret.BootTime = boot
ret.Uptime, _ = Uptime()
@ -87,12 +109,12 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) {
{
hostID, err := getMachineGuid()
if err == nil {
ret.HostID = strings.ToLower(hostID)
ret.HostID = hostID
}
}
{
procs, err := process.Pids()
procs, err := process.PidsWithContext(ctx)
if err == nil {
ret.Procs = uint64(len(procs))
}
@ -128,7 +150,7 @@ func getMachineGuid() (string, error) {
return "", fmt.Errorf("HostID incorrect: %q\n", hostID)
}
return hostID, nil
return strings.ToLower(hostID), nil
}
func Uptime() (uint64, error) {
@ -293,3 +315,35 @@ func KernelVersionWithContext(ctx context.Context) (string, error) {
_, _, version, err := PlatformInformation()
return version, err
}
func kernelArch() (string, error) {
var systemInfo systemInfo
procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&systemInfo)))
const (
PROCESSOR_ARCHITECTURE_INTEL = 0
PROCESSOR_ARCHITECTURE_ARM = 5
PROCESSOR_ARCHITECTURE_ARM64 = 12
PROCESSOR_ARCHITECTURE_IA64 = 6
PROCESSOR_ARCHITECTURE_AMD64 = 9
)
switch systemInfo.wProcessorArchitecture {
case PROCESSOR_ARCHITECTURE_INTEL:
if systemInfo.wProcessorLevel < 3 {
return "i386", nil
}
if systemInfo.wProcessorLevel > 6 {
return "i686", nil
}
return fmt.Sprintf("i%d86", systemInfo.wProcessorLevel), nil
case PROCESSOR_ARCHITECTURE_ARM:
return "arm", nil
case PROCESSOR_ARCHITECTURE_ARM64:
return "aarch64", nil
case PROCESSOR_ARCHITECTURE_IA64:
return "ia64", nil
case PROCESSOR_ARCHITECTURE_AMD64:
return "x86_64", nil
}
return "", nil
}

View file

@ -5,7 +5,7 @@ import (
)
type Warnings struct {
List []error
List []error
}
func (w *Warnings) Add(err error) {
@ -21,5 +21,5 @@ func (w *Warnings) Reference() error {
}
func (w *Warnings) Error() string {
return fmt.Sprintf("Number of warnings: %v", len(w.List))
return fmt.Sprintf("Number of warnings: %v", len(w.List))
}

View file

@ -58,6 +58,7 @@ type InterfaceAddr struct {
}
type InterfaceStat struct {
Index int `json:"index"`
MTU int `json:"mtu"` // maximum transmission unit
Name string `json:"name"` // e.g., "en0", "lo0", "eth0.100"
HardwareAddr string `json:"hardwareaddr"` // IEEE MAC-48, EUI-48 and EUI-64 form
@ -233,6 +234,7 @@ func InterfacesWithContext(ctx context.Context) ([]InterfaceStat, error) {
}
r := InterfaceStat{
Index: ifi.Index,
Name: ifi.Name,
MTU: ifi.MTU,
HardwareAddr: ifi.HardwareAddr.String(),

View file

@ -6,6 +6,7 @@ import (
"errors"
"math"
"runtime"
"sort"
"time"
"github.com/shirou/gopsutil/cpu"
@ -14,8 +15,9 @@ import (
)
var (
invoke common.Invoker = common.Invoke{}
ErrorNoChildren = errors.New("process does not have children")
invoke common.Invoker = common.Invoke{}
ErrorNoChildren = errors.New("process does not have children")
ErrorProcessNotRunning = errors.New("process does not exist")
)
type Process struct {
@ -29,6 +31,7 @@ type Process struct {
numThreads int32
memInfo *MemoryInfoStat
sigInfo *SignalInfoStat
createTime int64
lastCPUTimes *cpu.TimesStat
lastCPUTime time.Time
@ -136,6 +139,35 @@ func (p NumCtxSwitchesStat) String() string {
return string(s)
}
// Pids returns a slice of process ID list which are running now.
func Pids() ([]int32, error) {
return PidsWithContext(context.Background())
}
func PidsWithContext(ctx context.Context) ([]int32, error) {
pids, err := pidsWithContext(ctx)
sort.Slice(pids, func(i, j int) bool { return pids[i] < pids[j] })
return pids, err
}
// NewProcess creates a new Process instance, it only stores the pid and
// checks that the process exists. Other method on Process can be used
// to get more information about the process. An error will be returned
// if the process does not exist.
func NewProcess(pid int32) (*Process, error) {
p := &Process{Pid: pid}
exists, err := PidExists(pid)
if err != nil {
return p, err
}
if !exists {
return p, ErrorProcessNotRunning
}
go p.CreateTime()
return p, nil
}
func PidExists(pid int32) (bool, error) {
return PidExistsWithContext(context.Background(), pid)
}
@ -192,6 +224,41 @@ func (p *Process) PercentWithContext(ctx context.Context, interval time.Duration
return ret, nil
}
// IsRunning returns whether the process is still running or not.
func (p *Process) IsRunning() (bool, error) {
return p.IsRunningWithContext(context.Background())
}
func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
createTime, err := p.CreateTimeWithContext(ctx)
if err != nil {
return false, err
}
p2, err := NewProcess(p.Pid)
if err == ErrorProcessNotRunning {
return false, nil
}
createTime2, err := p2.CreateTimeWithContext(ctx)
if err != nil {
return false, err
}
return createTime == createTime2, nil
}
// CreateTime returns created time of the process in milliseconds since the epoch, in UTC.
func (p *Process) CreateTime() (int64, error) {
return p.CreateTimeWithContext(context.Background())
}
func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
if p.createTime != 0 {
return p.createTime, nil
}
createTime, err := p.createTimeWithContext(ctx)
p.createTime = createTime
return p.createTime, err
}
func calculatePercent(t1, t2 *cpu.TimesStat, delta float64, numcpu int) float64 {
if delta == 0 {
return 0

View file

@ -44,11 +44,7 @@ type MemoryInfoExStat struct {
type MemoryMapsStat struct {
}
func Pids() ([]int32, error) {
return PidsWithContext(context.Background())
}
func PidsWithContext(ctx context.Context) ([]int32, error) {
func pidsWithContext(ctx context.Context) ([]int32, error) {
var ret []int32
pids, err := callPsWithContext(ctx, "pid", 0, false)
@ -103,28 +99,6 @@ func (p *Process) Exe() (string, error) {
return p.ExeWithContext(context.Background())
}
func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
lsof_bin, err := exec.LookPath("lsof")
if err != nil {
return "", err
}
out, err := invoke.CommandWithContext(ctx, lsof_bin, "-p", strconv.Itoa(int(p.Pid)), "-Fpfn")
if err != nil {
return "", fmt.Errorf("bad call to lsof: %s", err)
}
txtFound := 0
lines := strings.Split(string(out), "\n")
for i := 1; i < len(lines); i += 2 {
if lines[i] == "ftxt" {
txtFound++
if txtFound == 2 {
return lines[i-1][1:], nil
}
}
}
return "", fmt.Errorf("missing txt data returned by lsof")
}
// Cmdline returns the command line arguments of the process as a string with
// each argument separated by 0x20 ascii character.
func (p *Process) Cmdline() (string, error) {
@ -155,11 +129,8 @@ func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error)
}
return r[0], err
}
func (p *Process) CreateTime() (int64, error) {
return p.CreateTimeWithContext(context.Background())
}
func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
r, err := callPsWithContext(ctx, "etime", p.Pid, false)
if err != nil {
return 0, err
@ -553,13 +524,6 @@ func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]
return nil, common.ErrNotImplementedError
}
func (p *Process) IsRunning() (bool, error) {
return p.IsRunningWithContext(context.Background())
}
func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
return true, common.ErrNotImplementedError
}
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
return p.MemoryMapsWithContext(context.Background(), grouped)
}
@ -634,12 +598,6 @@ func (p *Process) getKProcWithContext(ctx context.Context) (*KinfoProc, error) {
return &k, nil
}
func NewProcess(pid int32) (*Process, error) {
p := &Process{Pid: pid}
return p, nil
}
// call ps command.
// Return value deletes Header line(you must not input wrong arg).
// And splited by Space. Caller have responsibility to manage.

View file

@ -0,0 +1,30 @@
// +build darwin
// +build cgo
package process
// #include <stdlib.h>
// #include <libproc.h>
import "C"
import (
"context"
"fmt"
"unsafe"
)
func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
var c C.char // need a var for unsafe.Sizeof need a var
const bufsize = C.PROC_PIDPATHINFO_MAXSIZE * unsafe.Sizeof(c)
buffer := (*C.char)(C.malloc(C.size_t(bufsize)))
defer C.free(unsafe.Pointer(buffer))
ret, err := C.proc_pidpath(C.int(p.Pid), unsafe.Pointer(buffer), C.uint32_t(bufsize))
if err != nil {
return "", err
}
if ret <= 0 {
return "", fmt.Errorf("unknown error: proc_pidpath returned %d", ret)
}
return C.GoString(buffer), nil
}

View file

@ -0,0 +1,34 @@
// +build darwin
// +build !cgo
package process
import (
"context"
"fmt"
"os/exec"
"strconv"
"strings"
)
func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
lsof_bin, err := exec.LookPath("lsof")
if err != nil {
return "", err
}
out, err := invoke.CommandWithContext(ctx, lsof_bin, "-p", strconv.Itoa(int(p.Pid)), "-Fpfn")
if err != nil {
return "", fmt.Errorf("bad call to lsof: %s", err)
}
txtFound := 0
lines := strings.Split(string(out), "\n")
for i := 1; i < len(lines); i += 2 {
if lines[i] == "ftxt" {
txtFound++
if txtFound == 2 {
return lines[i-1][1:], nil
}
}
}
return "", fmt.Errorf("missing txt data returned by lsof")
}

View file

@ -28,11 +28,7 @@ type MemoryMapsStat struct {
type MemoryInfoExStat struct {
}
func Pids() ([]int32, error) {
return PidsWithContext(context.Background())
}
func PidsWithContext(ctx context.Context) ([]int32, error) {
func pidsWithContext(ctx context.Context) ([]int32, error) {
return []int32{}, common.ErrNotImplementedError
}
@ -44,10 +40,6 @@ func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
return nil, common.ErrNotImplementedError
}
func NewProcess(pid int32) (*Process, error) {
return nil, common.ErrNotImplementedError
}
func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
pids, err := PidsWithContext(ctx)
if err != nil {
@ -101,11 +93,8 @@ func (p *Process) CmdlineSlice() ([]string, error) {
func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
return []string{}, common.ErrNotImplementedError
}
func (p *Process) CreateTime() (int64, error) {
return p.CreateTimeWithContext(context.Background())
}
func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) Cwd() (string, error) {
@ -291,13 +280,7 @@ func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]net.IOCountersStat, error) {
return []net.IOCountersStat{}, common.ErrNotImplementedError
}
func (p *Process) IsRunning() (bool, error) {
return p.IsRunningWithContext(context.Background())
}
func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
return true, common.ErrNotImplementedError
}
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
return p.MemoryMapsWithContext(context.Background(), grouped)
}

View file

@ -23,11 +23,7 @@ type MemoryInfoExStat struct {
type MemoryMapsStat struct {
}
func Pids() ([]int32, error) {
return PidsWithContext(context.Background())
}
func PidsWithContext(ctx context.Context) ([]int32, error) {
func pidsWithContext(ctx context.Context) ([]int32, error) {
var ret []int32
procs, err := Processes()
if err != nil {
@ -120,11 +116,8 @@ func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error)
return strParts, nil
}
func (p *Process) CreateTime() (int64, error) {
return p.CreateTimeWithContext(context.Background())
}
func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) Cwd() (string, error) {
@ -432,13 +425,6 @@ func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]
return nil, common.ErrNotImplementedError
}
func (p *Process) IsRunning() (bool, error) {
return p.IsRunningWithContext(context.Background())
}
func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
return true, common.ErrNotImplementedError
}
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
return p.MemoryMapsWithContext(context.Background(), grouped)
}
@ -510,9 +496,3 @@ func (p *Process) getKProcWithContext(ctx context.Context) (*KinfoProc, error) {
}
return &k, nil
}
func NewProcess(pid int32) (*Process, error) {
p := &Process{Pid: pid}
return p, nil
}

View file

@ -64,22 +64,13 @@ func (m MemoryMapsStat) String() string {
return string(s)
}
// NewProcess creates a new Process instance, it only stores the pid and
// checks that the process exists. Other method on Process can be used
// to get more information about the process. An error will be returned
// if the process does not exist.
func NewProcess(pid int32) (*Process, error) {
_, err := os.Stat(common.HostProc(strconv.Itoa(int(pid))))
return &Process{Pid: pid}, err
}
// Ppid returns Parent Process ID of the process.
func (p *Process) Ppid() (int32, error) {
return p.PpidWithContext(context.Background())
}
func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
_, ppid, _, _, _, _, _, err := p.fillFromStat()
_, ppid, _, _, _, _, _, err := p.fillFromStatWithContext(ctx)
if err != nil {
return -1, err
}
@ -93,7 +84,7 @@ func (p *Process) Name() (string, error) {
func (p *Process) NameWithContext(ctx context.Context) (string, error) {
if p.name == "" {
if err := p.fillFromStatus(); err != nil {
if err := p.fillFromStatusWithContext(ctx); err != nil {
return "", err
}
}
@ -103,7 +94,7 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) {
// Tgid returns tgid, a Linux-synonym for user-space Pid
func (p *Process) Tgid() (int32, error) {
if p.tgid == 0 {
if err := p.fillFromStatus(); err != nil {
if err := p.fillFromStatusWithContext(context.Background()); err != nil {
return 0, err
}
}
@ -116,7 +107,7 @@ func (p *Process) Exe() (string, error) {
}
func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
return p.fillFromExe()
return p.fillFromExeWithContext(ctx)
}
// Cmdline returns the command line arguments of the process as a string with
@ -126,7 +117,7 @@ func (p *Process) Cmdline() (string, error) {
}
func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
return p.fillFromCmdline()
return p.fillFromCmdlineWithContext(ctx)
}
// CmdlineSlice returns the command line arguments of the process as a slice with each
@ -136,16 +127,11 @@ func (p *Process) CmdlineSlice() ([]string, error) {
}
func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
return p.fillSliceFromCmdline()
return p.fillSliceFromCmdlineWithContext(ctx)
}
// CreateTime returns created time of the process in milliseconds since the epoch, in UTC.
func (p *Process) CreateTime() (int64, error) {
return p.CreateTimeWithContext(context.Background())
}
func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
_, _, _, createTime, _, _, _, err := p.fillFromStat()
func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
_, _, _, createTime, _, _, _, err := p.fillFromStatWithContext(ctx)
if err != nil {
return 0, err
}
@ -158,7 +144,7 @@ func (p *Process) Cwd() (string, error) {
}
func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
return p.fillFromCwd()
return p.fillFromCwdWithContext(ctx)
}
// Parent returns parent Process of the process.
@ -167,7 +153,7 @@ func (p *Process) Parent() (*Process, error) {
}
func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
err := p.fillFromStatus()
err := p.fillFromStatusWithContext(ctx)
if err != nil {
return nil, err
}
@ -187,7 +173,7 @@ func (p *Process) Status() (string, error) {
}
func (p *Process) StatusWithContext(ctx context.Context) (string, error) {
err := p.fillFromStatus()
err := p.fillFromStatusWithContext(ctx)
if err != nil {
return "", err
}
@ -222,7 +208,7 @@ func (p *Process) Uids() ([]int32, error) {
}
func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
err := p.fillFromStatus()
err := p.fillFromStatusWithContext(ctx)
if err != nil {
return []int32{}, err
}
@ -235,7 +221,7 @@ func (p *Process) Gids() ([]int32, error) {
}
func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
err := p.fillFromStatus()
err := p.fillFromStatusWithContext(ctx)
if err != nil {
return []int32{}, err
}
@ -248,7 +234,7 @@ func (p *Process) Terminal() (string, error) {
}
func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
t, _, _, _, _, _, _, err := p.fillFromStat()
t, _, _, _, _, _, _, err := p.fillFromStatWithContext(ctx)
if err != nil {
return "", err
}
@ -267,7 +253,7 @@ func (p *Process) Nice() (int32, error) {
}
func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
_, _, _, _, _, nice, _, err := p.fillFromStat()
_, _, _, _, _, nice, _, err := p.fillFromStatWithContext(ctx)
if err != nil {
return 0, err
}
@ -300,16 +286,16 @@ func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
}
func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
rlimits, err := p.fillFromLimits()
rlimits, err := p.fillFromLimitsWithContext(ctx)
if !gatherUsed || err != nil {
return rlimits, err
}
_, _, _, _, rtprio, nice, _, err := p.fillFromStat()
_, _, _, _, rtprio, nice, _, err := p.fillFromStatWithContext(ctx)
if err != nil {
return nil, err
}
if err := p.fillFromStatus(); err != nil {
if err := p.fillFromStatusWithContext(ctx); err != nil {
return nil, err
}
@ -360,7 +346,7 @@ func (p *Process) IOCounters() (*IOCountersStat, error) {
}
func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
return p.fillFromIO()
return p.fillFromIOWithContext(ctx)
}
// NumCtxSwitches returns the number of the context switches of the process.
@ -369,7 +355,7 @@ func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
}
func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
err := p.fillFromStatus()
err := p.fillFromStatusWithContext(ctx)
if err != nil {
return nil, err
}
@ -382,7 +368,7 @@ func (p *Process) NumFDs() (int32, error) {
}
func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
_, fnames, err := p.fillFromfdList()
_, fnames, err := p.fillFromfdListWithContext(ctx)
return int32(len(fnames)), err
}
@ -392,7 +378,7 @@ func (p *Process) NumThreads() (int32, error) {
}
func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
err := p.fillFromStatus()
err := p.fillFromStatusWithContext(ctx)
if err != nil {
return 0, err
}
@ -413,7 +399,7 @@ func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesS
}
for _, tid := range tids {
_, _, cpuTimes, _, _, _, _, err := p.fillFromTIDStat(tid)
_, _, cpuTimes, _, _, _, _, err := p.fillFromTIDStatWithContext(ctx, tid)
if err != nil {
return nil, err
}
@ -429,7 +415,7 @@ func (p *Process) Times() (*cpu.TimesStat, error) {
}
func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
_, _, cpuTimes, _, _, _, _, err := p.fillFromStat()
_, _, cpuTimes, _, _, _, _, err := p.fillFromStatWithContext(ctx)
if err != nil {
return nil, err
}
@ -453,7 +439,7 @@ func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
}
func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
meminfo, _, err := p.fillFromStatm()
meminfo, _, err := p.fillFromStatmWithContext(ctx)
if err != nil {
return nil, err
}
@ -466,7 +452,7 @@ func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
}
func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
_, memInfoEx, err := p.fillFromStatm()
_, memInfoEx, err := p.fillFromStatmWithContext(ctx)
if err != nil {
return nil, err
}
@ -479,7 +465,7 @@ func (p *Process) PageFaults() (*PageFaultsStat, error) {
}
func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) {
_, _, _, _, _, _, pageFaults, err := p.fillFromStat()
_, _, _, _, _, _, pageFaults, err := p.fillFromStatWithContext(ctx)
if err != nil {
return nil, err
}
@ -518,7 +504,7 @@ func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
}
func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
_, ofs, err := p.fillFromfd()
_, ofs, err := p.fillFromfdWithContext(ctx)
if err != nil {
return nil, err
}
@ -559,16 +545,6 @@ func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]
return net.IOCountersByFile(pernic, filename)
}
// IsRunning returns whether the process is running or not.
// Not implemented yet.
func (p *Process) IsRunning() (bool, error) {
return p.IsRunningWithContext(context.Background())
}
func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
return true, common.ErrNotImplementedError
}
// MemoryMaps get memory maps from /proc/(pid)/smaps
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
return p.MemoryMapsWithContext(context.Background(), grouped)
@ -684,10 +660,6 @@ func limitToInt(val string) (int32, error) {
}
// Get num_fds from /proc/(pid)/limits
func (p *Process) fillFromLimits() ([]RlimitStat, error) {
return p.fillFromLimitsWithContext(context.Background())
}
func (p *Process) fillFromLimitsWithContext(ctx context.Context) ([]RlimitStat, error) {
pid := p.Pid
limitsFile := common.HostProc(strconv.Itoa(int(pid)), "limits")
@ -781,10 +753,6 @@ func (p *Process) fillFromLimitsWithContext(ctx context.Context) ([]RlimitStat,
}
// Get list of /proc/(pid)/fd files
func (p *Process) fillFromfdList() (string, []string, error) {
return p.fillFromfdListWithContext(context.Background())
}
func (p *Process) fillFromfdListWithContext(ctx context.Context) (string, []string, error) {
pid := p.Pid
statPath := common.HostProc(strconv.Itoa(int(pid)), "fd")
@ -798,12 +766,8 @@ func (p *Process) fillFromfdListWithContext(ctx context.Context) (string, []stri
}
// Get num_fds from /proc/(pid)/fd
func (p *Process) fillFromfd() (int32, []*OpenFilesStat, error) {
return p.fillFromfdWithContext(context.Background())
}
func (p *Process) fillFromfdWithContext(ctx context.Context) (int32, []*OpenFilesStat, error) {
statPath, fnames, err := p.fillFromfdList()
statPath, fnames, err := p.fillFromfdListWithContext(ctx)
if err != nil {
return 0, nil, err
}
@ -831,10 +795,6 @@ func (p *Process) fillFromfdWithContext(ctx context.Context) (int32, []*OpenFile
}
// Get cwd from /proc/(pid)/cwd
func (p *Process) fillFromCwd() (string, error) {
return p.fillFromCwdWithContext(context.Background())
}
func (p *Process) fillFromCwdWithContext(ctx context.Context) (string, error) {
pid := p.Pid
cwdPath := common.HostProc(strconv.Itoa(int(pid)), "cwd")
@ -846,10 +806,6 @@ func (p *Process) fillFromCwdWithContext(ctx context.Context) (string, error) {
}
// Get exe from /proc/(pid)/exe
func (p *Process) fillFromExe() (string, error) {
return p.fillFromExeWithContext(context.Background())
}
func (p *Process) fillFromExeWithContext(ctx context.Context) (string, error) {
pid := p.Pid
exePath := common.HostProc(strconv.Itoa(int(pid)), "exe")
@ -861,10 +817,6 @@ func (p *Process) fillFromExeWithContext(ctx context.Context) (string, error) {
}
// Get cmdline from /proc/(pid)/cmdline
func (p *Process) fillFromCmdline() (string, error) {
return p.fillFromCmdlineWithContext(context.Background())
}
func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) {
pid := p.Pid
cmdPath := common.HostProc(strconv.Itoa(int(pid)), "cmdline")
@ -882,10 +834,6 @@ func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error
return strings.Join(ret, " "), nil
}
func (p *Process) fillSliceFromCmdline() ([]string, error) {
return p.fillSliceFromCmdlineWithContext(context.Background())
}
func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) {
pid := p.Pid
cmdPath := common.HostProc(strconv.Itoa(int(pid)), "cmdline")
@ -909,10 +857,6 @@ func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string
}
// Get IO status from /proc/(pid)/io
func (p *Process) fillFromIO() (*IOCountersStat, error) {
return p.fillFromIOWithContext(context.Background())
}
func (p *Process) fillFromIOWithContext(ctx context.Context) (*IOCountersStat, error) {
pid := p.Pid
ioPath := common.HostProc(strconv.Itoa(int(pid)), "io")
@ -952,10 +896,6 @@ func (p *Process) fillFromIOWithContext(ctx context.Context) (*IOCountersStat, e
}
// Get memory info from /proc/(pid)/statm
func (p *Process) fillFromStatm() (*MemoryInfoStat, *MemoryInfoExStat, error) {
return p.fillFromStatmWithContext(context.Background())
}
func (p *Process) fillFromStatmWithContext(ctx context.Context) (*MemoryInfoStat, *MemoryInfoExStat, error) {
pid := p.Pid
memPath := common.HostProc(strconv.Itoa(int(pid)), "statm")
@ -1008,10 +948,6 @@ func (p *Process) fillFromStatmWithContext(ctx context.Context) (*MemoryInfoStat
}
// Get various status from /proc/(pid)/status
func (p *Process) fillFromStatus() error {
return p.fillFromStatusWithContext(context.Background())
}
func (p *Process) fillFromStatusWithContext(ctx context.Context) error {
pid := p.Pid
statPath := common.HostProc(strconv.Itoa(int(pid)), "status")
@ -1181,10 +1117,6 @@ func (p *Process) fillFromStatusWithContext(ctx context.Context) error {
return nil
}
func (p *Process) fillFromTIDStat(tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) {
return p.fillFromTIDStatWithContext(context.Background(), tid)
}
func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) {
pid := p.Pid
var statPath string
@ -1281,20 +1213,11 @@ func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (ui
return terminal, int32(ppid), cpuTimes, createTime, uint32(rtpriority), nice, faults, nil
}
func (p *Process) fillFromStat() (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) {
return p.fillFromStatWithContext(context.Background())
}
func (p *Process) fillFromStatWithContext(ctx context.Context) (uint64, int32, *cpu.TimesStat, int64, uint32, int32, *PageFaultsStat, error) {
return p.fillFromTIDStat(-1)
return p.fillFromTIDStatWithContext(ctx, -1)
}
// Pids returns a slice of process ID list which are running now.
func Pids() ([]int32, error) {
return PidsWithContext(context.Background())
}
func PidsWithContext(ctx context.Context) ([]int32, error) {
func pidsWithContext(ctx context.Context) ([]int32, error) {
return readPidsFromDir(common.HostProc())
}

View file

@ -26,11 +26,7 @@ type MemoryInfoExStat struct {
type MemoryMapsStat struct {
}
func Pids() ([]int32, error) {
return PidsWithContext(context.Background())
}
func PidsWithContext(ctx context.Context) ([]int32, error) {
func pidsWithContext(ctx context.Context) ([]int32, error) {
var ret []int32
procs, err := Processes()
if err != nil {
@ -118,11 +114,7 @@ func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) {
return strings.Join(argv, " "), nil
}
func (p *Process) CreateTime() (int64, error) {
return p.CreateTimeWithContext(context.Background())
}
func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
return 0, common.ErrNotImplementedError
}
func (p *Process) Cwd() (string, error) {
@ -419,13 +411,6 @@ func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]
return nil, common.ErrNotImplementedError
}
func (p *Process) IsRunning() (bool, error) {
return p.IsRunningWithContext(context.Background())
}
func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
return true, common.ErrNotImplementedError
}
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
return p.MemoryMapsWithContext(context.Background(), grouped)
}
@ -496,12 +481,6 @@ func (p *Process) getKProcWithContext(ctx context.Context) (*KinfoProc, error) {
return &k, nil
}
func NewProcess(pid int32) (*Process, error) {
p := &Process{Pid: pid}
return p, nil
}
func CallKernProcSyscall(op int32, arg int32) ([]byte, uint64, error) {
return CallKernProcSyscallWithContext(context.Background(), op, arg)
}

View file

@ -150,11 +150,7 @@ func init() {
0)
}
func Pids() ([]int32, error) {
return PidsWithContext(context.Background())
}
func PidsWithContext(ctx context.Context) ([]int32, error) {
func pidsWithContext(ctx context.Context) ([]int32, error) {
// inspired by https://gist.github.com/henkman/3083408
// and https://github.com/giampaolo/psutil/blob/1c3a15f637521ba5c0031283da39c733fda53e4c/psutil/arch/windows/process_info.c#L315-L329
var ret []int32
@ -324,11 +320,7 @@ func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error)
return strings.Split(cmdline, " "), nil
}
func (p *Process) CreateTime() (int64, error) {
return p.CreateTimeWithContext(context.Background())
}
func (p *Process) CreateTimeWithContext(ctx context.Context) (int64, error) {
func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
ru, err := getRusage(p.Pid)
if err != nil {
return 0, fmt.Errorf("could not get CreationDate: %s", err)
@ -520,11 +512,11 @@ func (p *Process) NumThreads() (int32, error) {
}
func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
dst, err := GetWin32ProcWithContext(ctx, p.Pid)
_, ret, _, err := getFromSnapProcess(p.Pid)
if err != nil {
return 0, fmt.Errorf("could not get ThreadCount: %s", err)
return 0, err
}
return int32(dst[0].ThreadCount), nil
return ret, nil
}
func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
return p.ThreadsWithContext(context.Background())
@ -644,7 +636,7 @@ func (p *Process) Connections() ([]net.ConnectionStat, error) {
}
func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
return nil, common.ErrNotImplementedError
return net.ConnectionsPidWithContext(ctx, "all", p.Pid)
}
func (p *Process) ConnectionsMax(max int) ([]net.ConnectionStat, error) {
@ -663,14 +655,6 @@ func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]
return nil, common.ErrNotImplementedError
}
func (p *Process) IsRunning() (bool, error) {
return p.IsRunningWithContext(context.Background())
}
func (p *Process) IsRunningWithContext(ctx context.Context) (bool, error) {
return true, common.ErrNotImplementedError
}
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
return p.MemoryMapsWithContext(context.Background(), grouped)
}
@ -680,12 +664,6 @@ func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]M
return &ret, common.ErrNotImplementedError
}
func NewProcess(pid int32) (*Process, error) {
p := &Process{Pid: pid}
return p, nil
}
func (p *Process) SendSignal(sig windows.Signal) error {
return p.SendSignalWithContext(context.Background(), sig)
}

2
vendor/modules.txt vendored
View file

@ -617,7 +617,7 @@ github.com/ryanuber/go-glob
github.com/samuel/go-zookeeper/zk
# github.com/satori/go.uuid v1.2.0
github.com/satori/go.uuid
# github.com/shirou/gopsutil v0.0.0-20190731134726-d80c43f9c984
# github.com/shirou/gopsutil v2.19.9+incompatible
github.com/shirou/gopsutil/cpu
github.com/shirou/gopsutil/disk
github.com/shirou/gopsutil/host