mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-10-17 10:09:05 +02:00
performancecounter: add a multiplier option to convert values to base units (#2773)
Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
db1ad936dc
commit
dfc5653376
@@ -65,6 +65,7 @@ YAML:
|
||||
- name: "Cache Faults/sec"
|
||||
metric: windows_performancecounter_memory_cache_faults_per_second # optional
|
||||
type: "gauge" # optional
|
||||
multiplier: 1 # optional
|
||||
```
|
||||
|
||||
</details>
|
||||
@@ -106,7 +107,8 @@ YAML:
|
||||
{
|
||||
"name": "Cache Faults/sec",
|
||||
"metric": "windows_performancecounter_memory_cache_faults_per_second",
|
||||
"type": "gauge"
|
||||
"type": "gauge",
|
||||
"multiplier": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -195,6 +197,21 @@ If not specified, the windows_exporter will try to determine the type based on t
|
||||
|
||||
This key is optional.
|
||||
|
||||
##### multiplier
|
||||
|
||||
A factor that the value is multiplied by before it is exported, to convert it to
|
||||
the base unit the Prometheus [naming conventions](https://prometheus.io/docs/practices/naming/#base-units)
|
||||
ask for. For example, `0.001` converts milliseconds to seconds, `0.01` percent to
|
||||
a ratio and `3600` hours to seconds. It must be a positive number, so counters
|
||||
keep counting up. If the multiplier is the reciprocal of an integer, like `0.001`,
|
||||
the value is divided by that integer instead, which avoids rounding artifacts
|
||||
such as `0.009000000000000001`. If not specified, the value is exported as is.
|
||||
|
||||
With the `raw` type, `PERF_100NSEC_TIMER_INV` counters such as `% Processor Time` are not converted to seconds
|
||||
and arrive in 100 ns ticks; a multiplier of `1e-7` converts them.
|
||||
|
||||
This key is optional.
|
||||
|
||||
##### labels
|
||||
|
||||
Labels is a map of key-value pairs that will be added as labels to the metric.
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
"github.com/prometheus-community/windows_exporter/internal/mi"
|
||||
"github.com/prometheus-community/windows_exporter/internal/multiplier"
|
||||
"github.com/prometheus-community/windows_exporter/internal/pdh"
|
||||
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
@@ -175,6 +176,15 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
|
||||
continue
|
||||
}
|
||||
|
||||
m, err := multiplier.New(counter.Multiplier)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("object %s: counter %s: %w", object.Name, counter.Name, err))
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
object.Counters[j].multiplier = m
|
||||
|
||||
if _, ok := object.valueIndex[counter.Name]; ok {
|
||||
errs = append(errs, fmt.Errorf("object %s: counter name %s is duplicated", object.Name, counter.Name))
|
||||
|
||||
@@ -328,7 +338,7 @@ func (c *Collector) collectObject(ch chan<- prometheus.Metric, perfDataObject Ob
|
||||
labels,
|
||||
),
|
||||
metricTypes[j],
|
||||
collectedCounterValue,
|
||||
counter.multiplier.Apply(collectedCounterValue),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,3 +440,57 @@ func TestCollectorMetricTypePerCounter(t *testing.T) {
|
||||
require.Equal(t, dto.MetricType_COUNTER, types["windows_performancecounter_process_io_read_bytes_sec"])
|
||||
}
|
||||
}
|
||||
|
||||
// TestCollectorMultiplier checks that the multiplier scales the exported value.
|
||||
// Commit Limit only changes when a page file is resized, so both objects read
|
||||
// the same value.
|
||||
func TestCollectorMultiplier(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c := performancecounter.New(&performancecounter.Config{
|
||||
Objects: []performancecounter.Object{
|
||||
{
|
||||
Name: "bytes",
|
||||
Object: "Memory",
|
||||
Counters: []performancecounter.Counter{{Name: "Commit Limit", Metric: "windows_test_commit_limit_bytes"}},
|
||||
},
|
||||
{
|
||||
Name: "kibibytes",
|
||||
Object: "Memory",
|
||||
Counters: []performancecounter.Counter{{Name: "Commit Limit", Metric: "windows_test_commit_limit_kibibytes", Multiplier: new(1.0 / 1024)}},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, c.Build(slog.New(slog.DiscardHandler), nil))
|
||||
t.Cleanup(func() { require.NoError(t, c.Close()) })
|
||||
|
||||
registry := prometheus.NewRegistry()
|
||||
registry.MustRegister(collectorAdapter{*c})
|
||||
|
||||
families, err := registry.Gather()
|
||||
require.NoError(t, err)
|
||||
|
||||
values := make(map[string]float64, len(families))
|
||||
for _, family := range families {
|
||||
values[family.GetName()] = family.GetMetric()[0].GetGauge().GetValue()
|
||||
}
|
||||
|
||||
require.Positive(t, values["windows_test_commit_limit_bytes"])
|
||||
require.Equal(t, values["windows_test_commit_limit_bytes"]/1024, values["windows_test_commit_limit_kibibytes"]) //nolint:testifylint // The result must be exact.
|
||||
}
|
||||
|
||||
func TestBuildInvalidMultiplier(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c := performancecounter.New(&performancecounter.Config{
|
||||
Objects: []performancecounter.Object{{
|
||||
Name: "memory",
|
||||
Object: "Memory",
|
||||
Counters: []performancecounter.Counter{{Name: "Commit Limit", Multiplier: new(-1.0)}},
|
||||
}},
|
||||
})
|
||||
|
||||
t.Cleanup(func() { require.NoError(t, c.Close()) })
|
||||
|
||||
require.ErrorContains(t, c.Build(slog.New(slog.DiscardHandler), nil), "object memory: counter Commit Limit: multiplier must be a positive finite number, got -1")
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package performancecounter
|
||||
|
||||
import (
|
||||
"github.com/prometheus-community/windows_exporter/internal/config/yamlstring"
|
||||
"github.com/prometheus-community/windows_exporter/internal/multiplier"
|
||||
"github.com/prometheus-community/windows_exporter/internal/pdh"
|
||||
"go.yaml.in/yaml/v3"
|
||||
)
|
||||
@@ -37,10 +38,14 @@ type Object struct {
|
||||
}
|
||||
|
||||
type Counter struct {
|
||||
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"`
|
||||
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"`
|
||||
Multiplier *float64 `json:"multiplier" yaml:"multiplier"`
|
||||
|
||||
// Resolved at Build time.
|
||||
multiplier multiplier.Multiplier
|
||||
}
|
||||
|
||||
// https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/54691ebe11bb9ec32b4e35cd31fcb94a352de134/receiver/windowsperfcountersreceiver/README.md?plain=1#L150
|
||||
|
||||
Reference in New Issue
Block a user