diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 5f74312404b..12a7cc44ad7 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -104,6 +104,7 @@ https://github.com/elastic/beats/compare/v5.1.1...master[Check the HEAD diff] - The Docker, Kafka, and Prometheus modules are now Beta, instead of experimental. {pull}3525[3525] - The HAProxy module is now GA, instead of experimental. {pull}3525[3525] - Add the ability to collect the environment variables from system processes. {pull}3337[3337] +- Add experimental metricset `perfmon` to Windows module. {pull}3758[3758] - Add memcached module with stats metricset. {pull}3693[3693] *Packetbeat* diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index eb34633eff0..119925546a6 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -32,6 +32,7 @@ grouped in the following categories: * <> * <> * <> +* <> * <> -- @@ -7518,6 +7519,52 @@ type: keyword Name of the user running the process. +[[exported-fields-windows]] +== Windows Fields + +[]beta Module for Windows + + + +[float] +== windows Fields + + + + + +[float] +== counters Fields + +Grouping of different counters + + + +[float] +=== windows.perfmon.counters.group + +type: string + +Name of the group. For example `processor` or `disk` + + + +[float] +=== windows.perfmon.counters.collectors.alias + +type: string + +Short form for the query + + +[float] +=== windows.perfmon.counters.collectors.query + +type: string + +The query. For example `\\Processor Information(_Total)\\% Processor Performance`. Backslashes have to be escaped. + + [[exported-fields-zookeeper]] == ZooKeeper Fields diff --git a/metricbeat/docs/modules/windows.asciidoc b/metricbeat/docs/modules/windows.asciidoc new file mode 100644 index 00000000000..4d31c2d77d6 --- /dev/null +++ b/metricbeat/docs/modules/windows.asciidoc @@ -0,0 +1,34 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-module-windows]] +== windows Module + +This is the windows Module. + + +[float] +=== Example Configuration + +The Windows module supports the standard configuration options that are described +in <>. Here is an example configuration: + +[source,yaml] +---- +metricbeat.modules: +#- module: windows +# metricsets: ["perfmon"] +# enabled: true +# period: 10s +# perfmon.counters:---- + +[float] +=== Metricsets + +The following metricsets are available: + +* <> + +include::windows/perfmon.asciidoc[] + diff --git a/metricbeat/docs/modules/windows/perfmon.asciidoc b/metricbeat/docs/modules/windows/perfmon.asciidoc new file mode 100644 index 00000000000..78270517922 --- /dev/null +++ b/metricbeat/docs/modules/windows/perfmon.asciidoc @@ -0,0 +1,19 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[metricbeat-metricset-windows-perfmon]] +include::../../../module/windows/perfmon/_meta/docs.asciidoc[] + + +==== Fields + +For a description of each field in the metricset, see the +<> section. + +Here is an example document generated by this metricset: + +[source,json] +---- +include::../../../module/windows/perfmon/_meta/data.json[] +---- diff --git a/metricbeat/docs/modules_list.asciidoc b/metricbeat/docs/modules_list.asciidoc index ab2aa4746b3..fa3cc0b0186 100644 --- a/metricbeat/docs/modules_list.asciidoc +++ b/metricbeat/docs/modules_list.asciidoc @@ -19,6 +19,7 @@ This file is generated! See scripts/docs_collector.py * <> * <> * <> + * <> * <> @@ -41,4 +42,5 @@ include::modules/postgresql.asciidoc[] include::modules/prometheus.asciidoc[] include::modules/redis.asciidoc[] include::modules/system.asciidoc[] +include::modules/windows.asciidoc[] include::modules/zookeeper.asciidoc[] diff --git a/metricbeat/include/list.go b/metricbeat/include/list.go index 9e85de587bd..38558e0337c 100644 --- a/metricbeat/include/list.go +++ b/metricbeat/include/list.go @@ -71,6 +71,8 @@ import ( _ "github.com/elastic/beats/metricbeat/module/system/network" _ "github.com/elastic/beats/metricbeat/module/system/process" _ "github.com/elastic/beats/metricbeat/module/system/socket" + _ "github.com/elastic/beats/metricbeat/module/windows" + _ "github.com/elastic/beats/metricbeat/module/windows/perfmon" _ "github.com/elastic/beats/metricbeat/module/zookeeper" _ "github.com/elastic/beats/metricbeat/module/zookeeper/mntr" ) diff --git a/metricbeat/metricbeat.full.yml b/metricbeat/metricbeat.full.yml index 9bf42e8dd28..629f0109d31 100644 --- a/metricbeat/metricbeat.full.yml +++ b/metricbeat/metricbeat.full.yml @@ -315,6 +315,12 @@ metricbeat.modules: # Redis AUTH password. Empty by default. #password: foobared +#------------------------------- Windows Module ------------------------------ +#- module: windows +# metricsets: ["perfmon"] +# enabled: true +# period: 10s +# perfmon.counters: #------------------------------ ZooKeeper Module ----------------------------- #- module: zookeeper #metricsets: ["mntr"] diff --git a/metricbeat/metricbeat.yml b/metricbeat/metricbeat.yml index 657ea61828d..93a86d97a95 100644 --- a/metricbeat/metricbeat.yml +++ b/metricbeat/metricbeat.yml @@ -46,6 +46,12 @@ metricbeat.modules: period: 10s processes: ['.*'] +#------------------------------- Windows Module ------------------------------ +#- module: windows +# metricsets: ["perfmon"] +# enabled: true +# period: 10s +# perfmon.counters: #================================ General ===================================== diff --git a/metricbeat/module/windows/_meta/config.yml b/metricbeat/module/windows/_meta/config.yml new file mode 100644 index 00000000000..65cd605f602 --- /dev/null +++ b/metricbeat/module/windows/_meta/config.yml @@ -0,0 +1,5 @@ +#- module: windows +# metricsets: ["perfmon"] +# enabled: true +# period: 10s +# perfmon.counters: \ No newline at end of file diff --git a/metricbeat/module/windows/_meta/docs.asciidoc b/metricbeat/module/windows/_meta/docs.asciidoc new file mode 100644 index 00000000000..af84197d6eb --- /dev/null +++ b/metricbeat/module/windows/_meta/docs.asciidoc @@ -0,0 +1,3 @@ +== windows Module + +This is the windows Module. diff --git a/metricbeat/module/windows/_meta/fields.yml b/metricbeat/module/windows/_meta/fields.yml new file mode 100644 index 00000000000..28f4daff198 --- /dev/null +++ b/metricbeat/module/windows/_meta/fields.yml @@ -0,0 +1,10 @@ +- key: windows + title: "Windows" + description: > + []beta + Module for Windows + fields: + - name: windows + type: group + description: > + fields: diff --git a/metricbeat/module/windows/doc.go b/metricbeat/module/windows/doc.go new file mode 100644 index 00000000000..f347c9171c8 --- /dev/null +++ b/metricbeat/module/windows/doc.go @@ -0,0 +1,4 @@ +/* +Package windows is a Metricbeat module that contains MetricSets. +*/ +package windows diff --git a/metricbeat/module/windows/perfmon/_meta/data.json b/metricbeat/module/windows/perfmon/_meta/data.json new file mode 100644 index 00000000000..2ba8f8e80e5 --- /dev/null +++ b/metricbeat/module/windows/perfmon/_meta/data.json @@ -0,0 +1,19 @@ +{ + "@timestamp":"2016-05-23T08:05:34.853Z", + "beat":{ + "hostname":"beathost", + "name":"beathost" + }, + "metricset":{ + "host":"localhost", + "module":"mysql", + "name":"status", + "rtt":44269 + }, + "windows":{ + "perfmon":{ + "example": "perfmon" + } + }, + "type":"metricsets" +} diff --git a/metricbeat/module/windows/perfmon/_meta/docs.asciidoc b/metricbeat/module/windows/perfmon/_meta/docs.asciidoc new file mode 100644 index 00000000000..1f1929fc8fb --- /dev/null +++ b/metricbeat/module/windows/perfmon/_meta/docs.asciidoc @@ -0,0 +1,24 @@ +=== windows perfmon MetricSet + +This is the perfmon metricset of the module windows. + +[float] +=== Features and configuration + +Metricset to collect performance counters. +Example configuration: +``` +- module: windows + metricsets: ["perfmon"] + enabled: true + period: 10s + perfmon.counters: + - group: "processor" + collectors: + - alias: "processor_time" + query: '\Processor Information(_Total)\% Processor Time' + - group: "disk" + collectors: + - alias: "bytes_written" + query: '\PhysicalDisk(_Total)\Disk Writes/sec' +``` diff --git a/metricbeat/module/windows/perfmon/_meta/fields.yml b/metricbeat/module/windows/perfmon/_meta/fields.yml new file mode 100644 index 00000000000..26e59b53110 --- /dev/null +++ b/metricbeat/module/windows/perfmon/_meta/fields.yml @@ -0,0 +1,26 @@ +- name: perfmon + type: group + fields: + - name: counters + type: group + description: > + Grouping of different counters + fields: + - name: group + type: string + description: > + Name of the group. For example `processor` or `disk` + + - name: collectors + type: group + fields: + - name: alias + type: string + description: > + Short form for the query + + - name: query + type: string + description: > + The query. For example `\\Processor Information(_Total)\\% Processor Performance`. Backslashes have to be escaped. + diff --git a/metricbeat/module/windows/perfmon/defs_windows.go b/metricbeat/module/windows/perfmon/defs_windows.go new file mode 100644 index 00000000000..8476af9d470 --- /dev/null +++ b/metricbeat/module/windows/perfmon/defs_windows.go @@ -0,0 +1,32 @@ +// +build ignore + +package perfmon + +/* +#include +#include +#include +#include +#include +#cgo LDFLAGS: -lpdh +*/ +import "C" + +const ( + ERROR_SUCCESS = C.ERROR_SUCCESS + PDH_STATUS_VALID_DATA = C.PDH_CSTATUS_VALID_DATA + PDH_STATUS_NEW_DATA = C.PDH_CSTATUS_NEW_DATA + PDH_NO_DATA = C.PDH_NO_DATA + PDH_STATUS_NO_OBJECT = C.PDH_CSTATUS_NO_OBJECT + PDH_STATUS_NO_COUNTER = C.PDH_CSTATUS_NO_COUNTER + PDH_STATUS_INVALID_DATA = C.PDH_CSTATUS_INVALID_DATA + PDH_INVALID_HANDLE = C.PDH_INVALID_HANDLE + PDH_INVALID_DATA = C.PDH_INVALID_DATA + PDH_NO_MORE_DATA = C.PDH_NO_MORE_DATA + PDH_CALC_NEGATIVE_DEMONIATOR = C.PDH_CALC_NEGATIVE_DENOMINATOR + PdhFmtDouble = C.PDH_FMT_DOUBLE + PdhFmtLarge = C.PDH_FMT_LARGE + PdhFmtLong = C.PDH_FMT_LONG +) + +type PdhCounterValue C.PDH_FMT_COUNTERVALUE diff --git a/metricbeat/module/windows/perfmon/defs_windows_386.go b/metricbeat/module/windows/perfmon/defs_windows_386.go new file mode 100644 index 00000000000..ea76c13bce8 --- /dev/null +++ b/metricbeat/module/windows/perfmon/defs_windows_386.go @@ -0,0 +1,25 @@ +package perfmon + +const ( + ERROR_SUCCESS = 0x0 + PDH_STATUS_VALID_DATA = 0x0 + PDH_STATUS_NEW_DATA = 0x1 + PDH_NO_DATA = 0x800007d5 + PDH_STATUS_NO_OBJECT = 0xc0000bb8 + PDH_STATUS_NO_COUNTER = 0xc0000bb9 + PDH_STATUS_INVALID_DATA = 0xc0000bba + PDH_INVALID_HANDLE = 0xc0000bbc + PDH_INVALID_DATA = 0xc0000bc6 + PDH_NO_MORE_DATA = 0xc0000bcc + PDH_CALC_NEGATIVE_DENOMINATOR = 0x800007d6 + PdhFmtDouble = 0x00000200 + PdhFmtLarge = 0x00000400 + PdhFmtLong = 0x00000100 +) + +type PdhCounterValue struct { + CStatus uint32 + Pad_cgo_0 [4]byte + LongValue int32 + Pad_cgo_1 [4]byte +} diff --git a/metricbeat/module/windows/perfmon/defs_windows_amd64.go b/metricbeat/module/windows/perfmon/defs_windows_amd64.go new file mode 100644 index 00000000000..ea76c13bce8 --- /dev/null +++ b/metricbeat/module/windows/perfmon/defs_windows_amd64.go @@ -0,0 +1,25 @@ +package perfmon + +const ( + ERROR_SUCCESS = 0x0 + PDH_STATUS_VALID_DATA = 0x0 + PDH_STATUS_NEW_DATA = 0x1 + PDH_NO_DATA = 0x800007d5 + PDH_STATUS_NO_OBJECT = 0xc0000bb8 + PDH_STATUS_NO_COUNTER = 0xc0000bb9 + PDH_STATUS_INVALID_DATA = 0xc0000bba + PDH_INVALID_HANDLE = 0xc0000bbc + PDH_INVALID_DATA = 0xc0000bc6 + PDH_NO_MORE_DATA = 0xc0000bcc + PDH_CALC_NEGATIVE_DENOMINATOR = 0x800007d6 + PdhFmtDouble = 0x00000200 + PdhFmtLarge = 0x00000400 + PdhFmtLong = 0x00000100 +) + +type PdhCounterValue struct { + CStatus uint32 + Pad_cgo_0 [4]byte + LongValue int32 + Pad_cgo_1 [4]byte +} diff --git a/metricbeat/module/windows/perfmon/doc.go b/metricbeat/module/windows/perfmon/doc.go new file mode 100644 index 00000000000..890ba1e53b5 --- /dev/null +++ b/metricbeat/module/windows/perfmon/doc.go @@ -0,0 +1,4 @@ +/* +Package perfmon collect windows performance counters. +*/ +package perfmon diff --git a/metricbeat/module/windows/perfmon/pdh_integration_windows_test.go b/metricbeat/module/windows/perfmon/pdh_integration_windows_test.go new file mode 100644 index 00000000000..85b9b703f25 --- /dev/null +++ b/metricbeat/module/windows/perfmon/pdh_integration_windows_test.go @@ -0,0 +1,58 @@ +// +build integration windows + +package perfmon + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestExistingCounter(t *testing.T) { + config := make([]CounterConfig, 1) + config[0].Name = "process" + config[0].Group = make([]CounterConfigGroup, 1) + config[0].Group[0].Alias = "processor_time" + config[0].Group[0].Query = "\\Processor Information(_Total)\\% Processor Time" + handle, err := GetHandle(config) + + assert.Zero(t, err) + + err = CloseQuery(handle.query) + + assert.Zero(t, err) +} + +func TestNonExistingCounter(t *testing.T) { + config := make([]CounterConfig, 1) + config[0].Name = "process" + config[0].Group = make([]CounterConfigGroup, 1) + config[0].Group[0].Alias = "processor_performance" + config[0].Group[0].Query = "\\Processor Information(_Total)\\not existing counter" + handle, err := GetHandle(config) + + assert.Equal(t, 3221228473, int(err)) + + if handle != nil { + err = CloseQuery(handle.query) + + assert.Zero(t, err) + } +} + +func TestNonExistingObject(t *testing.T) { + config := make([]CounterConfig, 1) + config[0].Name = "process" + config[0].Group = make([]CounterConfigGroup, 1) + config[0].Group[0].Alias = "processor_performance" + config[0].Group[0].Query = "\\non existing object\\% Processor Performance" + handle, err := GetHandle(config) + + assert.Equal(t, 3221228472, int(err)) + + if handle != nil { + err = CloseQuery(handle.query) + + assert.Zero(t, err) + } +} diff --git a/metricbeat/module/windows/perfmon/pdh_windows.go b/metricbeat/module/windows/perfmon/pdh_windows.go new file mode 100644 index 00000000000..7c69baf0361 --- /dev/null +++ b/metricbeat/module/windows/perfmon/pdh_windows.go @@ -0,0 +1,133 @@ +package perfmon + +import ( + "strconv" + "unsafe" + + "time" + + "github.com/elastic/beats/libbeat/common" +) + +type Handle struct { + status error + query uintptr + counterType int + counters []CounterGroup +} + +type CounterGroup struct { + GroupName string + Counters []Counter +} + +type Counter struct { + counterName string + counter uintptr + counterPath string + displayValue PdhCounterValue +} + +type PdhError uint32 + +var errorMapping = map[PdhError]string{ + PDH_INVALID_DATA: `PDH_INVALID_DATA`, + PDH_INVALID_HANDLE: `PDH_INVALID_HANDLE`, + PDH_NO_DATA: `PDH_NO_DATA`, + PDH_NO_MORE_DATA: `PDH_NO_MORE_DATA`, + PDH_STATUS_INVALID_DATA: `PDH_STATUS_INVALID_DATA`, + PDH_STATUS_NEW_DATA: `PDH_STATUS_NEW_DATA`, + PDH_STATUS_NO_COUNTER: `PDH_STATUS_NO_COUNTER`, + PDH_STATUS_NO_OBJECT: `PDH_STATUS_NO_OBJECT`, +} + +func GetHandle(config []CounterConfig) (*Handle, PdhError) { + q := &Handle{} + err := _PdhOpenQuery(0, 0, &q.query) + if err != ERROR_SUCCESS { + return nil, PdhError(err) + } + + counterGroups := make([]CounterGroup, len(config)) + q.counters = counterGroups + + for i, v := range config { + counterGroups[i] = CounterGroup{GroupName: v.Name, Counters: make([]Counter, len(v.Group))} + for j, v1 := range v.Group { + counterGroups[i].Counters[j] = Counter{counterName: v1.Alias, counterPath: v1.Query} + err := _PdhAddCounter(q.query, counterGroups[i].Counters[j].counterPath, 0, &counterGroups[i].Counters[j].counter) + if err != ERROR_SUCCESS { + return nil, PdhError(err) + } + } + } + + return q, 0 +} + +func (q *Handle) ReadData(firstFetch bool) (common.MapStr, PdhError) { + + err := _PdhCollectQueryData(q.query) + + if firstFetch { + // Most counters require two sample values in order to compute a displayable value. So wait and then collect the second value + time.Sleep(2000) + err = _PdhCollectQueryData(q.query) + } + + if err != ERROR_SUCCESS { + return nil, PdhError(err) + } + + result := common.MapStr{} + + for _, v := range q.counters { + groupVal := make(map[string]interface{}) + for _, v1 := range v.Counters { + err := _PdhGetFormattedCounterValue(v1.counter, PdhFmtDouble, q.counterType, &v1.displayValue) + if err != ERROR_SUCCESS { + switch err { + case PDH_CALC_NEGATIVE_DENOMINATOR: + { + //Sometimes counters return negative values. We can ignore this error. See here for a good explanation https://www.netiq.com/support/kb/doc.php?id=7010545 + groupVal[v1.counterName] = 0 + continue + } + default: + { + return nil, PdhError(err) + } + } + } + doubleValue := (*float64)(unsafe.Pointer(&v1.displayValue.LongValue)) + groupVal[v1.counterName] = *doubleValue + + } + result[v.GroupName] = groupVal + } + return result, 0 +} + +func CloseQuery(q uintptr) PdhError { + err := _PdhCloseQuery(q) + if err != ERROR_SUCCESS { + return PdhError(err) + } + + return 0 +} + +func (e PdhError) Error() string { + if val, ok := errorMapping[e]; ok { + return val + } + return strconv.FormatUint(uint64(e), 10) +} + +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output syscall_windows.go pdh.go +// Windows API calls +//sys _PdhOpenQuery(dataSource uintptr, userData uintptr, query *uintptr) (err uint32) = pdh.PdhOpenQuery +//sys _PdhAddCounter(query uintptr, counterPath string, userData uintptr, counter *uintptr) (err uint32) = pdh.PdhAddEnglishCounterW +//sys _PdhCollectQueryData(query uintptr) (err uint32) = pdh.PdhCollectQueryData +//sys _PdhGetFormattedCounterValue(counter uintptr, format uint32, counterType int, value *PdhCounterValue) (err uint32) = pdh.PdhGetFormattedCounterValue +//sys _PdhCloseQuery(query uintptr) (err uint32) = pdh.PdhCloseQuery diff --git a/metricbeat/module/windows/perfmon/perfmon.go b/metricbeat/module/windows/perfmon/perfmon.go new file mode 100644 index 00000000000..6404434ca18 --- /dev/null +++ b/metricbeat/module/windows/perfmon/perfmon.go @@ -0,0 +1,85 @@ +// +build windows + +package perfmon + +import ( + "errors" + + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" + "github.com/elastic/beats/metricbeat/mb" +) + +type CounterConfig struct { + Name string `config:"group" validate:"required"` + Group []CounterConfigGroup `config:"collectors" validate:"required"` +} + +type CounterConfigGroup struct { + Alias string `config:"alias" validate:"required"` + Query string `config:"query" validate:"required"` +} + +// init registers the MetricSet with the central registry. +// The New method will be called after the setup of the module and before starting to fetch data +func init() { + if err := mb.Registry.AddMetricSet("windows", "perfmon", New); err != nil { + panic(err) + } +} + +// MetricSet type defines all fields of the MetricSet +// As a minimum it must inherit the mb.BaseMetricSet fields, but can be extended with +// additional entries. These variables can be used to persist data or configuration between +// multiple fetch calls. +type MetricSet struct { + mb.BaseMetricSet + counters []CounterConfig + handle *Handle + firstFetch bool +} + +// New create a new instance of the MetricSet +// Part of new is also setting up the configuration by processing additional +// configuration entries if needed. +func New(base mb.BaseMetricSet) (mb.MetricSet, error) { + logp.Warn("BETA: The perfmon metricset is beta") + + config := struct { + CounterConfig []CounterConfig `config:"perfmon.counters" validate:"required"` + }{} + + if err := base.Module().UnpackConfig(&config); err != nil { + return nil, err + } + + query, err := GetHandle(config.CounterConfig) + + if err != ERROR_SUCCESS { + return nil, errors.New("initialization fails with error: " + err.Error()) + } + + return &MetricSet{ + BaseMetricSet: base, + counters: config.CounterConfig, + handle: query, + firstFetch: true, + }, nil +} + +// Fetch methods implements the data gathering and data conversion to the right format +// It returns the event which is then forward to the output. In case of an error, a +// descriptive error must be returned. +func (m *MetricSet) Fetch() (common.MapStr, error) { + + data, err := m.handle.ReadData(m.firstFetch) + if err != ERROR_SUCCESS { + return nil, errors.New("fetching fails wir error: " + err.Error()) + } + + if m.firstFetch { + m.firstFetch = false + } + + return data, nil +} diff --git a/metricbeat/module/windows/perfmon/syscall_windows.go b/metricbeat/module/windows/perfmon/syscall_windows.go new file mode 100644 index 00000000000..3549735c24c --- /dev/null +++ b/metricbeat/module/windows/perfmon/syscall_windows.go @@ -0,0 +1,59 @@ +// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT + +package perfmon + +import ( + "syscall" + "unsafe" +) + +var _ unsafe.Pointer + +var ( + modpdh = syscall.NewLazyDLL("pdh.dll") + + procPdhOpenQuery = modpdh.NewProc("PdhOpenQuery") + procPdhAddEnglishCounterW = modpdh.NewProc("PdhAddEnglishCounterW") + procPdhCollectQueryData = modpdh.NewProc("PdhCollectQueryData") + procPdhGetFormattedCounterValue = modpdh.NewProc("PdhGetFormattedCounterValue") + procPdhCloseQuery = modpdh.NewProc("PdhCloseQuery") +) + +func _PdhOpenQuery(dataSource uintptr, userData uintptr, query *uintptr) (err uint32) { + r0, _, _ := syscall.Syscall(procPdhOpenQuery.Addr(), 3, uintptr(dataSource), uintptr(userData), uintptr(unsafe.Pointer(query))) + err = uint32(r0) + return +} + +func _PdhAddCounter(query uintptr, counterPath string, userData uintptr, counter *uintptr) (err uint32) { + var _p0 *uint16 + _p0, _p1 := syscall.UTF16PtrFromString(counterPath) + if _p1 != nil { + return + } + return __PdhAddCounter(query, _p0, userData, counter) +} + +func __PdhAddCounter(query uintptr, counterPath *uint16, userData uintptr, counter *uintptr) (err uint32) { + r0, _, _ := syscall.Syscall6(procPdhAddEnglishCounterW.Addr(), 4, uintptr(query), uintptr(unsafe.Pointer(counterPath)), uintptr(userData), uintptr(unsafe.Pointer(counter)), 0, 0) + err = uint32(r0) + return +} + +func _PdhCollectQueryData(query uintptr) (err uint32) { + r0, _, _ := syscall.Syscall(procPdhCollectQueryData.Addr(), 1, uintptr(query), 0, 0) + err = uint32(r0) + return +} + +func _PdhGetFormattedCounterValue(counter uintptr, format uint32, counterType int, value *PdhCounterValue) (err uint32) { + r0, _, _ := syscall.Syscall6(procPdhGetFormattedCounterValue.Addr(), 4, uintptr(counter), uintptr(format), uintptr(counterType), uintptr(unsafe.Pointer(value)), 0, 0) + err = uint32(r0) + return +} + +func _PdhCloseQuery(query uintptr) (err uint32) { + r0, _, _ := syscall.Syscall(procPdhCloseQuery.Addr(), 1, uintptr(query), 0, 0) + err = uint32(r0) + return +}