pdh: report duplicate instances by occurrence instead of renaming them (#2742)

Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
Jan-Otto Kröpke
2026-10-16 09:58:43 +02:00
committed by GitHub
parent d8dbf852d1
commit 43d77f6869
32 changed files with 832 additions and 266 deletions
@@ -284,6 +284,13 @@ func (c *Collector) collectObject(ch chan<- prometheus.Metric, perfDataObject Ob
return fmt.Errorf("failed to collect data: %w", err)
}
// Some objects, e.g. Process, report the same instance name more than
// once. Each occurrence is published with a "#N" suffix, see the docs.
pdh.SuffixDuplicates(rows,
func(row *pdh.Row) *string { return &row.Name },
func(row *pdh.Row) int { return row.Occurrence },
)
metricTypes := counterMetricTypes(perfDataObject)
var errs []error
@@ -344,6 +344,46 @@ func TestBuildInvalidConfig(t *testing.T) {
}
}
// TestCollectorDuplicateInstances checks that the svchost processes, which the
// Process object reports with the same name, are published with suffixes.
func TestCollectorDuplicateInstances(t *testing.T) {
t.Parallel()
c := performancecounter.New(&performancecounter.Config{
Objects: []performancecounter.Object{{
Name: "process", Object: "Process", Instances: []string{"*"},
Counters: []performancecounter.Counter{{Name: "ID Process", Type: "gauge"}},
}},
})
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, "every series is unique")
instances := map[string]bool{}
for _, family := range families {
if family.GetName() != "windows_performancecounter_process_id_process" {
continue
}
for _, metric := range family.GetMetric() {
for _, label := range metric.GetLabel() {
if label.GetName() == "instance" {
instances[label.GetValue()] = true
}
}
}
}
require.True(t, instances["svchost"], "svchost")
require.True(t, instances["svchost#1"], "svchost#1")
}
func TestCollectorClose(t *testing.T) {
t.Parallel()