mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-10-17 10:09:05 +02:00
pdh: load a missing elapsed time base on a later sample (#2707)
Signed-off-by: Claude <noreply@anthropic.com> Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
5d6cf525bf
commit
c3b7a03128
@@ -509,6 +509,8 @@ func (c *Collector[T]) collect(dst *[]T, state *collectState) (err error) {
|
||||
defer state.names.removeUnseen()
|
||||
|
||||
for counterIndex := range c.counters {
|
||||
c.loadTimeBase(&c.counters[counterIndex])
|
||||
|
||||
for _, instance := range c.counters[counterIndex].Instances {
|
||||
itemCount, ok, err := c.getCounterArray(instance, &state.buf)
|
||||
if err != nil {
|
||||
@@ -538,6 +540,26 @@ func (c *Collector[T]) collect(dst *[]T, state *collectState) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadTimeBase reads the time base of a raw elapsed time counter that had none
|
||||
// when the collector was created. Early after a reboot, PDH can report no data
|
||||
// for it, e.g. for APP_POOL_WAS while WAS is still starting (#2313). Without a
|
||||
// time base, the counter has no valid value and every instance is omitted.
|
||||
func (c *Collector[T]) loadTimeBase(counter *Counter) {
|
||||
if c.resultType != CounterTypeRaw || counter.Type != PERF_ELAPSED_TIME || counter.Frequency > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, instance := range counter.Instances {
|
||||
var frequency int64
|
||||
|
||||
if ret := GetCounterTimeBase(instance, &frequency); ret == ErrorSuccess && frequency > 0 {
|
||||
counter.Frequency = frequency
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pdhBufferSlack is extra space allocated beyond the buffer size reported by PDH.
|
||||
// On Windows Server 2012 R2, PdhGetRawCounterArrayW reports the size of the item array of a single-instance
|
||||
// object (e.g. System) without the terminator of the empty instance name, and writes that terminator right after
|
||||
|
||||
@@ -363,6 +363,40 @@ func TestSetRawValueElapsedTime(t *testing.T) {
|
||||
require.True(t, c.setRawValue(&values, counter, RawCounter{FirstValue: 1, SecondValue: 2}))
|
||||
}
|
||||
|
||||
// TestCollectLoadsMissingTimeBase checks that an elapsed time counter whose time
|
||||
// base was not available when the collector was created gets it on a later
|
||||
// sample, instead of omitting every instance until a restart (#2313).
|
||||
func TestCollectLoadsMissingTimeBase(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type systemUpTime struct {
|
||||
SystemUpTime float64 `perfdata:"System Up Time"`
|
||||
}
|
||||
|
||||
collector, err := NewCollector[systemUpTime](slog.New(slog.DiscardHandler), CounterTypeRaw, "System", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(collector.Close)
|
||||
|
||||
require.Len(t, collector.counters, 1)
|
||||
|
||||
counter := &collector.counters[0]
|
||||
require.Equal(t, uint32(PERF_ELAPSED_TIME), counter.Type)
|
||||
|
||||
frequency := counter.Frequency
|
||||
require.Positive(t, frequency)
|
||||
|
||||
// As if GetCounterTimeBase reported no data at startup.
|
||||
counter.Frequency = 0
|
||||
|
||||
var dst []systemUpTime
|
||||
|
||||
require.NoError(t, collector.Collect(&dst))
|
||||
require.Equal(t, frequency, counter.Frequency)
|
||||
require.Len(t, dst, 1)
|
||||
require.Positive(t, dst[0].SystemUpTime)
|
||||
}
|
||||
|
||||
func TestMetricTypeForCounterType(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user