diff --git a/internal/collector/cpu/cpu.go b/internal/collector/cpu/cpu.go index e881516e8..d083932de 100644 --- a/internal/collector/cpu/cpu.go +++ b/internal/collector/cpu/cpu.go @@ -27,8 +27,8 @@ type Collector struct { perfDataCollector perfdata.Collector - processorRTCValues map[string]cpuCounter - processorMPerfValues map[string]cpuCounter + processorRTCValues map[string]utils.Counter + processorMPerfValues map[string]utils.Counter logicalProcessors *prometheus.Desc cStateSecondsTotal *prometheus.Desc @@ -46,11 +46,6 @@ type Collector struct { processorPrivilegedUtility *prometheus.Desc } -type cpuCounter struct { - lastValue uint32 - totalValue float64 -} - func New(config *Config) *Collector { if config == nil { config = &ConfigDefaults @@ -229,8 +224,8 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { nil, ) - c.processorRTCValues = map[string]cpuCounter{} - c.processorMPerfValues = map[string]cpuCounter{} + c.processorRTCValues = map[string]utils.Counter{} + c.processorMPerfValues = map[string]utils.Counter{} return nil } @@ -262,30 +257,28 @@ func (c *Collector) collectFull(ctx *types.ScrapeContext, logger *slog.Logger, c core := cpu.Name - if val, ok := c.processorRTCValues[core]; ok { - c.processorRTCValues[core] = cpuCounter{ - uint32(cpu.ProcessorRTC), - val.totalValue + float64(uint32(cpu.ProcessorRTC)-val.lastValue), - } + var ( + counterProcessorRTCValues utils.Counter + counterProcessorMPerfValues utils.Counter + ok bool + ) + + if counterProcessorRTCValues, ok = c.processorRTCValues[core]; ok { + counterProcessorRTCValues.AddValue(uint32(cpu.ProcessorRTC)) } else { - c.processorRTCValues[core] = cpuCounter{ - uint32(cpu.ProcessorRTC), - 0, - } + counterProcessorRTCValues = utils.NewCounter(uint32(cpu.ProcessorRTC)) } - if val, ok := c.processorMPerfValues[core]; ok { - c.processorMPerfValues[core] = cpuCounter{ - uint32(cpu.ProcessorMPerf), - val.totalValue + float64(uint32(cpu.ProcessorMPerf)-val.lastValue), - } + c.processorRTCValues[core] = counterProcessorRTCValues + + if counterProcessorMPerfValues, ok = c.processorMPerfValues[core]; ok { + counterProcessorMPerfValues.AddValue(uint32(cpu.ProcessorMPerf)) } else { - c.processorMPerfValues[core] = cpuCounter{ - uint32(cpu.ProcessorMPerf), - 0, - } + counterProcessorMPerfValues = utils.NewCounter(uint32(cpu.ProcessorMPerf)) } + c.processorMPerfValues[core] = counterProcessorMPerfValues + coreCount++ ch <- prometheus.MustNewConstMetric( @@ -385,13 +378,13 @@ func (c *Collector) collectFull(ctx *types.ScrapeContext, logger *slog.Logger, c ch <- prometheus.MustNewConstMetric( c.processorMPerf, prometheus.CounterValue, - c.processorMPerfValues[core].totalValue, + counterProcessorMPerfValues.Value(), core, ) ch <- prometheus.MustNewConstMetric( c.processorRTC, prometheus.CounterValue, - c.processorRTCValues[core].totalValue, + counterProcessorRTCValues.Value(), core, ) ch <- prometheus.MustNewConstMetric( @@ -428,30 +421,28 @@ func (c *Collector) collectPDH(ch chan<- prometheus.Metric) error { for core, coreData := range data { coreCount++ - if val, ok := c.processorRTCValues[core]; ok { - c.processorRTCValues[core] = cpuCounter{ - uint32(coreData[privilegedUtilitySeconds].SecondValue), - val.totalValue + float64(uint32(coreData[privilegedUtilitySeconds].SecondValue)-val.lastValue), - } + var ( + counterProcessorRTCValues utils.Counter + counterProcessorMPerfValues utils.Counter + ok bool + ) + + if counterProcessorRTCValues, ok = c.processorRTCValues[core]; ok { + counterProcessorRTCValues.AddValue(uint32(coreData[processorUtilityRate].SecondValue)) } else { - c.processorRTCValues[core] = cpuCounter{ - uint32(coreData[privilegedUtilitySeconds].SecondValue), - 0, - } + counterProcessorRTCValues = utils.NewCounter(uint32(coreData[privilegedUtilitySeconds].SecondValue)) } - if val, ok := c.processorMPerfValues[core]; ok { - c.processorMPerfValues[core] = cpuCounter{ - uint32(coreData[processorPerformance].SecondValue), - val.totalValue + float64(uint32(coreData[processorPerformance].SecondValue)-val.lastValue), - } + c.processorRTCValues[core] = counterProcessorRTCValues + + if counterProcessorMPerfValues, ok = c.processorMPerfValues[core]; ok { + counterProcessorMPerfValues.AddValue(uint32(coreData[processorPerformance].SecondValue)) } else { - c.processorMPerfValues[core] = cpuCounter{ - uint32(coreData[processorPerformance].SecondValue), - 0, - } + counterProcessorMPerfValues = utils.NewCounter(uint32(coreData[processorPerformance].SecondValue)) } + c.processorMPerfValues[core] = counterProcessorMPerfValues + ch <- prometheus.MustNewConstMetric( c.cStateSecondsTotal, prometheus.CounterValue, @@ -549,13 +540,13 @@ func (c *Collector) collectPDH(ch chan<- prometheus.Metric) error { ch <- prometheus.MustNewConstMetric( c.processorMPerf, prometheus.CounterValue, - coreData[processorPerformance].SecondValue, + counterProcessorMPerfValues.Value(), core, ) ch <- prometheus.MustNewConstMetric( c.processorRTC, prometheus.CounterValue, - coreData[processorUtilityRate].SecondValue, + counterProcessorRTCValues.Value(), core, ) ch <- prometheus.MustNewConstMetric( diff --git a/internal/perfdata/perfdata.go b/internal/perfdata/perfdata.go index e8ca62678..9d56c0bbf 100644 --- a/internal/perfdata/perfdata.go +++ b/internal/perfdata/perfdata.go @@ -27,8 +27,7 @@ var ( AllInstances = []string{"*"} ) -//nolint:ireturn -func NewCollector(engine Engine, object string, instances []string, counters []string) (Collector, error) { +func NewCollector(engine Engine, object string, instances []string, counters []string) (Collector, error) { //nolint:ireturn switch engine { case V1: return v1.NewCollector(object, instances, counters) diff --git a/internal/utils/counter.go b/internal/utils/counter.go new file mode 100644 index 000000000..c865b6530 --- /dev/null +++ b/internal/utils/counter.go @@ -0,0 +1,23 @@ +package utils + +type Counter struct { + lastValue uint32 + totalValue float64 +} + +// NewCounter creates a new Counter that accepts uint32 values and returns float64 values. +// It resolve the overflow issue of uint32 by using the difference between the last value and the current value. +func NewCounter(lastValue uint32) Counter { + return Counter{ + lastValue: lastValue, + totalValue: 0, + } +} + +func (c *Counter) AddValue(value uint32) { + c.totalValue += float64(value - c.lastValue) +} + +func (c *Counter) Value() float64 { + return c.totalValue +} diff --git a/internal/utils/counter_test.go b/internal/utils/counter_test.go new file mode 100644 index 000000000..1a06736e0 --- /dev/null +++ b/internal/utils/counter_test.go @@ -0,0 +1,24 @@ +package utils_test + +import ( + "math" + "testing" + + "github.com/prometheus-community/windows_exporter/internal/utils" + "github.com/stretchr/testify/assert" +) + +func TestCounter(t *testing.T) { + t.Parallel() + + c := utils.NewCounter(0) + assert.Equal(t, 0.0, c.Value()) //nolint:testifylint + + c.AddValue(1) + + assert.Equal(t, 1.0, c.Value()) //nolint:testifylint + + c.AddValue(math.MaxUint32) + + assert.Equal(t, float64(math.MaxUint32)+1.0, c.Value()) //nolint:testifylint +}