use StackExchange/wmi instead of invoking wmic process.
Note: This may not work on some old Windows XP.
This commit is contained in:
parent
b55d373cee
commit
64357f04e7
|
@ -3,9 +3,6 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
@ -75,37 +72,6 @@ func BytePtrToString(p *uint8) string {
|
|||
return string(a[:i])
|
||||
}
|
||||
|
||||
// exec wmic and return lines splited by newline
|
||||
func GetWmic(target string, query ...string) ([][]string, error) {
|
||||
cmd := []string{target}
|
||||
cmd = append(cmd, query...)
|
||||
cmd = append(cmd, "/format:csv")
|
||||
out, err := exec.Command("wmic", cmd...).Output()
|
||||
if err != nil {
|
||||
return [][]string{}, err
|
||||
}
|
||||
lines := strings.Split(string(out), "\r\r\n")
|
||||
if len(lines) <= 2 {
|
||||
return [][]string{}, fmt.Errorf("wmic result malformed: [%q]", lines)
|
||||
}
|
||||
var ret [][]string
|
||||
for _, l := range lines[2:] { // skip first two lines
|
||||
var lr []string
|
||||
for _, r := range strings.Split(l, ",") {
|
||||
if r == "" {
|
||||
continue
|
||||
}
|
||||
lr = append(lr, strings.TrimSpace(r))
|
||||
}
|
||||
if len(lr) != 0 {
|
||||
ret = append(ret, lr)
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
|
||||
}
|
||||
|
||||
// CounterInfo
|
||||
// copied from https://github.com/mackerelio/mackerel-agent/
|
||||
type CounterInfo struct {
|
||||
|
|
|
@ -3,14 +3,28 @@
|
|||
package cpu
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/StackExchange/wmi"
|
||||
|
||||
common "github.com/shirou/gopsutil/common"
|
||||
)
|
||||
|
||||
type Win32_Processor struct {
|
||||
LoadPercentage uint16
|
||||
L2CacheSize uint32
|
||||
Family uint16
|
||||
Manufacturer string
|
||||
Name string
|
||||
NumberOfLogicalProcessors uint32
|
||||
ProcessorId string
|
||||
Stepping *string
|
||||
MaxClockSpeed uint32
|
||||
}
|
||||
|
||||
// TODO: Get percpu
|
||||
func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
|
||||
var ret []CPUTimesStat
|
||||
|
@ -43,59 +57,41 @@ func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
|
|||
|
||||
func CPUInfo() ([]CPUInfoStat, error) {
|
||||
var ret []CPUInfoStat
|
||||
lines, err := common.GetWmic("cpu", "get", "Family,L2CacheSize,Manufacturer,Name,NumberOfLogicalProcessors,ProcessorId,Stepping")
|
||||
var dst []Win32_Processor
|
||||
q := wmi.CreateQuery(&dst, "")
|
||||
err := wmi.Query(q, &dst)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
for i, t := range lines {
|
||||
cache, err := strconv.Atoi(t[2])
|
||||
if err != nil {
|
||||
cache = 0
|
||||
}
|
||||
cores, err := strconv.Atoi(t[5])
|
||||
if err != nil {
|
||||
cores = 0
|
||||
}
|
||||
stepping := 0
|
||||
if len(t) > 7 {
|
||||
stepping, err = strconv.Atoi(t[6])
|
||||
if err != nil {
|
||||
stepping = 0
|
||||
}
|
||||
}
|
||||
for i, l := range dst {
|
||||
cpu := CPUInfoStat{
|
||||
CPU: int32(i),
|
||||
Family: t[1],
|
||||
CacheSize: int32(cache),
|
||||
VendorID: t[3],
|
||||
ModelName: t[4],
|
||||
Cores: int32(cores),
|
||||
PhysicalID: t[6],
|
||||
Stepping: int32(stepping),
|
||||
Family: fmt.Sprintf("%d", l.Family),
|
||||
CacheSize: int32(l.L2CacheSize),
|
||||
VendorID: l.Manufacturer,
|
||||
ModelName: l.Name,
|
||||
Cores: int32(l.NumberOfLogicalProcessors),
|
||||
PhysicalID: l.ProcessorId,
|
||||
Mhz: float64(l.MaxClockSpeed),
|
||||
Flags: []string{},
|
||||
}
|
||||
ret = append(ret, cpu)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func CPUPercent(interval time.Duration, percpu bool) ([]float64, error) {
|
||||
ret := []float64{}
|
||||
|
||||
lines, err := common.GetWmic("cpu", "get", "loadpercentage")
|
||||
var ret []float64
|
||||
var dst []Win32_Processor
|
||||
q := wmi.CreateQuery(&dst, "")
|
||||
err := wmi.Query(q, &dst)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
for _, l := range lines {
|
||||
if len(l) < 2 {
|
||||
continue
|
||||
}
|
||||
p, err := strconv.Atoi(l[1])
|
||||
if err != nil {
|
||||
p = 0
|
||||
}
|
||||
// but windows can only get one percent.
|
||||
ret = append(ret, float64(p)/100.0)
|
||||
for _, l := range dst {
|
||||
// use range but windows can only get one percent.
|
||||
ret = append(ret, float64(l.LoadPercentage)/100.0)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
package host
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/StackExchange/wmi"
|
||||
|
||||
common "github.com/shirou/gopsutil/common"
|
||||
process "github.com/shirou/gopsutil/process"
|
||||
)
|
||||
|
@ -16,6 +16,10 @@ var (
|
|||
procGetSystemTimeAsFileTime = common.Modkernel32.NewProc("GetSystemTimeAsFileTime")
|
||||
)
|
||||
|
||||
type Win32_OperatingSystem struct {
|
||||
LastBootUpTime time.Time
|
||||
}
|
||||
|
||||
func HostInfo() (*HostInfoStat, error) {
|
||||
ret := &HostInfoStat{}
|
||||
hostname, err := os.Hostname()
|
||||
|
@ -40,19 +44,15 @@ func HostInfo() (*HostInfoStat, error) {
|
|||
}
|
||||
|
||||
func BootTime() (uint64, error) {
|
||||
lines, err := common.GetWmic("os", "get", "LastBootUpTime")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(lines) == 0 || len(lines[0]) != 2 {
|
||||
return 0, fmt.Errorf("could not get LastBootUpTime")
|
||||
}
|
||||
format := "20060102150405"
|
||||
t, err := time.Parse(format, strings.Split(lines[0][1], ".")[0])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
now := time.Now()
|
||||
|
||||
var dst []Win32_OperatingSystem
|
||||
q := wmi.CreateQuery(&dst, "")
|
||||
err := wmi.Query(q, &dst)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
t := dst[0].LastBootUpTime.Local()
|
||||
return uint64(now.Sub(t).Seconds()), nil
|
||||
}
|
||||
|
||||
|
|
|
@ -5,10 +5,11 @@ package process
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/StackExchange/wmi"
|
||||
"github.com/shirou/w32"
|
||||
|
||||
common "github.com/shirou/gopsutil/common"
|
||||
|
@ -43,6 +44,48 @@ type MemoryInfoExStat struct {
|
|||
type MemoryMapsStat struct {
|
||||
}
|
||||
|
||||
type Win32_Process struct {
|
||||
Name string
|
||||
ExecutablePath *string
|
||||
CommandLine *string
|
||||
Priority uint32
|
||||
CreationDate *time.Time
|
||||
ProcessId uint32
|
||||
ThreadCount uint32
|
||||
|
||||
/*
|
||||
CSCreationClassName string
|
||||
CSName string
|
||||
Caption *string
|
||||
CreationClassName string
|
||||
Description *string
|
||||
ExecutionState *uint16
|
||||
HandleCount uint32
|
||||
KernelModeTime uint64
|
||||
MaximumWorkingSetSize *uint32
|
||||
MinimumWorkingSetSize *uint32
|
||||
OSCreationClassName string
|
||||
OSName string
|
||||
OtherOperationCount uint64
|
||||
OtherTransferCount uint64
|
||||
PageFaults uint32
|
||||
PageFileUsage uint32
|
||||
ParentProcessId uint32
|
||||
PeakPageFileUsage uint32
|
||||
PeakVirtualSize uint64
|
||||
PeakWorkingSetSize uint32
|
||||
PrivatePageCount uint64
|
||||
ReadOperationCount uint64
|
||||
ReadTransferCount uint64
|
||||
Status *string
|
||||
TerminationDate *time.Time
|
||||
UserModeTime uint64
|
||||
WorkingSetSize uint64
|
||||
WriteOperationCount uint64
|
||||
WriteTransferCount uint64
|
||||
*/
|
||||
}
|
||||
|
||||
func Pids() ([]int32, error) {
|
||||
var ret []int32
|
||||
|
||||
|
@ -66,38 +109,43 @@ func (p *Process) Ppid() (int32, error) {
|
|||
return ret, nil
|
||||
}
|
||||
func (p *Process) Name() (string, error) {
|
||||
query := fmt.Sprintf("ProcessId = %d", p.Pid)
|
||||
lines, err := common.GetWmic("process", "where", query, "get", "Name")
|
||||
var dst []Win32_Process
|
||||
query := fmt.Sprintf("WHERE ProcessId = %d", p.Pid)
|
||||
q := wmi.CreateQuery(&dst, query)
|
||||
err := wmi.Query(q, &dst)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(lines) == 0 {
|
||||
if len(dst) != 1 {
|
||||
return "", fmt.Errorf("could not get Name")
|
||||
}
|
||||
return lines[0][1], nil
|
||||
return dst[0].Name, nil
|
||||
}
|
||||
func (p *Process) Exe() (string, error) {
|
||||
query := fmt.Sprintf("ProcessId = %d", p.Pid)
|
||||
lines, err := common.GetWmic("process", "where", query, "get", "ExecutablePath")
|
||||
var dst []Win32_Process
|
||||
query := fmt.Sprintf("WHERE ProcessId = %d", p.Pid)
|
||||
q := wmi.CreateQuery(&dst, query)
|
||||
err := wmi.Query(q, &dst)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(lines) == 0 {
|
||||
if len(dst) != 1 {
|
||||
return "", fmt.Errorf("could not get ExecutablePath")
|
||||
}
|
||||
return lines[0][1], nil
|
||||
return *dst[0].ExecutablePath, nil
|
||||
}
|
||||
func (p *Process) Cmdline() (string, error) {
|
||||
query := fmt.Sprintf("ProcessId = %d", p.Pid)
|
||||
lines, err := common.GetWmic("process", "where", query, "get", "CommandLine")
|
||||
var dst []Win32_Process
|
||||
query := fmt.Sprintf("WHERE ProcessId = %d", p.Pid)
|
||||
q := wmi.CreateQuery(&dst, query)
|
||||
err := wmi.Query(q, &dst)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(lines) == 0 {
|
||||
return "", fmt.Errorf("could not get command line")
|
||||
if len(dst) != 1 {
|
||||
return "", fmt.Errorf("could not get CommandLine")
|
||||
}
|
||||
|
||||
return lines[0][1], nil
|
||||
return *dst[0].CommandLine, nil
|
||||
}
|
||||
func (p *Process) Cwd() (string, error) {
|
||||
return "", common.NotImplementedError
|
||||
|
@ -126,20 +174,17 @@ func (p *Process) Terminal() (string, error) {
|
|||
|
||||
// Nice returnes priority in Windows
|
||||
func (p *Process) Nice() (int32, error) {
|
||||
query := fmt.Sprintf("ProcessId = %d", p.Pid)
|
||||
lines, err := common.GetWmic("process", "where", query, "get", "Priority")
|
||||
var dst []Win32_Process
|
||||
query := fmt.Sprintf("WHERE ProcessId = %d", p.Pid)
|
||||
q := wmi.CreateQuery(&dst, query)
|
||||
err := wmi.Query(q, &dst)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(lines) == 0 {
|
||||
return 0, fmt.Errorf("could not get command line")
|
||||
if len(dst) != 1 {
|
||||
return 0, fmt.Errorf("could not get Priority")
|
||||
}
|
||||
priority, err := strconv.Atoi(lines[0][1])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int32(priority), nil
|
||||
return int32(dst[0].Priority), nil
|
||||
}
|
||||
func (p *Process) IOnice() (int32, error) {
|
||||
return 0, common.NotImplementedError
|
||||
|
@ -159,20 +204,17 @@ func (p *Process) NumFDs() (int32, error) {
|
|||
return 0, common.NotImplementedError
|
||||
}
|
||||
func (p *Process) NumThreads() (int32, error) {
|
||||
query := fmt.Sprintf("ProcessId = %d", p.Pid)
|
||||
lines, err := common.GetWmic("process", "where", query, "get", "ThreadCount")
|
||||
var dst []Win32_Process
|
||||
query := fmt.Sprintf("WHERE ProcessId = %d", p.Pid)
|
||||
q := wmi.CreateQuery(&dst, query)
|
||||
err := wmi.Query(q, &dst)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(lines) == 0 {
|
||||
return 0, fmt.Errorf("could not get command line")
|
||||
if len(dst) != 1 {
|
||||
return 0, fmt.Errorf("could not get ThreadCount")
|
||||
}
|
||||
count, err := strconv.Atoi(lines[0][1])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int32(count), nil
|
||||
return int32(dst[0].ThreadCount), nil
|
||||
}
|
||||
func (p *Process) Threads() (map[string]string, error) {
|
||||
ret := make(map[string]string, 0)
|
||||
|
@ -266,17 +308,19 @@ func (p *Process) getFromSnapProcess(pid int32) (int32, int32, string, error) {
|
|||
|
||||
// Get processes
|
||||
func processes() ([]*Process, error) {
|
||||
lines, err := common.GetWmic("process", "get", "processid")
|
||||
|
||||
var dst []Win32_Process
|
||||
q := wmi.CreateQuery(&dst, "")
|
||||
err := wmi.Query(q, &dst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return []*Process{}, err
|
||||
}
|
||||
var results []*Process
|
||||
for _, l := range lines {
|
||||
pid, err := strconv.Atoi(l[1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
p, err := NewProcess(int32(pid))
|
||||
if len(dst) == 0 {
|
||||
return []*Process{}, fmt.Errorf("could not get Process")
|
||||
}
|
||||
results := make([]*Process, 0, len(dst))
|
||||
for _, proc := range dst {
|
||||
p, err := NewProcess(int32(proc.ProcessId))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue