mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-10-17 10:09:05 +02:00
netframework: sample all .NET CLR counter objects in one PDH query (#2686)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
@@ -77,11 +77,15 @@ type Collector struct {
|
||||
// labels keeps the label pairs of the series of the last scrape. The
|
||||
// counters change on every scrape, but their process labels stay the
|
||||
// same while the process runs.
|
||||
labels labelcache.Cache
|
||||
config Config
|
||||
logger *slog.Logger
|
||||
perfFrequency float64
|
||||
closeFns []func()
|
||||
labels labelcache.Cache
|
||||
config Config
|
||||
logger *slog.Logger
|
||||
perfFrequency float64
|
||||
closeFns []func()
|
||||
// perfQuery samples the counters of all enabled sub-collectors at once.
|
||||
// The .NET CLR counter provider serves one query at a time and walks
|
||||
// every .NET process for each, so separate queries wait for each other.
|
||||
perfQuery *pdh.Query
|
||||
perfClrExceptions perfCollector[perfDataClrExceptions]
|
||||
perfClrInterop perfCollector[perfDataClrInterop]
|
||||
perfClrJIT perfCollector[perfDataClrJIT]
|
||||
@@ -210,6 +214,9 @@ func (c *Collector) Close() error {
|
||||
c.collectorFns = nil
|
||||
c.labels.Reset()
|
||||
|
||||
c.perfQuery.Close()
|
||||
c.perfQuery = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -230,6 +237,13 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
|
||||
c.perfFrequency = float64(frequency)
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
c.perfQuery, err = pdh.NewQuery()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open .NET CLR performance counter query: %w", err)
|
||||
}
|
||||
|
||||
c.collectorFns = make([]func(ch chan<- prometheus.Metric, scrape *labelcache.Scrape, maxScrapeDuration time.Duration) error, 0, len(c.config.CollectorsEnabled))
|
||||
|
||||
subCollectors := map[string]struct {
|
||||
@@ -340,6 +354,14 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
|
||||
// Collect sends the metric values for each metric
|
||||
// to the provided prometheus Metric channel.
|
||||
func (c *Collector) Collect(ch chan<- prometheus.Metric, maxScrapeDuration time.Duration) error {
|
||||
// The sub-collectors read this sample. Without any .NET process there is
|
||||
// no data; the sub-collectors report that themselves.
|
||||
if c.perfQuery != nil {
|
||||
if err := c.perfQuery.Collect(); err != nil && !errors.Is(err, pdh.ErrNoData) {
|
||||
return fmt.Errorf("failed to collect .NET CLR performance counters: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
scrape := c.labels.Begin()
|
||||
defer scrape.Commit()
|
||||
|
||||
@@ -354,10 +376,11 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric, maxScrapeDuration time.
|
||||
return g.Wait()
|
||||
}
|
||||
|
||||
// newPerfCollector retains ownership of partially initialized PDH queries.
|
||||
// Missing objects are optional; missing individual counters remain errors.
|
||||
func newPerfCollector[T any](logger *slog.Logger, object string) (perfCollector[T], error) {
|
||||
c, err := pdh.NewCollector[T](logger, pdh.CounterTypeRaw, object, pdh.InstancesAll)
|
||||
// newPerfCollector adds the counters of object to query and retains
|
||||
// ownership of partially initialized collectors. Missing objects are optional;
|
||||
// missing individual counters remain errors.
|
||||
func newPerfCollector[T any](logger *slog.Logger, query *pdh.Query, object string) (perfCollector[T], error) {
|
||||
c, err := pdh.NewQueryCollector[T](logger, query, pdh.CounterTypeRaw, object, pdh.InstancesAll)
|
||||
if err == nil {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ func (c *Collector) buildClrExceptions() error {
|
||||
|
||||
var err error
|
||||
|
||||
c.perfClrExceptions, err = newPerfCollector[perfDataClrExceptions](c.logger, ".NET CLR Exceptions")
|
||||
c.perfClrExceptions, err = newPerfCollector[perfDataClrExceptions](c.logger, c.perfQuery, ".NET CLR Exceptions")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ func (c *Collector) buildClrInterop() error {
|
||||
|
||||
var err error
|
||||
|
||||
c.perfClrInterop, err = newPerfCollector[perfDataClrInterop](c.logger, ".NET CLR Interop")
|
||||
c.perfClrInterop, err = newPerfCollector[perfDataClrInterop](c.logger, c.perfQuery, ".NET CLR Interop")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ func (c *Collector) buildClrJIT() error {
|
||||
|
||||
var err error
|
||||
|
||||
c.perfClrJIT, err = newPerfCollector[perfDataClrJIT](c.logger, ".NET CLR Jit")
|
||||
c.perfClrJIT, err = newPerfCollector[perfDataClrJIT](c.logger, c.perfQuery, ".NET CLR Jit")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ func (c *Collector) buildClrLoading() error {
|
||||
|
||||
var err error
|
||||
|
||||
c.perfClrLoading, err = newPerfCollector[perfDataClrLoading](c.logger, ".NET CLR Loading")
|
||||
c.perfClrLoading, err = newPerfCollector[perfDataClrLoading](c.logger, c.perfQuery, ".NET CLR Loading")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func (c *Collector) buildClrLocksAndThreads() error {
|
||||
|
||||
var err error
|
||||
|
||||
c.perfClrLocksAndThreads, err = newPerfCollector[perfDataClrLocksAndThreads](c.logger, ".NET CLR LocksAndThreads")
|
||||
c.perfClrLocksAndThreads, err = newPerfCollector[perfDataClrLocksAndThreads](c.logger, c.perfQuery, ".NET CLR LocksAndThreads")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func (c *Collector) buildClrMemory() error {
|
||||
|
||||
var err error
|
||||
|
||||
c.perfClrMemory, err = newPerfCollector[perfDataClrMemory](c.logger, ".NET CLR Memory")
|
||||
c.perfClrMemory, err = newPerfCollector[perfDataClrMemory](c.logger, c.perfQuery, ".NET CLR Memory")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func (c *Collector) buildClrRemoting() error {
|
||||
|
||||
var err error
|
||||
|
||||
c.perfClrRemoting, err = newPerfCollector[perfDataClrRemoting](c.logger, ".NET CLR Remoting")
|
||||
c.perfClrRemoting, err = newPerfCollector[perfDataClrRemoting](c.logger, c.perfQuery, ".NET CLR Remoting")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ func (c *Collector) buildClrSecurity() error {
|
||||
|
||||
var err error
|
||||
|
||||
c.perfClrSecurity, err = newPerfCollector[perfDataClrSecurity](c.logger, ".NET CLR Security")
|
||||
c.perfClrSecurity, err = newPerfCollector[perfDataClrSecurity](c.logger, c.perfQuery, ".NET CLR Security")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user