chore: Fix linter findings for `revive:exported` in `plugins/inputs/win*` (#16427)

This commit is contained in:
Paweł Żak 2025-01-27 19:34:59 +01:00 committed by GitHub
parent b074f0893d
commit 25de05a8fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 1012 additions and 1067 deletions

View File

@ -1,15 +1,12 @@
//go:build windows
// Package win_eventlog Input plugin to collect Windows Event Log messages
//
//revive:disable-next-line:var-naming
package win_eventlog
// Event is the event entry representation
// event is the event entry representation
// Only the most common elements are processed, human-readable data is rendered in Message
// More info on schema, if there will be need to add more:
// https://docs.microsoft.com/en-us/windows/win32/wes/eventschema-elements
type Event struct {
type event struct {
Source provider `xml:"System>Provider"`
EventID int `xml:"System>EventID"`
Version int `xml:"System>Version"`
@ -44,7 +41,7 @@ type eventData struct {
InnerXML []byte `xml:",innerxml"`
}
// provider is the Event provider information
// provider is the event provider information
type provider struct {
Name string `xml:"Name,attr"`
}
@ -55,24 +52,24 @@ type correlation struct {
RelatedActivityID string `xml:"RelatedActivityID,attr"`
}
// execution Info for Event
// execution Info for event
type execution struct {
ProcessID uint32 `xml:"ProcessID,attr"`
ThreadID uint32 `xml:"ThreadID,attr"`
ProcessName string
}
// security Data for Event
// security Data for event
type security struct {
UserID string `xml:"UserID,attr"`
}
// timeCreated field for Event
// timeCreated field for event
type timeCreated struct {
SystemTime string `xml:"SystemTime,attr"`
}
// renderingInfo is provided for events forwarded by Windows Event Collector
// renderingInfo is provided for events forwarded by Windows event Collector
// see https://learn.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtformatmessage#parameters
type renderingInfo struct {
Message string `xml:"Message"`

View File

@ -1,41 +1,36 @@
//go:build windows
// Package win_eventlog Input plugin to collect Windows Event Log messages
//
//revive:disable-next-line:var-naming
package win_eventlog
import "syscall"
// Event log error codes.
// event log error codes.
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
const (
//revive:disable:var-naming
ERROR_INSUFFICIENT_BUFFER syscall.Errno = 122
ERROR_NO_MORE_ITEMS syscall.Errno = 259
ERROR_INVALID_OPERATION syscall.Errno = 4317
//revive:enable:var-naming
errInsufficientBuffer syscall.Errno = 122
errNoMoreItems syscall.Errno = 259
errInvalidOperation syscall.Errno = 4317
)
// EvtSubscribeFlag defines the possible values that specify when to start subscribing to events.
type EvtSubscribeFlag uint32
// evtSubscribeFlag defines the possible values that specify when to start subscribing to events.
type evtSubscribeFlag uint32
// EVT_SUBSCRIBE_FLAGS enumeration
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa385588(v=vs.85).aspx
const (
EvtSubscribeToFutureEvents EvtSubscribeFlag = 1
EvtSubscribeStartAtOldestRecord EvtSubscribeFlag = 2
EvtSubscribeStartAfterBookmark EvtSubscribeFlag = 3
evtSubscribeToFutureEvents evtSubscribeFlag = 1
evtSubscribeStartAtOldestRecord evtSubscribeFlag = 2
evtSubscribeStartAfterBookmark evtSubscribeFlag = 3
)
// EvtRenderFlag uint32
type EvtRenderFlag uint32
// evtRenderFlag uint32
type evtRenderFlag uint32
// EVT_RENDER_FLAGS enumeration
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa385563(v=vs.85).aspx
const (
// Render the event as an XML string. For details on the contents of the XML string, see the Event schema.
EvtRenderEventXML EvtRenderFlag = 1
// Render the event as an XML string. For details on the contents of the XML string, see the event schema.
evtRenderEventXML evtRenderFlag = 1
// Render bookmark
EvtRenderBookmark EvtRenderFlag = 2
evtRenderBookmark evtRenderFlag = 2
)

View File

@ -1,8 +1,5 @@
//go:build windows
// Package win_eventlog Input plugin to collect Windows Event Log messages
//
//revive:disable-next-line:var-naming
package win_eventlog
import (
@ -18,8 +15,8 @@ import (
"golang.org/x/sys/windows"
)
// DecodeUTF16 to UTF8 bytes
func DecodeUTF16(b []byte) ([]byte, error) {
// decodeUTF16 to UTF8 bytes
func decodeUTF16(b []byte) ([]byte, error) {
if len(b)%2 != 0 {
return nil, errors.New("must have even length byte slice")
}
@ -41,9 +38,9 @@ func DecodeUTF16(b []byte) ([]byte, error) {
return ret.Bytes(), nil
}
// GetFromSnapProcess finds information about process by the given pid
// getFromSnapProcess finds information about process by the given pid
// Returns process name
func GetFromSnapProcess(pid uint32) (string, error) {
func getFromSnapProcess(pid uint32) (string, error) {
snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, pid)
if err != nil {
return "", err
@ -74,8 +71,8 @@ type xmlnode struct {
Nodes []xmlnode `xml:",any"`
}
// EventField for unique rendering
type EventField struct {
// eventField for unique rendering
type eventField struct {
Name string
Value string
}
@ -88,11 +85,11 @@ func (n *xmlnode) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
return d.DecodeElement((*node)(n), &start)
}
// UnrollXMLFields extracts fields from xml data
func UnrollXMLFields(data []byte, fieldsUsage map[string]int, separator string) ([]EventField, map[string]int) {
// unrollXMLFields extracts fields from xml data
func unrollXMLFields(data []byte, fieldsUsage map[string]int, separator string) ([]eventField, map[string]int) {
buf := bytes.NewBuffer(data)
dec := xml.NewDecoder(buf)
var fields []EventField
var fields []eventField
for {
var node xmlnode
err := dec.Decode(&node)
@ -106,7 +103,7 @@ func UnrollXMLFields(data []byte, fieldsUsage map[string]int, separator string)
if len(innerText) > 0 {
valueName := strings.Join(parents, separator)
fieldsUsage[valueName]++
field := EventField{Name: valueName, Value: innerText}
field := eventField{Name: valueName, Value: innerText}
fields = append(fields, field)
}
return true
@ -132,18 +129,17 @@ func walkXML(nodes []xmlnode, parents []string, separator string, f func(xmlnode
}
}
// UniqueFieldNames forms unique field names
// by adding _<num> if there are several of them
func UniqueFieldNames(fields []EventField, fieldsUsage map[string]int, separator string) []EventField {
// uniqueFieldNames forms unique field names by adding _<num> if there are several of them
func uniqueFieldNames(fields []eventField, fieldsUsage map[string]int, separator string) []eventField {
var fieldsCounter = make(map[string]int, len(fields))
fieldsUnique := make([]EventField, 0, len(fields))
fieldsUnique := make([]eventField, 0, len(fields))
for _, field := range fields {
fieldName := field.Name
if fieldsUsage[field.Name] > 1 {
fieldsCounter[field.Name]++
fieldName = fmt.Sprint(field.Name, separator, fieldsCounter[field.Name])
}
fieldsUnique = append(fieldsUnique, EventField{
fieldsUnique = append(fieldsUnique, eventField{
Name: fieldName,
Value: field.Value,
})

View File

@ -1,8 +1,5 @@
//go:build windows
// Package win_eventlog Input plugin to collect Windows Event Log messages
//
//revive:disable-next-line:var-naming
package win_eventlog
import (
@ -52,13 +49,13 @@ func TestDecodeUTF16(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := DecodeUTF16(tt.args.b)
got, err := decodeUTF16(tt.args.b)
if (err != nil) != tt.wantErr {
t.Errorf("DecodeUTF16() error = %v, wantErr %v", err, tt.wantErr)
t.Errorf("decodeUTF16() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("DecodeUTF16() = %v, want %v", got, tt.want)
t.Errorf("decodeUTF16() = %v, want %v", got, tt.want)
}
})
}
@ -110,7 +107,7 @@ func TestUnrollXMLFields(t *testing.T) {
tests := []struct {
name string
args args
want1 []EventField
want1 []eventField
want2 map[string]int
}{
{
@ -128,7 +125,7 @@ func TestUnrollXMLFields(t *testing.T) {
data: container.EventData.InnerXML,
fieldsUsage: map[string]int{},
},
want1: []EventField{
want1: []eventField{
{Name: "Data", Value: "2120-07-26T15:24:25Z"},
{Name: "Data", Value: "RulesEngine"},
{Name: "Data_Engine", Value: "RulesEngine"},
@ -141,7 +138,7 @@ func TestUnrollXMLFields(t *testing.T) {
data: container.UserData.InnerXML,
fieldsUsage: map[string]int{},
},
want1: []EventField{
want1: []eventField{
{Name: "CbsPackageChangeState_IntendedPackageState", Value: "5111"},
{Name: "CbsPackageChangeState_ErrorCode_Code", Value: "0x0"},
},
@ -153,7 +150,7 @@ func TestUnrollXMLFields(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := UnrollXMLFields(tt.args.data, tt.args.fieldsUsage, "_")
got, got1 := unrollXMLFields(tt.args.data, tt.args.fieldsUsage, "_")
if !reflect.DeepEqual(got, tt.want1) {
t.Errorf("ExtractFields() got = %v, want %v", got, tt.want1)
}
@ -166,25 +163,25 @@ func TestUnrollXMLFields(t *testing.T) {
func TestUniqueFieldNames(t *testing.T) {
type args struct {
fields []EventField
fields []eventField
fieldsUsage map[string]int
}
tests := []struct {
name string
args args
want []EventField
want []eventField
}{
{
name: "Unique values",
args: args{
fields: []EventField{
fields: []eventField{
{Name: "Data", Value: "2120-07-26T15:24:25Z"},
{Name: "Data", Value: "RulesEngine"},
{Name: "Engine", Value: "RulesEngine"},
},
fieldsUsage: map[string]int{"Data": 2, "Engine": 1},
},
want: []EventField{
want: []eventField{
{Name: "Data_1", Value: "2120-07-26T15:24:25Z"},
{Name: "Data_2", Value: "RulesEngine"},
{Name: "Engine", Value: "RulesEngine"},
@ -193,7 +190,7 @@ func TestUniqueFieldNames(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := UniqueFieldNames(tt.args.fields, tt.args.fieldsUsage, "_"); !reflect.DeepEqual(got, tt.want) {
if got := uniqueFieldNames(tt.args.fields, tt.args.fieldsUsage, "_"); !reflect.DeepEqual(got, tt.want) {
t.Errorf("PrintFields() = %v, want %v", got, tt.want)
}
})

View File

@ -1,9 +1,6 @@
//go:generate ../../../tools/readme_config_includer/generator
//go:build windows
// Package win_eventlog Input plugin to collect Windows Event Log messages
//
//revive:disable-next-line:var-naming
package win_eventlog
import (
@ -28,7 +25,8 @@ import (
//go:embed sample.conf
var sampleConfig string
// WinEventLog config
const bufferSize = 1 << 14
type WinEventLog struct {
Locale uint32 `toml:"locale"`
EventlogName string `toml:"eventlog_name"`
@ -46,16 +44,14 @@ type WinEventLog struct {
ExcludeEmpty []string `toml:"exclude_empty"`
Log telegraf.Logger `toml:"-"`
subscription EvtHandle
subscriptionFlag EvtSubscribeFlag
bookmark EvtHandle
subscription evtHandle
subscriptionFlag evtSubscribeFlag
bookmark evtHandle
tagFilter filter.Filter
fieldFilter filter.Filter
fieldEmptyFilter filter.Filter
}
const bufferSize = 1 << 14
func (*WinEventLog) SampleConfig() string {
return sampleConfig
}
@ -66,16 +62,16 @@ func (w *WinEventLog) Init() error {
w.BatchSize = 5
}
w.subscriptionFlag = EvtSubscribeToFutureEvents
w.subscriptionFlag = evtSubscribeToFutureEvents
if w.FromBeginning {
w.subscriptionFlag = EvtSubscribeStartAtOldestRecord
w.subscriptionFlag = evtSubscribeStartAtOldestRecord
}
if w.Query == "" {
w.Query = "*"
}
bookmark, err := _EvtCreateBookmark(nil)
bookmark, err := evtCreateBookmark(nil)
if err != nil {
return err
}
@ -96,7 +92,7 @@ func (w *WinEventLog) Init() error {
return nil
}
func (w *WinEventLog) Start(_ telegraf.Accumulator) error {
func (w *WinEventLog) Start(telegraf.Accumulator) error {
subscription, err := w.evtSubscribe()
if err != nil {
return fmt.Errorf("subscription of Windows Event Log failed: %w", err)
@ -107,11 +103,6 @@ func (w *WinEventLog) Start(_ telegraf.Accumulator) error {
return nil
}
func (w *WinEventLog) Stop() {
//nolint:errcheck // ending the subscription, error can be ignored
_ = _EvtClose(w.subscription)
}
func (w *WinEventLog) GetState() interface{} {
bookmarkXML, err := renderBookmark(w.bookmark)
if err != nil {
@ -132,22 +123,21 @@ func (w *WinEventLog) SetState(state interface{}) error {
return fmt.Errorf("conversion to pointer failed: %w", err)
}
bookmark, err := _EvtCreateBookmark(ptr)
bookmark, err := evtCreateBookmark(ptr)
if err != nil {
return fmt.Errorf("creating bookmark failed: %w", err)
}
w.bookmark = bookmark
w.subscriptionFlag = EvtSubscribeStartAfterBookmark
w.subscriptionFlag = evtSubscribeStartAfterBookmark
return nil
}
// Gather Windows Event Log entries
func (w *WinEventLog) Gather(acc telegraf.Accumulator) error {
for {
events, err := w.fetchEvents(w.subscription)
if err != nil {
if errors.Is(err, ERROR_NO_MORE_ITEMS) {
if errors.Is(err, errNoMoreItems) {
break
}
w.Log.Errorf("Error getting events: %v", err)
@ -163,7 +153,7 @@ func (w *WinEventLog) Gather(acc telegraf.Accumulator) error {
event := events[i]
evt := reflect.ValueOf(&event).Elem()
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
for i := 0; i < evt.NumField(); i++ {
fieldName := evt.Type().Field(i).Name
fieldType := evt.Field(i).Type().String()
@ -179,7 +169,7 @@ func (w *WinEventLog) Gather(acc telegraf.Accumulator) error {
fieldName = "ProcessID"
// Look up Process Name from pid
if should, _ := w.shouldProcessField("ProcessName"); should {
processName, err := GetFromSnapProcess(fieldValue)
processName, err := getFromSnapProcess(fieldValue)
if err == nil {
computedValues["ProcessName"] = processName
}
@ -250,18 +240,18 @@ func (w *WinEventLog) Gather(acc telegraf.Accumulator) error {
}
// Unroll additional XML
var xmlFields []EventField
var xmlFields []eventField
if w.ProcessUserData {
fieldsUserData, xmlFieldsUsage := UnrollXMLFields(event.UserData.InnerXML, fieldsUsage, w.Separator)
fieldsUserData, xmlFieldsUsage := unrollXMLFields(event.UserData.InnerXML, fieldsUsage, w.Separator)
xmlFields = append(xmlFields, fieldsUserData...)
fieldsUsage = xmlFieldsUsage
}
if w.ProcessEventData {
fieldsEventData, xmlFieldsUsage := UnrollXMLFields(event.EventData.InnerXML, fieldsUsage, w.Separator)
fieldsEventData, xmlFieldsUsage := unrollXMLFields(event.EventData.InnerXML, fieldsUsage, w.Separator)
xmlFields = append(xmlFields, fieldsEventData...)
fieldsUsage = xmlFieldsUsage
}
uniqueXMLFields := UniqueFieldNames(xmlFields, fieldsUsage, w.Separator)
uniqueXMLFields := uniqueFieldNames(xmlFields, fieldsUsage, w.Separator)
for _, xmlField := range uniqueXMLFields {
should, where := w.shouldProcessField(xmlField.Name)
if !should {
@ -282,6 +272,11 @@ func (w *WinEventLog) Gather(acc telegraf.Accumulator) error {
return nil
}
func (w *WinEventLog) Stop() {
//nolint:errcheck // ending the subscription, error can be ignored
_ = evtClose(w.subscription)
}
func (w *WinEventLog) shouldProcessField(field string) (should bool, list string) {
if w.tagFilter != nil && w.tagFilter.Match(field) {
return true, "tags"
@ -311,7 +306,7 @@ func (w *WinEventLog) shouldExcludeEmptyField(field, fieldType string, fieldValu
return false
}
func (w *WinEventLog) evtSubscribe() (EvtHandle, error) {
func (w *WinEventLog) evtSubscribe() (evtHandle, error) {
sigEvent, err := windows.CreateEvent(nil, 0, 0, nil)
if err != nil {
return 0, err
@ -328,11 +323,11 @@ func (w *WinEventLog) evtSubscribe() (EvtHandle, error) {
return 0, err
}
var bookmark EvtHandle
if w.subscriptionFlag == EvtSubscribeStartAfterBookmark {
var bookmark evtHandle
if w.subscriptionFlag == evtSubscribeStartAfterBookmark {
bookmark = w.bookmark
}
subsHandle, err := _EvtSubscribe(0, uintptr(sigEvent), logNamePtr, xqueryPtr, bookmark, 0, 0, w.subscriptionFlag)
subsHandle, err := evtSubscribe(0, uintptr(sigEvent), logNamePtr, xqueryPtr, bookmark, 0, 0, w.subscriptionFlag)
if err != nil {
return 0, err
}
@ -340,13 +335,13 @@ func (w *WinEventLog) evtSubscribe() (EvtHandle, error) {
return subsHandle, nil
}
func (w *WinEventLog) fetchEventHandles(subsHandle EvtHandle) ([]EvtHandle, error) {
func (w *WinEventLog) fetchEventHandles(subsHandle evtHandle) ([]evtHandle, error) {
var evtReturned uint32
eventHandles := make([]EvtHandle, w.BatchSize)
if err := _EvtNext(subsHandle, w.BatchSize, &eventHandles[0], 0, 0, &evtReturned); err != nil {
if errors.Is(err, ERROR_INVALID_OPERATION) && evtReturned == 0 {
return nil, ERROR_NO_MORE_ITEMS
eventHandles := make([]evtHandle, w.BatchSize)
if err := evtNext(subsHandle, w.BatchSize, &eventHandles[0], 0, 0, &evtReturned); err != nil {
if errors.Is(err, errInvalidOperation) && evtReturned == 0 {
return nil, errNoMoreItems
}
return nil, err
}
@ -354,8 +349,8 @@ func (w *WinEventLog) fetchEventHandles(subsHandle EvtHandle) ([]EvtHandle, erro
return eventHandles[:evtReturned], nil
}
func (w *WinEventLog) fetchEvents(subsHandle EvtHandle) ([]Event, error) {
var events []Event
func (w *WinEventLog) fetchEvents(subsHandle evtHandle) ([]event, error) {
var events []event
eventHandles, err := w.fetchEventHandles(subsHandle)
if err != nil {
@ -370,27 +365,27 @@ func (w *WinEventLog) fetchEvents(subsHandle EvtHandle) ([]Event, error) {
if event, err := w.renderEvent(eventHandle); err == nil {
events = append(events, event)
}
if err := _EvtUpdateBookmark(w.bookmark, eventHandle); err != nil && evterr == nil {
if err := evtUpdateBookmark(w.bookmark, eventHandle); err != nil && evterr == nil {
evterr = err
}
if err := _EvtClose(eventHandle); err != nil && evterr == nil {
if err := evtClose(eventHandle); err != nil && evterr == nil {
evterr = err
}
}
return events, evterr
}
func renderBookmark(bookmark EvtHandle) (string, error) {
func renderBookmark(bookmark evtHandle) (string, error) {
var bufferUsed, propertyCount uint32
buf := make([]byte, bufferSize)
err := _EvtRender(0, bookmark, EvtRenderBookmark, uint32(len(buf)), &buf[0], &bufferUsed, &propertyCount)
err := evtRender(0, bookmark, evtRenderBookmark, uint32(len(buf)), &buf[0], &bufferUsed, &propertyCount)
if err != nil {
return "", err
}
x, err := DecodeUTF16(buf[:bufferUsed])
x, err := decodeUTF16(buf[:bufferUsed])
if err != nil {
return "", err
}
@ -400,17 +395,17 @@ func renderBookmark(bookmark EvtHandle) (string, error) {
return string(x), err
}
func (w *WinEventLog) renderEvent(eventHandle EvtHandle) (Event, error) {
func (w *WinEventLog) renderEvent(eventHandle evtHandle) (event, error) {
var bufferUsed, propertyCount uint32
buf := make([]byte, bufferSize)
event := Event{}
err := _EvtRender(0, eventHandle, EvtRenderEventXML, uint32(len(buf)), &buf[0], &bufferUsed, &propertyCount)
event := event{}
err := evtRender(0, eventHandle, evtRenderEventXML, uint32(len(buf)), &buf[0], &bufferUsed, &propertyCount)
if err != nil {
return event, err
}
eventXML, err := DecodeUTF16(buf[:bufferUsed])
eventXML, err := decodeUTF16(buf[:bufferUsed])
if err != nil {
return event, err
}
@ -434,19 +429,19 @@ func (w *WinEventLog) renderEvent(eventHandle EvtHandle) (Event, error) {
return w.renderRemoteMessage(event)
}
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)
if err != nil {
return event, nil
}
defer _EvtClose(publisherHandle) //nolint:errcheck // Ignore error returned during Close
defer evtClose(publisherHandle) //nolint:errcheck // Ignore error returned during Close
// Populating text values
keywords, err := formatEventString(EvtFormatMessageKeyword, eventHandle, publisherHandle)
keywords, err := formatEventString(evtFormatMessageKeyword, eventHandle, publisherHandle)
if err == nil {
event.Keywords = keywords
}
message, err := formatEventString(EvtFormatMessageEvent, eventHandle, publisherHandle)
message, err := formatEventString(evtFormatMessageEvent, eventHandle, publisherHandle)
if err == nil {
if w.OnlyFirstLineOfMessage {
scanner := bufio.NewScanner(strings.NewReader(message))
@ -455,22 +450,22 @@ func (w *WinEventLog) renderLocalMessage(event Event, eventHandle EvtHandle) (Ev
}
event.Message = message
}
level, err := formatEventString(EvtFormatMessageLevel, eventHandle, publisherHandle)
level, err := formatEventString(evtFormatMessageLevel, eventHandle, publisherHandle)
if err == nil {
event.LevelText = level
}
task, err := formatEventString(EvtFormatMessageTask, eventHandle, publisherHandle)
task, err := formatEventString(evtFormatMessageTask, eventHandle, publisherHandle)
if err == nil {
event.TaskText = task
}
opcode, err := formatEventString(EvtFormatMessageOpcode, eventHandle, publisherHandle)
opcode, err := formatEventString(evtFormatMessageOpcode, eventHandle, publisherHandle)
if err == nil {
event.OpcodeText = opcode
}
return event, nil
}
func (w *WinEventLog) renderRemoteMessage(event Event) (Event, error) {
func (w *WinEventLog) renderRemoteMessage(event event) (event, error) {
// Populating text values from RenderingInfo part of the XML
if len(event.RenderingInfo.Keywords) > 0 {
event.Keywords = strings.Join(event.RenderingInfo.Keywords, ",")
@ -496,11 +491,11 @@ func (w *WinEventLog) renderRemoteMessage(event Event) (Event, error) {
return event, nil
}
func formatEventString(messageFlag EvtFormatMessageFlag, eventHandle, publisherHandle EvtHandle) (string, error) {
func formatEventString(messageFlag evtFormatMessageFlag, eventHandle, publisherHandle evtHandle) (string, error) {
var bufferUsed uint32
err := _EvtFormatMessage(publisherHandle, eventHandle, 0, 0, 0, messageFlag,
err := evtFormatMessage(publisherHandle, eventHandle, 0, 0, 0, messageFlag,
0, nil, &bufferUsed)
if err != nil && !errors.Is(err, ERROR_INSUFFICIENT_BUFFER) {
if err != nil && !errors.Is(err, errInsufficientBuffer) {
return "", err
}
@ -513,20 +508,20 @@ func formatEventString(messageFlag EvtFormatMessageFlag, eventHandle, publisherH
buffer := make([]byte, bufferUsed)
bufferUsed = 0
err = _EvtFormatMessage(publisherHandle, eventHandle, 0, 0, 0, messageFlag,
err = evtFormatMessage(publisherHandle, eventHandle, 0, 0, 0, messageFlag,
uint32(len(buffer)/2), &buffer[0], &bufferUsed)
bufferUsed *= 2
if err != nil {
return "", err
}
result, err := DecodeUTF16(buffer[:bufferUsed])
result, err := decodeUTF16(buffer[:bufferUsed])
if err != nil {
return "", err
}
var out string
if messageFlag == EvtFormatMessageKeyword {
if messageFlag == evtFormatMessageKeyword {
// Keywords are returned as array of a zero-terminated strings
splitZero := func(c rune) bool { return c == '\x00' }
eventKeywords := strings.FieldsFunc(string(result), splitZero)
@ -540,18 +535,14 @@ func formatEventString(messageFlag EvtFormatMessageFlag, eventHandle, publisherH
}
// openPublisherMetadata opens a handle to the publisher's metadata. Close must
// be called on returned EvtHandle when finished with the handle.
func openPublisherMetadata(
session EvtHandle,
publisherName string,
lang uint32,
) (EvtHandle, error) {
// be called on returned evtHandle when finished with the handle.
func openPublisherMetadata(session evtHandle, publisherName string, lang uint32) (evtHandle, error) {
p, err := syscall.UTF16PtrFromString(publisherName)
if err != nil {
return 0, err
}
h, err := _EvtOpenPublisherMetadata(session, p, nil, lang, 0)
h, err := evtOpenPublisherMetadata(session, p, nil, lang, 0)
if err != nil {
return 0, err
}

View File

@ -17,14 +17,14 @@ type WinEventLog struct {
Log telegraf.Logger `toml:"-"`
}
func (*WinEventLog) SampleConfig() string { return sampleConfig }
func (w *WinEventLog) Init() error {
w.Log.Warn("current platform is not supported")
w.Log.Warn("Current platform is not supported")
return nil
}
func (*WinEventLog) SampleConfig() string { return sampleConfig }
func (*WinEventLog) Gather(_ telegraf.Accumulator) error { return nil }
func (*WinEventLog) Start(_ telegraf.Accumulator) error { return nil }
func (*WinEventLog) Stop() {}
func (*WinEventLog) Gather(telegraf.Accumulator) error { return nil }
func init() {
inputs.Add("win_eventlog", func() telegraf.Input {

View File

@ -1,8 +1,5 @@
//go:build windows
// Package win_eventlog Input plugin to collect Windows Event Log messages
//
//revive:disable-next-line:var-naming
package win_eventlog
import (

View File

@ -1,8 +1,5 @@
//go:build windows
// Package win_eventlog Input plugin to collect Windows Event Log messages
//
//revive:disable-next-line:var-naming
package win_eventlog
import (
@ -14,50 +11,45 @@ import (
var _ unsafe.Pointer
// EvtHandle uintptr
type EvtHandle uintptr
// evtHandle uintptr
type evtHandle uintptr
// Do the interface allocations only once for common
// Errno values.
// Do the interface allocations only once for common errno values.
const (
//revive:disable-next-line:var-naming
errnoERROR_IO_PENDING = 997
errnoErrorIOPending = 997
)
var (
//revive:disable-next-line:var-naming
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errErrorIOPending error = syscall.Errno(errnoErrorIOPending)
)
// EvtFormatMessageFlag defines the values that specify the message string from
// the event to format.
type EvtFormatMessageFlag uint32
// evtFormatMessageFlag defines the values that specify the message string from the event to format.
type evtFormatMessageFlag uint32
// EVT_FORMAT_MESSAGE_FLAGS enumeration
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa385525(v=vs.85).aspx
const (
// EvtFormatMessageEvent - Format the event's message string.
EvtFormatMessageEvent EvtFormatMessageFlag = iota + 1
// EvtFormatMessageLevel - Format the message string of the level specified in the event.
EvtFormatMessageLevel
// EvtFormatMessageTask - Format the message string of the task specified in the event.
EvtFormatMessageTask
// EvtFormatMessageOpcode - Format the message string of the task specified in the event.
EvtFormatMessageOpcode
// EvtFormatMessageKeyword - Format the message string of the keywords specified in the event. If the
// evtFormatMessageEvent - Format the event's message string.
evtFormatMessageEvent evtFormatMessageFlag = iota + 1
// evtFormatMessageLevel - Format the message string of the level specified in the event.
evtFormatMessageLevel
// evtFormatMessageTask - Format the message string of the task specified in the event.
evtFormatMessageTask
// evtFormatMessageOpcode - Format the message string of the task specified in the event.
evtFormatMessageOpcode
// 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 null-terminated strings.
// Increment through the strings until your pointer points past the end of the used buffer.
EvtFormatMessageKeyword
evtFormatMessageKeyword
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
// errnoErr returns common boxed Errno values, to prevent allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return nil
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
case errnoErrorIOPending:
return errErrorIOPending
}
return e
@ -77,16 +69,16 @@ var (
)
//nolint:revive //argument-limit conditionally more arguments allowed
func _EvtSubscribe(
session EvtHandle,
func evtSubscribe(
session evtHandle,
signalEvent uintptr,
channelPath *uint16,
query *uint16,
bookmark EvtHandle,
bookmark evtHandle,
context uintptr,
callback syscall.Handle,
flags EvtSubscribeFlag,
) (EvtHandle, error) {
flags evtSubscribeFlag,
) (evtHandle, error) {
r0, _, e1 := syscall.SyscallN(
procEvtSubscribe.Addr(),
uintptr(session),
@ -100,7 +92,7 @@ func _EvtSubscribe(
)
var err error
handle := EvtHandle(r0)
handle := evtHandle(r0)
if handle == 0 {
if e1 != 0 {
err = errnoErr(e1)
@ -112,10 +104,10 @@ func _EvtSubscribe(
}
//nolint:revive //argument-limit conditionally more arguments allowed
func _EvtRender(
context EvtHandle,
fragment EvtHandle,
flags EvtRenderFlag,
func evtRender(
context evtHandle,
fragment evtHandle,
flags evtRenderFlag,
bufferSize uint32,
buffer *byte,
bufferUsed *uint32,
@ -143,7 +135,7 @@ func _EvtRender(
return err
}
func _EvtClose(object EvtHandle) error {
func evtClose(object evtHandle) error {
r1, _, e1 := syscall.SyscallN(procEvtClose.Addr(), uintptr(object))
var err error
if r1 == 0 {
@ -156,7 +148,7 @@ func _EvtClose(object EvtHandle) error {
return err
}
func _EvtNext(resultSet EvtHandle, eventArraySize uint32, eventArray *EvtHandle, timeout, flags uint32, numReturned *uint32) error {
func evtNext(resultSet evtHandle, eventArraySize uint32, eventArray *evtHandle, timeout, flags uint32, numReturned *uint32) error {
r1, _, e1 := syscall.SyscallN(
procEvtNext.Addr(),
uintptr(resultSet),
@ -179,13 +171,13 @@ func _EvtNext(resultSet EvtHandle, eventArraySize uint32, eventArray *EvtHandle,
}
//nolint:revive //argument-limit conditionally more arguments allowed
func _EvtFormatMessage(
publisherMetadata EvtHandle,
event EvtHandle,
func evtFormatMessage(
publisherMetadata evtHandle,
event evtHandle,
messageID uint32,
valueCount uint32,
values uintptr,
flags EvtFormatMessageFlag,
flags evtFormatMessageFlag,
bufferSize uint32,
buffer *byte,
bufferUsed *uint32,
@ -214,7 +206,7 @@ func _EvtFormatMessage(
return err
}
func _EvtOpenPublisherMetadata(session EvtHandle, publisherIdentity, logFilePath *uint16, locale, flags uint32) (EvtHandle, error) {
func evtOpenPublisherMetadata(session evtHandle, publisherIdentity, logFilePath *uint16, locale, flags uint32) (evtHandle, error) {
r0, _, e1 := syscall.SyscallN(
procEvtOpenPublisherMetadata.Addr(),
uintptr(session),
@ -225,7 +217,7 @@ func _EvtOpenPublisherMetadata(session EvtHandle, publisherIdentity, logFilePath
)
var err error
handle := EvtHandle(r0)
handle := evtHandle(r0)
if handle == 0 {
if e1 != 0 {
err = errnoErr(e1)
@ -236,10 +228,10 @@ func _EvtOpenPublisherMetadata(session EvtHandle, publisherIdentity, logFilePath
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
r0, _, e1 := syscall.SyscallN(procEvtCreateBookmark.Addr(), uintptr(unsafe.Pointer(bookmarkXML)))
handle := EvtHandle(r0)
handle := evtHandle(r0)
if handle != 0 {
return handle, nil
}
@ -249,7 +241,7 @@ func _EvtCreateBookmark(bookmarkXML *uint16) (EvtHandle, error) {
return handle, syscall.EINVAL
}
func _EvtUpdateBookmark(bookmark, event EvtHandle) error {
func evtUpdateBookmark(bookmark, event evtHandle) error {
r0, _, e1 := syscall.SyscallN(procEvtUpdateBookmark.Addr(), uintptr(bookmark), uintptr(event))
if r0 != 0 {
return nil

View File

@ -44,215 +44,214 @@ import (
// Error codes
const (
ErrorSuccess = 0
ErrorFailure = 1
ErrorInvalidFunction = 1
EpochDifferenceMicros int64 = 11644473600000000
errorSuccess = 0
errorFailure = 1
errorInvalidFunction = 1
epochDifferenceMicros int64 = 11644473600000000
)
type (
HANDLE uintptr
handle uintptr
)
// PDH error codes, which can be returned by all Pdh* functions. Taken from mingw-w64 pdhmsg.h
const (
PdhCstatusValidData = 0x00000000 // The returned data is valid.
PdhCstatusNewData = 0x00000001 // The return data value is valid and different from the last sample.
PdhCstatusNoMachine = 0x800007D0 // Unable to connect to the specified computer, or the computer is offline.
PdhCstatusNoInstance = 0x800007D1
PdhMoreData = 0x800007D2 // The PdhGetFormattedCounterArray* function can return this if there's 'more data to be displayed'.
PdhCstatusItemNotValidated = 0x800007D3
PdhRetry = 0x800007D4
PdhNoData = 0x800007D5 // The query does not currently contain any counters (for example, limited access)
PdhCalcNegativeDenominator = 0x800007D6
PdhCalcNegativeTimebase = 0x800007D7
PdhCalcNegativeValue = 0x800007D8
PdhDialogCancelled = 0x800007D9
PdhEndOfLogFile = 0x800007DA
PdhAsyncQueryTimeout = 0x800007DB
PdhCannotSetDefaultRealtimeDatasource = 0x800007DC
PdhCstatusNoObject = 0xC0000BB8
PdhCstatusNoCounter = 0xC0000BB9 // The specified counter could not be found.
PdhCstatusInvalidData = 0xC0000BBA // The counter was successfully found, but the data returned is not valid.
PdhMemoryAllocationFailure = 0xC0000BBB
PdhInvalidHandle = 0xC0000BBC
PdhInvalidArgument = 0xC0000BBD // Required argument is missing or incorrect.
PdhFunctionNotFound = 0xC0000BBE
PdhCstatusNoCountername = 0xC0000BBF
PdhCstatusBadCountername = 0xC0000BC0 // Unable to parse the counter path. Check the format and syntax of the specified path.
PdhInvalidBuffer = 0xC0000BC1
PdhInsufficientBuffer = 0xC0000BC2
PdhCannotConnectMachine = 0xC0000BC3
PdhInvalidPath = 0xC0000BC4
PdhInvalidInstance = 0xC0000BC5
PdhInvalidData = 0xC0000BC6 // specified counter does not contain valid data or a successful status code.
PdhNoDialogData = 0xC0000BC7
PdhCannotReadNameStrings = 0xC0000BC8
PdhLogFileCreateError = 0xC0000BC9
PdhLogFileOpenError = 0xC0000BCA
PdhLogTypeNotFound = 0xC0000BCB
PdhNoMoreData = 0xC0000BCC
PdhEntryNotInLogFile = 0xC0000BCD
PdhDataSourceIsLogFile = 0xC0000BCE
PdhDataSourceIsRealTime = 0xC0000BCF
PdhUnableReadLogHeader = 0xC0000BD0
PdhFileNotFound = 0xC0000BD1
PdhFileAlreadyExists = 0xC0000BD2
PdhNotImplemented = 0xC0000BD3
PdhStringNotFound = 0xC0000BD4
PdhUnableMapNameFiles = 0x80000BD5
PdhUnknownLogFormat = 0xC0000BD6
PdhUnknownLogsvcCommand = 0xC0000BD7
PdhLogsvcQueryNotFound = 0xC0000BD8
PdhLogsvcNotOpened = 0xC0000BD9
PdhWbemError = 0xC0000BDA
PdhAccessDenied = 0xC0000BDB
PdhLogFileTooSmall = 0xC0000BDC
PdhInvalidDatasource = 0xC0000BDD
PdhInvalidSqldb = 0xC0000BDE
PdhNoCounters = 0xC0000BDF
PdhSQLAllocFailed = 0xC0000BE0
PdhSQLAllocconFailed = 0xC0000BE1
PdhSQLExecDirectFailed = 0xC0000BE2
PdhSQLFetchFailed = 0xC0000BE3
PdhSQLRowcountFailed = 0xC0000BE4
PdhSQLMoreResultsFailed = 0xC0000BE5
PdhSQLConnectFailed = 0xC0000BE6
PdhSQLBindFailed = 0xC0000BE7
PdhCannotConnectWmiServer = 0xC0000BE8
PdhPlaCollectionAlreadyRunning = 0xC0000BE9
PdhPlaErrorScheduleOverlap = 0xC0000BEA
PdhPlaCollectionNotFound = 0xC0000BEB
PdhPlaErrorScheduleElapsed = 0xC0000BEC
PdhPlaErrorNostart = 0xC0000BED
PdhPlaErrorAlreadyExists = 0xC0000BEE
PdhPlaErrorTypeMismatch = 0xC0000BEF
PdhPlaErrorFilepath = 0xC0000BF0
PdhPlaServiceError = 0xC0000BF1
PdhPlaValidationError = 0xC0000BF2
PdhPlaValidationWarning = 0x80000BF3
PdhPlaErrorNameTooLong = 0xC0000BF4
PdhInvalidSQLLogFormat = 0xC0000BF5
PdhCounterAlreadyInQuery = 0xC0000BF6
PdhBinaryLogCorrupt = 0xC0000BF7
PdhLogSampleTooSmall = 0xC0000BF8
PdhOsLaterVersion = 0xC0000BF9
PdhOsEarlierVersion = 0xC0000BFA
PdhIncorrectAppendTime = 0xC0000BFB
PdhUnmatchedAppendCounter = 0xC0000BFC
PdhSQLAlterDetailFailed = 0xC0000BFD
PdhQueryPerfDataTimeout = 0xC0000BFE
pdhCstatusValidData = 0x00000000 // The returned data is valid.
pdhCstatusNewData = 0x00000001 // The return data value is valid and different from the last sample.
pdhCstatusNoMachine = 0x800007D0 // Unable to connect to the specified computer, or the computer is offline.
pdhCstatusNoInstance = 0x800007D1
pdhMoreData = 0x800007D2 // The pdhGetFormattedCounterArray* function can return this if there's 'more data to be displayed'.
pdhCstatusItemNotValidated = 0x800007D3
pdhRetry = 0x800007D4
pdhNoData = 0x800007D5 // The query does not currently contain any counters (for example, limited access)
pdhCalcNegativeDenominator = 0x800007D6
pdhCalcNegativeTimebase = 0x800007D7
pdhCalcNegativeValue = 0x800007D8
pdhDialogCancelled = 0x800007D9
pdhEndOfLogFile = 0x800007DA
pdhAsyncQueryTimeout = 0x800007DB
pdhCannotSetDefaultRealtimeDatasource = 0x800007DC
pdhCstatusNoObject = 0xC0000BB8
pdhCstatusNoCounter = 0xC0000BB9 // The specified counter could not be found.
pdhCstatusInvalidData = 0xC0000BBA // The counter was successfully found, but the data returned is not valid.
pdhMemoryAllocationFailure = 0xC0000BBB
pdhInvalidHandle = 0xC0000BBC
pdhInvalidArgument = 0xC0000BBD // Required argument is missing or incorrect.
pdhFunctionNotFound = 0xC0000BBE
pdhCstatusNoCountername = 0xC0000BBF
pdhCstatusBadCountername = 0xC0000BC0 // Unable to parse the counter path. Check the format and syntax of the specified path.
pdhInvalidBuffer = 0xC0000BC1
pdhInsufficientBuffer = 0xC0000BC2
pdhCannotConnectMachine = 0xC0000BC3
pdhInvalidPath = 0xC0000BC4
pdhInvalidInstance = 0xC0000BC5
pdhInvalidData = 0xC0000BC6 // specified counter does not contain valid data or a successful status code.
pdhNoDialogData = 0xC0000BC7
pdhCannotReadNameStrings = 0xC0000BC8
pdhLogFileCreateError = 0xC0000BC9
pdhLogFileOpenError = 0xC0000BCA
pdhLogTypeNotFound = 0xC0000BCB
pdhNoMoreData = 0xC0000BCC
pdhEntryNotInLogFile = 0xC0000BCD
pdhDataSourceIsLogFile = 0xC0000BCE
pdhDataSourceIsRealTime = 0xC0000BCF
pdhUnableReadLogHeader = 0xC0000BD0
pdhFileNotFound = 0xC0000BD1
pdhFileAlreadyExists = 0xC0000BD2
pdhNotImplemented = 0xC0000BD3
pdhStringNotFound = 0xC0000BD4
pdhUnableMapNameFiles = 0x80000BD5
pdhUnknownLogFormat = 0xC0000BD6
pdhUnknownLogsvcCommand = 0xC0000BD7
pdhLogsvcQueryNotFound = 0xC0000BD8
pdhLogsvcNotOpened = 0xC0000BD9
pdhWbemError = 0xC0000BDA
pdhAccessDenied = 0xC0000BDB
pdhLogFileTooSmall = 0xC0000BDC
pdhInvalidDatasource = 0xC0000BDD
pdhInvalidSqldb = 0xC0000BDE
pdhNoCounters = 0xC0000BDF
pdhSQLAllocFailed = 0xC0000BE0
pdhSQLAllocconFailed = 0xC0000BE1
pdhSQLExecDirectFailed = 0xC0000BE2
pdhSQLFetchFailed = 0xC0000BE3
pdhSQLRowcountFailed = 0xC0000BE4
pdhSQLMoreResultsFailed = 0xC0000BE5
pdhSQLConnectFailed = 0xC0000BE6
pdhSQLBindFailed = 0xC0000BE7
pdhCannotConnectWmiServer = 0xC0000BE8
pdhPlaCollectionAlreadyRunning = 0xC0000BE9
pdhPlaErrorScheduleOverlap = 0xC0000BEA
pdhPlaCollectionNotFound = 0xC0000BEB
pdhPlaErrorScheduleElapsed = 0xC0000BEC
pdhPlaErrorNostart = 0xC0000BED
pdhPlaErrorAlreadyExists = 0xC0000BEE
pdhPlaErrorTypeMismatch = 0xC0000BEF
pdhPlaErrorFilepath = 0xC0000BF0
pdhPlaServiceError = 0xC0000BF1
pdhPlaValidationError = 0xC0000BF2
pdhPlaValidationWarning = 0x80000BF3
pdhPlaErrorNameTooLong = 0xC0000BF4
pdhInvalidSQLLogFormat = 0xC0000BF5
pdhCounterAlreadyInQuery = 0xC0000BF6
pdhBinaryLogCorrupt = 0xC0000BF7
pdhLogSampleTooSmall = 0xC0000BF8
pdhOsLaterVersion = 0xC0000BF9
pdhOsEarlierVersion = 0xC0000BFA
pdhIncorrectAppendTime = 0xC0000BFB
pdhUnmatchedAppendCounter = 0xC0000BFC
pdhSQLAlterDetailFailed = 0xC0000BFD
pdhQueryPerfDataTimeout = 0xC0000BFE
)
var PDHErrors = map[uint32]string{
PdhCstatusValidData: "PDH_CSTATUS_VALID_DATA",
PdhCstatusNewData: "PDH_CSTATUS_NEW_DATA",
PdhCstatusNoMachine: "PDH_CSTATUS_NO_MACHINE",
PdhCstatusNoInstance: "PDH_CSTATUS_NO_INSTANCE",
PdhMoreData: "PDH_MORE_DATA",
PdhCstatusItemNotValidated: "PDH_CSTATUS_ITEM_NOT_VALIDATED",
PdhRetry: "PDH_RETRY",
PdhNoData: "PDH_NO_DATA",
PdhCalcNegativeDenominator: "PDH_CALC_NEGATIVE_DENOMINATOR",
PdhCalcNegativeTimebase: "PDH_CALC_NEGATIVE_TIMEBASE",
PdhCalcNegativeValue: "PDH_CALC_NEGATIVE_VALUE",
PdhDialogCancelled: "PDH_DIALOG_CANCELLED",
PdhEndOfLogFile: "PDH_END_OF_LOG_FILE",
PdhAsyncQueryTimeout: "PDH_ASYNC_QUERY_TIMEOUT",
PdhCannotSetDefaultRealtimeDatasource: "PDH_CANNOT_SET_DEFAULT_REALTIME_DATASOURCE",
PdhCstatusNoObject: "PDH_CSTATUS_NO_OBJECT",
PdhCstatusNoCounter: "PDH_CSTATUS_NO_COUNTER",
PdhCstatusInvalidData: "PDH_CSTATUS_INVALID_DATA",
PdhMemoryAllocationFailure: "PDH_MEMORY_ALLOCATION_FAILURE",
PdhInvalidHandle: "PDH_INVALID_HANDLE",
PdhInvalidArgument: "PDH_INVALID_ARGUMENT",
PdhFunctionNotFound: "PDH_FUNCTION_NOT_FOUND",
PdhCstatusNoCountername: "PDH_CSTATUS_NO_COUNTERNAME",
PdhCstatusBadCountername: "PDH_CSTATUS_BAD_COUNTERNAME",
PdhInvalidBuffer: "PDH_INVALID_BUFFER",
PdhInsufficientBuffer: "PDH_INSUFFICIENT_BUFFER",
PdhCannotConnectMachine: "PDH_CANNOT_CONNECT_MACHINE",
PdhInvalidPath: "PDH_INVALID_PATH",
PdhInvalidInstance: "PDH_INVALID_INSTANCE",
PdhInvalidData: "PDH_INVALID_DATA",
PdhNoDialogData: "PDH_NO_DIALOG_DATA",
PdhCannotReadNameStrings: "PDH_CANNOT_READ_NAME_STRINGS",
PdhLogFileCreateError: "PDH_LOG_FILE_CREATE_ERROR",
PdhLogFileOpenError: "PDH_LOG_FILE_OPEN_ERROR",
PdhLogTypeNotFound: "PDH_LOG_TYPE_NOT_FOUND",
PdhNoMoreData: "PDH_NO_MORE_DATA",
PdhEntryNotInLogFile: "PDH_ENTRY_NOT_IN_LOG_FILE",
PdhDataSourceIsLogFile: "PDH_DATA_SOURCE_IS_LOG_FILE",
PdhDataSourceIsRealTime: "PDH_DATA_SOURCE_IS_REAL_TIME",
PdhUnableReadLogHeader: "PDH_UNABLE_READ_LOG_HEADER",
PdhFileNotFound: "PDH_FILE_NOT_FOUND",
PdhFileAlreadyExists: "PDH_FILE_ALREADY_EXISTS",
PdhNotImplemented: "PDH_NOT_IMPLEMENTED",
PdhStringNotFound: "PDH_STRING_NOT_FOUND",
PdhUnableMapNameFiles: "PDH_UNABLE_MAP_NAME_FILES",
PdhUnknownLogFormat: "PDH_UNKNOWN_LOG_FORMAT",
PdhUnknownLogsvcCommand: "PDH_UNKNOWN_LOGSVC_COMMAND",
PdhLogsvcQueryNotFound: "PDH_LOGSVC_QUERY_NOT_FOUND",
PdhLogsvcNotOpened: "PDH_LOGSVC_NOT_OPENED",
PdhWbemError: "PDH_WBEM_ERROR",
PdhAccessDenied: "PDH_ACCESS_DENIED",
PdhLogFileTooSmall: "PDH_LOG_FILE_TOO_SMALL",
PdhInvalidDatasource: "PDH_INVALID_DATASOURCE",
PdhInvalidSqldb: "PDH_INVALID_SQLDB",
PdhNoCounters: "PDH_NO_COUNTERS",
PdhSQLAllocFailed: "PDH_SQL_ALLOC_FAILED",
PdhSQLAllocconFailed: "PDH_SQL_ALLOCCON_FAILED",
PdhSQLExecDirectFailed: "PDH_SQL_EXEC_DIRECT_FAILED",
PdhSQLFetchFailed: "PDH_SQL_FETCH_FAILED",
PdhSQLRowcountFailed: "PDH_SQL_ROWCOUNT_FAILED",
PdhSQLMoreResultsFailed: "PDH_SQL_MORE_RESULTS_FAILED",
PdhSQLConnectFailed: "PDH_SQL_CONNECT_FAILED",
PdhSQLBindFailed: "PDH_SQL_BIND_FAILED",
PdhCannotConnectWmiServer: "PDH_CANNOT_CONNECT_WMI_SERVER",
PdhPlaCollectionAlreadyRunning: "PDH_PLA_COLLECTION_ALREADY_RUNNING",
PdhPlaErrorScheduleOverlap: "PDH_PLA_ERROR_SCHEDULE_OVERLAP",
PdhPlaCollectionNotFound: "PDH_PLA_COLLECTION_NOT_FOUND",
PdhPlaErrorScheduleElapsed: "PDH_PLA_ERROR_SCHEDULE_ELAPSED",
PdhPlaErrorNostart: "PDH_PLA_ERROR_NOSTART",
PdhPlaErrorAlreadyExists: "PDH_PLA_ERROR_ALREADY_EXISTS",
PdhPlaErrorTypeMismatch: "PDH_PLA_ERROR_TYPE_MISMATCH",
PdhPlaErrorFilepath: "PDH_PLA_ERROR_FILEPATH",
PdhPlaServiceError: "PDH_PLA_SERVICE_ERROR",
PdhPlaValidationError: "PDH_PLA_VALIDATION_ERROR",
PdhPlaValidationWarning: "PDH_PLA_VALIDATION_WARNING",
PdhPlaErrorNameTooLong: "PDH_PLA_ERROR_NAME_TOO_LONG",
PdhInvalidSQLLogFormat: "PDH_INVALID_SQL_LOG_FORMAT",
PdhCounterAlreadyInQuery: "PDH_COUNTER_ALREADY_IN_QUERY",
PdhBinaryLogCorrupt: "PDH_BINARY_LOG_CORRUPT",
PdhLogSampleTooSmall: "PDH_LOG_SAMPLE_TOO_SMALL",
PdhOsLaterVersion: "PDH_OS_LATER_VERSION",
PdhOsEarlierVersion: "PDH_OS_EARLIER_VERSION",
PdhIncorrectAppendTime: "PDH_INCORRECT_APPEND_TIME",
PdhUnmatchedAppendCounter: "PDH_UNMATCHED_APPEND_COUNTER",
PdhSQLAlterDetailFailed: "PDH_SQL_ALTER_DETAIL_FAILED",
PdhQueryPerfDataTimeout: "PDH_QUERY_PERF_DATA_TIMEOUT",
var pdhErrors = map[uint32]string{
pdhCstatusValidData: "PDH_CSTATUS_VALID_DATA",
pdhCstatusNewData: "PDH_CSTATUS_NEW_DATA",
pdhCstatusNoMachine: "PDH_CSTATUS_NO_MACHINE",
pdhCstatusNoInstance: "PDH_CSTATUS_NO_INSTANCE",
pdhMoreData: "PDH_MORE_DATA",
pdhCstatusItemNotValidated: "PDH_CSTATUS_ITEM_NOT_VALIDATED",
pdhRetry: "PDH_RETRY",
pdhNoData: "PDH_NO_DATA",
pdhCalcNegativeDenominator: "PDH_CALC_NEGATIVE_DENOMINATOR",
pdhCalcNegativeTimebase: "PDH_CALC_NEGATIVE_TIMEBASE",
pdhCalcNegativeValue: "PDH_CALC_NEGATIVE_VALUE",
pdhDialogCancelled: "PDH_DIALOG_CANCELLED",
pdhEndOfLogFile: "PDH_END_OF_LOG_FILE",
pdhAsyncQueryTimeout: "PDH_ASYNC_QUERY_TIMEOUT",
pdhCannotSetDefaultRealtimeDatasource: "PDH_CANNOT_SET_DEFAULT_REALTIME_DATASOURCE",
pdhCstatusNoObject: "PDH_CSTATUS_NO_OBJECT",
pdhCstatusNoCounter: "PDH_CSTATUS_NO_COUNTER",
pdhCstatusInvalidData: "PDH_CSTATUS_INVALID_DATA",
pdhMemoryAllocationFailure: "PDH_MEMORY_ALLOCATION_FAILURE",
pdhInvalidHandle: "PDH_INVALID_HANDLE",
pdhInvalidArgument: "PDH_INVALID_ARGUMENT",
pdhFunctionNotFound: "PDH_FUNCTION_NOT_FOUND",
pdhCstatusNoCountername: "PDH_CSTATUS_NO_COUNTERNAME",
pdhCstatusBadCountername: "PDH_CSTATUS_BAD_COUNTERNAME",
pdhInvalidBuffer: "PDH_INVALID_BUFFER",
pdhInsufficientBuffer: "PDH_INSUFFICIENT_BUFFER",
pdhCannotConnectMachine: "PDH_CANNOT_CONNECT_MACHINE",
pdhInvalidPath: "PDH_INVALID_PATH",
pdhInvalidInstance: "PDH_INVALID_INSTANCE",
pdhInvalidData: "PDH_INVALID_DATA",
pdhNoDialogData: "PDH_NO_DIALOG_DATA",
pdhCannotReadNameStrings: "PDH_CANNOT_READ_NAME_STRINGS",
pdhLogFileCreateError: "PDH_LOG_FILE_CREATE_ERROR",
pdhLogFileOpenError: "PDH_LOG_FILE_OPEN_ERROR",
pdhLogTypeNotFound: "PDH_LOG_TYPE_NOT_FOUND",
pdhNoMoreData: "PDH_NO_MORE_DATA",
pdhEntryNotInLogFile: "PDH_ENTRY_NOT_IN_LOG_FILE",
pdhDataSourceIsLogFile: "PDH_DATA_SOURCE_IS_LOG_FILE",
pdhDataSourceIsRealTime: "PDH_DATA_SOURCE_IS_REAL_TIME",
pdhUnableReadLogHeader: "PDH_UNABLE_READ_LOG_HEADER",
pdhFileNotFound: "PDH_FILE_NOT_FOUND",
pdhFileAlreadyExists: "PDH_FILE_ALREADY_EXISTS",
pdhNotImplemented: "PDH_NOT_IMPLEMENTED",
pdhStringNotFound: "PDH_STRING_NOT_FOUND",
pdhUnableMapNameFiles: "PDH_UNABLE_MAP_NAME_FILES",
pdhUnknownLogFormat: "PDH_UNKNOWN_LOG_FORMAT",
pdhUnknownLogsvcCommand: "PDH_UNKNOWN_LOGSVC_COMMAND",
pdhLogsvcQueryNotFound: "PDH_LOGSVC_QUERY_NOT_FOUND",
pdhLogsvcNotOpened: "PDH_LOGSVC_NOT_OPENED",
pdhWbemError: "PDH_WBEM_ERROR",
pdhAccessDenied: "PDH_ACCESS_DENIED",
pdhLogFileTooSmall: "PDH_LOG_FILE_TOO_SMALL",
pdhInvalidDatasource: "PDH_INVALID_DATASOURCE",
pdhInvalidSqldb: "PDH_INVALID_SQLDB",
pdhNoCounters: "PDH_NO_COUNTERS",
pdhSQLAllocFailed: "PDH_SQL_ALLOC_FAILED",
pdhSQLAllocconFailed: "PDH_SQL_ALLOCCON_FAILED",
pdhSQLExecDirectFailed: "PDH_SQL_EXEC_DIRECT_FAILED",
pdhSQLFetchFailed: "PDH_SQL_FETCH_FAILED",
pdhSQLRowcountFailed: "PDH_SQL_ROWCOUNT_FAILED",
pdhSQLMoreResultsFailed: "PDH_SQL_MORE_RESULTS_FAILED",
pdhSQLConnectFailed: "PDH_SQL_CONNECT_FAILED",
pdhSQLBindFailed: "PDH_SQL_BIND_FAILED",
pdhCannotConnectWmiServer: "PDH_CANNOT_CONNECT_WMI_SERVER",
pdhPlaCollectionAlreadyRunning: "PDH_PLA_COLLECTION_ALREADY_RUNNING",
pdhPlaErrorScheduleOverlap: "PDH_PLA_ERROR_SCHEDULE_OVERLAP",
pdhPlaCollectionNotFound: "PDH_PLA_COLLECTION_NOT_FOUND",
pdhPlaErrorScheduleElapsed: "PDH_PLA_ERROR_SCHEDULE_ELAPSED",
pdhPlaErrorNostart: "PDH_PLA_ERROR_NOSTART",
pdhPlaErrorAlreadyExists: "PDH_PLA_ERROR_ALREADY_EXISTS",
pdhPlaErrorTypeMismatch: "PDH_PLA_ERROR_TYPE_MISMATCH",
pdhPlaErrorFilepath: "PDH_PLA_ERROR_FILEPATH",
pdhPlaServiceError: "PDH_PLA_SERVICE_ERROR",
pdhPlaValidationError: "PDH_PLA_VALIDATION_ERROR",
pdhPlaValidationWarning: "PDH_PLA_VALIDATION_WARNING",
pdhPlaErrorNameTooLong: "PDH_PLA_ERROR_NAME_TOO_LONG",
pdhInvalidSQLLogFormat: "PDH_INVALID_SQL_LOG_FORMAT",
pdhCounterAlreadyInQuery: "PDH_COUNTER_ALREADY_IN_QUERY",
pdhBinaryLogCorrupt: "PDH_BINARY_LOG_CORRUPT",
pdhLogSampleTooSmall: "PDH_LOG_SAMPLE_TOO_SMALL",
pdhOsLaterVersion: "PDH_OS_LATER_VERSION",
pdhOsEarlierVersion: "PDH_OS_EARLIER_VERSION",
pdhIncorrectAppendTime: "PDH_INCORRECT_APPEND_TIME",
pdhUnmatchedAppendCounter: "PDH_UNMATCHED_APPEND_COUNTER",
pdhSQLAlterDetailFailed: "PDH_SQL_ALTER_DETAIL_FAILED",
pdhQueryPerfDataTimeout: "PDH_QUERY_PERF_DATA_TIMEOUT",
}
// Formatting options for GetFormattedCounterValue().
const (
PdhFmtRaw = 0x00000010
PdhFmtAnsi = 0x00000020
PdhFmtUnicode = 0x00000040
PdhFmtLong = 0x00000100 // Return data as a long int.
PdhFmtDouble = 0x00000200 // Return data as a double precision floating point real.
PdhFmtLarge = 0x00000400 // Return data as a 64 bit integer.
PdhFmtNoscale = 0x00001000 // can be OR-ed: Do not apply the counter's default scaling factor.
PdhFmt1000 = 0x00002000 // can be OR-ed: multiply the actual value by 1,000.
PdhFmtNodata = 0x00004000 // can be OR-ed: unknown what this is for, MSDN says nothing.
PdhFmtNocap100 = 0x00008000 // can be OR-ed: do not cap values > 100.
PerfDetailCostly = 0x00010000
PerfDetailStandard = 0x0000FFFF
pdhFmtRaw = 0x00000010
pdhFmtAnsi = 0x00000020
pdhFmtUnicode = 0x00000040
pdhFmtLong = 0x00000100 // Return data as a long int.
pdhFmtDouble = 0x00000200 // Return data as a double precision floating point real.
pdhFmtLarge = 0x00000400 // Return data as a 64 bit integer.
pdhFmtNoscale = 0x00001000 // can be OR-ed: Do not apply the counter's default scaling factor.
pdhFmt1000 = 0x00002000 // can be OR-ed: multiply the actual value by 1,000.
pdhFmtNodata = 0x00004000 // can be OR-ed: unknown what this is for, MSDN says nothing.
pdhFmtNocap100 = 0x00008000 // can be OR-ed: do not cap values > 100.
perfDetailCostly = 0x00010000
perfDetailStandard = 0x0000FFFF
)
type (
pdhQueryHandle HANDLE // query handle
pdhCounterHandle HANDLE // counter handle
pdhQueryHandle handle // query handle
pdhCounterHandle handle // counter handle
)
var (
@ -260,19 +259,18 @@ var (
libPdhDll *syscall.DLL
// Functions
pdhAddCounterW *syscall.Proc
pdhAddEnglishCounterW *syscall.Proc
pdhCloseQuery *syscall.Proc
pdhCollectQueryData *syscall.Proc
pdhCollectQueryDataWithTime *syscall.Proc
pdhGetFormattedCounterValue *syscall.Proc
pdhGetFormattedCounterArrayW *syscall.Proc
pdhOpenQuery *syscall.Proc
pdhValidatePathW *syscall.Proc
pdhExpandWildCardPathW *syscall.Proc
pdhGetCounterInfoW *syscall.Proc
pdhGetRawCounterValue *syscall.Proc
pdhGetRawCounterArrayW *syscall.Proc
pdhAddCounterWProc *syscall.Proc
pdhAddEnglishCounterWProc *syscall.Proc
pdhCloseQueryProc *syscall.Proc
pdhCollectQueryDataProc *syscall.Proc
pdhCollectQueryDataWithTimeProc *syscall.Proc
pdhGetFormattedCounterValueProc *syscall.Proc
pdhGetFormattedCounterArrayWProc *syscall.Proc
pdhOpenQueryProc *syscall.Proc
pdhExpandWildCardPathWProc *syscall.Proc
pdhGetCounterInfoWProc *syscall.Proc
pdhGetRawCounterValueProc *syscall.Proc
pdhGetRawCounterArrayWProc *syscall.Proc
)
func init() {
@ -280,26 +278,25 @@ func init() {
libPdhDll = syscall.MustLoadDLL("pdh.dll")
// Functions
pdhAddCounterW = libPdhDll.MustFindProc("PdhAddCounterW")
pdhAddEnglishCounterW, _ = libPdhDll.FindProc("PdhAddEnglishCounterW") // XXX: only supported on versions > Vista.
pdhCloseQuery = libPdhDll.MustFindProc("PdhCloseQuery")
pdhCollectQueryData = libPdhDll.MustFindProc("PdhCollectQueryData")
pdhCollectQueryDataWithTime, _ = libPdhDll.FindProc("PdhCollectQueryDataWithTime")
pdhGetFormattedCounterValue = libPdhDll.MustFindProc("PdhGetFormattedCounterValue")
pdhGetFormattedCounterArrayW = libPdhDll.MustFindProc("PdhGetFormattedCounterArrayW")
pdhOpenQuery = libPdhDll.MustFindProc("PdhOpenQuery")
pdhValidatePathW = libPdhDll.MustFindProc("PdhValidatePathW")
pdhExpandWildCardPathW = libPdhDll.MustFindProc("PdhExpandWildCardPathW")
pdhGetCounterInfoW = libPdhDll.MustFindProc("PdhGetCounterInfoW")
pdhGetRawCounterValue = libPdhDll.MustFindProc("PdhGetRawCounterValue")
pdhGetRawCounterArrayW = libPdhDll.MustFindProc("PdhGetRawCounterArrayW")
pdhAddCounterWProc = libPdhDll.MustFindProc("PdhAddCounterW")
pdhAddEnglishCounterWProc, _ = libPdhDll.FindProc("PdhAddEnglishCounterW") // XXX: only supported on versions > Vista.
pdhCloseQueryProc = libPdhDll.MustFindProc("PdhCloseQuery")
pdhCollectQueryDataProc = libPdhDll.MustFindProc("PdhCollectQueryData")
pdhCollectQueryDataWithTimeProc, _ = libPdhDll.FindProc("PdhCollectQueryDataWithTime")
pdhGetFormattedCounterValueProc = libPdhDll.MustFindProc("PdhGetFormattedCounterValue")
pdhGetFormattedCounterArrayWProc = libPdhDll.MustFindProc("PdhGetFormattedCounterArrayW")
pdhOpenQueryProc = libPdhDll.MustFindProc("PdhOpenQuery")
pdhExpandWildCardPathWProc = libPdhDll.MustFindProc("PdhExpandWildCardPathW")
pdhGetCounterInfoWProc = libPdhDll.MustFindProc("PdhGetCounterInfoW")
pdhGetRawCounterValueProc = libPdhDll.MustFindProc("PdhGetRawCounterValue")
pdhGetRawCounterArrayWProc = libPdhDll.MustFindProc("PdhGetRawCounterArrayW")
}
// PdhAddCounter adds the specified counter to the query. This is the internationalized version. Preferably, use the
// function PdhAddEnglishCounter instead. hQuery is the query handle, which has been fetched by PdhOpenQuery.
// pdhAddCounter adds the specified counter to the query. This is the internationalized version. Preferably, use the
// function pdhAddEnglishCounter instead. hQuery is the query handle, which has been fetched by pdhOpenQuery.
// szFullCounterPath is a full, internationalized counter path (this will differ per Windows language version).
// dwUserData is a 'user-defined value', which becomes part of the counter information. To retrieve this value
// later, call PdhGetCounterInfo() and access dwQueryUserData of the pdhCounterInfo structure.
// later, call pdhGetCounterInfo() and access dwQueryUserData of the pdhCounterInfo structure.
//
// Examples of szFullCounterPath (in an English version of Windows):
//
@ -333,9 +330,9 @@ func init() {
// The typeperf command may also be pretty easy. To find all performance counters, simply execute:
//
// typeperf -qx
func PdhAddCounter(hQuery pdhQueryHandle, szFullCounterPath string, dwUserData uintptr, phCounter *pdhCounterHandle) uint32 {
func pdhAddCounter(hQuery pdhQueryHandle, szFullCounterPath string, dwUserData uintptr, phCounter *pdhCounterHandle) uint32 {
ptxt, _ := syscall.UTF16PtrFromString(szFullCounterPath)
ret, _, _ := pdhAddCounterW.Call(
ret, _, _ := pdhAddCounterWProc.Call(
uintptr(hQuery),
uintptr(unsafe.Pointer(ptxt)), //nolint:gosec // G103: Valid use of unsafe call to pass ptxt
dwUserData,
@ -344,21 +341,21 @@ func PdhAddCounter(hQuery pdhQueryHandle, szFullCounterPath string, dwUserData u
return uint32(ret)
}
// PdhAddEnglishCounterSupported returns true if PdhAddEnglishCounterW Win API function was found in pdh.dll.
// pdhAddEnglishCounterSupported returns true if PdhAddEnglishCounterW Win API function was found in pdh.dll.
// PdhAddEnglishCounterW function is not supported on pre-Windows Vista systems
func PdhAddEnglishCounterSupported() bool {
return pdhAddEnglishCounterW != nil
func pdhAddEnglishCounterSupported() bool {
return pdhAddEnglishCounterWProc != nil
}
// PdhAddEnglishCounter adds the specified language-neutral counter to the query. See the PdhAddCounter function. This function only exists on
// pdhAddEnglishCounter adds the specified language-neutral counter to the query. See the pdhAddCounter function. This function only exists on
// Windows versions higher than Vista.
func PdhAddEnglishCounter(hQuery pdhQueryHandle, szFullCounterPath string, dwUserData uintptr, phCounter *pdhCounterHandle) uint32 {
if pdhAddEnglishCounterW == nil {
return ErrorInvalidFunction
func pdhAddEnglishCounter(hQuery pdhQueryHandle, szFullCounterPath string, dwUserData uintptr, phCounter *pdhCounterHandle) uint32 {
if pdhAddEnglishCounterWProc == nil {
return errorInvalidFunction
}
ptxt, _ := syscall.UTF16PtrFromString(szFullCounterPath)
ret, _, _ := pdhAddEnglishCounterW.Call(
ret, _, _ := pdhAddEnglishCounterWProc.Call(
uintptr(hQuery),
uintptr(unsafe.Pointer(ptxt)), //nolint:gosec // G103: Valid use of unsafe call to pass ptxt
dwUserData,
@ -367,85 +364,85 @@ func PdhAddEnglishCounter(hQuery pdhQueryHandle, szFullCounterPath string, dwUse
return uint32(ret)
}
// PdhCloseQuery closes all counters contained in the specified query, closes all handles related to the query,
// pdhCloseQuery closes all counters contained in the specified query, closes all handles related to the query,
// and frees all memory associated with the query.
func PdhCloseQuery(hQuery pdhQueryHandle) uint32 {
ret, _, _ := pdhCloseQuery.Call(uintptr(hQuery))
func pdhCloseQuery(hQuery pdhQueryHandle) uint32 {
ret, _, _ := pdhCloseQueryProc.Call(uintptr(hQuery))
return uint32(ret)
}
// PdhCollectQueryData 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
// of the counter can be extracted with PdhGetFormattedCounterValue(). For example, the following code
// requires at least two calls:
//
// var handle win.PDH_HQUERY
// var counterHandle win.PDH_HCOUNTER
// ret := win.PdhOpenQuery(0, 0, &handle)
// ret = win.PdhAddEnglishCounter(handle, "\\Processor(_Total)\\% Idle Time", 0, &counterHandle)
// ret := win.pdhOpenQuery(0, 0, &handle)
// ret = win.pdhAddEnglishCounter(handle, "\\Processor(_Total)\\% Idle Time", 0, &counterHandle)
// var derp win.PDH_FMT_COUNTERVALUE_DOUBLE
//
// ret = win.PdhCollectQueryData(handle)
// ret = win.pdhCollectQueryData(handle)
// fmt.Printf("Collect return code is %x\n", ret) // return code will be PDH_CSTATUS_INVALID_DATA
// ret = win.PdhGetFormattedCounterValueDouble(counterHandle, 0, &derp)
// ret = win.pdhGetFormattedCounterValueDouble(counterHandle, 0, &derp)
//
// ret = win.PdhCollectQueryData(handle)
// ret = win.pdhCollectQueryData(handle)
// fmt.Printf("Collect return code is %x\n", ret) // return code will be ERROR_SUCCESS
// ret = win.PdhGetFormattedCounterValueDouble(counterHandle, 0, &derp)
// ret = win.pdhGetFormattedCounterValueDouble(counterHandle, 0, &derp)
//
// The PdhCollectQueryData will return an error in the first call because it needs two values for
// The pdhCollectQueryData will return an error in the first call because it needs two values for
// displaying the correct data for the processor idle time. The second call will have a 0 return code.
func PdhCollectQueryData(hQuery pdhQueryHandle) uint32 {
ret, _, _ := pdhCollectQueryData.Call(uintptr(hQuery))
func pdhCollectQueryData(hQuery pdhQueryHandle) uint32 {
ret, _, _ := pdhCollectQueryDataProc.Call(uintptr(hQuery))
return uint32(ret)
}
// PdhCollectQueryDataWithTime queries data from perfmon, retrieving the device/windows timestamp from the node it was collected on.
// pdhCollectQueryDataWithTime queries data from perfmon, retrieving the device/windows timestamp from the node it was collected on.
// Converts the filetime structure to a GO time class and returns the native time.
func PdhCollectQueryDataWithTime(hQuery pdhQueryHandle) (uint32, time.Time) {
func pdhCollectQueryDataWithTime(hQuery pdhQueryHandle) (uint32, time.Time) {
var localFileTime fileTime
//nolint:gosec // G103: Valid use of unsafe call to pass localFileTime
ret, _, _ := pdhCollectQueryDataWithTime.Call(uintptr(hQuery), uintptr(unsafe.Pointer(&localFileTime)))
ret, _, _ := pdhCollectQueryDataWithTimeProc.Call(uintptr(hQuery), uintptr(unsafe.Pointer(&localFileTime)))
if ret == ErrorSuccess {
if ret == errorSuccess {
var utcFileTime fileTime
ret, _, _ := kernelLocalFileTimeToFileTime.Call(
uintptr(unsafe.Pointer(&localFileTime)), //nolint:gosec // G103: Valid use of unsafe call to pass localFileTime
uintptr(unsafe.Pointer(&utcFileTime))) //nolint:gosec // G103: Valid use of unsafe call to pass utcFileTime
if ret == 0 {
return uint32(ErrorFailure), time.Now()
return uint32(errorFailure), time.Now()
}
// First convert 100-ns intervals to microseconds, then adjust for the
// epoch difference
var totalMicroSeconds int64
totalMicroSeconds = ((int64(utcFileTime.dwHighDateTime) << 32) | int64(utcFileTime.dwLowDateTime)) / 10
totalMicroSeconds -= EpochDifferenceMicros
totalMicroSeconds -= epochDifferenceMicros
retTime := time.Unix(0, totalMicroSeconds*1000)
return uint32(ErrorSuccess), retTime
return uint32(errorSuccess), retTime
}
return uint32(ret), time.Now()
}
// PdhGetFormattedCounterValueDouble formats the given hCounter using a 'double'. The result is set into the specialized union struct pValue.
// pdhGetFormattedCounterValueDouble formats the given hCounter using a 'double'. The result is set into the specialized union struct pValue.
// This function does not directly translate to a Windows counterpart due to union specialization tricks.
func PdhGetFormattedCounterValueDouble(hCounter pdhCounterHandle, lpdwType *uint32, pValue *pdhFmtCountervalueDouble) uint32 {
ret, _, _ := pdhGetFormattedCounterValue.Call(
func pdhGetFormattedCounterValueDouble(hCounter pdhCounterHandle, lpdwType *uint32, pValue *pdhFmtCountervalueDouble) uint32 {
ret, _, _ := pdhGetFormattedCounterValueProc.Call(
uintptr(hCounter),
uintptr(PdhFmtDouble|PdhFmtNocap100),
uintptr(pdhFmtDouble|pdhFmtNocap100),
uintptr(unsafe.Pointer(lpdwType)), //nolint:gosec // G103: Valid use of unsafe call to pass lpdwType
uintptr(unsafe.Pointer(pValue))) //nolint:gosec // G103: Valid use of unsafe call to pass pValue
return uint32(ret)
}
// PdhGetFormattedCounterArrayDouble returns an array of formatted counter values. Use this function when you want to format the counter values of a
// pdhGetFormattedCounterArrayDouble returns an array of formatted counter values. Use this function when you want to format the counter values of a
// counter that contains a wildcard character for the instance name. The itemBuffer must a slice of type pdhFmtCountervalueItemDouble.
// An example of how this function can be used:
//
@ -460,15 +457,15 @@ func PdhGetFormattedCounterValueDouble(hCounter pdhCounterHandle, lpdwType *uint
//
// for {
// // collect
// ret := win.PdhCollectQueryData(queryHandle)
// ret := win.pdhCollectQueryData(queryHandle)
// if ret == win.ERROR_SUCCESS {
// ret = win.PdhGetFormattedCounterArrayDouble(counterHandle, &bufSize, &bufCount, &emptyBuf[0]) // uses null ptr here according to MSDN.
// ret = win.pdhGetFormattedCounterArrayDouble(counterHandle, &bufSize, &bufCount, &emptyBuf[0]) // uses null ptr here according to MSDN.
// if ret == win.PDH_MORE_DATA {
// filledBuf := make([]win.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE, bufCount*size)
// ret = win.PdhGetFormattedCounterArrayDouble(counterHandle, &bufSize, &bufCount, &filledBuf[0])
// ret = win.pdhGetFormattedCounterArrayDouble(counterHandle, &bufSize, &bufCount, &filledBuf[0])
// for i := 0; i < int(bufCount); i++ {
// c := filledBuf[i]
// var s string = win.UTF16PtrToString(c.SzName)
// var s string = win.utf16PtrToString(c.SzName)
// fmt.Printf("Index %d -> %s, value %v\n", i, s, c.FmtValue.DoubleValue)
// }
//
@ -482,10 +479,10 @@ func PdhGetFormattedCounterValueDouble(hCounter pdhCounterHandle, lpdwType *uint
// time.Sleep(2000 * time.Millisecond)
// }
// }
func PdhGetFormattedCounterArrayDouble(hCounter pdhCounterHandle, lpdwBufferSize, lpdwBufferCount *uint32, itemBuffer *byte) uint32 {
ret, _, _ := pdhGetFormattedCounterArrayW.Call(
func pdhGetFormattedCounterArrayDouble(hCounter pdhCounterHandle, lpdwBufferSize, lpdwBufferCount *uint32, itemBuffer *byte) uint32 {
ret, _, _ := pdhGetFormattedCounterArrayWProc.Call(
uintptr(hCounter),
uintptr(PdhFmtDouble|PdhFmtNocap100),
uintptr(pdhFmtDouble|pdhFmtNocap100),
uintptr(unsafe.Pointer(lpdwBufferSize)), //nolint:gosec // G103: Valid use of unsafe call to pass lpdwBufferSize
uintptr(unsafe.Pointer(lpdwBufferCount)), //nolint:gosec // G103: Valid use of unsafe call to pass lpdwBufferCount
uintptr(unsafe.Pointer(itemBuffer))) //nolint:gosec // G103: Valid use of unsafe call to pass itemBuffer
@ -493,15 +490,15 @@ func PdhGetFormattedCounterArrayDouble(hCounter pdhCounterHandle, lpdwBufferSize
return uint32(ret)
}
// PdhOpenQuery creates a new query that is used to manage the collection of performance data.
// pdhOpenQuery creates a new query that is used to manage the collection of performance data.
// szDataSource is a null terminated string that specifies the name of the log file from which to
// retrieve the performance data. If 0, performance data is collected from a real-time data source.
// dwUserData is a user-defined value to associate with this query. To retrieve the user data later,
// call PdhGetCounterInfo and access dwQueryUserData of the pdhCounterInfo structure. phQuery is
// call pdhGetCounterInfo and access dwQueryUserData of the pdhCounterInfo structure. phQuery is
// the handle to the query, and must be used in subsequent calls. This function returns a PDH_
// constant error code, or ErrorSuccess if the call succeeded.
func PdhOpenQuery(szDataSource, dwUserData uintptr, phQuery *pdhQueryHandle) uint32 {
ret, _, _ := pdhOpenQuery.Call(
// constant error code, or errorSuccess if the call succeeded.
func pdhOpenQuery(szDataSource, dwUserData uintptr, phQuery *pdhQueryHandle) uint32 {
ret, _, _ := pdhOpenQueryProc.Call(
szDataSource,
dwUserData,
uintptr(unsafe.Pointer(phQuery))) //nolint:gosec // G103: Valid use of unsafe call to pass phQuery
@ -509,7 +506,7 @@ func PdhOpenQuery(szDataSource, dwUserData uintptr, phQuery *pdhQueryHandle) uin
return uint32(ret)
}
// PdhExpandWildCardPath examines the specified computer or log file and returns those counter paths that match the given counter path
// pdhExpandWildCardPath examines the specified computer or log file and returns those counter paths that match the given counter path
// which contains wildcard characters. The general counter path format is as follows:
//
// \\computer\object(parent/instance#index)\counter
@ -542,10 +539,10 @@ func PdhOpenQuery(szDataSource, dwUserData uintptr, phQuery *pdhQueryHandle) uin
// If a wildcard character is specified in the counter name, all counters of the specified object are returned.
//
// Partial counter path string matches (for example, "pro*") are supported.
func PdhExpandWildCardPath(szWildCardPath string, mszExpandedPathList *uint16, pcchPathListLength *uint32) uint32 {
func pdhExpandWildCardPath(szWildCardPath string, mszExpandedPathList *uint16, pcchPathListLength *uint32) uint32 {
ptxt, _ := syscall.UTF16PtrFromString(szWildCardPath)
flags := uint32(0) // expand instances and counters
ret, _, _ := pdhExpandWildCardPathW.Call(
ret, _, _ := pdhExpandWildCardPathWProc.Call(
0, // search counters on local computer
uintptr(unsafe.Pointer(ptxt)), //nolint:gosec // G103: Valid use of unsafe call to pass ptxt
uintptr(unsafe.Pointer(mszExpandedPathList)), //nolint:gosec // G103: Valid use of unsafe call to pass mszExpandedPathList
@ -555,27 +552,19 @@ func PdhExpandWildCardPath(szWildCardPath string, mszExpandedPathList *uint16, p
return uint32(ret)
}
// PdhValidatePath validates a path. Will return ErrorSuccess when ok, or PdhCstatusBadCountername when the path is erroneous.
func PdhValidatePath(path string) uint32 {
ptxt, _ := syscall.UTF16PtrFromString(path)
ret, _, _ := pdhValidatePathW.Call(uintptr(unsafe.Pointer(ptxt))) //nolint:gosec // G103: Valid use of unsafe call to pass ptxt
return uint32(ret)
}
func PdhFormatError(msgID uint32) string {
func pdhFormatError(msgID uint32) string {
var flags uint32 = windows.FORMAT_MESSAGE_FROM_HMODULE | windows.FORMAT_MESSAGE_ARGUMENT_ARRAY | windows.FORMAT_MESSAGE_IGNORE_INSERTS
buf := make([]uint16, 300)
_, err := windows.FormatMessage(flags, uintptr(libPdhDll.Handle), msgID, 0, buf, nil)
if err == nil {
return UTF16PtrToString(&buf[0])
return utf16PtrToString(&buf[0])
}
return fmt.Sprintf("(pdhErr=%d) %s", msgID, err.Error())
}
// PdhGetCounterInfo 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]
// 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]
// Determines whether explain text is retrieved. If you set this parameter to TRUE, the explain text for the counter is retrieved.
@ -590,8 +579,8 @@ func PdhFormatError(msgID uint32) string {
// Caller-allocated buffer that receives a pdhCounterInfo 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 pdhCounterHandle, bRetrieveExplainText int, pdwBufferSize *uint32, lpBuffer *byte) uint32 {
ret, _, _ := pdhGetCounterInfoW.Call(
func pdhGetCounterInfo(hCounter pdhCounterHandle, bRetrieveExplainText int, pdwBufferSize *uint32, lpBuffer *byte) uint32 {
ret, _, _ := pdhGetCounterInfoWProc.Call(
uintptr(hCounter),
uintptr(bRetrieveExplainText),
uintptr(unsafe.Pointer(pdwBufferSize)), //nolint:gosec // G103: Valid use of unsafe call to pass pdwBufferSize
@ -600,12 +589,12 @@ func PdhGetCounterInfo(hCounter pdhCounterHandle, bRetrieveExplainText int, pdwB
return uint32(ret)
}
// PdhGetRawCounterValue returns the current raw value of the counter.
// If the specified counter instance does not exist, this function will return ErrorSuccess
// pdhGetRawCounterValue returns the current raw value of the counter.
// If the specified counter instance does not exist, this function will return errorSuccess
// and the CStatus member of the pdhRawCounter structure will contain PdhCstatusNoInstance.
//
// hCounter [in]
// Handle of the counter from which to retrieve the current raw value. The PdhAddCounter function returns this handle.
// Handle of the counter from which to retrieve the current raw value. The pdhAddCounter function returns this handle.
//
// lpdwType [out]
// Receives the counter type. For a list of counter types, see the Counter Types section of the Windows Server 2003 Deployment Kit.
@ -613,8 +602,8 @@ func PdhGetCounterInfo(hCounter pdhCounterHandle, bRetrieveExplainText int, pdwB
//
// pValue [out]
// A pdhRawCounter structure that receives the counter value.
func PdhGetRawCounterValue(hCounter pdhCounterHandle, lpdwType *uint32, pValue *pdhRawCounter) uint32 {
ret, _, _ := pdhGetRawCounterValue.Call(
func pdhGetRawCounterValue(hCounter pdhCounterHandle, lpdwType *uint32, pValue *pdhRawCounter) uint32 {
ret, _, _ := pdhGetRawCounterValueProc.Call(
uintptr(hCounter),
uintptr(unsafe.Pointer(lpdwType)), //nolint:gosec // G103: Valid use of unsafe call to pass lpdwType
uintptr(unsafe.Pointer(pValue))) //nolint:gosec // G103: Valid use of unsafe call to pass pValue
@ -622,10 +611,10 @@ func PdhGetRawCounterValue(hCounter pdhCounterHandle, lpdwType *uint32, pValue *
return uint32(ret)
}
// PdhGetRawCounterArray 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.
// 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.
//
// lpdwBufferSize
// Size of the ItemBuffer buffer, in bytes. If zero on input, the function returns PdhMoreData and sets this parameter to the required buffer size.
@ -638,8 +627,8 @@ func PdhGetRawCounterValue(hCounter pdhCounterHandle, lpdwType *uint32, pValue *
// ItemBuffer
// Caller-allocated buffer that receives the array of pdhRawCounterItem structures; the structures contain the raw instance counter values.
// Set to NULL if lpdwBufferSize is zero.
func PdhGetRawCounterArray(hCounter pdhCounterHandle, lpdwBufferSize, lpdwBufferCount *uint32, itemBuffer *byte) uint32 {
ret, _, _ := pdhGetRawCounterArrayW.Call(
func pdhGetRawCounterArray(hCounter pdhCounterHandle, lpdwBufferSize, lpdwBufferCount *uint32, itemBuffer *byte) uint32 {
ret, _, _ := pdhGetRawCounterArrayWProc.Call(
uintptr(hCounter),
uintptr(unsafe.Pointer(lpdwBufferSize)), //nolint:gosec // G103: Valid use of unsafe call to pass lpdwBufferSize
uintptr(unsafe.Pointer(lpdwBufferCount)), //nolint:gosec // G103: Valid use of unsafe call to pass lpdwBufferCount

View File

@ -52,13 +52,6 @@ type pdhFmtCountervalueItemDouble struct {
FmtValue pdhFmtCountervalueDouble
}
// pdhFmtCountervalueItemLong is a union specialization for long values, used by PdhGetFormattedCounterArrayLong()
type PdhFmtCountervalueItemLong struct {
SzName *uint16 // pointer to a string
padding [4]byte //nolint:unused // Memory reservation
FmtValue pdhFmtCountervalueLong
}
// pdhCounterInfo structure contains information describing the properties of a counter. This information also includes the counter path.
type pdhCounterInfo struct {
//Size of the structure, including the appended strings, in bytes.
@ -78,9 +71,9 @@ type pdhCounterInfo struct {
LScale int32
//Default scale factor as suggested by the counter's provider.
LDefaultScale int32
//The value passed in the dwUserData parameter when calling PdhAddCounter.
//The value passed in the dwUserData parameter when calling pdhAddCounter.
DwUserData *uint32
//The value passed in the dwUserData parameter when calling PdhOpenQuery.
//The value passed in the dwUserData parameter when calling pdhOpenQuery.
DwQueryUserData *uint32
//Null-terminated string that specifies the full counter path. The string follows this structure in memory.
SzFullPath *uint16 // pointer to a string

View File

@ -38,7 +38,7 @@ type pdhFmtCountervalueDouble struct {
DoubleValue float64
}
// pdhFmtCountervalueItemDouble is a union specialization for double values, used by PdhGetFormattedCounterArrayDouble
// pdhFmtCountervalueItemDouble is a union specialization for double values, used by pdhGetFormattedCounterArrayDouble
type pdhFmtCountervalueItemDouble struct {
SzName *uint16
FmtValue pdhFmtCountervalueDouble
@ -63,9 +63,9 @@ type pdhCounterInfo struct {
LScale int32
// Default scale factor as suggested by the counter's provider.
LDefaultScale int32
// The value passed in the dwUserData parameter when calling PdhAddCounter.
// The value passed in the dwUserData parameter when calling pdhAddCounter.
DwUserData *uint32
// The value passed in the dwUserData parameter when calling PdhOpenQuery.
// The value passed in the dwUserData parameter when calling pdhOpenQuery.
DwQueryUserData *uint32
// Null-terminated string that specifies the full counter path. The string follows this structure in memory.
SzFullPath *uint16 // pointer to a string

View File

@ -62,9 +62,9 @@ type pdhCounterInfo struct {
LScale int32
//Default scale factor as suggested by the counter's provider.
LDefaultScale int32
//The value passed in the dwUserData parameter when calling PdhAddCounter.
//The value passed in the dwUserData parameter when calling pdhAddCounter.
DwUserData *uint32
//The value passed in the dwUserData parameter when calling PdhOpenQuery.
//The value passed in the dwUserData parameter when calling pdhOpenQuery.
DwQueryUserData *uint32
//Null-terminated string that specifies the full counter path. The string follows this structure in memory.
SzFullPath *uint16 // pointer to a string

View File

@ -17,36 +17,36 @@ var errBufferLimitReached = errors.New("buffer limit reached")
// counterValue is abstraction for pdhFmtCountervalueItemDouble
type counterValue struct {
InstanceName string
Value interface{}
instanceName string
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 {
Open() error
Close() error
AddCounterToQuery(counterPath string) (pdhCounterHandle, error)
AddEnglishCounterToQuery(counterPath string) (pdhCounterHandle, error)
GetCounterPath(counterHandle pdhCounterHandle) (string, error)
ExpandWildCardPath(counterPath string) ([]string, error)
GetFormattedCounterValueDouble(hCounter pdhCounterHandle) (float64, error)
GetRawCounterValue(hCounter pdhCounterHandle) (int64, error)
GetFormattedCounterArrayDouble(hCounter pdhCounterHandle) ([]counterValue, error)
GetRawCounterArray(hCounter pdhCounterHandle) ([]counterValue, error)
CollectData() error
CollectDataWithTime() (time.Time, error)
IsVistaOrNewer() bool
type performanceQuery interface {
open() error
close() error
addCounterToQuery(counterPath string) (pdhCounterHandle, error)
addEnglishCounterToQuery(counterPath string) (pdhCounterHandle, error)
getCounterPath(counterHandle pdhCounterHandle) (string, error)
expandWildCardPath(counterPath string) ([]string, error)
getFormattedCounterValueDouble(hCounter pdhCounterHandle) (float64, error)
getRawCounterValue(hCounter pdhCounterHandle) (int64, error)
getFormattedCounterArrayDouble(hCounter pdhCounterHandle) ([]counterValue, error)
getRawCounterArray(hCounter pdhCounterHandle) ([]counterValue, error)
collectData() error
collectDataWithTime() (time.Time, error)
isVistaOrNewer() bool
}
type PerformanceQueryCreator interface {
NewPerformanceQuery(string, uint32) PerformanceQuery
type performanceQueryCreator interface {
newPerformanceQuery(string, uint32) performanceQuery
}
// pdhError represents error returned from Performance Counters API
type pdhError struct {
ErrorCode uint32
errorCode uint32
errorText string
}
@ -54,14 +54,14 @@ func (m *pdhError) Error() string {
return m.errorText
}
func NewPdhError(code uint32) error {
func newPdhError(code uint32) error {
return &pdhError{
ErrorCode: code,
errorText: PdhFormatError(code),
errorCode: code,
errorText: pdhFormatError(code),
}
}
// performanceQueryImpl is implementation of PerformanceQuery interface, which calls phd.dll functions
// performanceQueryImpl is implementation of performanceQuery interface, which calls phd.dll functions
type performanceQueryImpl struct {
maxBufferSize uint32
query pdhQueryHandle
@ -69,75 +69,75 @@ type performanceQueryImpl struct {
type performanceQueryCreatorImpl struct{}
func (performanceQueryCreatorImpl) NewPerformanceQuery(_ string, maxBufferSize uint32) PerformanceQuery {
func (performanceQueryCreatorImpl) newPerformanceQuery(_ string, maxBufferSize uint32) performanceQuery {
return &performanceQueryImpl{maxBufferSize: maxBufferSize}
}
// Open creates a new counterPath that is used to manage the collection of performance data.
// open creates a new counterPath that is used to manage the collection of performance data.
// It returns counterPath handle used for subsequent calls for adding counters and querying data
func (m *performanceQueryImpl) Open() error {
func (m *performanceQueryImpl) open() error {
if m.query != 0 {
err := m.Close()
err := m.close()
if err != nil {
return err
}
}
var handle pdhQueryHandle
if ret := PdhOpenQuery(0, 0, &handle); ret != ErrorSuccess {
return NewPdhError(ret)
if ret := pdhOpenQuery(0, 0, &handle); ret != errorSuccess {
return newPdhError(ret)
}
m.query = handle
return nil
}
// Close closes the counterPath, releases associated counter handles and frees resources
func (m *performanceQueryImpl) Close() error {
// close closes the counterPath, releases associated counter handles and frees resources
func (m *performanceQueryImpl) close() error {
if m.query == 0 {
return errors.New("uninitialized query")
}
if ret := PdhCloseQuery(m.query); ret != ErrorSuccess {
return NewPdhError(ret)
if ret := pdhCloseQuery(m.query); ret != errorSuccess {
return newPdhError(ret)
}
m.query = 0
return nil
}
func (m *performanceQueryImpl) AddCounterToQuery(counterPath string) (pdhCounterHandle, error) {
func (m *performanceQueryImpl) addCounterToQuery(counterPath string) (pdhCounterHandle, error) {
var counterHandle pdhCounterHandle
if m.query == 0 {
return 0, errors.New("uninitialized query")
}
if ret := PdhAddCounter(m.query, counterPath, 0, &counterHandle); ret != ErrorSuccess {
return 0, NewPdhError(ret)
if ret := pdhAddCounter(m.query, counterPath, 0, &counterHandle); ret != errorSuccess {
return 0, newPdhError(ret)
}
return counterHandle, nil
}
func (m *performanceQueryImpl) AddEnglishCounterToQuery(counterPath string) (pdhCounterHandle, error) {
func (m *performanceQueryImpl) addEnglishCounterToQuery(counterPath string) (pdhCounterHandle, error) {
var counterHandle pdhCounterHandle
if m.query == 0 {
return 0, errors.New("uninitialized query")
}
if ret := PdhAddEnglishCounter(m.query, counterPath, 0, &counterHandle); ret != ErrorSuccess {
return 0, NewPdhError(ret)
if ret := pdhAddEnglishCounter(m.query, counterPath, 0, &counterHandle); ret != errorSuccess {
return 0, newPdhError(ret)
}
return counterHandle, nil
}
// GetCounterPath return counter information for given handle
func (m *performanceQueryImpl) GetCounterPath(counterHandle pdhCounterHandle) (string, error) {
// getCounterPath returns counter information for given handle
func (m *performanceQueryImpl) getCounterPath(counterHandle pdhCounterHandle) (string, error) {
for buflen := initialBufferSize; buflen <= m.maxBufferSize; buflen *= 2 {
buf := make([]byte, buflen)
// Get the info with the current buffer size
size := buflen
ret := PdhGetCounterInfo(counterHandle, 0, &size, &buf[0])
if ret == ErrorSuccess {
ret := pdhGetCounterInfo(counterHandle, 0, &size, &buf[0])
if ret == errorSuccess {
ci := (*pdhCounterInfo)(unsafe.Pointer(&buf[0])) //nolint:gosec // G103: Valid use of unsafe call to create PDH_COUNTER_INFO
return UTF16PtrToString(ci.SzFullPath), nil
return utf16PtrToString(ci.SzFullPath), nil
}
// Use the size as a hint if it exceeds the current buffer size
@ -146,24 +146,24 @@ func (m *performanceQueryImpl) GetCounterPath(counterHandle pdhCounterHandle) (s
}
// We got a non-recoverable error so exit here
if ret != PdhMoreData {
return "", NewPdhError(ret)
if ret != pdhMoreData {
return "", newPdhError(ret)
}
}
return "", errBufferLimitReached
}
// ExpandWildCardPath examines local computer and returns those counter paths that match the given counter path which contains wildcard characters.
func (m *performanceQueryImpl) ExpandWildCardPath(counterPath string) ([]string, error) {
// expandWildCardPath examines local computer and returns those counter paths that match the given counter path which contains wildcard characters.
func (m *performanceQueryImpl) expandWildCardPath(counterPath string) ([]string, error) {
for buflen := initialBufferSize; buflen <= m.maxBufferSize; buflen *= 2 {
buf := make([]uint16, buflen)
// Get the info with the current buffer size
size := buflen
ret := PdhExpandWildCardPath(counterPath, &buf[0], &size)
if ret == ErrorSuccess {
return UTF16ToStringArray(buf), nil
ret := pdhExpandWildCardPath(counterPath, &buf[0], &size)
if ret == errorSuccess {
return utf16ToStringArray(buf), nil
}
// Use the size as a hint if it exceeds the current buffer size
@ -172,43 +172,43 @@ func (m *performanceQueryImpl) ExpandWildCardPath(counterPath string) ([]string,
}
// We got a non-recoverable error so exit here
if ret != PdhMoreData {
return nil, NewPdhError(ret)
if ret != pdhMoreData {
return nil, newPdhError(ret)
}
}
return nil, errBufferLimitReached
}
// GetFormattedCounterValueDouble computes a displayable value for the specified counter
func (*performanceQueryImpl) GetFormattedCounterValueDouble(hCounter pdhCounterHandle) (float64, error) {
// getFormattedCounterValueDouble computes a displayable value for the specified counter
func (*performanceQueryImpl) getFormattedCounterValueDouble(hCounter pdhCounterHandle) (float64, error) {
var counterType uint32
var value pdhFmtCountervalueDouble
if ret := PdhGetFormattedCounterValueDouble(hCounter, &counterType, &value); ret != ErrorSuccess {
return 0, NewPdhError(ret)
if ret := pdhGetFormattedCounterValueDouble(hCounter, &counterType, &value); ret != errorSuccess {
return 0, newPdhError(ret)
}
if value.CStatus == PdhCstatusValidData || value.CStatus == PdhCstatusNewData {
if value.CStatus == pdhCstatusValidData || value.CStatus == pdhCstatusNewData {
return value.DoubleValue, nil
}
return 0, NewPdhError(value.CStatus)
return 0, newPdhError(value.CStatus)
}
func (m *performanceQueryImpl) GetFormattedCounterArrayDouble(hCounter pdhCounterHandle) ([]counterValue, error) {
func (m *performanceQueryImpl) getFormattedCounterArrayDouble(hCounter pdhCounterHandle) ([]counterValue, error) {
for buflen := initialBufferSize; buflen <= m.maxBufferSize; buflen *= 2 {
buf := make([]byte, buflen)
// Get the info with the current buffer size
var itemCount uint32
size := buflen
ret := PdhGetFormattedCounterArrayDouble(hCounter, &size, &itemCount, &buf[0])
if ret == ErrorSuccess {
ret := pdhGetFormattedCounterArrayDouble(hCounter, &size, &itemCount, &buf[0])
if ret == errorSuccess {
//nolint:gosec // G103: Valid use of unsafe call to create PDH_FMT_COUNTERVALUE_ITEM_DOUBLE
items := (*[1 << 20]pdhFmtCountervalueItemDouble)(unsafe.Pointer(&buf[0]))[:itemCount]
values := make([]counterValue, 0, itemCount)
for _, item := range items {
if item.FmtValue.CStatus == PdhCstatusValidData || item.FmtValue.CStatus == PdhCstatusNewData {
val := counterValue{UTF16PtrToString(item.SzName), item.FmtValue.DoubleValue}
if item.FmtValue.CStatus == pdhCstatusValidData || item.FmtValue.CStatus == pdhCstatusNewData {
val := counterValue{utf16PtrToString(item.SzName), item.FmtValue.DoubleValue}
values = append(values, val)
}
}
@ -221,29 +221,29 @@ func (m *performanceQueryImpl) GetFormattedCounterArrayDouble(hCounter pdhCounte
}
// We got a non-recoverable error so exit here
if ret != PdhMoreData {
return nil, NewPdhError(ret)
if ret != pdhMoreData {
return nil, newPdhError(ret)
}
}
return nil, errBufferLimitReached
}
func (m *performanceQueryImpl) GetRawCounterArray(hCounter pdhCounterHandle) ([]counterValue, error) {
func (m *performanceQueryImpl) getRawCounterArray(hCounter pdhCounterHandle) ([]counterValue, error) {
for buflen := initialBufferSize; buflen <= m.maxBufferSize; buflen *= 2 {
buf := make([]byte, buflen)
// Get the info with the current buffer size
var itemCount uint32
size := buflen
ret := PdhGetRawCounterArray(hCounter, &size, &itemCount, &buf[0])
if ret == ErrorSuccess {
ret := pdhGetRawCounterArray(hCounter, &size, &itemCount, &buf[0])
if ret == errorSuccess {
//nolint:gosec // G103: Valid use of unsafe call to create PDH_RAW_COUNTER_ITEM
items := (*[1 << 20]pdhRawCounterItem)(unsafe.Pointer(&buf[0]))[:itemCount]
values := make([]counterValue, 0, itemCount)
for _, item := range items {
if item.RawValue.CStatus == PdhCstatusValidData || item.RawValue.CStatus == PdhCstatusNewData {
val := counterValue{UTF16PtrToString(item.SzName), item.RawValue.FirstValue}
if item.RawValue.CStatus == pdhCstatusValidData || item.RawValue.CStatus == pdhCstatusNewData {
val := counterValue{utf16PtrToString(item.SzName), item.RawValue.FirstValue}
values = append(values, val)
}
}
@ -256,42 +256,42 @@ func (m *performanceQueryImpl) GetRawCounterArray(hCounter pdhCounterHandle) ([]
}
// We got a non-recoverable error so exit here
if ret != PdhMoreData {
return nil, NewPdhError(ret)
if ret != pdhMoreData {
return nil, newPdhError(ret)
}
}
return nil, errBufferLimitReached
}
func (m *performanceQueryImpl) CollectData() error {
func (m *performanceQueryImpl) collectData() error {
var ret uint32
if m.query == 0 {
return errors.New("uninitialized query")
}
if ret = PdhCollectQueryData(m.query); ret != ErrorSuccess {
return NewPdhError(ret)
if ret = pdhCollectQueryData(m.query); ret != errorSuccess {
return newPdhError(ret)
}
return nil
}
func (m *performanceQueryImpl) CollectDataWithTime() (time.Time, error) {
func (m *performanceQueryImpl) collectDataWithTime() (time.Time, error) {
if m.query == 0 {
return time.Now(), errors.New("uninitialized query")
}
ret, mtime := PdhCollectQueryDataWithTime(m.query)
if ret != ErrorSuccess {
return time.Now(), NewPdhError(ret)
ret, mtime := pdhCollectQueryDataWithTime(m.query)
if ret != errorSuccess {
return time.Now(), newPdhError(ret)
}
return mtime, nil
}
func (*performanceQueryImpl) IsVistaOrNewer() bool {
return PdhAddEnglishCounterSupported()
func (*performanceQueryImpl) isVistaOrNewer() bool {
return pdhAddEnglishCounterSupported()
}
func (m *performanceQueryImpl) GetRawCounterValue(hCounter pdhCounterHandle) (int64, error) {
func (m *performanceQueryImpl) getRawCounterValue(hCounter pdhCounterHandle) (int64, error) {
if m.query == 0 {
return 0, errors.New("uninitialised query")
}
@ -300,17 +300,17 @@ func (m *performanceQueryImpl) GetRawCounterValue(hCounter pdhCounterHandle) (in
var value pdhRawCounter
var ret uint32
if ret = PdhGetRawCounterValue(hCounter, &counterType, &value); ret == ErrorSuccess {
if value.CStatus == PdhCstatusValidData || value.CStatus == PdhCstatusNewData {
if ret = pdhGetRawCounterValue(hCounter, &counterType, &value); ret == errorSuccess {
if value.CStatus == pdhCstatusValidData || value.CStatus == pdhCstatusNewData {
return value.FirstValue, nil
}
return 0, NewPdhError(value.CStatus)
return 0, newPdhError(value.CStatus)
}
return 0, NewPdhError(ret)
return 0, newPdhError(ret)
}
// UTF16PtrToString converts Windows API LPTSTR (pointer to string) to go string
func UTF16PtrToString(s *uint16) string {
// utf16PtrToString converts Windows API LPTSTR (pointer to string) to go string
func utf16PtrToString(s *uint16) string {
if s == nil {
return ""
}
@ -318,16 +318,16 @@ func UTF16PtrToString(s *uint16) string {
return syscall.UTF16ToString((*[1 << 29]uint16)(unsafe.Pointer(s))[0:])
}
// UTF16ToStringArray converts list of Windows API NULL terminated strings to go string array
func UTF16ToStringArray(buf []uint16) []string {
// utf16ToStringArray converts list of Windows API NULL terminated strings to go string array
func utf16ToStringArray(buf []uint16) []string {
var strings []string
nextLineStart := 0
stringLine := UTF16PtrToString(&buf[0])
stringLine := utf16PtrToString(&buf[0])
for stringLine != "" {
strings = append(strings, stringLine)
nextLineStart += len([]rune(stringLine)) + 1
remainingBuf := buf[nextLineStart:]
stringLine = UTF16PtrToString(&remainingBuf[0])
stringLine = utf16PtrToString(&remainingBuf[0])
}
return strings
}

View File

@ -21,51 +21,56 @@ import (
//go:embed sample.conf
var sampleConfig string
var defaultMaxBufferSize = config.Size(100 * 1024 * 1024)
var (
defaultMaxBufferSize = config.Size(100 * 1024 * 1024)
sanitizedChars = strings.NewReplacer("/sec", "_persec", "/Sec", "_persec", " ", "_", "%", "Percent", `\`, "")
)
const emptyInstance = "------"
type WinPerfCounters struct {
PrintValid bool `toml:"PrintValid"`
PreVistaSupport bool `toml:"PreVistaSupport" deprecated:"1.7.0;1.35.0;determined dynamically"`
UsePerfCounterTime bool
Object []perfObject
CountersRefreshInterval config.Duration
UseWildcardsExpansion bool
LocalizeWildcardsExpansion bool
IgnoredErrors []string `toml:"IgnoredErrors"`
MaxBufferSize config.Size
Sources []string
PrintValid bool `toml:"PrintValid"`
PreVistaSupport bool `toml:"PreVistaSupport" deprecated:"1.7.0;1.35.0;determined dynamically"`
UsePerfCounterTime bool `toml:"UsePerfCounterTime"`
Object []perfObject `toml:"object"`
CountersRefreshInterval config.Duration `toml:"CountersRefreshInterval"`
UseWildcardsExpansion bool `toml:"UseWildcardsExpansion"`
LocalizeWildcardsExpansion bool `toml:"LocalizeWildcardsExpansion"`
IgnoredErrors []string `toml:"IgnoredErrors"`
MaxBufferSize config.Size `toml:"MaxBufferSize"`
Sources []string `toml:"Sources"`
Log telegraf.Logger
Log telegraf.Logger `toml:"-"`
lastRefreshed time.Time
queryCreator PerformanceQueryCreator
queryCreator performanceQueryCreator
hostCounters map[string]*hostCountersInfo
// cached os.Hostname()
cachedHostname string
}
type perfObject struct {
Sources []string `toml:"Sources"`
ObjectName string `toml:"ObjectName"`
Counters []string `toml:"Counters"`
Instances []string `toml:"Instances"`
Measurement string `toml:"Measurement"`
WarnOnMissing bool `toml:"WarnOnMissing"`
FailOnMissing bool `toml:"FailOnMissing"`
IncludeTotal bool `toml:"IncludeTotal"`
UseRawValues bool `toml:"UseRawValues"`
}
type hostCountersInfo struct {
// computer name used as key and for printing
computer string
// computer name used in tag
tag string
counters []*counter
query PerformanceQuery
query performanceQuery
timestamp time.Time
}
type perfObject struct {
Sources []string
ObjectName string
Counters []string
Instances []string
Measurement string
WarnOnMissing bool
FailOnMissing bool
IncludeTotal bool
UseRawValues bool
}
type counter struct {
counterPath string
computer string
@ -86,8 +91,103 @@ type instanceGrouping struct {
type fieldGrouping map[instanceGrouping]map[string]interface{}
var sanitizedChars = strings.NewReplacer("/sec", "_persec", "/Sec", "_persec",
" ", "_", "%", "Percent", `\`, "")
func (*WinPerfCounters) SampleConfig() string {
return sampleConfig
}
func (m *WinPerfCounters) Init() error {
// Check the buffer size
if m.MaxBufferSize < config.Size(initialBufferSize) {
return fmt.Errorf("maximum buffer size should at least be %d", 2*initialBufferSize)
}
if m.MaxBufferSize > math.MaxUint32 {
return fmt.Errorf("maximum buffer size should be smaller than %d", uint32(math.MaxUint32))
}
if m.UseWildcardsExpansion && !m.LocalizeWildcardsExpansion {
// Counters must not have wildcards with this option
found := false
wildcards := []string{"*", "?"}
for _, object := range m.Object {
for _, wildcard := range wildcards {
if strings.Contains(object.ObjectName, wildcard) {
found = true
m.Log.Errorf("Object: %s, contains wildcard %s", object.ObjectName, wildcard)
}
}
for _, counter := range object.Counters {
for _, wildcard := range wildcards {
if strings.Contains(counter, wildcard) {
found = true
m.Log.Errorf("Object: %s, counter: %s contains wildcard %s", object.ObjectName, counter, wildcard)
}
}
}
}
if found {
return errors.New("wildcards can't be used with LocalizeWildcardsExpansion=false")
}
}
return nil
}
func (m *WinPerfCounters) Gather(acc telegraf.Accumulator) error {
// Parse the config once
var err error
if m.lastRefreshed.IsZero() || (m.CountersRefreshInterval > 0 && m.lastRefreshed.Add(time.Duration(m.CountersRefreshInterval)).Before(time.Now())) {
if err := m.cleanQueries(); err != nil {
return err
}
if err := m.parseConfig(); err != nil {
return err
}
for _, hostCounterSet := range m.hostCounters {
// some counters need two data samples before computing a value
if err = hostCounterSet.query.collectData(); err != nil {
return m.checkError(err)
}
}
m.lastRefreshed = time.Now()
// minimum time between collecting two samples
time.Sleep(time.Second)
}
for _, hostCounterSet := range m.hostCounters {
if m.UsePerfCounterTime && hostCounterSet.query.isVistaOrNewer() {
hostCounterSet.timestamp, err = hostCounterSet.query.collectDataWithTime()
if err != nil {
return err
}
} else {
hostCounterSet.timestamp = time.Now()
if err := hostCounterSet.query.collectData(); err != nil {
return err
}
}
}
var wg sync.WaitGroup
// iterate over computers
for _, hostCounterInfo := range m.hostCounters {
wg.Add(1)
go func(hostInfo *hostCountersInfo) {
m.Log.Debugf("Gathering from %s", hostInfo.computer)
start := time.Now()
err := m.gatherComputerCounters(hostInfo, acc)
m.Log.Debugf("Gathering from %s finished in %v", hostInfo.computer, time.Since(start))
if err != nil && m.checkError(err) != nil {
acc.AddError(fmt.Errorf("error during collecting data on host %q: %w", hostInfo.computer, err))
}
wg.Done()
}(hostCounterInfo)
}
wg.Wait()
return nil
}
// extractCounterInfoFromCounterPath gets object name, instance name (if available) and counter name from counter path
// General Counter path pattern is: \\computer\object(parent/instance#index)\counter
@ -153,10 +253,6 @@ func extractCounterInfoFromCounterPath(counterPath string) (computer string, obj
return computer, object, instance, counter, nil
}
func (*WinPerfCounters) SampleConfig() string {
return sampleConfig
}
func (m *WinPerfCounters) hostname() string {
if m.cachedHostname != "" {
return m.cachedHostname
@ -195,7 +291,7 @@ func newCounter(
}
//nolint:revive //argument-limit conditionally more arguments allowed
func (m *WinPerfCounters) AddItem(counterPath, computer, objectName, instance, counterName, measurement string, includeTotal bool, useRawValue bool) error {
func (m *WinPerfCounters) addItem(counterPath, computer, objectName, instance, counterName, measurement string, includeTotal bool, useRawValue bool) error {
origCounterPath := counterPath
var err error
var counterHandle pdhCounterHandle
@ -211,20 +307,20 @@ func (m *WinPerfCounters) AddItem(counterPath, computer, objectName, instance, c
if !ok {
hostCounter = &hostCountersInfo{computer: computer, tag: sourceTag}
m.hostCounters[computer] = hostCounter
hostCounter.query = m.queryCreator.NewPerformanceQuery(computer, uint32(m.MaxBufferSize))
if err := hostCounter.query.Open(); err != nil {
hostCounter.query = m.queryCreator.newPerformanceQuery(computer, uint32(m.MaxBufferSize))
if err := hostCounter.query.open(); err != nil {
return err
}
hostCounter.counters = make([]*counter, 0)
}
if !hostCounter.query.IsVistaOrNewer() {
counterHandle, err = hostCounter.query.AddCounterToQuery(counterPath)
if !hostCounter.query.isVistaOrNewer() {
counterHandle, err = hostCounter.query.addCounterToQuery(counterPath)
if err != nil {
return err
}
} else {
counterHandle, err = hostCounter.query.AddEnglishCounterToQuery(counterPath)
counterHandle, err = hostCounter.query.addEnglishCounterToQuery(counterPath)
if err != nil {
return err
}
@ -232,11 +328,11 @@ func (m *WinPerfCounters) AddItem(counterPath, computer, objectName, instance, c
if m.UseWildcardsExpansion {
origInstance := instance
counterPath, err = hostCounter.query.GetCounterPath(counterHandle)
counterPath, err = hostCounter.query.getCounterPath(counterHandle)
if err != nil {
return err
}
counters, err := hostCounter.query.ExpandWildCardPath(counterPath)
counters, err := hostCounter.query.expandWildCardPath(counterPath)
if err != nil {
return err
}
@ -247,7 +343,7 @@ func (m *WinPerfCounters) AddItem(counterPath, computer, objectName, instance, c
}
for _, counterPath := range counters {
_, err := hostCounter.query.AddCounterToQuery(counterPath)
_, err := hostCounter.query.addCounterToQuery(counterPath)
if err != nil {
return err
}
@ -261,7 +357,7 @@ func (m *WinPerfCounters) AddItem(counterPath, computer, objectName, instance, c
if !m.LocalizeWildcardsExpansion {
// On localized installations of Windows, Telegraf
// should return English metrics, but
// ExpandWildCardPath returns localized counters. Undo
// expandWildCardPath returns localized counters. Undo
// that by using the original object and counter
// names, along with the expanded instance.
@ -272,7 +368,7 @@ func (m *WinPerfCounters) AddItem(counterPath, computer, objectName, instance, c
newInstance = instance
}
counterPath = formatPath(computer, origObjectName, newInstance, origCounterName)
counterHandle, err = hostCounter.query.AddEnglishCounterToQuery(counterPath)
counterHandle, err = hostCounter.query.addEnglishCounterToQuery(counterPath)
if err != nil {
return err
}
@ -287,7 +383,7 @@ func (m *WinPerfCounters) AddItem(counterPath, computer, objectName, instance, c
useRawValue,
)
} else {
counterHandle, err = hostCounter.query.AddCounterToQuery(counterPath)
counterHandle, err = hostCounter.query.addCounterToQuery(counterPath)
if err != nil {
return err
}
@ -335,8 +431,6 @@ func (m *WinPerfCounters) AddItem(counterPath, computer, objectName, instance, c
return nil
}
const emptyInstance = "------"
func formatPath(computer, objectName, instance, counter string) string {
path := ""
if instance == emptyInstance {
@ -350,7 +444,7 @@ func formatPath(computer, objectName, instance, counter string) string {
return path
}
func (m *WinPerfCounters) ParseConfig() error {
func (m *WinPerfCounters) parseConfig() error {
var counterPath string
if len(m.Sources) == 0 {
@ -380,7 +474,7 @@ func (m *WinPerfCounters) ParseConfig() error {
objectName := PerfObject.ObjectName
counterPath = formatPath(computer, objectName, instance, counter)
err := m.AddItem(counterPath, computer, objectName, instance, counter,
err := m.addItem(counterPath, computer, objectName, instance, counter,
PerfObject.Measurement, PerfObject.IncludeTotal, PerfObject.UseRawValues)
if err != nil {
if PerfObject.FailOnMissing || PerfObject.WarnOnMissing {
@ -402,7 +496,7 @@ func (m *WinPerfCounters) checkError(err error) error {
var pdhErr *pdhError
if errors.As(err, &pdhErr) {
for _, ignoredErrors := range m.IgnoredErrors {
if PDHErrors[pdhErr.ErrorCode] == ignoredErrors {
if pdhErrors[pdhErr.errorCode] == ignoredErrors {
return nil
}
}
@ -412,62 +506,6 @@ func (m *WinPerfCounters) checkError(err error) error {
return err
}
func (m *WinPerfCounters) Gather(acc telegraf.Accumulator) error {
// Parse the config once
var err error
if m.lastRefreshed.IsZero() || (m.CountersRefreshInterval > 0 && m.lastRefreshed.Add(time.Duration(m.CountersRefreshInterval)).Before(time.Now())) {
if err := m.cleanQueries(); err != nil {
return err
}
if err := m.ParseConfig(); err != nil {
return err
}
for _, hostCounterSet := range m.hostCounters {
// some counters need two data samples before computing a value
if err = hostCounterSet.query.CollectData(); err != nil {
return m.checkError(err)
}
}
m.lastRefreshed = time.Now()
// minimum time between collecting two samples
time.Sleep(time.Second)
}
for _, hostCounterSet := range m.hostCounters {
if m.UsePerfCounterTime && hostCounterSet.query.IsVistaOrNewer() {
hostCounterSet.timestamp, err = hostCounterSet.query.CollectDataWithTime()
if err != nil {
return err
}
} else {
hostCounterSet.timestamp = time.Now()
if err := hostCounterSet.query.CollectData(); err != nil {
return err
}
}
}
var wg sync.WaitGroup
// iterate over computers
for _, hostCounterInfo := range m.hostCounters {
wg.Add(1)
go func(hostInfo *hostCountersInfo) {
m.Log.Debugf("Gathering from %s", hostInfo.computer)
start := time.Now()
err := m.gatherComputerCounters(hostInfo, acc)
m.Log.Debugf("Gathering from %s finished in %v", hostInfo.computer, time.Since(start))
if err != nil && m.checkError(err) != nil {
acc.AddError(fmt.Errorf("error during collecting data on host %q: %w", hostInfo.computer, err))
}
wg.Done()
}(hostCounterInfo)
}
wg.Wait()
return nil
}
func (m *WinPerfCounters) gatherComputerCounters(hostCounterInfo *hostCountersInfo, acc telegraf.Accumulator) error {
var value interface{}
var err error
@ -477,9 +515,9 @@ func (m *WinPerfCounters) gatherComputerCounters(hostCounterInfo *hostCountersIn
// collect
if m.UseWildcardsExpansion {
if metric.useRawValue {
value, err = hostCounterInfo.query.GetRawCounterValue(metric.counterHandle)
value, err = hostCounterInfo.query.getRawCounterValue(metric.counterHandle)
} else {
value, err = hostCounterInfo.query.GetFormattedCounterValueDouble(metric.counterHandle)
value, err = hostCounterInfo.query.getFormattedCounterValueDouble(metric.counterHandle)
}
if err != nil {
// ignore invalid data as some counters from process instances returns this sometimes
@ -493,9 +531,9 @@ func (m *WinPerfCounters) gatherComputerCounters(hostCounterInfo *hostCountersIn
} else {
var counterValues []counterValue
if metric.useRawValue {
counterValues, err = hostCounterInfo.query.GetRawCounterArray(metric.counterHandle)
counterValues, err = hostCounterInfo.query.getRawCounterArray(metric.counterHandle)
} else {
counterValues, err = hostCounterInfo.query.GetFormattedCounterArrayDouble(metric.counterHandle)
counterValues, err = hostCounterInfo.query.getFormattedCounterArrayDouble(metric.counterHandle)
}
if err != nil {
// ignore invalid data as some counters from process instances returns this sometimes
@ -506,14 +544,14 @@ func (m *WinPerfCounters) gatherComputerCounters(hostCounterInfo *hostCountersIn
continue
}
for _, cValue := range counterValues {
if strings.Contains(metric.instance, "#") && strings.HasPrefix(metric.instance, cValue.InstanceName) {
if strings.Contains(metric.instance, "#") && strings.HasPrefix(metric.instance, cValue.instanceName) {
// If you are using a multiple instance identifier such as "w3wp#1"
// phd.dll returns only the first 2 characters of the identifier.
cValue.InstanceName = metric.instance
cValue.instanceName = metric.instance
}
if shouldIncludeMetric(metric, cValue) {
addCounterMeasurement(metric, cValue.InstanceName, cValue.Value, collectedFields)
addCounterMeasurement(metric, cValue.instanceName, cValue.value, collectedFields)
}
}
}
@ -535,7 +573,7 @@ func (m *WinPerfCounters) gatherComputerCounters(hostCounterInfo *hostCountersIn
func (m *WinPerfCounters) cleanQueries() error {
for _, hostCounterInfo := range m.hostCounters {
if err := hostCounterInfo.query.Close(); err != nil {
if err := hostCounterInfo.query.close(); err != nil {
return err
}
}
@ -548,11 +586,11 @@ func shouldIncludeMetric(metric *counter, cValue counterValue) bool {
// If IncludeTotal is set, include all.
return true
}
if metric.instance == "*" && !strings.Contains(cValue.InstanceName, "_Total") {
if metric.instance == "*" && !strings.Contains(cValue.instanceName, "_Total") {
// Catch if set to * and that it is not a '*_Total*' instance.
return true
}
if metric.instance == cValue.InstanceName {
if metric.instance == cValue.instanceName {
// Catch if we set it to total or some form of it
return true
}
@ -572,55 +610,17 @@ func addCounterMeasurement(metric *counter, instanceName string, value interface
func isKnownCounterDataError(err error) bool {
var pdhErr *pdhError
if errors.As(err, &pdhErr) && (pdhErr.ErrorCode == PdhInvalidData ||
pdhErr.ErrorCode == PdhCalcNegativeDenominator ||
pdhErr.ErrorCode == PdhCalcNegativeValue ||
pdhErr.ErrorCode == PdhCstatusInvalidData ||
pdhErr.ErrorCode == PdhCstatusNoInstance ||
pdhErr.ErrorCode == PdhNoData) {
if errors.As(err, &pdhErr) && (pdhErr.errorCode == pdhInvalidData ||
pdhErr.errorCode == pdhCalcNegativeDenominator ||
pdhErr.errorCode == pdhCalcNegativeValue ||
pdhErr.errorCode == pdhCstatusInvalidData ||
pdhErr.errorCode == pdhCstatusNoInstance ||
pdhErr.errorCode == pdhNoData) {
return true
}
return false
}
func (m *WinPerfCounters) Init() error {
// Check the buffer size
if m.MaxBufferSize < config.Size(initialBufferSize) {
return fmt.Errorf("maximum buffer size should at least be %d", 2*initialBufferSize)
}
if m.MaxBufferSize > math.MaxUint32 {
return fmt.Errorf("maximum buffer size should be smaller than %d", uint32(math.MaxUint32))
}
if m.UseWildcardsExpansion && !m.LocalizeWildcardsExpansion {
// Counters must not have wildcards with this option
found := false
wildcards := []string{"*", "?"}
for _, object := range m.Object {
for _, wildcard := range wildcards {
if strings.Contains(object.ObjectName, wildcard) {
found = true
m.Log.Errorf("Object: %s, contains wildcard %s", object.ObjectName, wildcard)
}
}
for _, counter := range object.Counters {
for _, wildcard := range wildcards {
if strings.Contains(counter, wildcard) {
found = true
m.Log.Errorf("Object: %s, counter: %s contains wildcard %s", object.ObjectName, counter, wildcard)
}
}
}
}
if found {
return errors.New("wildcards can't be used with LocalizeWildcardsExpansion=false")
}
}
return nil
}
func init() {
inputs.Add("win_perf_counters", func() telegraf.Input {
return &WinPerfCounters{

View File

@ -19,97 +19,97 @@ func TestWinPerformanceQueryImplIntegration(t *testing.T) {
}
query := &performanceQueryImpl{maxBufferSize: uint32(defaultMaxBufferSize)}
err := query.Close()
err := query.close()
require.Error(t, err, "uninitialized query must return errors")
_, err = query.AddCounterToQuery("")
_, err = query.addCounterToQuery("")
require.Error(t, err, "uninitialized query must return errors")
require.ErrorContains(t, err, "uninitialized")
_, err = query.AddEnglishCounterToQuery("")
_, err = query.addEnglishCounterToQuery("")
require.Error(t, err, "uninitialized query must return errors")
require.ErrorContains(t, err, "uninitialized")
err = query.CollectData()
err = query.collectData()
require.Error(t, err, "uninitialized query must return errors")
require.ErrorContains(t, err, "uninitialized")
require.NoError(t, query.Open())
require.NoError(t, query.open())
counterPath := "\\Processor Information(_Total)\\% Processor Time"
hCounter, err := query.AddCounterToQuery(counterPath)
hCounter, err := query.addCounterToQuery(counterPath)
require.NoError(t, err)
require.NotEqual(t, 0, hCounter)
require.NoError(t, query.Close())
require.NoError(t, query.close())
require.NoError(t, query.Open())
require.NoError(t, query.open())
hCounter, err = query.AddEnglishCounterToQuery(counterPath)
hCounter, err = query.addEnglishCounterToQuery(counterPath)
require.NoError(t, err)
require.NotEqual(t, 0, hCounter)
cp, err := query.GetCounterPath(hCounter)
cp, err := query.getCounterPath(hCounter)
require.NoError(t, err)
require.True(t, strings.HasSuffix(cp, counterPath))
require.NoError(t, query.CollectData())
require.NoError(t, query.collectData())
time.Sleep(time.Second)
require.NoError(t, query.CollectData())
require.NoError(t, query.collectData())
fcounter, err := query.GetFormattedCounterValueDouble(hCounter)
fcounter, err := query.getFormattedCounterValueDouble(hCounter)
require.NoError(t, err)
require.Greater(t, fcounter, float64(0))
rcounter, err := query.GetRawCounterValue(hCounter)
rcounter, err := query.getRawCounterValue(hCounter)
require.NoError(t, err)
require.Greater(t, rcounter, int64(10000000))
now := time.Now()
mtime, err := query.CollectDataWithTime()
mtime, err := query.collectDataWithTime()
require.NoError(t, err)
require.Less(t, mtime.Sub(now), time.Second)
counterPath = "\\Process(*)\\% Processor Time"
paths, err := query.ExpandWildCardPath(counterPath)
paths, err := query.expandWildCardPath(counterPath)
require.NoError(t, err)
require.NotNil(t, paths)
require.Greater(t, len(paths), 1)
counterPath = "\\Process(_Total)\\*"
paths, err = query.ExpandWildCardPath(counterPath)
paths, err = query.expandWildCardPath(counterPath)
require.NoError(t, err)
require.NotNil(t, paths)
require.Greater(t, len(paths), 1)
require.NoError(t, query.Open())
require.NoError(t, query.open())
counterPath = "\\Process(*)\\% Processor Time"
hCounter, err = query.AddEnglishCounterToQuery(counterPath)
hCounter, err = query.addEnglishCounterToQuery(counterPath)
require.NoError(t, err)
require.NotEqual(t, 0, hCounter)
require.NoError(t, query.CollectData())
require.NoError(t, query.collectData())
time.Sleep(time.Second)
require.NoError(t, query.CollectData())
require.NoError(t, query.collectData())
farr, err := query.GetFormattedCounterArrayDouble(hCounter)
farr, err := query.getFormattedCounterArrayDouble(hCounter)
var phdErr *pdhError
if errors.As(err, &phdErr) && phdErr.ErrorCode != PdhInvalidData && phdErr.ErrorCode != PdhCalcNegativeValue {
if errors.As(err, &phdErr) && phdErr.errorCode != pdhInvalidData && phdErr.errorCode != pdhCalcNegativeValue {
time.Sleep(time.Second)
farr, err = query.GetFormattedCounterArrayDouble(hCounter)
farr, err = query.getFormattedCounterArrayDouble(hCounter)
}
require.NoError(t, err)
require.NotEmpty(t, farr)
rarr, err := query.GetRawCounterArray(hCounter)
rarr, err := query.getRawCounterArray(hCounter)
require.NoError(t, err)
require.NotEmpty(t, rarr, "Too")
require.NoError(t, query.Close())
require.NoError(t, query.close())
}
func TestWinPerfCountersConfigGet1Integration(t *testing.T) {
@ -137,7 +137,7 @@ func TestWinPerfCountersConfigGet1Integration(t *testing.T) {
queryCreator: &performanceQueryCreatorImpl{},
}
require.NoError(t, m.ParseConfig())
require.NoError(t, m.parseConfig())
}
func TestWinPerfCountersConfigGet2Integration(t *testing.T) {
@ -165,7 +165,7 @@ func TestWinPerfCountersConfigGet2Integration(t *testing.T) {
queryCreator: &performanceQueryCreatorImpl{},
}
require.NoError(t, m.ParseConfig())
require.NoError(t, m.parseConfig())
hostCounters, ok := m.hostCounters["localhost"]
require.True(t, ok)
@ -204,7 +204,7 @@ func TestWinPerfCountersConfigGet3Integration(t *testing.T) {
queryCreator: &performanceQueryCreatorImpl{},
}
require.NoError(t, m.ParseConfig())
require.NoError(t, m.parseConfig())
hostCounters, ok := m.hostCounters["localhost"]
require.True(t, ok)
@ -241,7 +241,7 @@ func TestWinPerfCountersConfigGet4Integration(t *testing.T) {
queryCreator: &performanceQueryCreatorImpl{},
}
require.NoError(t, m.ParseConfig())
require.NoError(t, m.parseConfig())
hostCounters, ok := m.hostCounters["localhost"]
require.True(t, ok)
@ -278,7 +278,7 @@ func TestWinPerfCountersConfigGet5Integration(t *testing.T) {
queryCreator: &performanceQueryCreatorImpl{},
}
require.NoError(t, m.ParseConfig())
require.NoError(t, m.parseConfig())
hostCounters, ok := m.hostCounters["localhost"]
require.True(t, ok)
@ -315,7 +315,7 @@ func TestWinPerfCountersConfigGet6Integration(t *testing.T) {
queryCreator: &performanceQueryCreatorImpl{},
}
require.NoError(t, m.ParseConfig())
require.NoError(t, m.parseConfig())
_, ok := m.hostCounters["localhost"]
require.True(t, ok)
@ -343,7 +343,7 @@ func TestWinPerfCountersConfigGet7Integration(t *testing.T) {
queryCreator: &performanceQueryCreatorImpl{},
}
require.NoError(t, m.ParseConfig())
require.NoError(t, m.parseConfig())
hostCounters, ok := m.hostCounters["localhost"]
require.True(t, ok)
@ -380,7 +380,7 @@ func TestWinPerfCountersConfigError1Integration(t *testing.T) {
queryCreator: &performanceQueryCreatorImpl{},
}
require.Error(t, m.ParseConfig())
require.Error(t, m.parseConfig())
}
func TestWinPerfCountersConfigError2Integration(t *testing.T) {
@ -408,7 +408,7 @@ func TestWinPerfCountersConfigError2Integration(t *testing.T) {
queryCreator: &performanceQueryCreatorImpl{},
}
require.NoError(t, m.ParseConfig())
require.NoError(t, m.parseConfig())
var acc testutil.Accumulator
require.Error(t, m.Gather(&acc))
}
@ -438,7 +438,7 @@ func TestWinPerfCountersConfigError3Integration(t *testing.T) {
queryCreator: &performanceQueryCreatorImpl{},
}
require.Error(t, m.ParseConfig())
require.Error(t, m.parseConfig())
}
func TestWinPerfCountersCollect1Integration(t *testing.T) {

View File

@ -20,7 +20,7 @@ type WinPerfCounters struct {
func (*WinPerfCounters) SampleConfig() string { return sampleConfig }
func (w *WinPerfCounters) Init() error {
w.Log.Warn("current platform is not supported")
w.Log.Warn("Current platform is not supported")
return nil
}

View File

@ -22,16 +22,16 @@ type testCounter struct {
status uint32 // allows for tests against specific pdh_error codes, rather than assuming all cases of "value == 0" to indicate error conditions
}
type FakePerformanceQuery struct {
type fakePerformanceQuery struct {
counters map[string]testCounter
vistaAndNewer bool
expandPaths map[string][]string
openCalled bool
}
var MetricTime = time.Date(2018, 5, 28, 12, 0, 0, 0, time.UTC)
var metricTime = time.Date(2018, 5, 28, 12, 0, 0, 0, time.UTC)
func (m *testCounter) ToCounterValue(raw bool) *counterValue {
func (m *testCounter) toCounterValue(raw bool) *counterValue {
//nolint:dogsled,errcheck // only instance is needed for this helper function in tests
_, _, inst, _, _ := extractCounterInfoFromCounterPath(m.path)
if inst == "" {
@ -47,9 +47,9 @@ func (m *testCounter) ToCounterValue(raw bool) *counterValue {
return &counterValue{inst, val}
}
func (m *FakePerformanceQuery) Open() error {
func (m *fakePerformanceQuery) open() error {
if m.openCalled {
err := m.Close()
err := m.close()
if err != nil {
return err
}
@ -58,81 +58,81 @@ func (m *FakePerformanceQuery) Open() error {
return nil
}
func (m *FakePerformanceQuery) Close() error {
func (m *fakePerformanceQuery) close() error {
if !m.openCalled {
return errors.New("in Close: uninitialized query")
return errors.New("in close: uninitialized query")
}
m.openCalled = false
return nil
}
func (m *FakePerformanceQuery) AddCounterToQuery(counterPath string) (pdhCounterHandle, error) {
func (m *fakePerformanceQuery) addCounterToQuery(counterPath string) (pdhCounterHandle, error) {
if !m.openCalled {
return 0, errors.New("in AddCounterToQuery: uninitialized query")
return 0, errors.New("in addCounterToQuery: uninitialized query")
}
if c, ok := m.counters[counterPath]; ok {
return c.handle, nil
}
return 0, fmt.Errorf("in AddCounterToQuery: invalid counter path: %q", counterPath)
return 0, fmt.Errorf("in addCounterToQuery: invalid counter path: %q", counterPath)
}
func (m *FakePerformanceQuery) AddEnglishCounterToQuery(counterPath string) (pdhCounterHandle, error) {
func (m *fakePerformanceQuery) addEnglishCounterToQuery(counterPath string) (pdhCounterHandle, error) {
if !m.openCalled {
return 0, errors.New("in AddEnglishCounterToQuery: uninitialized query")
return 0, errors.New("in addEnglishCounterToQuery: uninitialized query")
}
if c, ok := m.counters[counterPath]; ok {
return c.handle, nil
}
return 0, fmt.Errorf("in AddEnglishCounterToQuery: invalid counter path: %q", counterPath)
return 0, fmt.Errorf("in addEnglishCounterToQuery: invalid counter path: %q", counterPath)
}
func (m *FakePerformanceQuery) GetCounterPath(counterHandle pdhCounterHandle) (string, error) {
func (m *fakePerformanceQuery) getCounterPath(counterHandle pdhCounterHandle) (string, error) {
for _, counter := range m.counters {
if counter.handle == counterHandle {
return counter.path, nil
}
}
return "", fmt.Errorf("in GetCounterPath: invalid handle: %q", counterHandle)
return "", fmt.Errorf("in getCounterPath: invalid handle: %q", counterHandle)
}
func (m *FakePerformanceQuery) ExpandWildCardPath(counterPath string) ([]string, error) {
func (m *fakePerformanceQuery) expandWildCardPath(counterPath string) ([]string, error) {
if e, ok := m.expandPaths[counterPath]; ok {
return e, nil
}
return nil, fmt.Errorf("in ExpandWildCardPath: invalid counter path: %q", counterPath)
return nil, fmt.Errorf("in expandWildCardPath: invalid counter path: %q", counterPath)
}
func (m *FakePerformanceQuery) GetFormattedCounterValueDouble(counterHandle pdhCounterHandle) (float64, error) {
func (m *fakePerformanceQuery) getFormattedCounterValueDouble(counterHandle pdhCounterHandle) (float64, error) {
if !m.openCalled {
return 0, errors.New("in GetFormattedCounterValueDouble: uninitialized query")
return 0, errors.New("in getFormattedCounterValueDouble: uninitialized query")
}
for _, counter := range m.counters {
if counter.handle == counterHandle {
if counter.status > 0 {
return 0, NewPdhError(counter.status)
return 0, newPdhError(counter.status)
}
return counter.value, nil
}
}
return 0, fmt.Errorf("in GetFormattedCounterValueDouble: invalid handle: %q", counterHandle)
return 0, fmt.Errorf("in getFormattedCounterValueDouble: invalid handle: %q", counterHandle)
}
func (m *FakePerformanceQuery) GetRawCounterValue(counterHandle pdhCounterHandle) (int64, error) {
func (m *fakePerformanceQuery) getRawCounterValue(counterHandle pdhCounterHandle) (int64, error) {
if !m.openCalled {
return 0, errors.New("in GetRawCounterValue: uninitialised query")
return 0, errors.New("in getRawCounterValue: uninitialised query")
}
for _, counter := range m.counters {
if counter.handle == counterHandle {
if counter.status > 0 {
return 0, NewPdhError(counter.status)
return 0, newPdhError(counter.status)
}
return int64(counter.value), nil
}
}
return 0, fmt.Errorf("in GetRawCounterValue: invalid handle: %q", counterHandle)
return 0, fmt.Errorf("in getRawCounterValue: invalid handle: %q", counterHandle)
}
func (m *FakePerformanceQuery) findCounterByPath(counterPath string) *testCounter {
func (m *fakePerformanceQuery) findCounterByPath(counterPath string) *testCounter {
for _, c := range m.counters {
if c.path == counterPath {
return &c
@ -141,9 +141,9 @@ func (m *FakePerformanceQuery) findCounterByPath(counterPath string) *testCounte
return nil
}
func (m *FakePerformanceQuery) GetFormattedCounterArrayDouble(hCounter pdhCounterHandle) ([]counterValue, error) {
func (m *fakePerformanceQuery) getFormattedCounterArrayDouble(hCounter pdhCounterHandle) ([]counterValue, error) {
if !m.openCalled {
return nil, errors.New("in GetFormattedCounterArrayDouble: uninitialized query")
return nil, errors.New("in getFormattedCounterArrayDouble: uninitialized query")
}
for _, c := range m.counters {
if c.handle == hCounter {
@ -152,24 +152,24 @@ func (m *FakePerformanceQuery) GetFormattedCounterArrayDouble(hCounter pdhCounte
for _, p := range e {
counter := m.findCounterByPath(p)
if counter == nil {
return nil, fmt.Errorf("in GetFormattedCounterArrayDouble: invalid counter: %q", p)
return nil, fmt.Errorf("in getFormattedCounterArrayDouble: invalid counter: %q", p)
}
if counter.status > 0 {
return nil, NewPdhError(counter.status)
return nil, newPdhError(counter.status)
}
counters = append(counters, *counter.ToCounterValue(false))
counters = append(counters, *counter.toCounterValue(false))
}
return counters, nil
}
return nil, fmt.Errorf("in GetFormattedCounterArrayDouble: invalid counter: %q", hCounter)
return nil, fmt.Errorf("in getFormattedCounterArrayDouble: invalid counter: %q", hCounter)
}
}
return nil, fmt.Errorf("in GetFormattedCounterArrayDouble: invalid counter: %q, no paths found", hCounter)
return nil, fmt.Errorf("in getFormattedCounterArrayDouble: invalid counter: %q, no paths found", hCounter)
}
func (m *FakePerformanceQuery) GetRawCounterArray(hCounter pdhCounterHandle) ([]counterValue, error) {
func (m *fakePerformanceQuery) getRawCounterArray(hCounter pdhCounterHandle) ([]counterValue, error) {
if !m.openCalled {
return nil, errors.New("in GetRawCounterArray: uninitialised query")
return nil, errors.New("in getRawCounterArray: uninitialised query")
}
for _, c := range m.counters {
if c.handle == hCounter {
@ -178,45 +178,45 @@ func (m *FakePerformanceQuery) GetRawCounterArray(hCounter pdhCounterHandle) ([]
for _, p := range e {
counter := m.findCounterByPath(p)
if counter == nil {
return nil, fmt.Errorf("in GetRawCounterArray: invalid counter: %q", p)
return nil, fmt.Errorf("in getRawCounterArray: invalid counter: %q", p)
}
if counter.status > 0 {
return nil, NewPdhError(counter.status)
return nil, newPdhError(counter.status)
}
counters = append(counters, *counter.ToCounterValue(true))
counters = append(counters, *counter.toCounterValue(true))
}
return counters, nil
}
return nil, fmt.Errorf("in GetRawCounterArray: invalid counter: %q", hCounter)
return nil, fmt.Errorf("in getRawCounterArray: invalid counter: %q", hCounter)
}
}
return nil, fmt.Errorf("in GetRawCounterArray: invalid counter: %q, no paths found", hCounter)
return nil, fmt.Errorf("in getRawCounterArray: invalid counter: %q, no paths found", hCounter)
}
func (m *FakePerformanceQuery) CollectData() error {
func (m *fakePerformanceQuery) collectData() error {
if !m.openCalled {
return errors.New("in CollectData: uninitialized query")
return errors.New("in collectData: uninitialized query")
}
return nil
}
func (m *FakePerformanceQuery) CollectDataWithTime() (time.Time, error) {
func (m *fakePerformanceQuery) collectDataWithTime() (time.Time, error) {
if !m.openCalled {
return time.Now(), errors.New("in CollectDataWithTime: uninitialized query")
return time.Now(), errors.New("in collectDataWithTime: uninitialized query")
}
return MetricTime, nil
return metricTime, nil
}
func (m *FakePerformanceQuery) IsVistaOrNewer() bool {
func (m *fakePerformanceQuery) isVistaOrNewer() bool {
return m.vistaAndNewer
}
type FakePerformanceQueryCreator struct {
fakeQueries map[string]*FakePerformanceQuery
type fakePerformanceQueryCreator struct {
fakeQueries map[string]*fakePerformanceQuery
}
func (m FakePerformanceQueryCreator) NewPerformanceQuery(computer string, _ uint32) PerformanceQuery {
var ret PerformanceQuery
func (m fakePerformanceQueryCreator) newPerformanceQuery(computer string, _ uint32) performanceQuery {
var ret performanceQuery
var ok bool
if ret, ok = m.fakeQueries[computer]; !ok {
panic(fmt.Errorf("query for %q not found", computer))
@ -332,8 +332,8 @@ func TestAddItemSimple(t *testing.T) {
Log: testutil.Logger{},
PrintValid: false,
Object: nil,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap(cps1, []float64{1.1}, []uint32{0}),
expandPaths: map[string][]string{
cps1[0]: cps1,
@ -343,7 +343,7 @@ func TestAddItemSimple(t *testing.T) {
},
},
}
err = m.AddItem(cps1[0], "localhost", "O", "I", "c", "test", false, false)
err = m.addItem(cps1[0], "localhost", "O", "I", "c", "test", false, false)
require.NoError(t, err)
counters, ok := m.hostCounters["localhost"]
require.True(t, ok)
@ -364,8 +364,8 @@ func TestAddItemInvalidCountPath(t *testing.T) {
PrintValid: false,
Object: nil,
UseWildcardsExpansion: true,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap(cps1, []float64{1.1}, []uint32{0}),
expandPaths: map[string][]string{
cps1[0]: {"\\O/C"},
@ -376,7 +376,7 @@ func TestAddItemInvalidCountPath(t *testing.T) {
},
}
require.NoError(t, err)
err = m.AddItem("\\O\\C", "localhost", "O", "------", "C", "test", false, false)
err = m.addItem("\\O\\C", "localhost", "O", "------", "C", "test", false, false)
require.Error(t, err)
}
@ -389,8 +389,8 @@ func TestParseConfigBasic(t *testing.T) {
Log: testutil.Logger{},
PrintValid: false,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap(cps1, []float64{1.1, 1.2, 1.3, 1.4}, []uint32{0, 0, 0, 0}),
expandPaths: map[string][]string{
cps1[0]: {cps1[0]},
@ -404,7 +404,7 @@ func TestParseConfigBasic(t *testing.T) {
},
}
require.NoError(t, err)
err = m.ParseConfig()
err = m.parseConfig()
require.NoError(t, err)
counters, ok := m.hostCounters["localhost"]
require.True(t, ok)
@ -413,7 +413,7 @@ func TestParseConfigBasic(t *testing.T) {
require.NoError(t, err)
m.UseWildcardsExpansion = true
err = m.ParseConfig()
err = m.parseConfig()
require.NoError(t, err)
counters, ok = m.hostCounters["localhost"]
require.True(t, ok)
@ -441,8 +441,8 @@ func TestParseConfigMultiComps(t *testing.T) {
Log: testutil.Logger{},
PrintValid: false,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{
"localhost": {
counters: createCounterMap(append(append(cps11, cps21...), cps31...),
[]float64{1.1, 1.1, 1.2, 2.1, 2.2, 1.1, 1.2, 1.3},
@ -495,7 +495,7 @@ func TestParseConfigMultiComps(t *testing.T) {
},
}
require.NoError(t, err)
err = m.ParseConfig()
err = m.parseConfig()
require.NoError(t, err)
require.Len(t, m.hostCounters, 3)
@ -673,8 +673,8 @@ func TestParseConfigMultiCompsOverrideMultiplePerfObjects(t *testing.T) {
Log: testutil.Logger{},
PrintValid: false,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap(cps1,
[]float64{1.1, 1.2, 1.3, 1.4},
[]uint32{0, 0, 0, 0}),
@ -714,7 +714,7 @@ func TestParseConfigMultiCompsOverrideMultiplePerfObjects(t *testing.T) {
},
}
require.NoError(t, err)
err = m.ParseConfig()
err = m.parseConfig()
require.NoError(t, err)
require.Len(t, m.hostCounters, 3)
@ -825,8 +825,8 @@ func TestParseConfigMultiCompsOverrideOnePerfObject(t *testing.T) {
Log: testutil.Logger{},
PrintValid: false,
Object: []perfObject{perfObj, createPerfObject("", "m", "O1", []string{"I"}, []string{"C"}, false, false, false)[0]},
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{
"localhost": {
counters: createCounterMap(cps21,
[]float64{1.1},
@ -865,7 +865,7 @@ func TestParseConfigMultiCompsOverrideOnePerfObject(t *testing.T) {
},
}
require.NoError(t, err)
err = m.ParseConfig()
err = m.parseConfig()
require.NoError(t, err)
require.Len(t, m.hostCounters, 3)
@ -953,8 +953,8 @@ func TestParseConfigLocalhost(t *testing.T) {
Log: testutil.Logger{},
PrintValid: false,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap(cps1, []float64{1.1}, []uint32{0}),
expandPaths: map[string][]string{
cps1[0]: {cps1[0]},
@ -965,7 +965,7 @@ func TestParseConfigLocalhost(t *testing.T) {
},
}
err = m.ParseConfig()
err = m.parseConfig()
require.NoError(t, err)
hostCounters, ok := m.hostCounters["localhost"]
@ -980,7 +980,7 @@ func TestParseConfigLocalhost(t *testing.T) {
m.Object[0].Sources = []string{""}
err = m.ParseConfig()
err = m.parseConfig()
require.NoError(t, err)
hostCounters, ok = m.hostCounters["localhost"]
@ -1000,8 +1000,8 @@ func TestParseConfigNoInstance(t *testing.T) {
PrintValid: false,
Object: perfObjects,
UseWildcardsExpansion: false,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap(cps1, []float64{1.1, 1.2}, []uint32{0, 0}),
expandPaths: map[string][]string{
cps1[0]: {cps1[0]},
@ -1013,7 +1013,7 @@ func TestParseConfigNoInstance(t *testing.T) {
},
}
err = m.ParseConfig()
err = m.parseConfig()
require.NoError(t, err)
counters, ok := m.hostCounters["localhost"]
require.True(t, ok)
@ -1023,7 +1023,7 @@ func TestParseConfigNoInstance(t *testing.T) {
err = m.cleanQueries()
require.NoError(t, err)
err = m.ParseConfig()
err = m.parseConfig()
require.NoError(t, err)
counters, ok = m.hostCounters["localhost"]
require.True(t, ok)
@ -1038,8 +1038,8 @@ func TestParseConfigInvalidCounterError(t *testing.T) {
Log: testutil.Logger{},
PrintValid: false,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap(cps1, []float64{1.1, 1.2, 1.3}, []uint32{0, 0, 0}),
expandPaths: map[string][]string{
cps1[0]: {cps1[0]},
@ -1052,14 +1052,14 @@ func TestParseConfigInvalidCounterError(t *testing.T) {
},
}
err = m.ParseConfig()
err = m.parseConfig()
require.Error(t, err)
err = m.cleanQueries()
require.NoError(t, err)
m.UseWildcardsExpansion = true
err = m.ParseConfig()
err = m.parseConfig()
require.Error(t, err)
err = m.cleanQueries()
require.NoError(t, err)
@ -1073,8 +1073,8 @@ func TestParseConfigInvalidCounterNoError(t *testing.T) {
Log: testutil.Logger{},
PrintValid: false,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap(cps1, []float64{1.1, 1.2, 1.3}, []uint32{0, 0, 0}),
expandPaths: map[string][]string{
cps1[0]: {cps1[0]},
@ -1087,14 +1087,14 @@ func TestParseConfigInvalidCounterNoError(t *testing.T) {
},
}
err = m.ParseConfig()
err = m.parseConfig()
require.NoError(t, err)
err = m.cleanQueries()
require.NoError(t, err)
m.UseWildcardsExpansion = true
err = m.ParseConfig()
err = m.parseConfig()
require.NoError(t, err)
err = m.cleanQueries()
require.NoError(t, err)
@ -1109,8 +1109,8 @@ func TestParseConfigTotalExpansion(t *testing.T) {
PrintValid: false,
UseWildcardsExpansion: true,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap(append(cps1, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 0}, []uint32{0, 0, 0, 0, 0}),
expandPaths: map[string][]string{
"\\O(*)\\*": cps1,
@ -1121,7 +1121,7 @@ func TestParseConfigTotalExpansion(t *testing.T) {
},
LocalizeWildcardsExpansion: true,
}
err = m.ParseConfig()
err = m.parseConfig()
require.NoError(t, err)
counters, ok := m.hostCounters["localhost"]
require.True(t, ok)
@ -1136,8 +1136,8 @@ func TestParseConfigTotalExpansion(t *testing.T) {
PrintValid: false,
UseWildcardsExpansion: true,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap(append(cps1, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 0}, []uint32{0, 0, 0, 0, 0}),
expandPaths: map[string][]string{
"\\O(*)\\*": cps1,
@ -1149,7 +1149,7 @@ func TestParseConfigTotalExpansion(t *testing.T) {
LocalizeWildcardsExpansion: true,
}
err = m.ParseConfig()
err = m.parseConfig()
require.NoError(t, err)
counters, ok = m.hostCounters["localhost"]
require.True(t, ok)
@ -1167,8 +1167,8 @@ func TestParseConfigExpand(t *testing.T) {
PrintValid: false,
UseWildcardsExpansion: true,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap(append(cps1, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 0}, []uint32{0, 0, 0, 0, 0}),
expandPaths: map[string][]string{
"\\O(*)\\*": cps1,
@ -1179,7 +1179,7 @@ func TestParseConfigExpand(t *testing.T) {
},
LocalizeWildcardsExpansion: true,
}
err = m.ParseConfig()
err = m.parseConfig()
require.NoError(t, err)
counters, ok := m.hostCounters["localhost"]
require.True(t, ok)
@ -1200,8 +1200,8 @@ func TestSimpleGather(t *testing.T) {
Log: testutil.Logger{},
PrintValid: false,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap([]string{cp1}, []float64{1.2}, []uint32{0}),
expandPaths: map[string][]string{
cp1: {cp1},
@ -1251,9 +1251,9 @@ func TestSimpleGatherNoData(t *testing.T) {
Log: testutil.Logger{},
PrintValid: false,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
counters: createCounterMap([]string{cp1}, []float64{1.2}, []uint32{PdhNoData}),
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap([]string{cp1}, []float64{1.2}, []uint32{pdhNoData}),
expandPaths: map[string][]string{
cp1: {cp1},
},
@ -1305,8 +1305,8 @@ func TestSimpleGatherWithTimestamp(t *testing.T) {
PrintValid: false,
UsePerfCounterTime: true,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap([]string{cp1}, []float64{1.2}, []uint32{0}),
expandPaths: map[string][]string{
cp1: {cp1},
@ -1330,7 +1330,7 @@ func TestSimpleGatherWithTimestamp(t *testing.T) {
"source": hostname(),
}
acc1.AssertContainsTaggedFields(t, measurement, fields1, tags1)
require.True(t, acc1.HasTimestamp(measurement, MetricTime))
require.True(t, acc1.HasTimestamp(measurement, metricTime))
err = m.cleanQueries()
require.NoError(t, err)
}
@ -1347,9 +1347,9 @@ func TestGatherError(t *testing.T) {
Log: testutil.Logger{},
PrintValid: false,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
counters: createCounterMap([]string{cp1}, []float64{-2}, []uint32{PdhPlaValidationWarning}),
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap([]string{cp1}, []float64{-2}, []uint32{pdhPlaValidationWarning}),
expandPaths: map[string][]string{
cp1: {cp1},
},
@ -1390,9 +1390,9 @@ func TestGatherInvalidDataIgnore(t *testing.T) {
Log: testutil.Logger{},
PrintValid: false,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
counters: createCounterMap(cps1, []float64{1.2, 1, 0}, []uint32{0, PdhInvalidData, 0}),
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap(cps1, []float64{1.2, 1, 0}, []uint32{0, pdhInvalidData, 0}),
expandPaths: map[string][]string{
cps1[0]: {cps1[0]},
cps1[1]: {cps1[1]},
@ -1440,7 +1440,7 @@ func TestGatherRefreshingWithExpansion(t *testing.T) {
measurement := "test"
perfObjects := createPerfObject("", measurement, "O", []string{"*"}, []string{"*"}, true, false, false)
cps1 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2"}
fpm := &FakePerformanceQuery{
fpm := &fakePerformanceQuery{
counters: createCounterMap(append(cps1, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 0}, []uint32{0, 0, 0, 0, 0}),
expandPaths: map[string][]string{
"\\O(*)\\*": cps1,
@ -1452,8 +1452,8 @@ func TestGatherRefreshingWithExpansion(t *testing.T) {
PrintValid: false,
Object: perfObjects,
UseWildcardsExpansion: true,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": fpm},
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": fpm},
},
CountersRefreshInterval: config.Duration(time.Second * 10),
LocalizeWildcardsExpansion: true,
@ -1491,7 +1491,7 @@ func TestGatherRefreshingWithExpansion(t *testing.T) {
acc1.AssertContainsTaggedFields(t, measurement, fields2, tags2)
cps2 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2", "\\O(I3)\\C1", "\\O(I3)\\C2"}
fpm = &FakePerformanceQuery{
fpm = &fakePerformanceQuery{
counters: createCounterMap(append(cps2, "\\O(*)\\*"), []float64{1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 0}, []uint32{0, 0, 0, 0, 0, 0, 0}),
expandPaths: map[string][]string{
"\\O(*)\\*": cps2,
@ -1499,8 +1499,8 @@ func TestGatherRefreshingWithExpansion(t *testing.T) {
vistaAndNewer: true,
}
m.queryCreator = &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": fpm},
m.queryCreator = &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": fpm},
}
var acc2 testutil.Accumulator
@ -1548,7 +1548,7 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
measurement := "test"
perfObjects := createPerfObject("", measurement, "O", []string{"*"}, []string{"C1", "C2"}, true, false, false)
cps1 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2"}
fpm := &FakePerformanceQuery{
fpm := &fakePerformanceQuery{
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{
"\\O(*)\\C1": {cps1[0], cps1[2]},
@ -1561,8 +1561,8 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
PrintValid: false,
Object: perfObjects,
UseWildcardsExpansion: false,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": fpm},
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": fpm},
},
CountersRefreshInterval: config.Duration(time.Second * 10)}
var acc1 testutil.Accumulator
@ -1596,7 +1596,7 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
acc1.AssertContainsTaggedFields(t, measurement, fields2, tags2)
// test finding new instance
cps2 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I2)\\C1", "\\O(I2)\\C2", "\\O(I3)\\C1", "\\O(I3)\\C2"}
fpm = &FakePerformanceQuery{
fpm = &fakePerformanceQuery{
counters: createCounterMap(
append([]string{"\\O(*)\\C1", "\\O(*)\\C2"}, cps2...),
[]float64{0, 0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6},
@ -1612,8 +1612,8 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
err = m.cleanQueries()
require.NoError(t, err)
m.lastRefreshed = time.Time{}
m.queryCreator = &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": fpm},
m.queryCreator = &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": fpm},
}
var acc2 testutil.Accumulator
@ -1643,7 +1643,7 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
// test changed configuration
perfObjects = createPerfObject("", measurement, "O", []string{"*"}, []string{"C1", "C2", "C3"}, true, false, false)
cps3 := []string{"\\O(I1)\\C1", "\\O(I1)\\C2", "\\O(I1)\\C3", "\\O(I2)\\C1", "\\O(I2)\\C2", "\\O(I2)\\C3"}
fpm = &FakePerformanceQuery{
fpm = &fakePerformanceQuery{
counters: createCounterMap(
append([]string{"\\O(*)\\C1", "\\O(*)\\C2", "\\O(*)\\C3"}, cps3...),
[]float64{0, 0, 0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6},
@ -1659,8 +1659,8 @@ func TestGatherRefreshingWithoutExpansion(t *testing.T) {
err = m.cleanQueries()
m.lastRefreshed = time.Time{}
require.NoError(t, err)
m.queryCreator = &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": fpm},
m.queryCreator = &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": fpm},
}
m.Object = perfObjects
@ -1710,8 +1710,8 @@ func TestGatherTotalNoExpansion(t *testing.T) {
PrintValid: false,
UseWildcardsExpansion: false,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
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},
@ -1789,8 +1789,8 @@ func TestGatherMultiComps(t *testing.T) {
Log: testutil.Logger{},
PrintValid: false,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
fakeQueries: map[string]*fakePerformanceQuery{"localhost": {
counters: createCounterMap(cps1,
[]float64{1.1, 1.2, 1.3, 1.4},
[]uint32{0, 0, 0, 0}),
@ -1908,8 +1908,8 @@ func TestGatherRaw(t *testing.T) {
PrintValid: false,
UseWildcardsExpansion: false,
Object: perfObjects,
queryCreator: &FakePerformanceQueryCreator{
fakeQueries: map[string]*FakePerformanceQuery{"localhost": {
queryCreator: &fakePerformanceQueryCreator{
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},
@ -2000,16 +2000,16 @@ var stringArraySingleItem = []string{
}
func TestUTF16ToStringArray(t *testing.T) {
singleItem := UTF16ToStringArray(unicodeStringListSingleItem)
singleItem := utf16ToStringArray(unicodeStringListSingleItem)
require.Equal(t, singleItem, stringArraySingleItem, "Not equal single arrays")
noItem := UTF16ToStringArray(unicodeStringListNoItem)
noItem := utf16ToStringArray(unicodeStringListNoItem)
require.Nil(t, noItem)
engStrings := UTF16ToStringArray(unicodeStringListWithEnglishChars)
engStrings := utf16ToStringArray(unicodeStringListWithEnglishChars)
require.Equal(t, engStrings, stringArrayWithEnglishChars, "Not equal eng arrays")
czechStrings := UTF16ToStringArray(unicodeStringListWithCzechChars)
czechStrings := utf16ToStringArray(unicodeStringListWithCzechChars)
require.Equal(t, czechStrings, stringArrayWithCzechChars, "Not equal czech arrays")
}
@ -2069,7 +2069,7 @@ func TestCheckError(t *testing.T) {
{
Name: "Ignore PDH_NO_DATA",
Err: &pdhError{
ErrorCode: uint32(PdhNoData),
errorCode: uint32(pdhNoData),
},
IgnoredErrors: []string{
"PDH_NO_DATA",
@ -2079,10 +2079,10 @@ func TestCheckError(t *testing.T) {
{
Name: "Don't ignore PDH_NO_DATA",
Err: &pdhError{
ErrorCode: uint32(PdhNoData),
errorCode: uint32(pdhNoData),
},
ExpectedErr: &pdhError{
ErrorCode: uint32(PdhNoData),
errorCode: uint32(pdhNoData),
},
},
}

View File

@ -23,90 +23,33 @@ import (
//go:embed sample.conf
var sampleConfig string
type serviceError struct {
Message string
Service string
Err error
type WinServices struct {
ServiceNames []string `toml:"service_names"`
ServiceNamesExcluded []string `toml:"excluded_service_names"`
Log telegraf.Logger `toml:"-"`
mgrProvider managerProvider
servicesFilter filter.Filter
}
func (e *serviceError) Error() string {
return fmt.Sprintf("%s: %q: %v", e.Message, e.Service, e.Err)
}
func IsPermission(err error) bool {
var serviceErr *serviceError
if errors.As(err, &serviceErr) {
return errors.Is(serviceErr, fs.ErrPermission)
}
return false
}
// WinService provides interface for svc.Service
type WinService interface {
// winService provides interface for svc.Service
type winService interface {
Close() error
Config() (mgr.Config, error)
Query() (svc.Status, error)
}
// ManagerProvider sets interface for acquiring manager instance, like mgr.Mgr
type ManagerProvider interface {
Connect() (WinServiceManager, error)
// managerProvider sets interface for acquiring manager instance, like mgr.Mgr
type managerProvider interface {
connect() (winServiceManager, error)
}
// WinServiceManager provides interface for mgr.Mgr
type WinServiceManager interface {
Disconnect() error
OpenService(name string) (WinService, error)
ListServices() ([]string, error)
}
// winSvcMgr is wrapper for mgr.Mgr implementing WinServiceManager interface
type winSvcMgr struct {
realMgr *mgr.Mgr
}
func (m *winSvcMgr) Disconnect() error {
return m.realMgr.Disconnect()
}
func (m *winSvcMgr) OpenService(name string) (WinService, error) {
serviceName, err := syscall.UTF16PtrFromString(name)
if err != nil {
return nil, fmt.Errorf("cannot convert service name %q: %w", name, err)
}
h, err := windows.OpenService(m.realMgr.Handle, serviceName, windows.GENERIC_READ)
if err != nil {
return nil, err
}
return &mgr.Service{Name: name, Handle: h}, nil
}
func (m *winSvcMgr) ListServices() ([]string, error) {
return m.realMgr.ListServices()
}
// mgProvider is an implementation of WinServiceManagerProvider interface returning winSvcMgr
type mgProvider struct {
}
func (*mgProvider) Connect() (WinServiceManager, error) {
h, err := windows.OpenSCManager(nil, nil, windows.GENERIC_READ)
if err != nil {
return nil, err
}
scmgr := &mgr.Mgr{Handle: h}
return &winSvcMgr{scmgr}, nil
}
// WinServices is an implementation if telegraf.Input interface, providing info about Windows Services
type WinServices struct {
Log telegraf.Logger
ServiceNames []string `toml:"service_names"`
ServiceNamesExcluded []string `toml:"excluded_service_names"`
mgrProvider ManagerProvider
servicesFilter filter.Filter
// winServiceManager provides interface for mgr.Mgr
type winServiceManager interface {
disconnect() error
openService(name string) (winService, error)
listServices() ([]string, error)
}
type serviceInfo struct {
@ -142,11 +85,11 @@ func (m *WinServices) Init() error {
}
func (m *WinServices) Gather(acc telegraf.Accumulator) error {
scmgr, err := m.mgrProvider.Connect()
scmgr, err := m.mgrProvider.connect()
if err != nil {
return fmt.Errorf("could not open service manager: %w", err)
}
defer scmgr.Disconnect()
defer scmgr.disconnect()
serviceNames, err := m.listServices(scmgr)
if err != nil {
@ -156,7 +99,7 @@ func (m *WinServices) Gather(acc telegraf.Accumulator) error {
for _, srvName := range serviceNames {
service, err := collectServiceInfo(scmgr, srvName)
if err != nil {
if IsPermission(err) {
if isPermission(err) {
m.Log.Debug(err.Error())
} else {
m.Log.Error(err.Error())
@ -183,8 +126,8 @@ func (m *WinServices) Gather(acc telegraf.Accumulator) error {
}
// listServices returns a list of services to gather.
func (m *WinServices) listServices(scmgr WinServiceManager) ([]string, error) {
names, err := scmgr.ListServices()
func (m *WinServices) listServices(scmgr winServiceManager) ([]string, error) {
names, err := scmgr.listServices()
if err != nil {
return nil, fmt.Errorf("could not list services: %w", err)
}
@ -201,14 +144,22 @@ func (m *WinServices) listServices(scmgr WinServiceManager) ([]string, error) {
return services, nil
}
func isPermission(err error) bool {
var serviceErr *serviceError
if errors.As(err, &serviceErr) {
return errors.Is(serviceErr, fs.ErrPermission)
}
return false
}
// collectServiceInfo gathers info about a service.
func collectServiceInfo(scmgr WinServiceManager, serviceName string) (*serviceInfo, error) {
srv, err := scmgr.OpenService(serviceName)
func collectServiceInfo(scmgr winServiceManager, serviceName string) (*serviceInfo, error) {
srv, err := scmgr.openService(serviceName)
if err != nil {
return nil, &serviceError{
Message: "could not open service",
Service: serviceName,
Err: err,
message: "could not open service",
service: serviceName,
err: err,
}
}
defer srv.Close()
@ -216,18 +167,18 @@ func collectServiceInfo(scmgr WinServiceManager, serviceName string) (*serviceIn
srvStatus, err := srv.Query()
if err != nil {
return nil, &serviceError{
Message: "could not query service",
Service: serviceName,
Err: err,
message: "could not query service",
service: serviceName,
err: err,
}
}
srvCfg, err := srv.Config()
if err != nil {
return nil, &serviceError{
Message: "could not get config of service",
Service: serviceName,
Err: err,
message: "could not get config of service",
service: serviceName,
err: err,
}
}
@ -240,6 +191,54 @@ func collectServiceInfo(scmgr WinServiceManager, serviceName string) (*serviceIn
return serviceInfo, nil
}
type serviceError struct {
message string
service string
err error
}
func (e *serviceError) Error() string {
return fmt.Sprintf("%s: %q: %v", e.message, e.service, e.err)
}
// winSvcMgr is wrapper for mgr.Mgr implementing winServiceManager interface
type winSvcMgr struct {
realMgr *mgr.Mgr
}
func (m *winSvcMgr) disconnect() error {
return m.realMgr.Disconnect()
}
func (m *winSvcMgr) openService(name string) (winService, error) {
serviceName, err := syscall.UTF16PtrFromString(name)
if err != nil {
return nil, fmt.Errorf("cannot convert service name %q: %w", name, err)
}
h, err := windows.OpenService(m.realMgr.Handle, serviceName, windows.GENERIC_READ)
if err != nil {
return nil, err
}
return &mgr.Service{Name: name, Handle: h}, nil
}
func (m *winSvcMgr) listServices() ([]string, error) {
return m.realMgr.ListServices()
}
// mgProvider is an implementation of WinServiceManagerProvider interface returning winSvcMgr
type mgProvider struct {
}
func (*mgProvider) connect() (winServiceManager, error) {
h, err := windows.OpenSCManager(nil, nil, windows.GENERIC_READ)
if err != nil {
return nil, err
}
scmgr := &mgr.Mgr{Handle: h}
return &winSvcMgr{scmgr}, nil
}
func init() {
inputs.Add("win_services", func() telegraf.Input {
return &WinServices{

View File

@ -10,31 +10,31 @@ import (
"github.com/stretchr/testify/require"
)
var InvalidServices = []string{"XYZ1@", "ZYZ@", "SDF_@#"}
var KnownServices = []string{"LanmanServer", "TermService"}
var invalidServices = []string{"XYZ1@", "ZYZ@", "SDF_@#"}
var knownServices = []string{"LanmanServer", "TermService"}
func TestListIntegration(t *testing.T) {
if testing.Short() {
t.Skip("Skipping integration test in short mode")
}
provider := &mgProvider{}
scmgr, err := provider.Connect()
scmgr, err := provider.connect()
require.NoError(t, err)
defer func() {
err := scmgr.Disconnect()
err := scmgr.disconnect()
require.NoError(t, err)
}()
winServices := &WinServices{
ServiceNames: KnownServices,
ServiceNames: knownServices,
}
require.NoError(t, winServices.Init())
services, err := winServices.listServices(scmgr)
require.NoError(t, err)
require.Len(t, services, 2, "Different number of services")
require.Equal(t, services[0], KnownServices[0])
require.Equal(t, services[1], KnownServices[1])
require.Equal(t, services[0], knownServices[0])
require.Equal(t, services[1], knownServices[1])
}
func TestEmptyListIntegration(t *testing.T) {
@ -42,10 +42,10 @@ func TestEmptyListIntegration(t *testing.T) {
t.Skip("Skipping integration test in short mode")
}
provider := &mgProvider{}
scmgr, err := provider.Connect()
scmgr, err := provider.connect()
require.NoError(t, err)
defer func() {
err := scmgr.Disconnect()
err := scmgr.disconnect()
require.NoError(t, err)
}()
@ -65,7 +65,7 @@ func TestGatherErrorsIntegration(t *testing.T) {
}
ws := &WinServices{
Log: testutil.Logger{},
ServiceNames: InvalidServices,
ServiceNames: invalidServices,
mgrProvider: &mgProvider{},
}

View File

@ -23,6 +23,7 @@ func (w *WinServices) Init() error {
w.Log.Warn("Current platform is not supported")
return nil
}
func (*WinServices) Gather(telegraf.Accumulator) error { return nil }
func init() {

View File

@ -18,7 +18,7 @@ import (
// testData is DD wrapper for unit testing of WinServices
type testData struct {
// collection that will be returned in ListServices if service array passed into WinServices constructor is empty
// collection that will be returned in listServices if service array passed into WinServices constructor is empty
queryServiceList []string
mgrConnectError error
mgrListServicesError error
@ -39,23 +39,23 @@ type FakeSvcMgr struct {
testData testData
}
func (*FakeSvcMgr) Disconnect() error {
func (*FakeSvcMgr) disconnect() error {
return nil
}
func (m *FakeSvcMgr) OpenService(name string) (WinService, error) {
func (m *FakeSvcMgr) openService(name string) (winService, error) {
for _, s := range m.testData.services {
if s.serviceName == name {
if s.serviceOpenError != nil {
return nil, s.serviceOpenError
}
return &FakeWinSvc{s}, nil
return &fakeWinSvc{s}, nil
}
}
return nil, fmt.Errorf("cannot find service %q", name)
}
func (m *FakeSvcMgr) ListServices() ([]string, error) {
func (m *FakeSvcMgr) listServices() ([]string, error) {
if m.testData.mgrListServicesError != nil {
return nil, m.testData.mgrListServicesError
}
@ -66,21 +66,22 @@ type FakeMgProvider struct {
testData testData
}
func (m *FakeMgProvider) Connect() (WinServiceManager, error) {
func (m *FakeMgProvider) connect() (winServiceManager, error) {
if m.testData.mgrConnectError != nil {
return nil, m.testData.mgrConnectError
}
return &FakeSvcMgr{m.testData}, nil
}
type FakeWinSvc struct {
type fakeWinSvc struct {
testData serviceTestInfo
}
func (*FakeWinSvc) Close() error {
func (*fakeWinSvc) Close() error {
return nil
}
func (m *FakeWinSvc) Config() (mgr.Config, error) {
func (m *fakeWinSvc) Config() (mgr.Config, error) {
if m.testData.serviceConfigError != nil {
return mgr.Config{}, m.testData.serviceConfigError
}
@ -98,7 +99,8 @@ func (m *FakeWinSvc) Config() (mgr.Config, error) {
Description: "",
}, nil
}
func (m *FakeWinSvc) Query() (svc.Status, error) {
func (m *fakeWinSvc) Query() (svc.Status, error) {
if m.testData.serviceQueryError != nil {
return svc.Status{}, m.testData.serviceQueryError
}

View File

@ -15,8 +15,7 @@ import (
"github.com/influxdata/telegraf/internal"
)
// Method struct
type Method struct {
type method struct {
Namespace string `toml:"namespace"`
ClassName string `toml:"class_name"`
Method string `toml:"method"`
@ -30,7 +29,7 @@ type Method struct {
tagFilter filter.Filter
}
func (m *Method) prepare(host string, username, password config.Secret) error {
func (m *method) prepare(host string, username, password config.Secret) error {
// Compile the filter
f, err := filter.Compile(m.TagPropertiesInclude)
if err != nil {
@ -66,7 +65,7 @@ func (m *Method) prepare(host string, username, password config.Secret) error {
return nil
}
func (m *Method) execute(acc telegraf.Accumulator) error {
func (m *method) execute(acc telegraf.Accumulator) error {
// The only way to run WMI queries in parallel while being thread-safe is to
// ensure the CoInitialize[Ex]() call is bound to its current OS thread.
// Otherwise, attempting to initialize and run parallel queries across

View File

@ -17,8 +17,7 @@ import (
"github.com/influxdata/telegraf/internal"
)
// Query struct
type Query struct {
type query struct {
Namespace string `toml:"namespace"`
ClassName string `toml:"class_name"`
Properties []string `toml:"properties"`
@ -31,7 +30,7 @@ type Query struct {
tagFilter filter.Filter
}
func (q *Query) prepare(host string, username, password config.Secret) error {
func (q *query) prepare(host string, username, password config.Secret) error {
// Compile the filter
f, err := filter.Compile(q.TagPropertiesInclude)
if err != nil {
@ -74,7 +73,7 @@ func (q *Query) prepare(host string, username, password config.Secret) error {
return nil
}
func (q *Query) execute(acc telegraf.Accumulator) error {
func (q *query) execute(acc telegraf.Accumulator) error {
// The only way to run WMI queries in parallel while being thread-safe is to
// ensure the CoInitialize[Ex]() call is bound to its current OS thread.
// Otherwise, attempting to initialize and run parallel queries across
@ -143,7 +142,7 @@ func (q *Query) execute(acc telegraf.Accumulator) error {
return nil
}
func (q *Query) extractProperties(acc telegraf.Accumulator, itemRaw *ole.VARIANT) error {
func (q *query) extractProperties(acc telegraf.Accumulator, itemRaw *ole.VARIANT) error {
tags, fields := make(map[string]string), make(map[string]interface{})
if q.host != "" {

View File

@ -16,20 +16,22 @@ import (
//go:embed sample.conf
var sampleConfig string
// Wmi struct
// S_FALSE is returned by CoInitializeEx if it was already called on this thread.
const sFalse = 0x00000001
type Wmi struct {
Host string `toml:"host"`
Username config.Secret `toml:"username"`
Password config.Secret `toml:"password"`
Queries []Query `toml:"query"`
Methods []Method `toml:"method"`
Queries []query `toml:"query"`
Methods []method `toml:"method"`
Log telegraf.Logger `toml:"-"`
}
// S_FALSE is returned by CoInitializeEx if it was already called on this thread.
const sFalse = 0x00000001
func (*Wmi) SampleConfig() string {
return sampleConfig
}
// Init function
func (w *Wmi) Init() error {
for i := range w.Queries {
q := &w.Queries[i]
@ -48,28 +50,22 @@ func (w *Wmi) Init() error {
return nil
}
// SampleConfig function
func (*Wmi) SampleConfig() string {
return sampleConfig
}
// Gather function
func (w *Wmi) Gather(acc telegraf.Accumulator) error {
var wg sync.WaitGroup
for _, query := range w.Queries {
for _, q := range w.Queries {
wg.Add(1)
go func(q Query) {
go func(q query) {
defer wg.Done()
acc.AddError(q.execute(acc))
}(query)
}(q)
}
for _, method := range w.Methods {
for _, m := range w.Methods {
wg.Add(1)
go func(m Method) {
go func(m method) {
defer wg.Done()
acc.AddError(m.execute(acc))
}(method)
}(m)
}
wg.Wait()

View File

@ -17,12 +17,14 @@ type Wmi struct {
Log telegraf.Logger `toml:"-"`
}
func (*Wmi) SampleConfig() string { return sampleConfig }
func (w *Wmi) Init() error {
w.Log.Warn("current platform is not supported")
w.Log.Warn("Current platform is not supported")
return nil
}
func (*Wmi) SampleConfig() string { return sampleConfig }
func (*Wmi) Gather(_ telegraf.Accumulator) error { return nil }
func (*Wmi) Gather(telegraf.Accumulator) error { return nil }
func init() {
inputs.Add("win_wmi", func() telegraf.Input { return &Wmi{} })

View File

@ -19,7 +19,7 @@ var sysDrive = os.Getenv("SystemDrive") + `\` // C:\
func TestBuildWqlStatements(t *testing.T) {
plugin := &Wmi{
Queries: []Query{
Queries: []query{
{
Namespace: "ROOT\\cimv2",
ClassName: "Win32_Volume",
@ -53,7 +53,7 @@ func TestQueryIntegration(t *testing.T) {
}
plugin := &Wmi{
Queries: []Query{
Queries: []query{
{
Namespace: "ROOT\\cimv2",
ClassName: "Win32_Volume",
@ -84,7 +84,7 @@ func TestMethodIntegration(t *testing.T) {
}
plugin := &Wmi{
Methods: []Method{
Methods: []method{
{
Namespace: "ROOT\\default",
ClassName: "StdRegProv",