//go:generate ../../../tools/readme_config_includer/generator package net import ( _ "embed" "fmt" "net" "os" "path/filepath" "strconv" "strings" "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/config" "github.com/influxdata/telegraf/filter" "github.com/influxdata/telegraf/internal" "github.com/influxdata/telegraf/plugins/common/psutil" "github.com/influxdata/telegraf/plugins/inputs" ) //go:embed sample.conf var sampleConfig string type Net struct { Interfaces []string `toml:"interfaces"` IgnoreProtocolStats bool `toml:"ignore_protocol_stats"` filter filter.Filter ps psutil.PS skipChecks bool } func (*Net) SampleConfig() string { return sampleConfig } func (n *Net) Init() error { if !n.IgnoreProtocolStats { config.PrintOptionValueDeprecationNotice("inputs.net", "ignore_protocol_stats", "false", telegraf.DeprecationInfo{ Since: "1.27.3", RemovalIn: "1.36.0", Notice: "use the 'inputs.nstat' plugin instead for protocol stats", }, ) } // So not use the interface list of the system if the HOST_PROC variable is // set as the interfaces are determined by a syscall and therefore might // differ especially in container environments. n.skipChecks = os.Getenv("HOST_PROC") != "" return nil } func (n *Net) Gather(acc telegraf.Accumulator) error { netio, err := n.ps.NetIO() if err != nil { return fmt.Errorf("error getting net io info: %w", err) } if n.filter == nil { if n.filter, err = filter.Compile(n.Interfaces); err != nil { return fmt.Errorf("error compiling filter: %w", err) } } interfaces, err := net.Interfaces() if err != nil { return fmt.Errorf("error getting list of interfaces: %w", err) } interfacesByName := make(map[string]net.Interface, len(interfaces)) for _, iface := range interfaces { interfacesByName[iface.Name] = iface } for _, io := range netio { if len(n.Interfaces) != 0 { var found bool if n.filter.Match(io.Name) { found = true } if !found { continue } } else if !n.skipChecks { iface, ok := interfacesByName[io.Name] if !ok { continue } if iface.Flags&net.FlagLoopback == net.FlagLoopback { continue } if iface.Flags&net.FlagUp == 0 { continue } } tags := map[string]string{ "interface": io.Name, } fields := map[string]interface{}{ "bytes_sent": io.BytesSent, "bytes_recv": io.BytesRecv, "packets_sent": io.PacketsSent, "packets_recv": io.PacketsRecv, "err_in": io.Errin, "err_out": io.Errout, "drop_in": io.Dropin, "drop_out": io.Dropout, "speed": getInterfaceSpeed(io.Name), } acc.AddCounter("net", fields, tags) } // Get system wide stats for different network protocols // (ignore these stats if the call fails) if !n.IgnoreProtocolStats { //nolint:errcheck // stats ignored on fail netprotos, _ := n.ps.NetProto() fields := make(map[string]interface{}) for _, proto := range netprotos { for stat, value := range proto.Stats { name := fmt.Sprintf("%s_%s", strings.ToLower(proto.Protocol), strings.ToLower(stat)) fields[name] = value } } tags := map[string]string{ "interface": "all", } acc.AddFields("net", fields, tags) } return nil } // Get the interface speed from /sys/class/net/*/speed file. returns -1 if unsupported func getInterfaceSpeed(ioName string) int64 { sysPath := internal.GetSysPath() raw, err := os.ReadFile(filepath.Join(sysPath, "class", "net", ioName, "speed")) if err != nil { return -1 } speed, err := strconv.ParseInt(strings.TrimSuffix(string(raw), "\n"), 10, 64) if err != nil { return -1 } return speed } func init() { inputs.Add("net", func() telegraf.Input { return &Net{ps: psutil.NewSystemPS()} }) }