Compare commits

...

3 Commits

Author SHA1 Message Date
dependabot[bot]
4cd9627ebf chore(deps): bump golang.org/x/sys from 0.28.0 to 0.29.0 (#1825)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 10:07:25 +01:00
Jan-Otto Kröpke
81ea4c6223 performancecounter: fix panic with counter names having brackets (#1822)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2024-12-27 22:12:23 +01:00
Jan-Otto Kröpke
78386557d4 iis: fix panic (#1820)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2024-12-22 13:13:25 +01:00
7 changed files with 66 additions and 46 deletions

2
go.mod
View File

@@ -14,7 +14,7 @@ require (
github.com/prometheus/common v0.61.0
github.com/prometheus/exporter-toolkit v0.13.2
github.com/stretchr/testify v1.10.0
golang.org/x/sys v0.28.0
golang.org/x/sys v0.29.0
gopkg.in/yaml.v3 v3.0.1
)

4
go.sum
View File

@@ -163,8 +163,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=

View File

@@ -405,7 +405,7 @@ func (c *Collector) collectW3SVCW3WP(ch chan<- prometheus.Metric) error {
}
func (c *Collector) collectW3SVCW3WPv8(ch chan<- prometheus.Metric) error {
err := c.w3SVCW3WPPerfDataCollector.Collect(&c.perfDataObjectW3SVCW3WPV8)
err := c.w3SVCW3WPPerfDataCollectorV8.Collect(&c.perfDataObjectW3SVCW3WPV8)
if err != nil {
return fmt.Errorf("failed to collect APP_POOL_WAS metrics: %w", err)
}

View File

@@ -20,6 +20,7 @@ import (
"fmt"
"log/slog"
"reflect"
"regexp"
"slices"
"strings"
"time"
@@ -34,6 +35,8 @@ import (
const Name = "performancecounter"
var reNonAlphaNum = regexp.MustCompile(`[^a-zA-Z0-9]`)
type Config struct {
Objects []Object `yaml:"objects"`
}
@@ -51,8 +54,6 @@ type Collector struct {
objects []Object
metricNameReplacer *strings.Replacer
// meta
subCollectorScrapeDurationDesc *prometheus.Desc
subCollectorScrapeSuccessDesc *prometheus.Desc
@@ -115,15 +116,6 @@ func (c *Collector) Close() error {
func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
c.logger = logger.With(slog.String("collector", Name))
c.metricNameReplacer = strings.NewReplacer(
".", "",
"%", "",
"/", "_",
" ", "_",
"-", "_",
)
c.objects = make([]Object, 0, len(c.config.Objects))
names := make([]string, 0, len(c.config.Objects))
@@ -152,7 +144,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
for j, counter := range object.Counters {
if counter.Metric == "" {
c.config.Objects[i].Counters[j].Metric = c.sanitizeMetricName(
c.config.Objects[i].Counters[j].Metric = sanitizeMetricName(
fmt.Sprintf("%s_%s_%s_%s", types.Namespace, Name, object.Object, counter.Name),
)
}
@@ -171,11 +163,27 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
}
counters = append(counters, counter.Name)
fields = append(fields, reflect.StructField{
Name: strings.ToUpper(c.sanitizeMetricName(counter.Name)),
Type: reflect.TypeOf(float64(0)),
Tag: reflect.StructTag(fmt.Sprintf(`perfdata:"%s"`, counter.Name)),
})
field, err := func(name string) (_ reflect.StructField, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("failed to create field for %s: %v", name, r)
}
}()
return reflect.StructField{
Name: strings.ToUpper(sanitizeMetricName(name)),
Type: reflect.TypeOf(float64(0)),
Tag: reflect.StructTag(fmt.Sprintf(`perfdata:"%s"`, name)),
}, nil
}(counter.Name)
if err != nil {
errs = append(errs, err)
continue
}
fields = append(fields, field)
}
if object.Instances != nil {
@@ -276,7 +284,7 @@ func (c *Collector) collectObject(ch chan<- prometheus.Metric, perfDataObject Ob
for _, counter := range perfDataObject.Counters {
val := reflect.ValueOf(sliceValue).Index(i)
field := val.FieldByName(strings.ToUpper(c.sanitizeMetricName(counter.Name)))
field := val.FieldByName(strings.ToUpper(sanitizeMetricName(counter.Name)))
if !field.IsValid() {
errs = append(errs, fmt.Errorf("%s not found in collected data", counter.Name))
@@ -355,6 +363,6 @@ func (c *Collector) collectObject(ch chan<- prometheus.Metric, perfDataObject Ob
return errors.Join(errs...)
}
func (c *Collector) sanitizeMetricName(name string) string {
return strings.Trim(c.metricNameReplacer.Replace(strings.ToLower(name)), "_")
func sanitizeMetricName(name string) string {
return strings.Trim(reNonAlphaNum.ReplaceAllString(strings.ToLower(name), "_"), "_")
}

View File

@@ -25,6 +25,7 @@ import (
"testing"
"github.com/prometheus-community/windows_exporter/internal/collector/performancecounter"
"github.com/prometheus-community/windows_exporter/internal/pdh"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/stretchr/testify/assert"
@@ -126,6 +127,14 @@ windows_performancecounter_processor_information_processor_time\{core="0,0",stat
counters: []performancecounter.Counter{{Name: "Available Bytes", Type: "gauge"}, {Name: "Available Bytes", Type: "gauge"}},
expectedMetrics: nil,
},
{
name: "counter with spaces and brackets",
object: "invalid",
instances: nil,
buildErr: pdh.NewPdhError(pdh.CstatusNoObject).Error(),
counters: []performancecounter.Counter{{Name: "Total Memory Usage --- Non-Paged Pool", Type: "counter"}, {Name: "Max Session Input Delay (ms)", Type: "counter"}},
expectedMetrics: nil,
},
} {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()

View File

@@ -16,13 +16,13 @@
package vmware
type perfDataCounterValuesCPU struct {
CouEffectiveVMSpeedMHz float64 `perfdata:"Effective VM Speed in MHz"` // \VM Processor(*)\Effective VM Speed in MHz
CpuHostProcessorSpeedMHz float64 `perfdata:"Host processor speed in MHz"` // \VM Processor(*)\Host processor speed in MHz
CpuLimitMHz float64 `perfdata:"Limit in MHz"` // \VM Processor(*)\Limit in MHz
CpuReservationMHz float64 `perfdata:"Reservation in MHz"` // \VM Processor(*)\Reservation in MHz
CpuShares float64 `perfdata:"Shares"` // \VM Processor(*)\Shares
CpuStolenMs float64 `perfdata:"CPU stolen time"` // \VM Processor(*)\CPU stolen time
CpuTimePercents float64 `perfdata:"% Processor Time"` // \VM Processor(*)\% Processor Time
CPUEffectiveVMSpeedMHz float64 `perfdata:"Effective VM Speed in MHz"` // \VM Processor(*)\Effective VM Speed in MHz
CPUHostProcessorSpeedMHz float64 `perfdata:"Host processor speed in MHz"` // \VM Processor(*)\Host processor speed in MHz
CPULimitMHz float64 `perfdata:"Limit in MHz"` // \VM Processor(*)\Limit in MHz
CPUReservationMHz float64 `perfdata:"Reservation in MHz"` // \VM Processor(*)\Reservation in MHz
CPUShares float64 `perfdata:"Shares"` // \VM Processor(*)\Shares
CPUStolenMs float64 `perfdata:"CPU stolen time"` // \VM Processor(*)\CPU stolen time
CPUTimePercents float64 `perfdata:"% Processor Time"` // \VM Processor(*)\% Processor Time
}
type perfDataCounterValuesMemory struct {

View File

@@ -93,11 +93,19 @@ func (c *Collector) Close() error {
}
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
var err error
var (
err error
errs []error
)
c.perfDataCollectorCPU, err = pdh.NewCollector[perfDataCounterValuesCPU]("VM Processor", pdh.InstancesTotal)
if err != nil {
return fmt.Errorf("failed to create VM Processor collector: %w", err)
errs = append(errs, fmt.Errorf("failed to create VM Processor collector: %w", err))
}
c.perfDataCollectorMemory, err = pdh.NewCollector[perfDataCounterValuesMemory]("VM Memory", nil)
if err != nil {
errs = append(errs, fmt.Errorf("failed to create VM Memory collector: %w", err))
}
c.cpuLimitMHz = prometheus.NewDesc(
@@ -143,11 +151,6 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
nil,
)
c.perfDataCollectorMemory, err = pdh.NewCollector[perfDataCounterValuesMemory]("VM Memory", nil)
if err != nil {
return fmt.Errorf("failed to create VM Memory collector: %w", err)
}
c.memActive = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_active_bytes"),
"The estimated amount of memory the virtual machine is actively using.",
@@ -221,7 +224,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
nil,
)
return nil
return errors.Join(errs...)
}
// Collect sends the metric values for each metric
@@ -330,43 +333,43 @@ func (c *Collector) collectCpu(ch chan<- prometheus.Metric) error {
ch <- prometheus.MustNewConstMetric(
c.cpuLimitMHz,
prometheus.GaugeValue,
c.perfDataObjectCPU[0].CpuLimitMHz,
c.perfDataObjectCPU[0].CPULimitMHz,
)
ch <- prometheus.MustNewConstMetric(
c.cpuReservationMHz,
prometheus.GaugeValue,
c.perfDataObjectCPU[0].CpuReservationMHz,
c.perfDataObjectCPU[0].CPUReservationMHz,
)
ch <- prometheus.MustNewConstMetric(
c.cpuShares,
prometheus.GaugeValue,
c.perfDataObjectCPU[0].CpuShares,
c.perfDataObjectCPU[0].CPUShares,
)
ch <- prometheus.MustNewConstMetric(
c.cpuStolenTotal,
prometheus.CounterValue,
utils.MilliSecToSec(c.perfDataObjectCPU[0].CpuStolenMs),
utils.MilliSecToSec(c.perfDataObjectCPU[0].CPUStolenMs),
)
ch <- prometheus.MustNewConstMetric(
c.cpuTimeTotal,
prometheus.CounterValue,
utils.MilliSecToSec(c.perfDataObjectCPU[0].CpuTimePercents),
utils.MilliSecToSec(c.perfDataObjectCPU[0].CPUTimePercents),
)
ch <- prometheus.MustNewConstMetric(
c.cpuEffectiveVMSpeedMHz,
prometheus.GaugeValue,
c.perfDataObjectCPU[0].CouEffectiveVMSpeedMHz,
c.perfDataObjectCPU[0].CPUEffectiveVMSpeedMHz,
)
ch <- prometheus.MustNewConstMetric(
c.hostProcessorSpeedMHz,
prometheus.GaugeValue,
c.perfDataObjectCPU[0].CpuHostProcessorSpeedMHz,
c.perfDataObjectCPU[0].CPUHostProcessorSpeedMHz,
)
return nil