diff --git a/command/command_windows.go b/command/command_windows.go index 30730171a..0748d9f8e 100644 --- a/command/command_windows.go +++ b/command/command_windows.go @@ -27,7 +27,7 @@ func metricsGenerators(conf *config.Config) []metrics.Generator { var err error generators := []metrics.Generator{} - if g, err = metricsWindows.NewLoadavg5Generator(); err == nil { + if g, err = metricsWindows.NewProcessorQueueLengthGenerator(); err == nil { generators = append(generators, g) } if g, err = metricsWindows.NewCPUUsageGenerator(); err == nil { diff --git a/metrics/windows/cpuusage.go b/metrics/windows/cpuusage.go index 213ca78c5..1d5216231 100644 --- a/metrics/windows/cpuusage.go +++ b/metrics/windows/cpuusage.go @@ -3,32 +3,80 @@ package windows import ( + "syscall" + "unsafe" + "github.com/mackerelio/mackerel-agent/logging" "github.com/mackerelio/mackerel-agent/metrics" - "github.com/mackerelio/mackerel-agent/util" + "github.com/mackerelio/mackerel-agent/util/windows" ) -// CPUUsageGenerator XXX +// CPUUsageGenerator is struct of windows api type CPUUsageGenerator struct { + query syscall.Handle + counters []*windows.CounterInfo } -var cpuUsageLogger = logging.GetLogger("metrics.cpuusage") +var cpuUsageLogger = logging.GetLogger("cpu.user.percentage") -// NewCPUUsageGenerator XXX +// NewCPUUsageGenerator is set up windows api func NewCPUUsageGenerator() (*CPUUsageGenerator, error) { - return &CPUUsageGenerator{}, nil + g := &CPUUsageGenerator{0, nil} + + var err error + g.query, err = windows.CreateQuery() + if err != nil { + cpuUsageLogger.Criticalf(err.Error()) + return nil, err + } + var counter *windows.CounterInfo + + counter, err = windows.CreateCounter(g.query, "cpu.user.percentage", `\Processor(_Total)\% User Time`) + if err != nil { + cpuUsageLogger.Criticalf(err.Error()) + return nil, err + } + g.counters = append(g.counters, counter) + + counter, err = windows.CreateCounter(g.query, "cpu.system.percentage", `\Processor(_Total)\% Privileged Time`) + if err != nil { + cpuUsageLogger.Criticalf(err.Error()) + return nil, err + } + g.counters = append(g.counters, counter) + + counter, err = windows.CreateCounter(g.query, "cpu.idle.percentage", `\Processor(_Total)\% Idle Time`) + if err != nil { + cpuUsageLogger.Criticalf(err.Error()) + return nil, err + } + g.counters = append(g.counters, counter) + return g, nil } // Generate XXX func (g *CPUUsageGenerator) Generate() (metrics.Values, error) { - cpuusage := make(map[string]float64) - cpuusageValue, err := util.GetWmicToFloat("cpu", "loadpercentage") - if err != nil { - cpuusageValue = 0 + r, _, err := windows.PdhCollectQueryData.Call(uintptr(g.query)) + if r != 0 && err != nil { + if r == windows.PDH_NO_DATA { + cpuUsageLogger.Infof("this metric has not data. ") + return nil, err + } + return nil, err } - cpuusage["cpu.user.percentage"] = cpuusageValue - cpuusage["cpu.idle.percentage"] = 100 - cpuusageValue - cpuUsageLogger.Debugf("cpuusage : %s", cpuusage) - return metrics.Values(cpuusage), nil + + results := make(map[string]float64) + for _, v := range g.counters { + var fmtValue windows.PDH_FMT_COUNTERVALUE_DOUBLE + r, _, err := windows.PdhGetFormattedCounterValue.Call(uintptr(v.Counter), windows.PDH_FMT_DOUBLE, uintptr(0), uintptr(unsafe.Pointer(&fmtValue))) + if r != 0 && r != windows.PDH_INVALID_DATA { + return nil, err + } + results[v.PostName] = fmtValue.DoubleValue + } + + cpuUsageLogger.Debugf("cpuusage: %q", results) + + return results, nil } diff --git a/metrics/windows/cpuusage_test.go b/metrics/windows/cpuusage_test.go index fa59b8e37..bac1e9c0e 100644 --- a/metrics/windows/cpuusage_test.go +++ b/metrics/windows/cpuusage_test.go @@ -8,11 +8,18 @@ import "testing" var cpuUsageMetricNames = []string{ "cpu.user.percentage", "cpu.idle.percentage", + "cpu.system.percentage", } func TestCPUUsageGenerate(t *testing.T) { - g := &CPUUsageGenerator{} - values, _ := g.Generate() + g, err := NewCPUUsageGenerator() + if err != nil { + t.Errorf("should not raise error: %v", err) + } + values, err := g.Generate() + if err != nil { + t.Errorf("should not raise error: %v", err) + } for _, metricName := range cpuUsageMetricNames { value, ok := values[metricName] diff --git a/metrics/windows/memory.go b/metrics/windows/memory.go index d399b93a5..af8561dbc 100644 --- a/metrics/windows/memory.go +++ b/metrics/windows/memory.go @@ -36,8 +36,8 @@ func (g *MemoryGenerator) Generate() (metrics.Values, error) { ret["memory.free"] = free ret["memory.total"] = total ret["memory.used"] = total - free - ret["memory.swap_total"] = float64(memoryStatusEx.TotalVirtual) / 1024 - ret["memory.swap_free"] = float64(memoryStatusEx.AvailVirtual) / 1024 + ret["memory.pagefile_total"] = float64(memoryStatusEx.TotalPageFile) / 1024 + ret["memory.pagefile_free"] = float64(memoryStatusEx.AvailPageFile) / 1024 memoryLogger.Debugf("memory : %s", ret) return metrics.Values(ret), nil diff --git a/metrics/windows/memory_test.go b/metrics/windows/memory_test.go index 06776781c..23c77961e 100644 --- a/metrics/windows/memory_test.go +++ b/metrics/windows/memory_test.go @@ -16,8 +16,8 @@ func TestMemoryGenerator(t *testing.T) { for _, name := range []string{ "total", "free", - "swap_total", - "swap_free", + "pagefile_total", + "pagefile_free", "used", } { if _, ok := values["memory."+name]; !ok { diff --git a/metrics/windows/loadavg5.go b/metrics/windows/processor_queue_length.go similarity index 57% rename from metrics/windows/loadavg5.go rename to metrics/windows/processor_queue_length.go index 30ae99d97..052be9398 100644 --- a/metrics/windows/loadavg5.go +++ b/metrics/windows/processor_queue_length.go @@ -11,28 +11,28 @@ import ( "github.com/mackerelio/mackerel-agent/util/windows" ) -// Loadavg5Generator XXX -type Loadavg5Generator struct { +// ProcessorQueueLengthGenerator is struct of windows api +type ProcessorQueueLengthGenerator struct { query syscall.Handle counters []*windows.CounterInfo } -var loadavg5Logger = logging.GetLogger("metrics.loadavg5") +var processorQueueLengthLogger = logging.GetLogger("metrics.processor_queue_length") -// NewLoadavg5Generator XXX -func NewLoadavg5Generator() (*Loadavg5Generator, error) { - g := &Loadavg5Generator{0, nil} +// NewProcessorQueueLengthGenerator is set up windows api +func NewProcessorQueueLengthGenerator() (*ProcessorQueueLengthGenerator, error) { + g := &ProcessorQueueLengthGenerator{0, nil} var err error g.query, err = windows.CreateQuery() if err != nil { - loadavg5Logger.Criticalf(err.Error()) + processorQueueLengthLogger.Criticalf(err.Error()) return nil, err } - counter, err := windows.CreateCounter(g.query, "loadavg5", `\System\Processor Queue Length`) + counter, err := windows.CreateCounter(g.query, "processor_queue_length", `\System\Processor Queue Length`) if err != nil { - loadavg5Logger.Criticalf(err.Error()) + processorQueueLengthLogger.Criticalf(err.Error()) return nil, err } g.counters = append(g.counters, counter) @@ -40,12 +40,12 @@ func NewLoadavg5Generator() (*Loadavg5Generator, error) { } // Generate XXX -func (g *Loadavg5Generator) Generate() (metrics.Values, error) { +func (g *ProcessorQueueLengthGenerator) Generate() (metrics.Values, error) { r, _, err := windows.PdhCollectQueryData.Call(uintptr(g.query)) if r != 0 && err != nil { if r == windows.PDH_NO_DATA { - loadavg5Logger.Infof("this metric has not data. ") + processorQueueLengthLogger.Infof("this metric has not data. ") return nil, err } return nil, err @@ -61,7 +61,7 @@ func (g *Loadavg5Generator) Generate() (metrics.Values, error) { results[v.PostName] = fmtValue.DoubleValue } - loadavg5Logger.Debugf("loadavg5: %q", results) + processorQueueLengthLogger.Debugf("processor_queue_length: %q", results) return results, nil } diff --git a/metrics/windows/loadavg5_test.go b/metrics/windows/processor_queue_length_test.go similarity index 59% rename from metrics/windows/loadavg5_test.go rename to metrics/windows/processor_queue_length_test.go index 63efab2ef..6e019d243 100644 --- a/metrics/windows/loadavg5_test.go +++ b/metrics/windows/processor_queue_length_test.go @@ -6,8 +6,8 @@ import ( "testing" ) -func TestLoadavg5Generator(t *testing.T) { - g, _ := NewLoadavg5Generator() +func TestProcessorQueueLengthGenerator(t *testing.T) { + g, _ := NewProcessorQueueLengthGenerator() _, err := g.Generate() if err != nil {