Convert the tcp collector to use perflib instead of WMI

Using perflib is substantially faster and more reliable than using WMI to
retrieve Windows performance counter data.

Signed-off-by: Michael Allen <MAllen@laserfiche.com>
This commit is contained in:
Michael Allen
2020-10-07 22:25:58 -07:00
parent 922c08b85b
commit 380eff24c9

View File

@@ -4,13 +4,13 @@ package collector
import ( import (
"errors" "errors"
"github.com/StackExchange/wmi"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/log" "github.com/prometheus/common/log"
) )
func init() { func init() {
registerCollector("tcp", NewTCPCollector) registerCollector("tcp", NewTCPCollector, "TCPv4")
} }
// A TCPCollector is a Prometheus collector for WMI Win32_PerfRawData_Tcpip_TCPv4 metrics // A TCPCollector is a Prometheus collector for WMI Win32_PerfRawData_Tcpip_TCPv4 metrics
@@ -91,7 +91,7 @@ func NewTCPCollector() (Collector, error) {
// Collect sends the metric values for each metric // Collect sends the metric values for each metric
// to the provided prometheus Metric channel. // to the provided prometheus Metric channel.
func (c *TCPCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error { func (c *TCPCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
if desc, err := c.collect(ch); err != nil { if desc, err := c.collect(ctx, ch); err != nil {
log.Error("failed collecting tcp metrics:", desc, err) log.Error("failed collecting tcp metrics:", desc, err)
return err return err
} }
@@ -100,74 +100,73 @@ func (c *TCPCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric)
// Win32_PerfRawData_Tcpip_TCPv4 docs // Win32_PerfRawData_Tcpip_TCPv4 docs
// - https://msdn.microsoft.com/en-us/library/aa394341(v=vs.85).aspx // - https://msdn.microsoft.com/en-us/library/aa394341(v=vs.85).aspx
type Win32_PerfRawData_Tcpip_TCPv4 struct { type tcp struct {
ConnectionFailures uint64 ConnectionFailures float64 `perflib:"Connection Failures"`
ConnectionsActive uint64 ConnectionsActive float64 `perflib:"Connections Active"`
ConnectionsEstablished uint64 ConnectionsEstablished float64 `perflib:"Connections Established"`
ConnectionsPassive uint64 ConnectionsPassive float64 `perflib:"Connections Passive"`
ConnectionsReset uint64 ConnectionsReset float64 `perflib:"Connections Reset"`
SegmentsPersec uint64 SegmentsPersec float64 `perflib:"Segments/sec"`
SegmentsReceivedPersec uint64 SegmentsReceivedPersec float64 `perflib:"Segments Received/sec"`
SegmentsRetransmittedPersec uint64 SegmentsRetransmittedPersec float64 `perflib:"Segments Retransmitted/sec"`
SegmentsSentPersec uint64 SegmentsSentPersec float64 `perflib:"Segments Sent/sec"`
} }
func (c *TCPCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) { func (c *TCPCollector) collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) (*prometheus.Desc, error) {
var dst []Win32_PerfRawData_Tcpip_TCPv4 var dst []tcp
q := queryAll(&dst) if err := unmarshalObject(ctx.perfObjects["TCPv4"], &dst); err != nil {
if err := wmi.Query(q, &dst); err != nil {
return nil, err return nil, err
} }
if len(dst) == 0 { if len(dst) == 0 {
return nil, errors.New("WMI query returned empty result set") return nil, errors.New("TCPv4 performance object not available")
} }
// Counters // Counters
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.ConnectionFailures, c.ConnectionFailures,
prometheus.CounterValue, prometheus.CounterValue,
float64(dst[0].ConnectionFailures), dst[0].ConnectionFailures,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.ConnectionsActive, c.ConnectionsActive,
prometheus.CounterValue, prometheus.CounterValue,
float64(dst[0].ConnectionsActive), dst[0].ConnectionsActive,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.ConnectionsEstablished, c.ConnectionsEstablished,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(dst[0].ConnectionsEstablished), dst[0].ConnectionsEstablished,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.ConnectionsPassive, c.ConnectionsPassive,
prometheus.CounterValue, prometheus.CounterValue,
float64(dst[0].ConnectionsPassive), dst[0].ConnectionsPassive,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.ConnectionsReset, c.ConnectionsReset,
prometheus.CounterValue, prometheus.CounterValue,
float64(dst[0].ConnectionsReset), dst[0].ConnectionsReset,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.SegmentsTotal, c.SegmentsTotal,
prometheus.CounterValue, prometheus.CounterValue,
float64(dst[0].SegmentsPersec), dst[0].SegmentsPersec,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.SegmentsReceivedTotal, c.SegmentsReceivedTotal,
prometheus.CounterValue, prometheus.CounterValue,
float64(dst[0].SegmentsReceivedPersec), dst[0].SegmentsReceivedPersec,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.SegmentsRetransmittedTotal, c.SegmentsRetransmittedTotal,
prometheus.CounterValue, prometheus.CounterValue,
float64(dst[0].SegmentsRetransmittedPersec), dst[0].SegmentsRetransmittedPersec,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.SegmentsSentTotal, c.SegmentsSentTotal,
prometheus.CounterValue, prometheus.CounterValue,
float64(dst[0].SegmentsSentPersec), dst[0].SegmentsSentPersec,
) )
return nil, nil return nil, nil