120 lines
2.6 KiB
Go
120 lines
2.6 KiB
Go
// +build linux
|
|
|
|
package conntrack
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/influxdata/telegraf"
|
|
"github.com/influxdata/telegraf/plugins/inputs"
|
|
"path/filepath"
|
|
)
|
|
|
|
type Conntrack struct {
|
|
Path string
|
|
Dirs []string
|
|
Files []string
|
|
}
|
|
|
|
const (
|
|
inputName = "conntrack"
|
|
)
|
|
|
|
var dfltDirs = []string{
|
|
"/proc/sys/net/ipv4/netfilter",
|
|
"/proc/sys/net/netfilter",
|
|
}
|
|
|
|
var dfltFiles = []string{
|
|
"ip_conntrack_count",
|
|
"ip_conntrack_max",
|
|
"nf_conntrack_count",
|
|
"nf_conntrack_max",
|
|
}
|
|
|
|
func (c *Conntrack) setDefaults() {
|
|
if len(c.Dirs) == 0 {
|
|
c.Dirs = dfltDirs
|
|
}
|
|
|
|
if len(c.Files) == 0 {
|
|
c.Files = dfltFiles
|
|
}
|
|
}
|
|
|
|
func (c *Conntrack) Description() string {
|
|
return "Collects conntrack stats from the configured directories and files."
|
|
}
|
|
|
|
var sampleConfig = `
|
|
## The following defaults would work with multiple versions of conntrack.
|
|
## Note the nf_ and ip_ filename prefixes are mutually exclusive across
|
|
## kernel versions, as are the directory locations.
|
|
|
|
## Superset of filenames to look for within the conntrack dirs.
|
|
## Missing files will be ignored.
|
|
files = ["ip_conntrack_count","ip_conntrack_max",
|
|
"nf_conntrack_count","nf_conntrack_max"]
|
|
|
|
## Directories to search within for the conntrack files above.
|
|
## Missing directories will be ignored.
|
|
dirs = ["/proc/sys/net/ipv4/netfilter","/proc/sys/net/netfilter"]
|
|
`
|
|
|
|
func (c *Conntrack) SampleConfig() string {
|
|
return sampleConfig
|
|
}
|
|
|
|
func (c *Conntrack) Gather(acc telegraf.Accumulator) error {
|
|
c.setDefaults()
|
|
|
|
var metricKey string
|
|
fields := make(map[string]interface{})
|
|
|
|
for _, dir := range c.Dirs {
|
|
for _, file := range c.Files {
|
|
// NOTE: no system will have both nf_ and ip_ prefixes,
|
|
// so we're safe to branch on suffix only.
|
|
parts := strings.SplitN(file, "_", 2)
|
|
if len(parts) < 2 {
|
|
continue
|
|
}
|
|
metricKey = "ip_" + parts[1]
|
|
|
|
fName := filepath.Join(dir, file)
|
|
if _, err := os.Stat(fName); err != nil {
|
|
continue
|
|
}
|
|
|
|
contents, err := ioutil.ReadFile(fName)
|
|
if err != nil {
|
|
acc.AddError(fmt.Errorf("E! failed to read file '%s': %v", fName, err))
|
|
continue
|
|
}
|
|
|
|
v := strings.TrimSpace(string(contents))
|
|
fields[metricKey], err = strconv.ParseFloat(v, 64)
|
|
if err != nil {
|
|
acc.AddError(fmt.Errorf("E! failed to parse metric, expected number but "+
|
|
" found '%s': %v", v, err))
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(fields) == 0 {
|
|
return fmt.Errorf("Conntrack input failed to collect metrics. " +
|
|
"Is the conntrack kernel module loaded?")
|
|
}
|
|
|
|
acc.AddFields(inputName, fields, nil)
|
|
return nil
|
|
}
|
|
|
|
func init() {
|
|
inputs.Add(inputName, func() telegraf.Input { return &Conntrack{} })
|
|
}
|