node_exporter/collector/ipvs.go
Matthias Rampke 37c7e5e60f Add IPVS stats collector.
This collector exposes IPVS status from `/proc/net/ip_vs` and stats from
`/proc/net/ip_vs_stats`.

Note that it is _not_ tested with IPv6, YMMV.
2015-05-08 14:02:47 +00:00

172 lines
4.6 KiB
Go

// +build !noipvs
package collector
import (
"fmt"
"strconv"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/procfs"
)
type ipvsCollector struct {
Collector
fs procfs.FS
backendConnectionsActive, backendConnectionsInact, backendWeight *prometheus.GaugeVec
connections, incomingPackets, outgoingPackets, incomingBytes, outgoingBytes prometheus.Counter
}
func init() {
Factories["ipvs"] = NewIPVSCollector
}
// NewIPVSCollector sets up a new collector for IPVS metrics. It accepts the
// "procfs" config parameter to override the default proc location (/proc).
func NewIPVSCollector(config Config) (Collector, error) {
return newIPVSCollector(config)
}
func newIPVSCollector(config Config) (*ipvsCollector, error) {
var (
ipvsBackendLabelNames = []string{
"local_address",
"local_port",
"remote_address",
"remote_port",
"proto",
}
c ipvsCollector
subsystem string
err error
)
if p, ok := config.Config["procfs"]; !ok {
c.fs, err = procfs.NewFS(procfs.DefaultMountPoint)
} else {
c.fs, err = procfs.NewFS(p)
}
if err != nil {
return nil, err
}
if s, ok := config.Config["ipvs_subsystem"]; ok {
subsystem = s
} else {
subsystem = "ipvs"
}
c.connections = prometheus.NewCounter(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: subsystem,
Name: "connections_total",
Help: "The total number of connections made.",
},
)
c.incomingPackets = prometheus.NewCounter(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: subsystem,
Name: "incoming_packets_total",
Help: "The total number of incoming packets.",
},
)
c.outgoingPackets = prometheus.NewCounter(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: subsystem,
Name: "outgoing_packets_total",
Help: "The total number of outgoing packets.",
},
)
c.incomingBytes = prometheus.NewCounter(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: subsystem,
Name: "incoming_bytes_total",
Help: "The total amount of incoming data.",
},
)
c.outgoingBytes = prometheus.NewCounter(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: subsystem,
Name: "outgoing_bytes_total",
Help: "The total amount of outgoing data.",
},
)
c.backendConnectionsActive = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: subsystem,
Name: "backend_connections_active",
Help: "The current active connections by local and remote address.",
},
ipvsBackendLabelNames,
)
c.backendConnectionsInact = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: subsystem,
Name: "backend_connections_inactive",
Help: "The current inactive connections by local and remote address.",
},
ipvsBackendLabelNames,
)
c.backendWeight = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: subsystem,
Name: "backend_weight",
Help: "The current backend weight by local and remote address.",
},
ipvsBackendLabelNames,
)
return &c, nil
}
func (c *ipvsCollector) Update(ch chan<- prometheus.Metric) error {
ipvsStats, err := c.fs.NewIPVSStats()
if err != nil {
return fmt.Errorf("could not get IPVS stats: %s", err)
}
c.connections.Set(float64(ipvsStats.Connections))
c.incomingPackets.Set(float64(ipvsStats.IncomingPackets))
c.outgoingPackets.Set(float64(ipvsStats.OutgoingPackets))
c.incomingBytes.Set(float64(ipvsStats.IncomingBytes))
c.outgoingBytes.Set(float64(ipvsStats.OutgoingBytes))
c.connections.Collect(ch)
c.incomingPackets.Collect(ch)
c.outgoingPackets.Collect(ch)
c.incomingBytes.Collect(ch)
c.outgoingBytes.Collect(ch)
backendStats, err := c.fs.NewIPVSBackendStatus()
if err != nil {
return fmt.Errorf("could not get backend status: %s", err)
}
for _, backend := range backendStats {
labelValues := []string{
backend.LocalAddress.String(),
strconv.FormatUint(uint64(backend.LocalPort), 10),
backend.RemoteAddress.String(),
strconv.FormatUint(uint64(backend.RemotePort), 10),
backend.Proto,
}
c.backendConnectionsActive.WithLabelValues(labelValues...).Set(float64(backend.ActiveConn))
c.backendConnectionsInact.WithLabelValues(labelValues...).Set(float64(backend.InactConn))
c.backendWeight.WithLabelValues(labelValues...).Set(float64(backend.Weight))
}
c.backendConnectionsActive.Collect(ch)
c.backendConnectionsInact.Collect(ch)
c.backendWeight.Collect(ch)
return nil
}