mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-03-11 13:06:36 +00:00
process: Use registry collector for V1 data (#1814)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
178
internal/pdh/registry/collector.go
Normal file
178
internal/pdh/registry/collector.go
Normal file
@@ -0,0 +1,178 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus-community/windows_exporter/internal/mi"
|
||||
"github.com/prometheus-community/windows_exporter/internal/pdh"
|
||||
)
|
||||
|
||||
type Collector struct {
|
||||
object string
|
||||
query string
|
||||
|
||||
counters map[string]Counter
|
||||
nameIndexValue int
|
||||
}
|
||||
|
||||
type Counter struct {
|
||||
Name string
|
||||
Desc string
|
||||
Instances map[string]uint32
|
||||
Type uint32
|
||||
Frequency float64
|
||||
|
||||
FieldIndexValue int
|
||||
FieldIndexSecondValue int
|
||||
}
|
||||
|
||||
func NewCollector[T any](object string, _ []string) (*Collector, error) {
|
||||
collector := &Collector{
|
||||
object: object,
|
||||
query: MapCounterToIndex(object),
|
||||
nameIndexValue: -1,
|
||||
counters: make(map[string]Counter),
|
||||
}
|
||||
|
||||
var values [0]T
|
||||
valueType := reflect.TypeOf(values).Elem()
|
||||
|
||||
if f, ok := valueType.FieldByName("Name"); ok {
|
||||
if f.Type.Kind() == reflect.String {
|
||||
collector.nameIndexValue = f.Index[0]
|
||||
}
|
||||
}
|
||||
|
||||
for _, f := range reflect.VisibleFields(valueType) {
|
||||
counterName, ok := f.Tag.Lookup("perfdata")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
var counter Counter
|
||||
if counter, ok = collector.counters[counterName]; !ok {
|
||||
counter = Counter{
|
||||
Name: counterName,
|
||||
FieldIndexSecondValue: -1,
|
||||
FieldIndexValue: -1,
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasSuffix(counterName, ",secondvalue") {
|
||||
counterName = strings.TrimSuffix(counterName, ",secondvalue")
|
||||
|
||||
counter.FieldIndexSecondValue = f.Index[0]
|
||||
} else {
|
||||
counter.FieldIndexValue = f.Index[0]
|
||||
}
|
||||
|
||||
collector.counters[counterName] = counter
|
||||
}
|
||||
|
||||
var collectValues []T
|
||||
|
||||
if err := collector.Collect(&collectValues); err != nil {
|
||||
return nil, fmt.Errorf("failed to collect initial data: %w", err)
|
||||
}
|
||||
|
||||
return collector, nil
|
||||
}
|
||||
|
||||
func (c *Collector) Describe() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (c *Collector) Collect(data any) error {
|
||||
dv := reflect.ValueOf(data)
|
||||
if dv.Kind() != reflect.Ptr || dv.IsNil() {
|
||||
return mi.ErrInvalidEntityType
|
||||
}
|
||||
|
||||
dv = dv.Elem()
|
||||
|
||||
elemType := dv.Type().Elem()
|
||||
elemValue := reflect.ValueOf(reflect.New(elemType).Interface()).Elem()
|
||||
|
||||
if dv.Kind() != reflect.Slice || elemType.Kind() != reflect.Struct {
|
||||
return mi.ErrInvalidEntityType
|
||||
}
|
||||
|
||||
perfObjects, err := QueryPerformanceData(c.query, c.object)
|
||||
if err != nil {
|
||||
return fmt.Errorf("QueryPerformanceData: %w", err)
|
||||
}
|
||||
|
||||
if len(perfObjects) == 0 || perfObjects[0] == nil || len(perfObjects[0].Instances) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if dv.Len() != 0 {
|
||||
dv.Set(reflect.MakeSlice(dv.Type(), 0, len(perfObjects[0].Instances)))
|
||||
}
|
||||
|
||||
dv.Clear()
|
||||
|
||||
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 = pdh.InstanceEmpty
|
||||
}
|
||||
|
||||
if c.nameIndexValue != -1 {
|
||||
elemValue.Field(c.nameIndexValue).SetString(instanceName)
|
||||
}
|
||||
|
||||
dv.Set(reflect.Append(dv, elemValue))
|
||||
index := dv.Len() - 1
|
||||
|
||||
for _, perfCounter := range perfInstance.Counters {
|
||||
if perfCounter.Def.IsBaseValue && !perfCounter.Def.IsNanosecondCounter {
|
||||
continue
|
||||
}
|
||||
|
||||
counter, ok := c.counters[perfCounter.Def.Name]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
switch perfCounter.Def.CounterType {
|
||||
case pdh.PERF_ELAPSED_TIME:
|
||||
dv.Index(index).
|
||||
Field(counter.FieldIndexValue).
|
||||
SetFloat(float64((perfCounter.Value - pdh.WindowsEpoch) / perfObject.Frequency))
|
||||
case pdh.PERF_100NSEC_TIMER, pdh.PERF_PRECISION_100NS_TIMER:
|
||||
dv.Index(index).
|
||||
Field(counter.FieldIndexValue).
|
||||
SetFloat(float64(perfCounter.Value) * pdh.TicksToSecondScaleFactor)
|
||||
default:
|
||||
if counter.FieldIndexSecondValue != -1 {
|
||||
dv.Index(index).
|
||||
Field(counter.FieldIndexSecondValue).
|
||||
SetFloat(float64(perfCounter.SecondValue))
|
||||
}
|
||||
|
||||
if counter.FieldIndexValue != -1 {
|
||||
dv.Index(index).
|
||||
Field(counter.FieldIndexValue).
|
||||
SetFloat(float64(perfCounter.Value))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Collector) Close() {}
|
||||
Reference in New Issue
Block a user