performancecounter: rename collector (#1787)

Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
Jan-Otto Kröpke
2024-11-30 11:24:01 +01:00
committed by GitHub
parent a359acb3d1
commit 9db94aa66a
13 changed files with 452 additions and 323 deletions

View File

@@ -13,14 +13,12 @@
//go:build windows
package perfdata
package performancecounter
import (
"encoding/json"
"fmt"
"log/slog"
"maps"
"slices"
"strings"
"github.com/alecthomas/kingpin/v2"
@@ -30,7 +28,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
const Name = "perfdata"
const Name = "performancecounter"
type Config struct {
Objects []Object `yaml:"objects"`
@@ -41,9 +39,11 @@ var ConfigDefaults = Config{
Objects: make([]Object, 0),
}
// A Collector is a Prometheus collector for perfdata metrics.
// A Collector is a Prometheus collector for performance counter metrics.
type Collector struct {
config Config
logger *slog.Logger
}
func New(config *Config) *Collector {
@@ -70,7 +70,7 @@ func NewWithFlags(app *kingpin.Application) *Collector {
var objects string
app.Flag(
"collector.perfdata.objects",
"collector.performancecounter.objects",
"Objects of performance data to observe. See docs for more information on how to use this flag. By default, no objects are observed.",
).Default("").StringVar(&objects)
@@ -102,10 +102,19 @@ func (c *Collector) Close() error {
}
func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
logger.Warn("The perfdata collector is in an experimental state! The configuration may change in future. Please report any issues.")
c.logger = logger.With(slog.String("collector", Name))
for i, object := range c.config.Objects {
collector, err := perfdata.NewCollector(object.Object, object.Instances, slices.Sorted(maps.Keys(object.Counters)))
counters := make([]string, 0, len(object.Counters))
for j, counter := range object.Counters {
counters = append(counters, counter.Name)
if counter.Metric == "" {
c.config.Objects[i].Counters[j].Metric = sanitizeMetricName(fmt.Sprintf("%s_%s_%s_%s", types.Namespace, Name, object.Object, counter.Name))
}
}
collector, err := perfdata.NewCollector(object.Object, object.Instances, counters)
if err != nil {
return fmt.Errorf("failed to create v2 collector: %w", err)
}
@@ -123,40 +132,64 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *Collector) Collect(ch chan<- prometheus.Metric) error {
for _, object := range c.config.Objects {
data, err := object.collector.Collect()
for _, perfDataObject := range c.config.Objects {
collectedPerfData, err := perfDataObject.collector.Collect()
if err != nil {
return fmt.Errorf("failed to collect data: %w", err)
}
for instance, counters := range data {
for counter, value := range counters {
var labels prometheus.Labels
if instance != perfdata.InstanceEmpty {
labels = prometheus.Labels{object.InstanceLabel: instance}
for collectedInstance, collectedInstanceCounters := range collectedPerfData {
for _, counter := range perfDataObject.Counters {
collectedCounterValue, ok := collectedInstanceCounters[counter.Name]
if !ok {
c.logger.Warn(fmt.Sprintf("counter %s not found in collected data", counter.Name))
continue
}
metricType := value.Type
labels := make(prometheus.Labels, len(counter.Labels)+1)
if collectedInstance != perfdata.InstanceEmpty {
labels[perfDataObject.InstanceLabel] = collectedInstance
}
if val, ok := object.Counters[counter]; ok {
switch val.Type {
case "counter":
metricType = prometheus.CounterValue
case "gauge":
metricType = prometheus.GaugeValue
}
for key, value := range counter.Labels {
labels[key] = value
}
var metricType prometheus.ValueType
switch counter.Type {
case "counter":
metricType = prometheus.CounterValue
case "gauge":
metricType = prometheus.GaugeValue
default:
metricType = collectedCounterValue.Type
}
ch <- prometheus.MustNewConstMetric(
prometheus.NewDesc(
sanitizeMetricName(fmt.Sprintf("%s_perfdata_%s_%s", types.Namespace, object.Object, counter)),
fmt.Sprintf("Performance data for \\%s\\%s", object.Object, counter),
counter.Metric,
"windows_exporter: custom Performance Counter metric",
nil,
labels,
),
metricType,
value.FirstValue,
collectedCounterValue.FirstValue,
)
if collectedCounterValue.SecondValue != 0 {
ch <- prometheus.MustNewConstMetric(
prometheus.NewDesc(
counter.Metric+"_second",
"windows_exporter: custom Performance Counter metric",
nil,
labels,
),
metricType,
collectedCounterValue.SecondValue,
)
}
}
}
}

View File

@@ -13,19 +13,19 @@
//go:build windows
package perfdata_test
package performancecounter_test
import (
"testing"
"github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/collector/perfdata"
"github.com/prometheus-community/windows_exporter/internal/collector/performancecounter"
"github.com/prometheus-community/windows_exporter/internal/utils/testutils"
)
func BenchmarkCollector(b *testing.B) {
perfDataObjects := `[{"object":"Processor Information","instances":["*"],"counters":{"*": {}}}]`
perfDataObjects := `[{"object":"Processor Information","instances":["*"],"instance_label":"core","counters":[{"name":"% Processor Time","metric":"windows_performancecounter_processor_information_processor_time","labels":{"state":"active"}},{"name":"% Idle Time","metric":"windows_performancecounter_processor_information_processor_time","labels":{"state":"idle"}}]},{"object":"Memory","counters":[{"name":"Cache Faults/sec","type":"counter"}]}]`
kingpin.CommandLine.GetArg("collector.perfdata.objects").StringVar(&perfDataObjects)
testutils.FuncBenchmarkCollector(b, perfdata.Name, perfdata.NewWithFlags)
testutils.FuncBenchmarkCollector(b, performancecounter.Name, performancecounter.NewWithFlags)
}

View File

@@ -13,7 +13,7 @@
//go:build windows
package perfdata_test
package performancecounter_test
import (
"fmt"
@@ -24,7 +24,7 @@ import (
"regexp"
"testing"
"github.com/prometheus-community/windows_exporter/internal/collector/perfdata"
"github.com/prometheus-community/windows_exporter/internal/collector/performancecounter"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/stretchr/testify/assert"
@@ -32,7 +32,7 @@ import (
)
type collectorAdapter struct {
perfdata.Collector
performancecounter.Collector
}
// Describe implements the prometheus.Collector interface.
@@ -51,31 +51,40 @@ func TestCollector(t *testing.T) {
for _, tc := range []struct {
object string
instances []string
counters map[string]perfdata.Counter
instanceLabel string
counters []performancecounter.Counter
expectedMetrics *regexp.Regexp
}{
{
object: "Memory",
instances: nil,
counters: map[string]perfdata.Counter{"Available Bytes": {Type: "gauge"}},
expectedMetrics: regexp.MustCompile(`^# HELP windows_perfdata_memory_available_bytes Performance data for \\\\Memory\\\\Available Bytes\s*# TYPE windows_perfdata_memory_available_bytes gauge\s*windows_perfdata_memory_available_bytes \d`),
counters: []performancecounter.Counter{{Name: "Available Bytes", Type: "gauge"}},
expectedMetrics: regexp.MustCompile(`^# HELP windows_performancecounter_memory_available_bytes windows_exporter: custom Performance Counter metric\S*\s*# TYPE windows_performancecounter_memory_available_bytes gauge\s*windows_performancecounter_memory_available_bytes \d`),
},
{
object: "Process",
instances: []string{"*"},
counters: map[string]perfdata.Counter{"Thread Count": {Type: "counter"}},
expectedMetrics: regexp.MustCompile(`^# HELP windows_perfdata_process_thread_count Performance data for \\\\Process\\\\Thread Count\s*# TYPE windows_perfdata_process_thread_count counter\s*windows_perfdata_process_thread_count\{instance=".+"} \d`),
counters: []performancecounter.Counter{{Name: "Thread Count", Type: "counter"}},
expectedMetrics: regexp.MustCompile(`^# HELP windows_performancecounter_process_thread_count windows_exporter: custom Performance Counter metric\S*\s*# TYPE windows_performancecounter_process_thread_count counter\s*windows_performancecounter_process_thread_count\{instance=".+"} \d`),
},
{
object: "Processor Information",
instances: []string{"*"},
instanceLabel: "core",
counters: []performancecounter.Counter{{Name: "% Processor Time", Metric: "windows_performancecounter_processor_information_processor_time", Labels: map[string]string{"state": "active"}}, {Name: "% Idle Time", Metric: "windows_performancecounter_processor_information_processor_time", Labels: map[string]string{"state": "idle"}}},
expectedMetrics: regexp.MustCompile(`^# HELP windows_performancecounter_processor_information_processor_time windows_exporter: custom Performance Counter metric\s+# TYPE windows_performancecounter_processor_information_processor_time counter\s+windows_performancecounter_processor_information_processor_time\{core="0,0",state="active"} [0-9.e+]+\s+windows_performancecounter_processor_information_processor_time\{core="0,0",state="idle"} [0-9.e+]+`),
},
} {
t.Run(tc.object, func(t *testing.T) {
t.Parallel()
perfDataCollector := perfdata.New(&perfdata.Config{
Objects: []perfdata.Object{
perfDataCollector := performancecounter.New(&performancecounter.Config{
Objects: []performancecounter.Object{
{
Object: tc.object,
Instances: tc.instances,
Counters: tc.counters,
Object: tc.object,
Instances: tc.instances,
InstanceLabel: tc.instanceLabel,
Counters: tc.counters,
},
},
})

View File

@@ -13,19 +13,24 @@
//go:build windows
package perfdata
package performancecounter
import "github.com/prometheus-community/windows_exporter/internal/perfdata"
type Object struct {
Object string `json:"object" yaml:"object"`
Instances []string `json:"instances" yaml:"instances"`
Counters map[string]Counter `json:"counters" yaml:"counters"`
InstanceLabel string `json:"instance_label" yaml:"instance_label"` //nolint:tagliatelle
Object string `json:"object" yaml:"object"`
Instances []string `json:"instances" yaml:"instances"`
Counters []Counter `json:"counters" yaml:"counters"`
InstanceLabel string `json:"instance_label" yaml:"instance_label"` //nolint:tagliatelle
collector *perfdata.Collector
}
type Counter struct {
Type string `json:"type" yaml:"type"`
Name string `json:"name" yaml:"name"`
Type string `json:"type" yaml:"type"`
Metric string `json:"metric" yaml:"metric"`
Labels map[string]string `json:"labels" yaml:"labels"`
}
// https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/54691ebe11bb9ec32b4e35cd31fcb94a352de134/receiver/windowsperfcountersreceiver/README.md?plain=1#L150