process: fix fallback to V1 collector (#1667)

This commit is contained in:
Jan-Otto Kröpke
2024-10-03 23:44:36 +02:00
committed by GitHub
parent 79baf9921d
commit 2a9a11bd01
5 changed files with 159 additions and 120 deletions

View File

@@ -162,6 +162,7 @@ func (c *Collector) Build(logger *slog.Logger, wmiClient *wmi.Client) error {
if utils.PDHEnabled() {
counters := []string{
processID,
percentProcessorTime,
percentPrivilegedTime,
percentUserTime,
@@ -181,7 +182,6 @@ func (c *Collector) Build(logger *slog.Logger, wmiClient *wmi.Client) error {
pageFileBytes,
poolNonPagedBytes,
poolPagedBytes,
processID,
priorityBase,
privateBytes,
threadCount,
@@ -195,37 +195,8 @@ func (c *Collector) Build(logger *slog.Logger, wmiClient *wmi.Client) error {
var err error
c.perfDataCollector, err = perfdata.NewCollector("Process V2", c.config.PerfCounterInstances, counters)
if errors.Is(err, perfdata.NewPdhError(perfdata.PdhNoData)) {
counters = []string{
percentProcessorTime,
percentPrivilegedTime,
percentUserTime,
creatingProcessID,
elapsedTime,
handleCount,
idProcess,
ioDataBytesPerSec,
ioDataOperationsPerSec,
ioOtherBytesPerSec,
ioOtherOperationsPerSec,
ioReadBytesPerSec,
ioReadOperationsPerSec,
ioWriteBytesPerSec,
ioWriteOperationsPerSec,
pageFaultsPerSec,
pageFileBytesPeak,
pageFileBytes,
poolNonPagedBytes,
poolPagedBytes,
priorityBase,
privateBytes,
threadCount,
virtualBytesPeak,
virtualBytes,
workingSetPrivate,
workingSetPeak,
workingSet,
}
if errors.Is(err, perfdata.NewPdhError(perfdata.PdhCstatusNoObject)) {
counters[0] = idProcess
c.perfDataCollector, err = perfdata.NewCollector("Process", c.config.PerfCounterInstances, counters)
}

View File

@@ -1,11 +1,18 @@
package process_test
import (
"io"
"log/slog"
"sync"
"testing"
"time"
"github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/collector/process"
"github.com/prometheus-community/windows_exporter/internal/testutils"
"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/require"
"github.com/yusufpapurcu/wmi"
)
func BenchmarkProcessCollector(b *testing.B) {
@@ -15,3 +22,49 @@ func BenchmarkProcessCollector(b *testing.B) {
// No context name required as collector source is WMI
testutils.FuncBenchmarkCollector(b, process.Name, process.NewWithFlags)
}
func TestProcessCollector(t *testing.T) {
t.Setenv("WINDOWS_EXPORTER_PERF_COUNTERS_ENGINE", "pdh")
var (
metrics []prometheus.Metric
err error
)
logger := slog.New(slog.NewTextHandler(io.Discard, nil))
c := process.New(nil)
ch := make(chan prometheus.Metric, 10000)
wmiClient := &wmi.Client{
AllowMissingFields: true,
}
wmiClient.SWbemServicesClient, err = wmi.InitializeSWbemServices(wmiClient)
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, c.Close(logger))
})
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
for metric := range ch {
metrics = append(metrics, metric)
}
}()
require.NoError(t, c.Build(logger, wmiClient))
time.Sleep(1 * time.Second)
require.NoError(t, c.Collect(nil, logger, ch))
close(ch)
wg.Wait()
require.NotEmpty(t, metrics)
}

View File

@@ -1,11 +1,26 @@
package perfdata
import "errors"
// Error represents error returned from Performance Counters API.
type Error struct {
ErrorCode uint32
errorText string
}
func (m *Error) Is(err error) bool {
if err == nil {
return false
}
var e *Error
if errors.As(err, &e) {
return m.ErrorCode == e.ErrorCode
}
return false
}
func (m *Error) Error() string {
return m.errorText
}

View File

@@ -57,92 +57,92 @@ type (
// 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 uint32 = 0x00000000 // The returned data is valid.
PdhCstatusNewData uint32 = 0x00000001 // The return data value is valid and different from the last sample.
PdhCstatusNoMachine uint32 = 0x800007D0 // Unable to connect to the specified computer, or the computer is offline.
PdhCstatusNoInstance uint32 = 0x800007D1
PdhMoreData uint32 = 0x800007D2 // The PdhGetFormattedCounterArray* function can return this if there's 'more data to be displayed'.
PdhCstatusItemNotValidated uint32 = 0x800007D3
PdhRetry uint32 = 0x800007D4
PdhNoData uint32 = 0x800007D5 // The query does not currently contain any counters (for example, limited access)
PdhCalcNegativeDenominator uint32 = 0x800007D6
PdhCalcNegativeTimebase uint32 = 0x800007D7
PdhCalcNegativeValue uint32 = 0x800007D8
PdhDialogCancelled uint32 = 0x800007D9
PdhEndOfLogFile uint32 = 0x800007DA
PdhAsyncQueryTimeout uint32 = 0x800007DB
PdhCannotSetDefaultRealtimeDatasource uint32 = 0x800007DC
PdhCstatusNoObject uint32 = 0xC0000BB8
PdhCstatusNoCounter uint32 = 0xC0000BB9 // The specified counter could not be found.
PdhCstatusInvalidData uint32 = 0xC0000BBA // The counter was successfully found, but the data returned is not valid.
PdhMemoryAllocationFailure uint32 = 0xC0000BBB
PdhInvalidHandle uint32 = 0xC0000BBC
PdhInvalidArgument uint32 = 0xC0000BBD // Required argument is missing or incorrect.
PdhFunctionNotFound uint32 = 0xC0000BBE
PdhCstatusNoCountername uint32 = 0xC0000BBF
PdhCstatusBadCountername uint32 = 0xC0000BC0 // Unable to parse the counter path. Check the format and syntax of the specified path.
PdhInvalidBuffer uint32 = 0xC0000BC1
PdhInsufficientBuffer uint32 = 0xC0000BC2
PdhCannotConnectMachine uint32 = 0xC0000BC3
PdhInvalidPath uint32 = 0xC0000BC4
PdhInvalidInstance uint32 = 0xC0000BC5
PdhInvalidData uint32 = 0xC0000BC6 // specified counter does not contain valid data or a successful status code.
PdhNoDialogData uint32 = 0xC0000BC7
PdhCannotReadNameStrings uint32 = 0xC0000BC8
PdhLogFileCreateError uint32 = 0xC0000BC9
PdhLogFileOpenError uint32 = 0xC0000BCA
PdhLogTypeNotFound uint32 = 0xC0000BCB
PdhNoMoreData uint32 = 0xC0000BCC
PdhEntryNotInLogFile uint32 = 0xC0000BCD
PdhDataSourceIsLogFile uint32 = 0xC0000BCE
PdhDataSourceIsRealTime uint32 = 0xC0000BCF
PdhUnableReadLogHeader uint32 = 0xC0000BD0
PdhFileNotFound uint32 = 0xC0000BD1
PdhFileAlreadyExists uint32 = 0xC0000BD2
PdhNotImplemented uint32 = 0xC0000BD3
PdhStringNotFound uint32 = 0xC0000BD4
PdhUnableMapNameFiles uint32 = 0x80000BD5
PdhUnknownLogFormat uint32 = 0xC0000BD6
PdhUnknownLogsvcCommand uint32 = 0xC0000BD7
PdhLogsvcQueryNotFound uint32 = 0xC0000BD8
PdhLogsvcNotOpened uint32 = 0xC0000BD9
PdhWbemError uint32 = 0xC0000BDA
PdhAccessDenied uint32 = 0xC0000BDB
PdhLogFileTooSmall uint32 = 0xC0000BDC
PdhInvalidDatasource uint32 = 0xC0000BDD
PdhInvalidSqldb uint32 = 0xC0000BDE
PdhNoCounters uint32 = 0xC0000BDF
PdhSQLAllocFailed uint32 = 0xC0000BE0
PdhSQLAllocconFailed uint32 = 0xC0000BE1
PdhSQLExecDirectFailed uint32 = 0xC0000BE2
PdhSQLFetchFailed uint32 = 0xC0000BE3
PdhSQLRowcountFailed uint32 = 0xC0000BE4
PdhSQLMoreResultsFailed uint32 = 0xC0000BE5
PdhSQLConnectFailed uint32 = 0xC0000BE6
PdhSQLBindFailed uint32 = 0xC0000BE7
PdhCannotConnectWmiServer uint32 = 0xC0000BE8
PdhPlaCollectionAlreadyRunning uint32 = 0xC0000BE9
PdhPlaErrorScheduleOverlap uint32 = 0xC0000BEA
PdhPlaCollectionNotFound uint32 = 0xC0000BEB
PdhPlaErrorScheduleElapsed uint32 = 0xC0000BEC
PdhPlaErrorNostart uint32 = 0xC0000BED
PdhPlaErrorAlreadyExists uint32 = 0xC0000BEE
PdhPlaErrorTypeMismatch uint32 = 0xC0000BEF
PdhPlaErrorFilepath uint32 = 0xC0000BF0
PdhPlaServiceError uint32 = 0xC0000BF1
PdhPlaValidationError uint32 = 0xC0000BF2
PdhPlaValidationWarning uint32 = 0x80000BF3
PdhPlaErrorNameTooLong uint32 = 0xC0000BF4
PdhInvalidSQLLogFormat uint32 = 0xC0000BF5
PdhCounterAlreadyInQuery uint32 = 0xC0000BF6
PdhBinaryLogCorrupt uint32 = 0xC0000BF7
PdhLogSampleTooSmall uint32 = 0xC0000BF8
PdhOsLaterVersion uint32 = 0xC0000BF9
PdhOsEarlierVersion uint32 = 0xC0000BFA
PdhIncorrectAppendTime uint32 = 0xC0000BFB
PdhUnmatchedAppendCounter uint32 = 0xC0000BFC
PdhSQLAlterDetailFailed uint32 = 0xC0000BFD
PdhQueryPerfDataTimeout uint32 = 0xC0000BFE
)
var PDHErrors = map[uint32]string{

View File

@@ -3,6 +3,6 @@ package types
import "regexp"
var (
RegExpAny = regexp.MustCompile(".+")
RegExpEmpty = regexp.MustCompile("")
RegExpAny = regexp.MustCompile("^(?:.+)$")
RegExpEmpty = regexp.MustCompile("^(?:)$")
)