mirror of
https://github.com/prometheus/node_exporter.git
synced 2024-12-27 14:39:53 -08:00
Gather additional link info from ethtool.
The ethtool_cmd struct from the linux kernel contains information about the speeds and features supported by a network device. This includes speeds and duplex but also features like autonegotiate and 802.3x pause frames. Closes #1444 Signed-off-by: W. Andrew Denton <git@flying-snail.net>
This commit is contained in:
parent
11bb2f8a95
commit
77a3c9bc20
|
@ -194,7 +194,7 @@ Name | Description | OS
|
|||
buddyinfo | Exposes statistics of memory fragments as reported by /proc/buddyinfo. | Linux
|
||||
devstat | Exposes device statistics | Dragonfly, FreeBSD
|
||||
drbd | Exposes Distributed Replicated Block Device statistics (to version 8.4) | Linux
|
||||
ethtool | Exposes network interface and network driver statistics equivalent to `ethtool -S` and `ethtool -i`. | Linux
|
||||
ethtool | Exposes network interface information and network driver statistics equivalent to `ethtool`, `ethtool -S`, and `ethtool -i`. | Linux
|
||||
interrupts | Exposes detailed interrupts statistics. | Linux, OpenBSD
|
||||
ksmd | Exposes kernel and system statistics from `/sys/kernel/mm/ksm`. | Linux
|
||||
logind | Exposes session counts from [logind](http://www.freedesktop.org/wiki/Software/systemd/logind/). | Linux
|
||||
|
|
|
@ -38,6 +38,12 @@ import (
|
|||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
// These are in _bytes_ to match bytes-per-second speeds from netclass.
|
||||
Mbps = 1000000.0 / 8.0
|
||||
Gbps = 1000.0 * Mbps
|
||||
)
|
||||
|
||||
var (
|
||||
ethtoolDeviceInclude = kingpin.Flag("collector.ethtool.device-include", "Regexp of ethtool devices to include (mutually exclusive to device-exclude).").String()
|
||||
ethtoolDeviceExclude = kingpin.Flag("collector.ethtool.device-exclude", "Regexp of ethtool devices to exclude (mutually exclusive to device-include).").String()
|
||||
|
@ -49,6 +55,7 @@ var (
|
|||
type Ethtool interface {
|
||||
DriverInfo(string) (ethtool.DrvInfo, error)
|
||||
Stats(string) (map[string]uint64, error)
|
||||
LinkInfo(string) (ethtool.EthtoolCmd, error)
|
||||
}
|
||||
|
||||
type ethtoolLibrary struct {
|
||||
|
@ -63,6 +70,12 @@ func (e *ethtoolLibrary) Stats(intf string) (map[string]uint64, error) {
|
|||
return e.ethtool.Stats(intf)
|
||||
}
|
||||
|
||||
func (e *ethtoolLibrary) LinkInfo(intf string) (ethtool.EthtoolCmd, error) {
|
||||
var ethtoolCmd ethtool.EthtoolCmd
|
||||
_, err := ethtoolCmd.CmdGet(intf)
|
||||
return ethtoolCmd, err
|
||||
}
|
||||
|
||||
type ethtoolCollector struct {
|
||||
fs sysfs.FS
|
||||
entries map[string]*prometheus.Desc
|
||||
|
@ -130,6 +143,58 @@ func makeEthtoolCollector(logger log.Logger) (*ethtoolCollector, error) {
|
|||
"Network interface packets sent",
|
||||
[]string{"device"}, nil,
|
||||
),
|
||||
|
||||
// link info
|
||||
"supported_port": prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "network", "supported_port_info"),
|
||||
"Type of ports or PHYs supported by network device",
|
||||
[]string{"device", "type"}, nil,
|
||||
),
|
||||
"supported_speed": prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "network", "supported_speed_bytes"),
|
||||
"Combination of speeds and features supported by network device",
|
||||
[]string{"device", "duplex", "mode"}, nil,
|
||||
),
|
||||
"supported_autonegotiate": prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "network", "autonegotiate_supported"),
|
||||
"If this port device supports autonegotiate",
|
||||
[]string{"device"}, nil,
|
||||
),
|
||||
"supported_pause": prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "network", "pause_supported"),
|
||||
"If this port device supports pause frames",
|
||||
[]string{"device"}, nil,
|
||||
),
|
||||
"supported_asymmetricpause": prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "network", "asymmetricpause_supported"),
|
||||
"If this port device supports asymmetric pause frames",
|
||||
[]string{"device"}, nil,
|
||||
),
|
||||
"advertised_speed": prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "network", "advertised_speed_bytes"),
|
||||
"Combination of speeds and features offered by network device",
|
||||
[]string{"device", "duplex", "mode"}, nil,
|
||||
),
|
||||
"advertised_autonegotiate": prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "network", "autonegotiate_advertised"),
|
||||
"If this port device offers autonegotiate",
|
||||
[]string{"device"}, nil,
|
||||
),
|
||||
"advertised_pause": prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "network", "pause_advertised"),
|
||||
"If this port device offers pause capability",
|
||||
[]string{"device"}, nil,
|
||||
),
|
||||
"advertised_asymmetricpause": prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "network", "asymmetricpause_advertised"),
|
||||
"If this port device offers asymmetric pause capability",
|
||||
[]string{"device"}, nil,
|
||||
),
|
||||
"autonegotiate": prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "network", "autonegotiate"),
|
||||
"If this port is using autonegotiate",
|
||||
[]string{"device"}, nil,
|
||||
),
|
||||
},
|
||||
infoDesc: prometheus.NewDesc(
|
||||
prometheus.BuildFQName(namespace, "ethtool", "info"),
|
||||
|
@ -156,6 +221,128 @@ func NewEthtoolCollector(logger log.Logger) (Collector, error) {
|
|||
return makeEthtoolCollector(logger)
|
||||
}
|
||||
|
||||
// updatePortCapabilities generates metrics for autonegotiate, pause and asymmetricpause.
|
||||
// The bit offsets here correspond to ethtool_link_mode_bit_indices in linux/include/uapi/linux/ethtool.h
|
||||
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/ethtool.h
|
||||
func (c *ethtoolCollector) updatePortCapabilities(ch chan<- prometheus.Metric, prefix string, device string, linkModes uint32) {
|
||||
autonegotiate := 0.0
|
||||
pause := 0.0
|
||||
asymmetricPause := 0.0
|
||||
if linkModes&(1<<6) != 0 {
|
||||
autonegotiate = 1.0
|
||||
}
|
||||
if linkModes&(1<<13) != 0 {
|
||||
pause = 1.0
|
||||
}
|
||||
if linkModes&(1<<14) != 0 {
|
||||
asymmetricPause = 1.0
|
||||
}
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[fmt.Sprintf("%s_autonegotiate", prefix)], prometheus.GaugeValue, autonegotiate, device)
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[fmt.Sprintf("%s_pause", prefix)], prometheus.GaugeValue, pause, device)
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[fmt.Sprintf("%s_asymmetricpause", prefix)], prometheus.GaugeValue, asymmetricPause, device)
|
||||
}
|
||||
|
||||
// updatePortInfo generates port type metrics to indicate if the network devices supports Twisted Pair, optical fiber, etc.
|
||||
// The bit offsets here correspond to ethtool_link_mode_bit_indices in linux/include/uapi/linux/ethtool.h
|
||||
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/ethtool.h
|
||||
func (c *ethtoolCollector) updatePortInfo(ch chan<- prometheus.Metric, device string, linkModes uint32) {
|
||||
if linkModes&(1<<7) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries["supported_port"], prometheus.GaugeValue, 1.0, device, "TP")
|
||||
}
|
||||
if linkModes&(1<<8) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries["supported_port"], prometheus.GaugeValue, 1.0, device, "AUI")
|
||||
}
|
||||
if linkModes&(1<<9) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries["supported_port"], prometheus.GaugeValue, 1.0, device, "MII")
|
||||
}
|
||||
if linkModes&(1<<10) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries["supported_port"], prometheus.GaugeValue, 1.0, device, "FIBRE")
|
||||
}
|
||||
if linkModes&(1<<11) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries["supported_port"], prometheus.GaugeValue, 1.0, device, "BNC")
|
||||
}
|
||||
if linkModes&(1<<16) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries["supported_port"], prometheus.GaugeValue, 1.0, device, "Backplane")
|
||||
}
|
||||
}
|
||||
|
||||
// updateSpeeds generates metrics corresponding to the speeds and duplex modes supported or advertised by the network device.
|
||||
// The bit offsets here correspond to ethtool_link_mode_bit_indices in linux/include/uapi/linux/ethtool.h
|
||||
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/ethtool.h
|
||||
func (c *ethtoolCollector) updateSpeeds(ch chan<- prometheus.Metric, prefix string, device string, linkModes uint32) {
|
||||
linkMode := fmt.Sprintf("%s_speed", prefix)
|
||||
|
||||
if linkModes&(1<<0) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 10*Mbps, device, "half", "10baseT")
|
||||
}
|
||||
if linkModes&(1<<1) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 10*Mbps, device, "full", "10baseT")
|
||||
}
|
||||
if linkModes&(1<<2) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 100*Mbps, device, "half", "100baseT")
|
||||
}
|
||||
if linkModes&(1<<3) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 100*Mbps, device, "full", "100baseT")
|
||||
}
|
||||
if linkModes&(1<<4) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 1000*Mbps, device, "half", "1000baseT")
|
||||
}
|
||||
if linkModes&(1<<5) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 1000*Mbps, device, "full", "1000baseT")
|
||||
}
|
||||
if linkModes&(1<<12) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 10*Gbps, device, "full", "10000baseT")
|
||||
}
|
||||
if linkModes&(1<<15) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 2.5*Gbps, device, "full", "2500baseX")
|
||||
}
|
||||
if linkModes&(1<<17) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 1*Gbps, device, "full", "1000baseKX")
|
||||
}
|
||||
if linkModes&(1<<18) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 10*Gbps, device, "full", "10000baseKX4")
|
||||
}
|
||||
if linkModes&(1<<19) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 10*Gbps, device, "full", "10000baseKR")
|
||||
}
|
||||
if linkModes&(1<<20) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 10*Gbps, device, "full", "10000baseR_FEC")
|
||||
}
|
||||
if linkModes&(1<<21) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 20*Gbps, device, "full", "20000baseMLD2")
|
||||
}
|
||||
if linkModes&(1<<22) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 20*Gbps, device, "full", "20000baseKR2")
|
||||
}
|
||||
if linkModes&(1<<23) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 40*Gbps, device, "full", "40000baseKR4")
|
||||
}
|
||||
if linkModes&(1<<24) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 40*Gbps, device, "full", "40000baseCR4")
|
||||
}
|
||||
if linkModes&(1<<25) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 40*Gbps, device, "full", "40000baseSR4")
|
||||
}
|
||||
if linkModes&(1<<26) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 40*Gbps, device, "full", "40000baseLR4")
|
||||
}
|
||||
if linkModes&(1<<27) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 56*Gbps, device, "full", "56000baseKR4")
|
||||
}
|
||||
if linkModes&(1<<28) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 56*Gbps, device, "full", "56000baseCR4")
|
||||
}
|
||||
if linkModes&(1<<29) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 56*Gbps, device, "full", "56000baseSR4")
|
||||
}
|
||||
if linkModes&(1<<30) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 56*Gbps, device, "full", "56000baseLR4")
|
||||
}
|
||||
if linkModes&(1<<31) != 0 {
|
||||
ch <- prometheus.MustNewConstMetric(c.entries[linkMode], prometheus.GaugeValue, 25*Gbps, device, "full", "25000baseCR")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ethtoolCollector) Update(ch chan<- prometheus.Metric) error {
|
||||
netClass, err := c.fs.NetClass()
|
||||
if err != nil {
|
||||
|
@ -178,6 +365,26 @@ func (c *ethtoolCollector) Update(ch chan<- prometheus.Metric) error {
|
|||
continue
|
||||
}
|
||||
|
||||
linkInfo, err := c.ethtool.LinkInfo(device)
|
||||
if err == nil {
|
||||
c.updateSpeeds(ch, "supported", device, linkInfo.Supported)
|
||||
c.updatePortInfo(ch, device, linkInfo.Supported)
|
||||
c.updatePortCapabilities(ch, "supported", device, linkInfo.Supported)
|
||||
c.updateSpeeds(ch, "advertised", device, linkInfo.Advertising)
|
||||
c.updatePortCapabilities(ch, "advertised", device, linkInfo.Advertising)
|
||||
ch <- prometheus.MustNewConstMetric(c.entries["autonegotiate"], prometheus.GaugeValue, float64(linkInfo.Autoneg), device)
|
||||
} else {
|
||||
if errno, ok := err.(syscall.Errno); ok {
|
||||
if err == unix.EOPNOTSUPP {
|
||||
level.Debug(c.logger).Log("msg", "ethtool link info error", "err", err, "device", device, "errno", uint(errno))
|
||||
} else if errno != 0 {
|
||||
level.Error(c.logger).Log("msg", "ethtool link info error", "err", err, "device", device, "errno", uint(errno))
|
||||
}
|
||||
} else {
|
||||
level.Error(c.logger).Log("msg", "ethtool link info error", "err", err, "device", device)
|
||||
}
|
||||
}
|
||||
|
||||
drvInfo, err := c.ethtool.DriverInfo(device)
|
||||
|
||||
if err == nil {
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
"github.com/go-kit/log"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/testutil"
|
||||
"github.com/safchain/ethtool"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
@ -33,6 +34,28 @@ type EthtoolFixture struct {
|
|||
fixturePath string
|
||||
}
|
||||
|
||||
type testEthtoolCollector struct {
|
||||
dsc Collector
|
||||
}
|
||||
|
||||
func (c testEthtoolCollector) Collect(ch chan<- prometheus.Metric) {
|
||||
c.dsc.Update(ch)
|
||||
}
|
||||
|
||||
func (c testEthtoolCollector) Describe(ch chan<- *prometheus.Desc) {
|
||||
prometheus.DescribeByCollect(c, ch)
|
||||
}
|
||||
|
||||
func NewTestEthtoolCollector(logger log.Logger) (prometheus.Collector, error) {
|
||||
dsc, err := NewEthtoolTestCollector(logger)
|
||||
if err != nil {
|
||||
return testEthtoolCollector{}, err
|
||||
}
|
||||
return testEthtoolCollector{
|
||||
dsc: dsc,
|
||||
}, err
|
||||
}
|
||||
|
||||
func (e *EthtoolFixture) DriverInfo(intf string) (ethtool.DrvInfo, error) {
|
||||
res := ethtool.DrvInfo{}
|
||||
|
||||
|
@ -110,6 +133,130 @@ func (e *EthtoolFixture) Stats(intf string) (map[string]uint64, error) {
|
|||
return res, err
|
||||
}
|
||||
|
||||
func readModes(modes string) uint32 {
|
||||
var out uint32
|
||||
for _, mode := range strings.Split(modes, " ") {
|
||||
if mode == "10baseT/Half" {
|
||||
out |= (1 << 0)
|
||||
}
|
||||
if mode == "10baseT/Full" {
|
||||
out |= (1 << 1)
|
||||
}
|
||||
if mode == "100baseT/Half" {
|
||||
out |= (1 << 2)
|
||||
}
|
||||
if mode == "100baseT/Full" {
|
||||
out |= (1 << 3)
|
||||
}
|
||||
if mode == "1000baseT/Half" {
|
||||
out |= (1 << 4)
|
||||
}
|
||||
if mode == "1000baseT/Full" {
|
||||
out |= (1 << 5)
|
||||
}
|
||||
if mode == "10000baseT/Full" {
|
||||
out |= (1 << 12)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func readPortTypes(portTypes string) uint32 {
|
||||
var out uint32
|
||||
for _, ptype := range strings.Split(portTypes, " ") {
|
||||
ptype = strings.Trim(ptype, " \t")
|
||||
if ptype == "TP" {
|
||||
out |= (1 << 7)
|
||||
}
|
||||
if ptype == "MII" {
|
||||
out |= (1 << 9)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (e *EthtoolFixture) LinkInfo(intf string) (ethtool.EthtoolCmd, error) {
|
||||
var res ethtool.EthtoolCmd
|
||||
fixtureFile, err := os.Open(filepath.Join(e.fixturePath, intf, "settings"))
|
||||
if e, ok := err.(*os.PathError); ok && e.Err == syscall.ENOENT {
|
||||
// The fixture for this interface doesn't exist. Translate that to unix.EOPNOTSUPP
|
||||
// to replicate an interface that doesn't support ethtool stats
|
||||
return res, unix.EOPNOTSUPP
|
||||
}
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
defer fixtureFile.Close()
|
||||
|
||||
scanner := bufio.NewScanner(fixtureFile)
|
||||
readingSupportedLinkModes := false
|
||||
readingAdvertisedLinkModes := false
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, "#") || strings.HasPrefix(line, "Settings for") {
|
||||
continue
|
||||
}
|
||||
line = strings.Trim(line, " \t")
|
||||
|
||||
if (readingAdvertisedLinkModes || readingSupportedLinkModes) && strings.Contains(line, ":") {
|
||||
readingAdvertisedLinkModes = false
|
||||
readingSupportedLinkModes = false
|
||||
}
|
||||
|
||||
if readingAdvertisedLinkModes {
|
||||
res.Advertising |= readModes(line)
|
||||
continue
|
||||
} else if readingSupportedLinkModes {
|
||||
res.Supported |= readModes(line)
|
||||
continue
|
||||
}
|
||||
|
||||
items := strings.Split(line, ": ")
|
||||
if items[0] == "Supported pause frame use" {
|
||||
if items[1] == "Symmetric" {
|
||||
res.Supported |= (1 << 13)
|
||||
} else if items[1] == "Receive-only" {
|
||||
res.Supported |= (1 << 14)
|
||||
}
|
||||
}
|
||||
if items[0] == "Advertised pause frame use" {
|
||||
if items[1] == "Symmetric" {
|
||||
res.Advertising |= (1 << 13)
|
||||
} else if items[1] == "Receive-only" {
|
||||
res.Advertising |= (1 << 14)
|
||||
}
|
||||
}
|
||||
if items[0] == "Supported ports" {
|
||||
res.Supported |= readPortTypes(items[1])
|
||||
}
|
||||
if items[0] == "Supported link modes" {
|
||||
res.Supported |= readModes(items[1])
|
||||
readingSupportedLinkModes = true
|
||||
}
|
||||
if items[0] == "Advertised link modes" {
|
||||
res.Advertising |= readModes(items[1])
|
||||
readingAdvertisedLinkModes = true
|
||||
}
|
||||
if items[0] == "Supports auto-negotiation" {
|
||||
if items[1] == "Yes" {
|
||||
res.Supported |= (1 << 6)
|
||||
}
|
||||
}
|
||||
if items[0] == "Advertised auto-negotiation" {
|
||||
if items[1] == "Yes" {
|
||||
res.Advertising |= (1 << 6)
|
||||
}
|
||||
}
|
||||
if items[0] == "Auto-negotiation" {
|
||||
if items[1] == "on" {
|
||||
res.Autoneg = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func NewEthtoolTestCollector(logger log.Logger) (Collector, error) {
|
||||
collector, err := makeEthtoolCollector(logger)
|
||||
collector.ethtool = &EthtoolFixture{
|
||||
|
@ -138,30 +285,103 @@ func TestBuildEthtoolFQName(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEthtoolCollector(t *testing.T) {
|
||||
testcases := []string{
|
||||
prometheus.NewDesc("node_ethtool_info",
|
||||
"A metric with a constant '1' value labeled by bus_info, device, driver, expansion_rom_version, firmware_version, version.",
|
||||
[]string{"bus_info", "device", "driver", "expansion_rom_version", "firmware_version", "version"}, nil).String(),
|
||||
prometheus.NewDesc("node_ethtool_align_errors", "Network interface align_errors", []string{"device"}, nil).String(),
|
||||
prometheus.NewDesc("node_ethtool_received_broadcast", "Network interface rx_broadcast", []string{"device"}, nil).String(),
|
||||
prometheus.NewDesc("node_ethtool_received_errors_total", "Number of received frames with errors", []string{"device"}, nil).String(),
|
||||
prometheus.NewDesc("node_ethtool_received_missed", "Network interface rx_missed", []string{"device"}, nil).String(),
|
||||
prometheus.NewDesc("node_ethtool_received_multicast", "Network interface rx_multicast", []string{"device"}, nil).String(),
|
||||
prometheus.NewDesc("node_ethtool_received_packets_total", "Network interface packets received", []string{"device"}, nil).String(),
|
||||
prometheus.NewDesc("node_ethtool_received_unicast", "Network interface rx_unicast", []string{"device"}, nil).String(),
|
||||
prometheus.NewDesc("node_ethtool_transmitted_aborted", "Network interface tx_aborted", []string{"device"}, nil).String(),
|
||||
prometheus.NewDesc("node_ethtool_transmitted_errors_total", "Number of sent frames with errors", []string{"device"}, nil).String(),
|
||||
prometheus.NewDesc("node_ethtool_transmitted_multi_collisions", "Network interface tx_multi_collisions", []string{"device"}, nil).String(),
|
||||
prometheus.NewDesc("node_ethtool_transmitted_packets_total", "Network interface packets sent", []string{"device"}, nil).String(),
|
||||
}
|
||||
|
||||
func TestEthToolCollector(t *testing.T) {
|
||||
testcase := `# HELP node_ethtool_align_errors Network interface align_errors
|
||||
# TYPE node_ethtool_align_errors untyped
|
||||
node_ethtool_align_errors{device="eth0"} 0
|
||||
# HELP node_ethtool_info A metric with a constant '1' value labeled by bus_info, device, driver, expansion_rom_version, firmware_version, version.
|
||||
# TYPE node_ethtool_info gauge
|
||||
node_ethtool_info{bus_info="0000:00:1f.6",device="eth0",driver="e1000e",expansion_rom_version="",firmware_version="0.5-4",version="5.11.0-22-generic"} 1
|
||||
# HELP node_ethtool_received_broadcast Network interface rx_broadcast
|
||||
# TYPE node_ethtool_received_broadcast untyped
|
||||
node_ethtool_received_broadcast{device="eth0"} 5792
|
||||
# HELP node_ethtool_received_errors_total Number of received frames with errors
|
||||
# TYPE node_ethtool_received_errors_total untyped
|
||||
node_ethtool_received_errors_total{device="eth0"} 0
|
||||
# HELP node_ethtool_received_missed Network interface rx_missed
|
||||
# TYPE node_ethtool_received_missed untyped
|
||||
node_ethtool_received_missed{device="eth0"} 401
|
||||
# HELP node_ethtool_received_multicast Network interface rx_multicast
|
||||
# TYPE node_ethtool_received_multicast untyped
|
||||
node_ethtool_received_multicast{device="eth0"} 23973
|
||||
# HELP node_ethtool_received_packets_total Network interface packets received
|
||||
# TYPE node_ethtool_received_packets_total untyped
|
||||
node_ethtool_received_packets_total{device="eth0"} 1.260062e+06
|
||||
# HELP node_ethtool_received_unicast Network interface rx_unicast
|
||||
# TYPE node_ethtool_received_unicast untyped
|
||||
node_ethtool_received_unicast{device="eth0"} 1.230297e+06
|
||||
# HELP node_ethtool_transmitted_aborted Network interface tx_aborted
|
||||
# TYPE node_ethtool_transmitted_aborted untyped
|
||||
node_ethtool_transmitted_aborted{device="eth0"} 0
|
||||
# HELP node_ethtool_transmitted_errors_total Number of sent frames with errors
|
||||
# TYPE node_ethtool_transmitted_errors_total untyped
|
||||
node_ethtool_transmitted_errors_total{device="eth0"} 0
|
||||
# HELP node_ethtool_transmitted_multi_collisions Network interface tx_multi_collisions
|
||||
# TYPE node_ethtool_transmitted_multi_collisions untyped
|
||||
node_ethtool_transmitted_multi_collisions{device="eth0"} 0
|
||||
# HELP node_ethtool_transmitted_packets_total Network interface packets sent
|
||||
# TYPE node_ethtool_transmitted_packets_total untyped
|
||||
node_ethtool_transmitted_packets_total{device="eth0"} 961500
|
||||
# HELP node_ethtool_transmitted_single_collisions Network interface tx_single_collisions
|
||||
# TYPE node_ethtool_transmitted_single_collisions untyped
|
||||
node_ethtool_transmitted_single_collisions{device="eth0"} 0
|
||||
# HELP node_ethtool_transmitted_underrun Network interface tx_underrun
|
||||
# TYPE node_ethtool_transmitted_underrun untyped
|
||||
node_ethtool_transmitted_underrun{device="eth0"} 0
|
||||
# HELP node_network_advertised_speed_bytes Combination of speeds and features offered by network device
|
||||
# TYPE node_network_advertised_speed_bytes gauge
|
||||
node_network_advertised_speed_bytes{device="eth0",duplex="full",mode="1000baseT"} 1.25e+08
|
||||
node_network_advertised_speed_bytes{device="eth0",duplex="full",mode="100baseT"} 1.25e+07
|
||||
node_network_advertised_speed_bytes{device="eth0",duplex="full",mode="10baseT"} 1.25e+06
|
||||
node_network_advertised_speed_bytes{device="eth0",duplex="half",mode="100baseT"} 1.25e+07
|
||||
node_network_advertised_speed_bytes{device="eth0",duplex="half",mode="10baseT"} 1.25e+06
|
||||
# HELP node_network_asymmetricpause_advertised If this port device offers asymmetric pause capability
|
||||
# TYPE node_network_asymmetricpause_advertised gauge
|
||||
node_network_asymmetricpause_advertised{device="eth0"} 0
|
||||
# HELP node_network_asymmetricpause_supported If this port device supports asymmetric pause frames
|
||||
# TYPE node_network_asymmetricpause_supported gauge
|
||||
node_network_asymmetricpause_supported{device="eth0"} 0
|
||||
# HELP node_network_autonegotiate If this port is using autonegotiate
|
||||
# TYPE node_network_autonegotiate gauge
|
||||
node_network_autonegotiate{device="eth0"} 1
|
||||
# HELP node_network_autonegotiate_advertised If this port device offers autonegotiate
|
||||
# TYPE node_network_autonegotiate_advertised gauge
|
||||
node_network_autonegotiate_advertised{device="eth0"} 1
|
||||
# HELP node_network_autonegotiate_supported If this port device supports autonegotiate
|
||||
# TYPE node_network_autonegotiate_supported gauge
|
||||
node_network_autonegotiate_supported{device="eth0"} 1
|
||||
# HELP node_network_pause_advertised If this port device offers pause capability
|
||||
# TYPE node_network_pause_advertised gauge
|
||||
node_network_pause_advertised{device="eth0"} 1
|
||||
# HELP node_network_pause_supported If this port device supports pause frames
|
||||
# TYPE node_network_pause_supported gauge
|
||||
node_network_pause_supported{device="eth0"} 1
|
||||
# HELP node_network_supported_port_info Type of ports or PHYs supported by network device
|
||||
# TYPE node_network_supported_port_info gauge
|
||||
node_network_supported_port_info{device="eth0",type="MII"} 1
|
||||
node_network_supported_port_info{device="eth0",type="TP"} 1
|
||||
# HELP node_network_supported_speed_bytes Combination of speeds and features supported by network device
|
||||
# TYPE node_network_supported_speed_bytes gauge
|
||||
node_network_supported_speed_bytes{device="eth0",duplex="full",mode="10000baseT"} 1.25e+09
|
||||
node_network_supported_speed_bytes{device="eth0",duplex="full",mode="1000baseT"} 1.25e+08
|
||||
node_network_supported_speed_bytes{device="eth0",duplex="full",mode="100baseT"} 1.25e+07
|
||||
node_network_supported_speed_bytes{device="eth0",duplex="full",mode="10baseT"} 1.25e+06
|
||||
node_network_supported_speed_bytes{device="eth0",duplex="half",mode="100baseT"} 1.25e+07
|
||||
node_network_supported_speed_bytes{device="eth0",duplex="half",mode="10baseT"} 1.25e+06
|
||||
`
|
||||
*sysPath = "fixtures/sys"
|
||||
|
||||
collector, err := NewEthtoolTestCollector(log.NewNopLogger())
|
||||
logger := log.NewLogfmtLogger(os.Stderr)
|
||||
collector, err := NewEthtoolTestCollector(logger)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c, err := NewTestEthtoolCollector(logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
reg := prometheus.NewRegistry()
|
||||
reg.MustRegister(c)
|
||||
|
||||
sink := make(chan prometheus.Metric)
|
||||
go func() {
|
||||
|
@ -172,18 +392,8 @@ func TestEthtoolCollector(t *testing.T) {
|
|||
close(sink)
|
||||
}()
|
||||
|
||||
for _, expected := range testcases {
|
||||
metric := (<-sink)
|
||||
if metric == nil {
|
||||
t.Fatalf("Expected '%s' but got nothing (nil).", expected)
|
||||
}
|
||||
|
||||
got := metric.Desc().String()
|
||||
metric.Desc()
|
||||
if expected != got {
|
||||
t.Errorf("Expected '%s' but got '%s'", expected, got)
|
||||
} else {
|
||||
t.Logf("Successfully got '%s'", got)
|
||||
}
|
||||
err = testutil.GatherAndCompare(reg, strings.NewReader(testcase))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
26
collector/fixtures/ethtool/eth0/settings
Normal file
26
collector/fixtures/ethtool/eth0/settings
Normal file
|
@ -0,0 +1,26 @@
|
|||
# ethtool eth0
|
||||
Settings for eth0:
|
||||
Supported ports: [ TP MII ]
|
||||
Supported link modes: 10baseT/Half 10baseT/Full
|
||||
100baseT/Half 100baseT/Full
|
||||
1000baseT/Full 10000baseT/Full
|
||||
Supported pause frame use: Symmetric
|
||||
Supports auto-negotiation: Yes
|
||||
Supported FEC modes: Not reported
|
||||
Advertised link modes: 10baseT/Half 10baseT/Full
|
||||
100baseT/Half 100baseT/Full
|
||||
1000baseT/Full
|
||||
Advertised pause frame use: Symmetric
|
||||
Advertised auto-negotiation: Yes
|
||||
Advertised FEC modes: Not reported
|
||||
Speed: 1000Mb/s
|
||||
Duplex: Full
|
||||
Auto-negotiation: on
|
||||
Port: Twisted Pair
|
||||
PHYAD: 1
|
||||
Transceiver: internal
|
||||
MDI-X: off (auto)
|
||||
netlink error: Operation not permitted
|
||||
Current message level: 0x00000007 (7)
|
||||
drv probe link
|
||||
Link detected: yes
|
Loading…
Reference in a new issue