chore: Fix linter findings for Windows (part2) (#13096)

Co-authored-by: pzak <pzak>
This commit is contained in:
Paweł Żak 2023-04-25 11:29:23 +02:00 committed by GitHub
parent 1d3afd469f
commit 4d4bed4ec4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 158 additions and 121 deletions

View File

@ -22,9 +22,11 @@ type eventLogger struct {
logger *eventlog.Log logger *eventlog.Log
} }
func (t *eventLogger) Write(b []byte) (n int, err error) { func (t *eventLogger) Write(b []byte) (int, error) {
var err error
loc := prefixRegex.FindIndex(b) loc := prefixRegex.FindIndex(b)
n = len(b) n := len(b)
if loc == nil { if loc == nil {
err = t.logger.Info(1, string(b)) err = t.logger.Info(1, string(b))
} else if n > 2 { //skip empty log messages } else if n > 2 { //skip empty log messages
@ -39,7 +41,7 @@ func (t *eventLogger) Write(b []byte) (n int, err error) {
} }
} }
return return n, err
} }
type eventLoggerCreator struct { type eventLoggerCreator struct {

View File

@ -5,6 +5,7 @@ package logger
import ( import (
"bytes" "bytes"
"encoding/xml" "encoding/xml"
"fmt"
"log" "log"
"os/exec" "os/exec"
"testing" "testing"
@ -30,7 +31,12 @@ type Event struct {
func getEventLog(t *testing.T, since time.Time) []Event { func getEventLog(t *testing.T, since time.Time) []Event {
timeStr := since.UTC().Format(time.RFC3339) timeStr := since.UTC().Format(time.RFC3339)
timeStr = timeStr[:19] timeStr = timeStr[:19]
cmd := exec.Command("wevtutil", "qe", "Application", "/rd:true", "/q:Event[System[TimeCreated[@SystemTime >= '"+timeStr+"'] and Provider[@Name='telegraf']]]") args := []string{
"qe",
"Application",
"/rd:true",
fmt.Sprintf("/q:Event[System[TimeCreated[@SystemTime >= %q] and Provider[@Name='telegraf']]]", timeStr)}
cmd := exec.Command("wevtutil", args...)
var out bytes.Buffer var out bytes.Buffer
cmd.Stdout = &out cmd.Stdout = &out
err := cmd.Run() err := cmd.Run()

View File

@ -45,7 +45,7 @@ func DecodeUTF16(b []byte) ([]byte, error) {
// GetFromSnapProcess finds information about process by the given pid // GetFromSnapProcess finds information about process by the given pid
// Returns process parent pid, threads info handle and process name // Returns process parent pid, threads info handle and process name
func GetFromSnapProcess(pid uint32) (uint32, uint32, string, error) { func GetFromSnapProcess(pid uint32) (uint32, uint32, string, error) {
snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(pid)) snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, pid)
if err != nil { if err != nil {
return 0, 0, "", err return 0, 0, "", err
} }
@ -56,9 +56,9 @@ func GetFromSnapProcess(pid uint32) (uint32, uint32, string, error) {
return 0, 0, "", err return 0, 0, "", err
} }
for { for {
if pe32.ProcessID == uint32(pid) { if pe32.ProcessID == pid {
szexe := windows.UTF16ToString(pe32.ExeFile[:]) szexe := windows.UTF16ToString(pe32.ExeFile[:])
return uint32(pe32.ParentProcessID), uint32(pe32.Threads), szexe, nil return pe32.ParentProcessID, pe32.Threads, szexe, nil
} }
if err = windows.Process32Next(snap, &pe32); err != nil { if err = windows.Process32Next(snap, &pe32); err != nil {
break break
@ -139,7 +139,7 @@ func walkXML(nodes []xmlnode, parents []string, separator string, f func(xmlnode
// by adding _<num> if there are several of them // by adding _<num> if there are several of them
func UniqueFieldNames(fields []EventField, fieldsUsage map[string]int, separator string) []EventField { func UniqueFieldNames(fields []EventField, fieldsUsage map[string]int, separator string) []EventField {
var fieldsCounter = map[string]int{} var fieldsCounter = map[string]int{}
var fieldsUnique []EventField fieldsUnique := make([]EventField, 0, len(fields))
for _, field := range fields { for _, field := range fields {
fieldName := field.Name fieldName := field.Name
if fieldsUsage[field.Name] > 1 { if fieldsUsage[field.Name] > 1 {

View File

@ -127,12 +127,13 @@ func (w *WinEventLog) Gather(acc telegraf.Accumulator) error {
return err return err
} }
for _, event := range events { for i := range events {
// Prepare fields names usage counter // Prepare fields names usage counter
var fieldsUsage = map[string]int{} var fieldsUsage = map[string]int{}
tags := map[string]string{} tags := map[string]string{}
fields := map[string]interface{}{} fields := map[string]interface{}{}
event := events[i]
evt := reflect.ValueOf(&event).Elem() evt := reflect.ValueOf(&event).Elem()
timeStamp := time.Now() timeStamp := time.Now()
// Walk through all fields of Event struct to process System tags or fields // Walk through all fields of Event struct to process System tags or fields
@ -403,17 +404,16 @@ func (w *WinEventLog) renderEvent(eventHandle EvtHandle) (Event, error) {
return event, err return event, err
} }
err = xml.Unmarshal([]byte(eventXML), &event) err = xml.Unmarshal(eventXML, &event)
if err != nil { if err != nil {
// We can return event without most text values, //nolint:nilerr // We can return event without most text values, that way we will not lose information
// that way we will not loose information
// This can happen when processing Forwarded Events // This can happen when processing Forwarded Events
return event, nil return event, nil
} }
// Do resolve local messages the usual way, while using built-in information for events forwarded by WEC. // Do resolve local messages the usual way, while using built-in information for events forwarded by WEC.
// This is a safety measure as the underlying Windows-internal EvtFormatMessage might segfault in cases // This is a safety measure as the underlying Windows-internal EvtFormatMessage might segfault in cases
// where the publisher (i.e. the remote machine which forwared the event) is unavailable e.g. due to // where the publisher (i.e. the remote machine which forwarded the event) is unavailable e.g. due to
// a reboot. See https://github.com/influxdata/telegraf/issues/12328 for the full story. // a reboot. See https://github.com/influxdata/telegraf/issues/12328 for the full story.
if event.RenderingInfo == nil { if event.RenderingInfo == nil {
return w.renderLocalMessage(event, eventHandle) return w.renderLocalMessage(event, eventHandle)
@ -426,7 +426,7 @@ func (w *WinEventLog) renderEvent(eventHandle EvtHandle) (Event, error) {
func (w *WinEventLog) renderLocalMessage(event Event, eventHandle EvtHandle) (Event, error) { func (w *WinEventLog) renderLocalMessage(event Event, eventHandle EvtHandle) (Event, error) {
publisherHandle, err := openPublisherMetadata(0, event.Source.Name, w.Locale) publisherHandle, err := openPublisherMetadata(0, event.Source.Name, w.Locale)
if err != nil { if err != nil {
return event, nil return event, nil //nolint:nilerr // We can return event without most values
} }
defer _EvtClose(publisherHandle) defer _EvtClose(publisherHandle)

View File

@ -36,21 +36,18 @@ type EvtFormatMessageFlag uint32
// EVT_FORMAT_MESSAGE_FLAGS enumeration // EVT_FORMAT_MESSAGE_FLAGS enumeration
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa385525(v=vs.85).aspx // https://msdn.microsoft.com/en-us/library/windows/desktop/aa385525(v=vs.85).aspx
const ( const (
//revive:disable:var-naming // EvtFormatMessageEvent - Format the event's message string.
// Format the event's message string.
EvtFormatMessageEvent EvtFormatMessageFlag = iota + 1 EvtFormatMessageEvent EvtFormatMessageFlag = iota + 1
// Format the message string of the level specified in the event. // EvtFormatMessageLevel - Format the message string of the level specified in the event.
EvtFormatMessageLevel EvtFormatMessageLevel
// Format the message string of the task specified in the event. // EvtFormatMessageTask - Format the message string of the task specified in the event.
EvtFormatMessageTask EvtFormatMessageTask
// Format the message string of the task specified in the event. // EvtFormatMessageOpcode - Format the message string of the task specified in the event.
EvtFormatMessageOpcode EvtFormatMessageOpcode
// Format the message string of the keywords specified in the event. If the // EvtFormatMessageKeyword - Format the message string of the keywords specified in the event. If the
// event specifies multiple keywords, the formatted string is a list of // event specifies multiple keywords, the formatted string is a list of null-terminated strings.
// null-terminated strings. Increment through the strings until your pointer // Increment through the strings until your pointer points past the end of the used buffer.
// points past the end of the used buffer.
EvtFormatMessageKeyword EvtFormatMessageKeyword
//revive:enable:var-naming
) )
// errnoErr returns common boxed Errno values, to prevent // errnoErr returns common boxed Errno values, to prevent
@ -88,21 +85,21 @@ func _EvtSubscribe(
context uintptr, context uintptr,
callback syscall.Handle, callback syscall.Handle,
flags EvtSubscribeFlag, flags EvtSubscribeFlag,
) (handle EvtHandle, err error) { ) (EvtHandle, error) {
r0, _, e1 := syscall.Syscall9( r0, _, e1 := syscall.SyscallN(
procEvtSubscribe.Addr(), procEvtSubscribe.Addr(),
8,
uintptr(session), uintptr(session),
uintptr(signalEvent), signalEvent,
uintptr(unsafe.Pointer(channelPath)), //nolint:gosec // G103: Valid use of unsafe call to pass channelPath uintptr(unsafe.Pointer(channelPath)), //nolint:gosec // G103: Valid use of unsafe call to pass channelPath
uintptr(unsafe.Pointer(query)), //nolint:gosec // G103: Valid use of unsafe call to pass query uintptr(unsafe.Pointer(query)), //nolint:gosec // G103: Valid use of unsafe call to pass query
uintptr(bookmark), uintptr(bookmark),
uintptr(context), context,
uintptr(callback), uintptr(callback),
uintptr(flags), uintptr(flags),
0,
) )
handle = EvtHandle(r0)
var err error
handle := EvtHandle(r0)
if handle == 0 { if handle == 0 {
if e1 != 0 { if e1 != 0 {
err = errnoErr(e1) err = errnoErr(e1)
@ -110,7 +107,7 @@ func _EvtSubscribe(
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return handle, err
} }
func _EvtRender( func _EvtRender(
@ -121,10 +118,9 @@ func _EvtRender(
buffer *byte, buffer *byte,
bufferUsed *uint32, bufferUsed *uint32,
propertyCount *uint32, propertyCount *uint32,
) (err error) { ) error {
r1, _, e1 := syscall.Syscall9( r1, _, e1 := syscall.SyscallN(
procEvtRender.Addr(), procEvtRender.Addr(),
7,
uintptr(context), uintptr(context),
uintptr(fragment), uintptr(fragment),
uintptr(flags), uintptr(flags),
@ -132,9 +128,9 @@ func _EvtRender(
uintptr(unsafe.Pointer(buffer)), //nolint:gosec // G103: Valid use of unsafe call to pass buffer uintptr(unsafe.Pointer(buffer)), //nolint:gosec // G103: Valid use of unsafe call to pass buffer
uintptr(unsafe.Pointer(bufferUsed)), //nolint:gosec // G103: Valid use of unsafe call to pass bufferUsed uintptr(unsafe.Pointer(bufferUsed)), //nolint:gosec // G103: Valid use of unsafe call to pass bufferUsed
uintptr(unsafe.Pointer(propertyCount)), //nolint:gosec // G103: Valid use of unsafe call to pass propertyCount uintptr(unsafe.Pointer(propertyCount)), //nolint:gosec // G103: Valid use of unsafe call to pass propertyCount
0,
0,
) )
var err error
if r1 == 0 { if r1 == 0 {
if e1 != 0 { if e1 != 0 {
err = errnoErr(e1) err = errnoErr(e1)
@ -142,11 +138,12 @@ func _EvtRender(
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return err
} }
func _EvtClose(object EvtHandle) (err error) { func _EvtClose(object EvtHandle) error {
r1, _, e1 := syscall.Syscall(procEvtClose.Addr(), 1, uintptr(object), 0, 0) r1, _, e1 := syscall.SyscallN(procEvtClose.Addr(), uintptr(object))
var err error
if r1 == 0 { if r1 == 0 {
if e1 != 0 { if e1 != 0 {
err = errnoErr(e1) err = errnoErr(e1)
@ -154,13 +151,12 @@ func _EvtClose(object EvtHandle) (err error) {
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return err
} }
func _EvtNext(resultSet EvtHandle, eventArraySize uint32, eventArray *EvtHandle, timeout uint32, flags uint32, numReturned *uint32) (err error) { func _EvtNext(resultSet EvtHandle, eventArraySize uint32, eventArray *EvtHandle, timeout uint32, flags uint32, numReturned *uint32) error {
r1, _, e1 := syscall.Syscall6( r1, _, e1 := syscall.SyscallN(
procEvtNext.Addr(), procEvtNext.Addr(),
6,
uintptr(resultSet), uintptr(resultSet),
uintptr(eventArraySize), uintptr(eventArraySize),
uintptr(unsafe.Pointer(eventArray)), //nolint:gosec // G103: Valid use of unsafe call to pass eventArray uintptr(unsafe.Pointer(eventArray)), //nolint:gosec // G103: Valid use of unsafe call to pass eventArray
@ -168,6 +164,8 @@ func _EvtNext(resultSet EvtHandle, eventArraySize uint32, eventArray *EvtHandle,
uintptr(flags), uintptr(flags),
uintptr(unsafe.Pointer(numReturned)), //nolint:gosec // G103: Valid use of unsafe call to pass numReturned uintptr(unsafe.Pointer(numReturned)), //nolint:gosec // G103: Valid use of unsafe call to pass numReturned
) )
var err error
if r1 == 0 { if r1 == 0 {
if e1 != 0 { if e1 != 0 {
err = errnoErr(e1) err = errnoErr(e1)
@ -175,7 +173,7 @@ func _EvtNext(resultSet EvtHandle, eventArraySize uint32, eventArray *EvtHandle,
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return err
} }
func _EvtFormatMessage( func _EvtFormatMessage(
@ -188,20 +186,21 @@ func _EvtFormatMessage(
bufferSize uint32, bufferSize uint32,
buffer *byte, buffer *byte,
bufferUsed *uint32, bufferUsed *uint32,
) (err error) { ) error {
r1, _, e1 := syscall.Syscall9( r1, _, e1 := syscall.SyscallN(
procEvtFormatMessage.Addr(), procEvtFormatMessage.Addr(),
9,
uintptr(publisherMetadata), uintptr(publisherMetadata),
uintptr(event), uintptr(event),
uintptr(messageID), uintptr(messageID),
uintptr(valueCount), uintptr(valueCount),
uintptr(values), values,
uintptr(flags), uintptr(flags),
uintptr(bufferSize), uintptr(bufferSize),
uintptr(unsafe.Pointer(buffer)), //nolint:gosec // G103: Valid use of unsafe call to pass buffer uintptr(unsafe.Pointer(buffer)), //nolint:gosec // G103: Valid use of unsafe call to pass buffer
uintptr(unsafe.Pointer(bufferUsed)), //nolint:gosec // G103: Valid use of unsafe call to pass bufferUsed uintptr(unsafe.Pointer(bufferUsed)), //nolint:gosec // G103: Valid use of unsafe call to pass bufferUsed
) )
var err error
if r1 == 0 { if r1 == 0 {
if e1 != 0 { if e1 != 0 {
err = errnoErr(e1) err = errnoErr(e1)
@ -209,21 +208,21 @@ func _EvtFormatMessage(
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return err
} }
func _EvtOpenPublisherMetadata(session EvtHandle, publisherIdentity *uint16, logFilePath *uint16, locale uint32, flags uint32) (handle EvtHandle, err error) { func _EvtOpenPublisherMetadata(session EvtHandle, publisherIdentity *uint16, logFilePath *uint16, locale uint32, flags uint32) (EvtHandle, error) {
r0, _, e1 := syscall.Syscall6( r0, _, e1 := syscall.SyscallN(
procEvtOpenPublisherMetadata.Addr(), procEvtOpenPublisherMetadata.Addr(),
5,
uintptr(session), uintptr(session),
uintptr(unsafe.Pointer(publisherIdentity)), //nolint:gosec // G103: Valid use of unsafe call to pass publisherIdentity uintptr(unsafe.Pointer(publisherIdentity)), //nolint:gosec // G103: Valid use of unsafe call to pass publisherIdentity
uintptr(unsafe.Pointer(logFilePath)), //nolint:gosec // G103: Valid use of unsafe call to pass logFilePath uintptr(unsafe.Pointer(logFilePath)), //nolint:gosec // G103: Valid use of unsafe call to pass logFilePath
uintptr(locale), uintptr(locale),
uintptr(flags), uintptr(flags),
0,
) )
handle = EvtHandle(r0)
var err error
handle := EvtHandle(r0)
if handle == 0 { if handle == 0 {
if e1 != 0 { if e1 != 0 {
err = errnoErr(e1) err = errnoErr(e1)
@ -231,12 +230,12 @@ func _EvtOpenPublisherMetadata(session EvtHandle, publisherIdentity *uint16, log
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return handle, err
} }
func _EvtCreateBookmark(bookmarkXML *uint16) (EvtHandle, error) { func _EvtCreateBookmark(bookmarkXML *uint16) (EvtHandle, error) {
//nolint:gosec // G103: Valid use of unsafe call to pass bookmarkXML //nolint:gosec // G103: Valid use of unsafe call to pass bookmarkXML
r0, _, e1 := syscall.Syscall(procEvtCreateBookmark.Addr(), 1, uintptr(unsafe.Pointer(bookmarkXML)), 0, 0) r0, _, e1 := syscall.SyscallN(procEvtCreateBookmark.Addr(), uintptr(unsafe.Pointer(bookmarkXML)))
handle := EvtHandle(r0) handle := EvtHandle(r0)
if handle != 0 { if handle != 0 {
return handle, nil return handle, nil
@ -248,7 +247,7 @@ func _EvtCreateBookmark(bookmarkXML *uint16) (EvtHandle, error) {
} }
func _EvtUpdateBookmark(bookmark, event EvtHandle) error { func _EvtUpdateBookmark(bookmark, event EvtHandle) error {
r0, _, e1 := syscall.Syscall(procEvtUpdateBookmark.Addr(), 2, uintptr(bookmark), uintptr(event), 0) r0, _, e1 := syscall.SyscallN(procEvtUpdateBookmark.Addr(), uintptr(bookmark), uintptr(event))
if r0 != 0 { if r0 != 0 {
return nil return nil
} }

View File

@ -308,7 +308,7 @@ func init() {
// \\LogicalDisk(C:)\% Free Space // \\LogicalDisk(C:)\% Free Space
// //
// To view all (internationalized...) counters on a system, there are three non-programmatic ways: perfmon utility, // To view all (internationalized...) counters on a system, there are three non-programmatic ways: perfmon utility,
// the typeperf command, and the the registry editor. perfmon.exe is perhaps the easiest way, because it's basically a // the typeperf command, and the registry editor. perfmon.exe is perhaps the easiest way, because it's basically a
// full implementation of the pdh.dll API, except with a GUI and all that. The registry setting also provides an // full implementation of the pdh.dll API, except with a GUI and all that. The registry setting also provides an
// interface to the available counters, and can be found at the following key: // interface to the available counters, and can be found at the following key:
// //
@ -376,7 +376,7 @@ func PdhCloseQuery(hQuery PDH_HQUERY) uint32 {
return uint32(ret) return uint32(ret)
} }
// Collects the current raw data value for all counters in the specified query and updates the status // PdhCollectQueryData collects the current raw data value for all counters in the specified query and updates the status
// code of each counter. With some counters, this function needs to be repeatedly called before the value // code of each counter. With some counters, this function needs to be repeatedly called before the value
// of the counter can be extracted with PdhGetFormattedCounterValue(). For example, the following code // of the counter can be extracted with PdhGetFormattedCounterValue(). For example, the following code
// requires at least two calls: // requires at least two calls:
@ -510,13 +510,13 @@ func PdhOpenQuery(szDataSource uintptr, dwUserData uintptr, phQuery *PDH_HQUERY)
return uint32(ret) return uint32(ret)
} }
// PdhExpandWildCardPath examines the specified computer or log file and returns those counter paths that match the given counter path which contains wildcard characters. // PdhExpandWildCardPath examines the specified computer or log file and returns those counter paths that match the given counter path
// The general counter path format is as follows: // which contains wildcard characters. The general counter path format is as follows:
// //
// \\computer\object(parent/instance#index)\counter // \\computer\object(parent/instance#index)\counter
// //
// The parent, instance, index, and counter components of the counter path may contain either a valid name or a wildcard character. The computer, parent, instance, // The parent, instance, index, and counter components of the counter path may contain either a valid name or a wildcard character.
// and index components are not necessary for all counters. // The computer, parent, instance, and index components are not necessary for all counters.
// //
// The following is a list of the possible formats: // The following is a list of the possible formats:
// //
@ -532,11 +532,13 @@ func PdhOpenQuery(szDataSource uintptr, dwUserData uintptr, phQuery *PDH_HQUERY)
// \object\counter // \object\counter
// Use an asterisk (*) as the wildcard character, for example, \object(*)\counter. // Use an asterisk (*) as the wildcard character, for example, \object(*)\counter.
// //
// If a wildcard character is specified in the parent name, all instances of the specified object that match the specified instance and counter fields will be returned. // If a wildcard character is specified in the parent name, all instances of the specified object
// that match the specified instance and counter fields will be returned.
// For example, \object(*/instance)\counter. // For example, \object(*/instance)\counter.
// //
// If a wildcard character is specified in the instance name, all instances of the specified object and parent object will be returned if all instance names // If a wildcard character is specified in the instance name, all instances of the specified object and parent object will be returned if all instance names
// corresponding to the specified index match the wildcard character. For example, \object(parent/*)\counter. If the object does not contain an instance, an error occurs. // corresponding to the specified index match the wildcard character. For example, \object(parent/*)\counter.
// If the object does not contain an instance, an error occurs.
// //
// If a wildcard character is specified in the counter name, all counters of the specified object are returned. // If a wildcard character is specified in the counter name, all counters of the specified object are returned.
// //
@ -572,18 +574,23 @@ func PdhFormatError(msgId uint32) string {
return fmt.Sprintf("(pdhErr=%d) %s", msgId, err.Error()) return fmt.Sprintf("(pdhErr=%d) %s", msgId, err.Error())
} }
// Retrieves information about a counter, such as data size, counter type, path, and user-supplied data values // PdhGetCounterInfo retrieves information about a counter, such as data size, counter type, path, and user-supplied data values
// hCounter [in] // hCounter [in]
// Handle of the counter from which you want to retrieve information. The PdhAddCounter function returns this handle. // Handle of the counter from which you want to retrieve information. The PdhAddCounter function returns this handle.
// //
// bRetrieveExplainText [in] // bRetrieveExplainText [in]
// Determines whether explain text is retrieved. If you set this parameter to TRUE, the explain text for the counter is retrieved. If you set this parameter to FALSE, the field in the returned buffer is NULL. // Determines whether explain text is retrieved. If you set this parameter to TRUE, the explain text for the counter is retrieved.
// If you set this parameter to FALSE, the field in the returned buffer is NULL.
// //
// pdwBufferSize [in, out] // pdwBufferSize [in, out]
// Size of the lpBuffer buffer, in bytes. If zero on input, the function returns PDH_MORE_DATA and sets this parameter to the required buffer size. If the buffer is larger than the required size, the function sets this parameter to the actual size of the buffer that was used. If the specified size on input is greater than zero but less than the required size, you should not rely on the returned size to reallocate the buffer. // Size of the lpBuffer buffer, in bytes. If zero on input, the function returns PDH_MORE_DATA and sets this parameter to the required buffer size.
// If the buffer is larger than the required size, the function sets this parameter to the actual size of the buffer that was used.
// If the specified size on input is greater than zero but less than the required size, you should not rely on the returned size to reallocate the buffer.
// //
// lpBuffer [out] // lpBuffer [out]
// Caller-allocated buffer that receives a PDH_COUNTER_INFO structure. The structure is variable-length, because the string data is appended to the end of the fixed-format portion of the structure. This is done so that all data is returned in a single buffer allocated by the caller. Set to NULL if pdwBufferSize is zero. // Caller-allocated buffer that receives a PDH_COUNTER_INFO structure.
// The structure is variable-length, because the string data is appended to the end of the fixed-format portion of the structure.
// This is done so that all data is returned in a single buffer allocated by the caller. Set to NULL if pdwBufferSize is zero.
func PdhGetCounterInfo(hCounter PDH_HCOUNTER, bRetrieveExplainText int, pdwBufferSize *uint32, lpBuffer *byte) uint32 { func PdhGetCounterInfo(hCounter PDH_HCOUNTER, bRetrieveExplainText int, pdwBufferSize *uint32, lpBuffer *byte) uint32 {
ret, _, _ := pdh_GetCounterInfoW.Call( ret, _, _ := pdh_GetCounterInfoW.Call(
uintptr(hCounter), uintptr(hCounter),
@ -594,7 +601,7 @@ func PdhGetCounterInfo(hCounter PDH_HCOUNTER, bRetrieveExplainText int, pdwBuffe
return uint32(ret) return uint32(ret)
} }
// Returns the current raw value of the counter. // PdhGetRawCounterValue returns the current raw value of the counter.
// If the specified counter instance does not exist, this function will return ERROR_SUCCESS // If the specified counter instance does not exist, this function will return ERROR_SUCCESS
// and the CStatus member of the PDH_RAW_COUNTER structure will contain PDH_CSTATUS_NO_INSTANCE. // and the CStatus member of the PDH_RAW_COUNTER structure will contain PDH_CSTATUS_NO_INSTANCE.
// //
@ -616,7 +623,7 @@ func PdhGetRawCounterValue(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_
return uint32(ret) return uint32(ret)
} }
// Returns an array of raw values from the specified counter. Use this function when you want to retrieve the raw counter values // PdhGetRawCounterArray returns an array of raw values from the specified counter. Use this function when you want to retrieve the raw counter values
// of a counter that contains a wildcard character for the instance name. // of a counter that contains a wildcard character for the instance name.
// hCounter // hCounter
// Handle of the counter for whose current raw instance values you want to retrieve. The PdhAddCounter function returns this handle. // Handle of the counter for whose current raw instance values you want to retrieve. The PdhAddCounter function returns this handle.

View File

@ -32,37 +32,38 @@
package win_perf_counters package win_perf_counters
// Union specialization for double values // PDH_FMT_COUNTERVALUE_DOUBLE is an union specialization for double values
type PDH_FMT_COUNTERVALUE_DOUBLE struct { type PDH_FMT_COUNTERVALUE_DOUBLE struct {
CStatus uint32 CStatus uint32
DoubleValue float64 DoubleValue float64
} }
// Union specialization for 64 bit integer values // PDH_FMT_COUNTERVALUE_LARGE is a union specialization for 64-bit integer values
type PDH_FMT_COUNTERVALUE_LARGE struct { type PDH_FMT_COUNTERVALUE_LARGE struct {
CStatus uint32 CStatus uint32
LargeValue int64 LargeValue int64
} }
// Union specialization for long values // PDH_FMT_COUNTERVALUE_LONG is a union specialization for long values
type PDH_FMT_COUNTERVALUE_LONG struct { type PDH_FMT_COUNTERVALUE_LONG struct {
CStatus uint32 CStatus uint32
LongValue int32 LongValue int32
padding [4]byte padding [4]byte
} }
// PDH_FMT_COUNTERVALUE_ITEM_DOUBLE is a union specialization for double values, used by PdhGetFormattedCounterArrayDouble
type PDH_FMT_COUNTERVALUE_ITEM_DOUBLE struct { type PDH_FMT_COUNTERVALUE_ITEM_DOUBLE struct {
SzName *uint16 SzName *uint16
FmtValue PDH_FMT_COUNTERVALUE_DOUBLE FmtValue PDH_FMT_COUNTERVALUE_DOUBLE
} }
// Union specialization for 'large' values, used by PdhGetFormattedCounterArrayLarge() // PDH_FMT_COUNTERVALUE_ITEM_LARGE is n union specialization for 'large' values, used by PdhGetFormattedCounterArrayLarge()
type PDH_FMT_COUNTERVALUE_ITEM_LARGE struct { type PDH_FMT_COUNTERVALUE_ITEM_LARGE struct {
SzName *uint16 // pointer to a string SzName *uint16 // pointer to a string
FmtValue PDH_FMT_COUNTERVALUE_LARGE FmtValue PDH_FMT_COUNTERVALUE_LARGE
} }
// Union specialization for long values, used by PdhGetFormattedCounterArrayLong() // PDH_FMT_COUNTERVALUE_ITEM_LONG is n union specialization for long values, used by PdhGetFormattedCounterArrayLong()
type PDH_FMT_COUNTERVALUE_ITEM_LONG struct { type PDH_FMT_COUNTERVALUE_ITEM_LONG struct {
SzName *uint16 // pointer to a string SzName *uint16 // pointer to a string
FmtValue PDH_FMT_COUNTERVALUE_LONG FmtValue PDH_FMT_COUNTERVALUE_LONG
@ -72,7 +73,8 @@ type PDH_FMT_COUNTERVALUE_ITEM_LONG struct {
type PDH_COUNTER_INFO struct { type PDH_COUNTER_INFO struct {
//Size of the structure, including the appended strings, in bytes. //Size of the structure, including the appended strings, in bytes.
DwLength uint32 DwLength uint32
//Counter type. For a list of counter types, see the Counter Types section of the <a "href=http://go.microsoft.com/fwlink/p/?linkid=84422">Windows Server 2003 Deployment Kit</a>. //Counter type. For a list of counter types,
//see the Counter Types section of the <a "href=http://go.microsoft.com/fwlink/p/?linkid=84422">Windows Server 2003 Deployment Kit</a>.
//The counter type constants are defined in Winperf.h. //The counter type constants are defined in Winperf.h.
DwType uint32 DwType uint32
//Counter version information. Not used. //Counter version information. Not used.
@ -100,8 +102,8 @@ type PDH_COUNTER_INFO struct {
//Null-terminated string that contains the name of the object instance specified in the counter path. Is NULL, if the path does not specify an instance. //Null-terminated string that contains the name of the object instance specified in the counter path. Is NULL, if the path does not specify an instance.
//The string follows this structure in memory. //The string follows this structure in memory.
SzInstanceName *uint16 // pointer to a string SzInstanceName *uint16 // pointer to a string
//Null-terminated string that contains the name of the parent instance specified in the counter path. Is NULL, if the path does not specify a parent instance. //Null-terminated string that contains the name of the parent instance specified in the counter path.
//The string follows this structure in memory. //Is NULL, if the path does not specify a parent instance. The string follows this structure in memory.
SzParentInstance *uint16 // pointer to a string SzParentInstance *uint16 // pointer to a string
//Instance index specified in the counter path. Is 0, if the path does not specify an instance index. //Instance index specified in the counter path. Is 0, if the path does not specify an instance index.
DwInstanceIndex uint32 // pointer to a string DwInstanceIndex uint32 // pointer to a string
@ -113,10 +115,11 @@ type PDH_COUNTER_INFO struct {
DataBuffer [1]uint32 // pointer to an extra space DataBuffer [1]uint32 // pointer to an extra space
} }
// The PDH_RAW_COUNTER structure returns the data as it was collected from the counter provider. No translation, formatting, or other interpretation is performed on the data // The PDH_RAW_COUNTER structure returns the data as it was collected from the counter provider.
// No translation, formatting, or other interpretation is performed on the data
type PDH_RAW_COUNTER struct { type PDH_RAW_COUNTER struct {
// Counter status that indicates if the counter value is valid. Check this member before using the data in a calculation or displaying its value. For a list of possible values, // Counter status that indicates if the counter value is valid. Check this member before using the data in a calculation or displaying its value.
// see https://docs.microsoft.com/windows/desktop/PerfCtrs/checking-pdh-interface-return-values // For a list of possible values, see https://docs.microsoft.com/windows/desktop/PerfCtrs/checking-pdh-interface-return-values
CStatus uint32 CStatus uint32
// Local time for when the data was collected // Local time for when the data was collected
TimeStamp FILETIME TimeStamp FILETIME

View File

@ -10,13 +10,15 @@ import (
"unsafe" "unsafe"
) )
// PerformanceQuery is abstraction for PDH_FMT_COUNTERVALUE_ITEM_DOUBLE // CounterValue is abstraction for PDH_FMT_COUNTERVALUE_ITEM_DOUBLE
type CounterValue struct { type CounterValue struct {
InstanceName string InstanceName string
Value interface{} Value interface{}
} }
// PerformanceQuery provides wrappers around Windows performance counters API for easy usage in GO // PerformanceQuery provides wrappers around Windows performance counters API for easy usage in GO
//
//nolint:interfacebloat // conditionally allow to contain more methods
type PerformanceQuery interface { type PerformanceQuery interface {
Open() error Open() error
Close() error Close() error

View File

@ -165,7 +165,17 @@ func (m *WinPerfCounters) hostname() string {
return m.cachedHostname return m.cachedHostname
} }
func newCounter(counterHandle PDH_HCOUNTER, counterPath string, computer string, objectName string, instance string, counterName string, measurement string, includeTotal bool, useRawValue bool) *counter { func newCounter(
counterHandle PDH_HCOUNTER,
counterPath string,
computer string,
objectName string,
instance string,
counterName string,
measurement string,
includeTotal bool,
useRawValue bool,
) *counter {
measurementName := sanitizedChars.Replace(measurement) measurementName := sanitizedChars.Replace(measurement)
if measurementName == "" { if measurementName == "" {
measurementName = "win_perf_counters" measurementName = "win_perf_counters"
@ -364,7 +374,8 @@ func (m *WinPerfCounters) ParseConfig() error {
counterPath = formatPath(computer, objectname, instance, counter) counterPath = formatPath(computer, objectname, instance, counter)
err := m.AddItem(counterPath, computer, objectname, instance, counter, PerfObject.Measurement, PerfObject.IncludeTotal, PerfObject.UseRawValues) err := m.AddItem(counterPath, computer, objectname, instance, counter,
PerfObject.Measurement, PerfObject.IncludeTotal, PerfObject.UseRawValues)
if err != nil { if err != nil {
if PerfObject.FailOnMissing || PerfObject.WarnOnMissing { if PerfObject.FailOnMissing || PerfObject.WarnOnMissing {
m.Log.Errorf("invalid counterPath %q: %s", counterPath, err.Error()) m.Log.Errorf("invalid counterPath %q: %s", counterPath, err.Error())

View File

@ -535,10 +535,9 @@ func TestWinPerfcountersConfigError2Integration(t *testing.T) {
Log: testutil.Logger{}, Log: testutil.Logger{},
} }
err := m.ParseConfig() require.Error(t, m.ParseConfig())
var acc testutil.Accumulator var acc testutil.Accumulator
err = m.Gather(&acc) require.Error(t, m.Gather(&acc))
require.Error(t, err)
} }
func TestWinPerfcountersConfigError3Integration(t *testing.T) { func TestWinPerfcountersConfigError3Integration(t *testing.T) {

View File

@ -232,14 +232,22 @@ type FakePerformanceQueryCreator struct {
func (m FakePerformanceQueryCreator) NewPerformanceQuery(computer string) PerformanceQuery { func (m FakePerformanceQueryCreator) NewPerformanceQuery(computer string) PerformanceQuery {
var ret PerformanceQuery var ret PerformanceQuery
var ok bool var ok bool
ret = nil
if ret, ok = m.fakeQueries[computer]; !ok { if ret, ok = m.fakeQueries[computer]; !ok {
panic(fmt.Errorf("query for %s not found", computer)) panic(fmt.Errorf("query for %s not found", computer))
} }
return ret return ret
} }
func createPerfObject(computer string, measurement string, object string, instances []string, counters []string, failOnMissing bool, includeTotal bool, useRawValues bool) []perfobject { func createPerfObject(
computer string,
measurement string,
object string,
instances []string,
counters []string,
failOnMissing bool,
includeTotal bool,
useRawValues bool,
) []perfobject {
PerfObject := perfobject{ PerfObject := perfobject{
ObjectName: object, ObjectName: object,
Instances: instances, Instances: instances,
@ -250,11 +258,11 @@ func createPerfObject(computer string, measurement string, object string, instan
IncludeTotal: includeTotal, IncludeTotal: includeTotal,
UseRawValues: useRawValues, UseRawValues: useRawValues,
} }
if computer != "" { if computer != "" {
PerfObject.Sources = []string{computer} PerfObject.Sources = []string{computer}
} }
perfObjects := []perfobject{PerfObject} return []perfobject{PerfObject}
return perfObjects
} }
func createCounterMap(counterPaths []string, values []float64, status []uint32) map[string]testCounter { func createCounterMap(counterPaths []string, values []float64, status []uint32) map[string]testCounter {
@ -1348,11 +1356,7 @@ func TestGatherError(t *testing.T) {
if testing.Short() { if testing.Short() {
t.Skip("Skipping long taking test in short mode") t.Skip("Skipping long taking test in short mode")
} }
var err error
expectedError := "error during collecting data on host 'localhost': error while getting value for counter \\O(I)\\C: The information passed is not valid.\r\n"
if testing.Short() {
t.Skip("Skipping long taking test in short mode")
}
measurement := "test" measurement := "test"
perfObjects := createPerfObject("", measurement, "O", []string{"I"}, []string{"C"}, false, false, false) perfObjects := createPerfObject("", measurement, "O", []string{"I"}, []string{"C"}, false, false, false)
cp1 := "\\O(I)\\C" cp1 := "\\O(I)\\C"
@ -1371,26 +1375,24 @@ func TestGatherError(t *testing.T) {
}, },
}, },
} }
expectedError := "error during collecting data on host 'localhost': error while getting value for counter \\O(I)\\C: " +
"The information passed is not valid.\r\n"
var acc1 testutil.Accumulator var acc1 testutil.Accumulator
err = m.Gather(&acc1) require.NoError(t, m.Gather(&acc1))
require.NoError(t, err)
require.Len(t, acc1.Errors, 1) require.Len(t, acc1.Errors, 1)
require.Equal(t, expectedError, acc1.Errors[0].Error()) require.Equal(t, expectedError, acc1.Errors[0].Error())
m.UseWildcardsExpansion = true m.UseWildcardsExpansion = true
err = m.cleanQueries() require.NoError(t, m.cleanQueries())
require.NoError(t, err)
m.lastRefreshed = time.Time{} m.lastRefreshed = time.Time{}
var acc2 testutil.Accumulator var acc2 testutil.Accumulator
require.NoError(t, m.Gather(&acc2))
err = m.Gather(&acc2)
require.NoError(t, err)
require.Len(t, acc2.Errors, 1) require.Len(t, acc2.Errors, 1)
require.Equal(t, expectedError, acc2.Errors[0].Error()) require.Equal(t, expectedError, acc2.Errors[0].Error())
err = m.cleanQueries() require.NoError(t, m.cleanQueries())
require.NoError(t, err)
} }
func TestGatherInvalidDataIgnore(t *testing.T) { func TestGatherInvalidDataIgnore(t *testing.T) {
@ -1728,7 +1730,10 @@ func TestGatherTotalNoExpansion(t *testing.T) {
Object: perfObjects, Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{ queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": { fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
counters: createCounterMap(append([]string{"\\O(*)\\C1", "\\O(*)\\C2"}, cps1...), []float64{0, 0, 1.1, 1.2, 1.3, 1.4}, []uint32{0, 0, 0, 0, 0, 0}), counters: createCounterMap(
append([]string{"\\O(*)\\C1", "\\O(*)\\C2"}, cps1...),
[]float64{0, 0, 1.1, 1.2, 1.3, 1.4},
[]uint32{0, 0, 0, 0, 0, 0}),
expandPaths: map[string][]string{ expandPaths: map[string][]string{
"\\O(*)\\C1": {cps1[0], cps1[2]}, "\\O(*)\\C1": {cps1[0], cps1[2]},
"\\O(*)\\C2": {cps1[1], cps1[3]}, "\\O(*)\\C2": {cps1[1], cps1[3]},
@ -1923,7 +1928,10 @@ func TestGatherRaw(t *testing.T) {
Object: perfObjects, Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{ queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": { fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
counters: createCounterMap(append([]string{"\\O(*)\\C1", "\\O(*)\\C2"}, cps1...), []float64{0, 0, 1.1, 2.2, 3.3, 4.4}, []uint32{0, 0, 0, 0, 0, 0}), counters: createCounterMap(
append([]string{"\\O(*)\\C1", "\\O(*)\\C2"}, cps1...),
[]float64{0, 0, 1.1, 2.2, 3.3, 4.4},
[]uint32{0, 0, 0, 0, 0, 0}),
expandPaths: map[string][]string{ expandPaths: map[string][]string{
"\\O(*)\\C1": {cps1[0], cps1[2]}, "\\O(*)\\C1": {cps1[0], cps1[2]},
"\\O(*)\\C2": {cps1[1], cps1[3]}, "\\O(*)\\C2": {cps1[1], cps1[3]},

View File

@ -53,7 +53,7 @@ func (m *FakeSvcMgr) OpenService(name string) (WinService, error) {
} }
} }
} }
return nil, fmt.Errorf("Cannot find service %s", name) return nil, fmt.Errorf("cannot find service %q", name)
} }
func (m *FakeSvcMgr) ListServices() ([]string, error) { func (m *FakeSvcMgr) ListServices() ([]string, error) {
@ -116,15 +116,15 @@ func (m *FakeWinSvc) Query() (svc.Status, error) {
} }
var testErrors = []testData{ var testErrors = []testData{
{nil, errors.New("Fake mgr connect error"), nil, nil}, {nil, errors.New("fake mgr connect error"), nil, nil},
{nil, nil, errors.New("Fake mgr list services error"), nil}, {nil, nil, errors.New("fake mgr list services error"), nil},
{[]string{"Fake service 1", "Fake service 2", "Fake service 3"}, nil, nil, []serviceTestInfo{ {[]string{"Fake service 1", "Fake service 2", "Fake service 3"}, nil, nil, []serviceTestInfo{
{errors.New("Fake srv open error"), nil, nil, "Fake service 1", "", 0, 0}, {errors.New("fake srv open error"), nil, nil, "Fake service 1", "", 0, 0},
{nil, errors.New("Fake srv query error"), nil, "Fake service 2", "", 0, 0}, {nil, errors.New("fake srv query error"), nil, "Fake service 2", "", 0, 0},
{nil, nil, errors.New("Fake srv config error"), "Fake service 3", "", 0, 0}, {nil, nil, errors.New("fake srv config error"), "Fake service 3", "", 0, 0},
}}, }},
{[]string{"Fake service 1"}, nil, nil, []serviceTestInfo{ {[]string{"Fake service 1"}, nil, nil, []serviceTestInfo{
{errors.New("Fake srv open error"), nil, nil, "Fake service 1", "", 0, 0}, {errors.New("fake srv open error"), nil, nil, "Fake service 1", "", 0, 0},
}}, }},
} }
@ -206,8 +206,8 @@ func TestGatherContainsTag(t *testing.T) {
for _, s := range testSimpleData[0].services { for _, s := range testSimpleData[0].services {
fields := make(map[string]interface{}) fields := make(map[string]interface{})
tags := make(map[string]string) tags := make(map[string]string)
fields["state"] = int(s.state) fields["state"] = s.state
fields["startup_mode"] = int(s.startUpMode) fields["startup_mode"] = s.startUpMode
tags["service_name"] = s.serviceName tags["service_name"] = s.serviceName
tags["display_name"] = s.displayName tags["display_name"] = s.displayName
acc1.AssertContainsTaggedFields(t, "win_services", fields, tags) acc1.AssertContainsTaggedFields(t, "win_services", fields, tags)
@ -227,8 +227,8 @@ func TestExcludingNamesTag(t *testing.T) {
for _, s := range testSimpleData[0].services { for _, s := range testSimpleData[0].services {
fields := make(map[string]interface{}) fields := make(map[string]interface{})
tags := make(map[string]string) tags := make(map[string]string)
fields["state"] = int(s.state) fields["state"] = s.state
fields["startup_mode"] = int(s.startUpMode) fields["startup_mode"] = s.startUpMode
tags["service_name"] = s.serviceName tags["service_name"] = s.serviceName
tags["display_name"] = s.displayName tags["display_name"] = s.displayName
acc1.AssertDoesNotContainsTaggedFields(t, "win_services", fields, tags) acc1.AssertDoesNotContainsTaggedFields(t, "win_services", fields, tags)