feat(ethtool): Possibility to skip gathering metrics for downed interfaces (#12087)
This commit is contained in:
parent
2ed413bdb0
commit
284edccf92
|
|
@ -14,6 +14,12 @@ on the network device and driver.
|
|||
## List of interfaces to ignore when pulling metrics.
|
||||
# interface_exclude = ["eth1"]
|
||||
|
||||
## Plugin behavior for downed interfaces
|
||||
## Available choices:
|
||||
## - expose: collect & report metrics for down interfaces
|
||||
## - skip: ignore interfaces that are marked down
|
||||
# down_interfaces = "expose"
|
||||
|
||||
## Some drivers declare statistics with extra whitespace, different spacing,
|
||||
## and mix cases. This list, when enabled, can be used to clean the keys.
|
||||
## Here are the current possible normalizations:
|
||||
|
|
|
|||
|
|
@ -5,11 +5,14 @@ import (
|
|||
"net"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/filter"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
var downInterfacesBehaviors = []string{"expose", "skip"}
|
||||
|
||||
type Command interface {
|
||||
Init() error
|
||||
DriverName(intf string) (string, error)
|
||||
|
|
@ -24,11 +27,16 @@ type Ethtool struct {
|
|||
// This is the list of interface names to ignore
|
||||
InterfaceExclude []string `toml:"interface_exclude"`
|
||||
|
||||
// Behavior regarding metrics for downed interfaces
|
||||
DownInterfaces string `toml:" down_interfaces"`
|
||||
|
||||
// Normalization on the key names
|
||||
NormalizeKeys []string `toml:"normalize_keys"`
|
||||
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
|
||||
interfaceFilter filter.Filter
|
||||
|
||||
// the ethtool command
|
||||
command Command
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
package ethtool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
|
@ -14,6 +15,7 @@ import (
|
|||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/filter"
|
||||
"github.com/influxdata/telegraf/internal/choice"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
|
|
@ -21,6 +23,24 @@ type CommandEthtool struct {
|
|||
ethtool *ethtoolLib.Ethtool
|
||||
}
|
||||
|
||||
func (e *Ethtool) Init() error {
|
||||
var err error
|
||||
e.interfaceFilter, err = filter.NewIncludeExcludeFilter(e.InterfaceInclude, e.InterfaceExclude)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if e.DownInterfaces == "" {
|
||||
e.DownInterfaces = "expose"
|
||||
}
|
||||
|
||||
if err = choice.Check(e.DownInterfaces, downInterfacesBehaviors); err != nil {
|
||||
return fmt.Errorf("down_interfaces: %w", err)
|
||||
}
|
||||
|
||||
return e.command.Init()
|
||||
}
|
||||
|
||||
func (e *Ethtool) Gather(acc telegraf.Accumulator) error {
|
||||
// Get the list of interfaces
|
||||
interfaces, err := e.command.Interfaces()
|
||||
|
|
@ -29,17 +49,11 @@ func (e *Ethtool) Gather(acc telegraf.Accumulator) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
interfaceFilter, err := filter.NewIncludeExcludeFilter(e.InterfaceInclude, e.InterfaceExclude)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// parallelize the ethtool call in event of many interfaces
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for _, iface := range interfaces {
|
||||
// Check this isn't a loop back and that its matched by the filter
|
||||
if (iface.Flags&net.FlagLoopback == 0) && interfaceFilter.Match(iface.Name) {
|
||||
if e.interfaceEligibleForGather(iface) {
|
||||
wg.Add(1)
|
||||
|
||||
go func(i net.Interface) {
|
||||
|
|
@ -54,9 +68,18 @@ func (e *Ethtool) Gather(acc telegraf.Accumulator) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Initialise the Command Tool
|
||||
func (e *Ethtool) Init() error {
|
||||
return e.command.Init()
|
||||
func (e *Ethtool) interfaceEligibleForGather(iface net.Interface) bool {
|
||||
// Don't gather if it is a loop back, or it isn't matched by the filter
|
||||
if isLoopback(iface) || !e.interfaceFilter.Match(iface.Name) {
|
||||
return false
|
||||
}
|
||||
|
||||
// For downed interfaces, gather only for "expose"
|
||||
if !interfaceUp(iface) {
|
||||
return e.DownInterfaces == "expose"
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Gather the stats for the interface.
|
||||
|
|
@ -81,7 +104,7 @@ func (e *Ethtool) gatherEthtoolStats(iface net.Interface, acc telegraf.Accumulat
|
|||
return
|
||||
}
|
||||
|
||||
fields[fieldInterfaceUp] = e.interfaceUp(iface)
|
||||
fields[fieldInterfaceUp] = interfaceUp(iface)
|
||||
for k, v := range stats {
|
||||
fields[e.normalizeKey(k)] = v
|
||||
}
|
||||
|
|
@ -134,7 +157,11 @@ func inStringSlice(slice []string, value string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (e *Ethtool) interfaceUp(iface net.Interface) bool {
|
||||
func isLoopback(iface net.Interface) bool {
|
||||
return (iface.Flags & net.FlagLoopback) != 0
|
||||
}
|
||||
|
||||
func interfaceUp(iface net.Interface) bool {
|
||||
return (iface.Flags & net.FlagUp) != 0
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -292,6 +292,7 @@ func setup() {
|
|||
command = &Ethtool{
|
||||
InterfaceInclude: []string{},
|
||||
InterfaceExclude: []string{},
|
||||
DownInterfaces: "expose",
|
||||
command: c,
|
||||
}
|
||||
}
|
||||
|
|
@ -315,9 +316,12 @@ func toStringMapUint(in map[string]interface{}) map[string]uint64 {
|
|||
|
||||
func TestGather(t *testing.T) {
|
||||
setup()
|
||||
var acc testutil.Accumulator
|
||||
|
||||
err := command.Gather(&acc)
|
||||
err := command.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err = command.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, acc.Metrics, 2)
|
||||
|
||||
|
|
@ -342,11 +346,14 @@ func TestGather(t *testing.T) {
|
|||
|
||||
func TestGatherIncludeInterfaces(t *testing.T) {
|
||||
setup()
|
||||
var acc testutil.Accumulator
|
||||
|
||||
command.InterfaceInclude = append(command.InterfaceInclude, "eth1")
|
||||
|
||||
err := command.Gather(&acc)
|
||||
err := command.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err = command.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, acc.Metrics, 1)
|
||||
|
||||
|
|
@ -373,11 +380,14 @@ func TestGatherIncludeInterfaces(t *testing.T) {
|
|||
|
||||
func TestGatherIgnoreInterfaces(t *testing.T) {
|
||||
setup()
|
||||
var acc testutil.Accumulator
|
||||
|
||||
command.InterfaceExclude = append(command.InterfaceExclude, "eth1")
|
||||
|
||||
err := command.Gather(&acc)
|
||||
err := command.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err = command.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, acc.Metrics, 1)
|
||||
|
||||
|
|
@ -402,6 +412,30 @@ func TestGatherIgnoreInterfaces(t *testing.T) {
|
|||
acc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth2, expectedTagsEth2)
|
||||
}
|
||||
|
||||
func TestSkipMetricsForInterfaceDown(t *testing.T) {
|
||||
setup()
|
||||
|
||||
command.DownInterfaces = "skip"
|
||||
|
||||
err := command.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err = command.Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, acc.Metrics, 1)
|
||||
|
||||
expectedFieldsEth1 := toStringMapInterface(interfaceMap["eth1"].Stat)
|
||||
expectedFieldsEth1["interface_up_counter"] = expectedFieldsEth1["interface_up"]
|
||||
expectedFieldsEth1["interface_up"] = true
|
||||
|
||||
expectedTagsEth1 := map[string]string{
|
||||
"interface": "eth1",
|
||||
"driver": "driver1",
|
||||
}
|
||||
acc.AssertContainsTaggedFields(t, pluginName, expectedFieldsEth1, expectedTagsEth1)
|
||||
}
|
||||
|
||||
type TestCase struct {
|
||||
normalization []string
|
||||
stats map[string]interface{}
|
||||
|
|
@ -525,8 +559,11 @@ func TestNormalizedKeys(t *testing.T) {
|
|||
command: cmd,
|
||||
}
|
||||
|
||||
err := command.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
var acc testutil.Accumulator
|
||||
err := command.Gather(&acc)
|
||||
err = command.Gather(&acc)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, acc.Metrics, 1)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,12 @@
|
|||
## List of interfaces to ignore when pulling metrics.
|
||||
# interface_exclude = ["eth1"]
|
||||
|
||||
## Plugin behavior for downed interfaces
|
||||
## Available choices:
|
||||
## - expose: collect & report metrics for down interfaces
|
||||
## - skip: ignore interfaces that are marked down
|
||||
# down_interfaces = "expose"
|
||||
|
||||
## Some drivers declare statistics with extra whitespace, different spacing,
|
||||
## and mix cases. This list, when enabled, can be used to clean the keys.
|
||||
## Here are the current possible normalizations:
|
||||
|
|
|
|||
Loading…
Reference in New Issue