chore: Fix linter findings for `revive:exported` in `plugins/inputs/win*` (#16427)
This commit is contained in:
parent
b074f0893d
commit
25de05a8fc
|
|
@ -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"`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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{},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 != "" {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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{} })
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in New Issue