logical_disk: Implement Perfdata collector (#1673)

This commit is contained in:
Jan-Otto Kröpke
2024-10-07 00:15:54 +02:00
committed by GitHub
parent efb20b1e31
commit 2ef1a5fdf1
19 changed files with 400 additions and 88 deletions

View File

@@ -2,6 +2,7 @@ package v1
import (
"fmt"
"strings"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
"github.com/prometheus/client_golang/prometheus"
@@ -43,11 +44,23 @@ func (c *Collector) Collect() (map[string]map[string]perftypes.CounterValues, er
return nil, fmt.Errorf("QueryPerformanceData: %w", err)
}
if len(perfObjects) == 0 {
return map[string]map[string]perftypes.CounterValues{}, nil
}
data := make(map[string]map[string]perftypes.CounterValues, len(perfObjects[0].Instances))
for _, perfObject := range perfObjects {
if perfObject.Name != c.object {
continue
}
for _, perfInstance := range perfObject.Instances {
instanceName := perfInstance.Name
if strings.HasSuffix(instanceName, "_Total") {
continue
}
if instanceName == "" || instanceName == "*" {
instanceName = perftypes.EmptyInstance
}
@@ -57,6 +70,10 @@ func (c *Collector) Collect() (map[string]map[string]perftypes.CounterValues, er
}
for _, perfCounter := range perfInstance.Counters {
if perfCounter.Def.IsBaseValue && !perfCounter.Def.IsNanosecondCounter {
continue
}
if _, ok := data[instanceName][perfCounter.Def.Name]; !ok {
data[instanceName][perfCounter.Def.Name] = perftypes.CounterValues{
Type: prometheus.GaugeValue,

View File

@@ -117,16 +117,16 @@ import (
"fmt"
"io"
"strings"
"time"
"unsafe"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
"golang.org/x/sys/windows"
)
// TODO: There's a LittleEndian field in the PERF header - we ought to check it.
var bo = binary.LittleEndian
const averageCount64Type = 1073874176
// PerfObject Top-level performance object (like "Process").
type PerfObject struct {
Name string
@@ -221,13 +221,18 @@ func queryRawData(query string) ([]byte, error) {
(*byte)(unsafe.Pointer(&buffer[0])),
&bufLen)
if errors.Is(err, error(windows.ERROR_MORE_DATA)) {
switch {
case errors.Is(err, error(windows.ERROR_MORE_DATA)):
newBuffer := make([]byte, len(buffer)+16384)
copy(newBuffer, buffer)
buffer = newBuffer
continue
} else if err != nil {
case errors.Is(err, error(windows.ERROR_BUSY)):
time.Sleep(50 * time.Millisecond)
continue
case err != nil:
var errNo windows.Errno
if errors.As(err, &errNo) {
return nil, fmt.Errorf("ReqQueryValueEx failed: %w errno %d", err, uint(errNo))
@@ -349,7 +354,7 @@ func QueryPerformanceData(query string) ([]*PerfObject, error) {
IsCounter: def.CounterType&0x400 == 0x400,
IsBaseValue: def.CounterType&0x00030000 == 0x00030000,
IsNanosecondCounter: def.CounterType&0x00100000 == 0x00100000,
HasSecondValue: def.CounterType == averageCount64Type,
HasSecondValue: def.CounterType == perftypes.PERF_AVERAGE_BULK,
}
}