adding snmptranslate MIB-lookup integration

This commit is contained in:
Cameron Sparr 2016-07-29 17:27:35 +01:00
parent a3706a31e6
commit aa86a535cb
3 changed files with 78 additions and 20 deletions

View File

@ -1379,7 +1379,7 @@
# # Retrieves SNMP values from remote agents # # Retrieves SNMP values from remote agents
# [[inputs.snmp]] # [[inputs.snmp]]
# agents = [ "127.0.0.1:161" ] # agents = ["127.0.0.1:161"]
# version = 2 # Values: 1, 2, or 3 # version = 2 # Values: 1, 2, or 3
# #
# ## SNMPv1 & SNMPv2 parameters # ## SNMPv1 & SNMPv2 parameters
@ -1399,6 +1399,8 @@
# #
# ## measurement name # ## measurement name
# name = "system" # name = "system"
# ## SNMP fields are gotten by using an "snmpget" request. If a name is not
# ## specified, we attempt to use snmptranslate on the OID to get the MIB name.
# [[inputs.snmp.field]] # [[inputs.snmp.field]]
# name = "hostname" # name = "hostname"
# oid = ".1.2.3.0.1.1" # oid = ".1.2.3.0.1.1"
@ -1406,13 +1408,14 @@
# name = "uptime" # name = "uptime"
# oid = ".1.2.3.0.1.200" # oid = ".1.2.3.0.1.200"
# [[inputs.snmp.field]] # [[inputs.snmp.field]]
# name = "load"
# oid = ".1.2.3.0.1.201" # oid = ".1.2.3.0.1.201"
# #
# [[inputs.snmp.table]] # [[inputs.snmp.table]]
# # measurement name # ## measurement name
# name = "remote_servers" # name = "remote_servers"
# inherit_tags = [ "hostname" ] # inherit_tags = ["hostname"]
# ## SNMP table fields must be specified individually. If the table field has
# ## multiple rows, they will all be gotten.
# [[inputs.snmp.table.field]] # [[inputs.snmp.table.field]]
# name = "server" # name = "server"
# oid = ".1.2.3.0.0.0" # oid = ".1.2.3.0.0.0"

View File

@ -4,11 +4,13 @@ import (
"fmt" "fmt"
"math" "math"
"net" "net"
"os/exec"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/influxdata/telegraf" "github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/plugins/inputs" "github.com/influxdata/telegraf/plugins/inputs"
"github.com/soniah/gosnmp" "github.com/soniah/gosnmp"
@ -16,7 +18,7 @@ import (
const description = `Retrieves SNMP values from remote agents` const description = `Retrieves SNMP values from remote agents`
const sampleConfig = ` const sampleConfig = `
agents = [ "127.0.0.1:161" ] agents = ["127.0.0.1:161"]
version = 2 # Values: 1, 2, or 3 version = 2 # Values: 1, 2, or 3
## SNMPv1 & SNMPv2 parameters ## SNMPv1 & SNMPv2 parameters
@ -36,6 +38,8 @@ const sampleConfig = `
## measurement name ## measurement name
name = "system" name = "system"
## SNMP fields are gotten by using an "snmpget" request. If a name is not
## specified, we attempt to use snmptranslate on the OID to get the MIB name.
[[inputs.snmp.field]] [[inputs.snmp.field]]
name = "hostname" name = "hostname"
oid = ".1.2.3.0.1.1" oid = ".1.2.3.0.1.1"
@ -43,13 +47,14 @@ const sampleConfig = `
name = "uptime" name = "uptime"
oid = ".1.2.3.0.1.200" oid = ".1.2.3.0.1.200"
[[inputs.snmp.field]] [[inputs.snmp.field]]
name = "load"
oid = ".1.2.3.0.1.201" oid = ".1.2.3.0.1.201"
[[inputs.snmp.table]] [[inputs.snmp.table]]
# measurement name ## measurement name
name = "remote_servers" name = "remote_servers"
inherit_tags = [ "hostname" ] inherit_tags = ["hostname"]
## SNMP table fields must be specified individually. If the table field has
## multiple rows, they will all be gotten.
[[inputs.snmp.table.field]] [[inputs.snmp.table.field]]
name = "server" name = "server"
oid = ".1.2.3.0.0.0" oid = ".1.2.3.0.0.0"
@ -102,6 +107,8 @@ type Snmp struct {
Fields []Field `toml:"field"` Fields []Field `toml:"field"`
connectionCache map[string]snmpConnection connectionCache map[string]snmpConnection
inited bool
} }
// Table holds the configuration for a SNMP table. // Table holds the configuration for a SNMP table.
@ -189,15 +196,6 @@ func Errorf(err error, msg string, format ...interface{}) error {
} }
} }
func init() {
inputs.Add("snmp", func() telegraf.Input {
return &Snmp{
Retries: 5,
MaxRepetitions: 50,
}
})
}
// SampleConfig returns the default configuration of the input. // SampleConfig returns the default configuration of the input.
func (s *Snmp) SampleConfig() string { func (s *Snmp) SampleConfig() string {
return sampleConfig return sampleConfig
@ -212,6 +210,10 @@ func (s *Snmp) Description() string {
// Any error encountered does not halt the process. The errors are accumulated // Any error encountered does not halt the process. The errors are accumulated
// and returned at the end. // and returned at the end.
func (s *Snmp) Gather(acc telegraf.Accumulator) error { func (s *Snmp) Gather(acc telegraf.Accumulator) error {
if !s.inited {
s.initOidNames()
}
s.inited = true
var errs Errors var errs Errors
for _, agent := range s.Agents { for _, agent := range s.Agents {
gs, err := s.getConnection(agent) gs, err := s.getConnection(agent)
@ -244,7 +246,52 @@ func (s *Snmp) Gather(acc telegraf.Accumulator) error {
return errs return errs
} }
func (s *Snmp) gatherTable(acc telegraf.Accumulator, gs snmpConnection, t Table, topTags map[string]string, walk bool) error { // initOidNames loops through each [[inputs.snmp.field]] defined.
// If the field doesn't have a 'name' defined, it will attempt to use
// snmptranslate to get a name for the OID. If snmptranslate doesn't return a
// name, or snmptranslate is not available, then use the OID as the name.
func (s *Snmp) initOidNames() {
bin, _ := exec.LookPath("snmptranslate")
// Lookup names for each OID defined as a "field"
for i, field := range s.Fields {
if field.Name != "" {
continue
}
s.Fields[i].Name = lookupOidName(bin, field.Oid)
}
// Lookup names for each OID defined as a "table.field"
for i, table := range s.Tables {
for j, field := range table.Fields {
if field.Name != "" {
continue
}
s.Tables[i].Fields[j].Name = lookupOidName(bin, field.Oid)
}
}
}
func lookupOidName(bin, oid string) string {
name := oid
if bin != "" {
out, err := internal.CombinedOutputTimeout(
exec.Command(bin, "-Os", oid),
time.Millisecond*250)
if err == nil && len(out) > 0 {
name = strings.TrimSpace(string(out))
}
}
return name
}
func (s *Snmp) gatherTable(
acc telegraf.Accumulator,
gs snmpConnection,
t Table,
topTags map[string]string,
walk bool,
) error {
rt, err := t.Build(gs, walk) rt, err := t.Build(gs, walk)
if err != nil { if err != nil {
return err return err
@ -296,7 +343,6 @@ func (t Table) Build(gs snmpConnection, walk bool) (*RTable, error) {
// ifv contains a mapping of table OID index to field value // ifv contains a mapping of table OID index to field value
ifv := map[string]interface{}{} ifv := map[string]interface{}{}
if !walk { if !walk {
// This is used when fetching non-table fields. Fields configured a the top // This is used when fetching non-table fields. Fields configured a the top
// scope of the plugin. // scope of the plugin.
@ -622,3 +668,12 @@ func fieldConvert(conv string, v interface{}) interface{} {
return v return v
} }
func init() {
inputs.Add("snmp", func() telegraf.Input {
return &Snmp{
Retries: 5,
MaxRepetitions: 50,
}
})
}

View File

@ -93,7 +93,7 @@ func TestSampleConfig(t *testing.T) {
Fields: []Field{ Fields: []Field{
{Name: "hostname", Oid: ".1.2.3.0.1.1"}, {Name: "hostname", Oid: ".1.2.3.0.1.1"},
{Name: "uptime", Oid: ".1.2.3.0.1.200"}, {Name: "uptime", Oid: ".1.2.3.0.1.200"},
{Name: "load", Oid: ".1.2.3.0.1.201"}, {Name: "", Oid: ".1.2.3.0.1.201"},
}, },
Tables: []Table{ Tables: []Table{
{ {