github.com/mackerelio/mackerel-agent-plugins@v0.89.3/mackerel-plugin-snmp/lib/snmp.go (about) 1 package mpsnmp 2 3 import ( 4 "flag" 5 "fmt" 6 "log" 7 "strconv" 8 "strings" 9 "time" 10 11 "github.com/gosnmp/gosnmp" 12 mp "github.com/mackerelio/go-mackerel-plugin-helper" 13 ) 14 15 // SNMPMetrics metrics 16 type SNMPMetrics struct { 17 OID string 18 Metrics mp.Metrics 19 } 20 21 // SNMPPlugin mackerel plugin for snmp 22 type SNMPPlugin struct { 23 GraphName string 24 GraphUnit string 25 Host string 26 Port uint16 27 Community string 28 Tempfile string 29 SNMPMetricsSlice []SNMPMetrics 30 } 31 32 // FetchMetrics interface for mackerelplugin 33 func (m SNMPPlugin) FetchMetrics() (map[string]interface{}, error) { 34 stat := make(map[string]interface{}) 35 36 gosnmp.Default.Target = m.Host 37 gosnmp.Default.Port = m.Port 38 gosnmp.Default.Community = m.Community 39 gosnmp.Default.Version = gosnmp.Version2c 40 gosnmp.Default.Timeout = time.Duration(30) * time.Second 41 42 err := gosnmp.Default.Connect() 43 if err != nil { 44 return nil, err 45 } 46 defer gosnmp.Default.Conn.Close() 47 48 for _, sm := range m.SNMPMetricsSlice { 49 resp, err := gosnmp.Default.Get([]string{sm.OID}) 50 if err != nil { 51 log.Println("SNMP get failed: ", err) 52 continue 53 } 54 55 ret, err := strconv.ParseFloat(fmt.Sprint(resp.Variables[0].Value), 64) 56 if err != nil { 57 // NOTE: Cannot assume strconv.ParseFloat("%s", resp.Variables[0].Value) 58 // first, as resp.Variables[0].Value may be an int class, etc. 59 // Normally, an object values such as INTEGER or Counter are 60 // successfully accepted in the above conversions. 61 // However, STRING object values are passed as byte arrays, so the above 62 // conversion will result in an error. 63 ret, err = strconv.ParseFloat(fmt.Sprintf("%s", resp.Variables[0].Value), 64) 64 if err != nil { 65 log.Println(err) 66 continue 67 } 68 } 69 70 stat[sm.Metrics.Name] = ret 71 } 72 73 return stat, err 74 } 75 76 // GraphDefinition interface for mackerelplugin 77 func (m SNMPPlugin) GraphDefinition() map[string]mp.Graphs { 78 metrics := []mp.Metrics{} 79 for _, sm := range m.SNMPMetricsSlice { 80 metrics = append(metrics, sm.Metrics) 81 } 82 83 return map[string]mp.Graphs{ 84 m.GraphName: { 85 Label: m.GraphName, 86 Unit: m.GraphUnit, 87 Metrics: metrics, 88 }, 89 } 90 } 91 92 // Do the plugin 93 func Do() { 94 optGraphName := flag.String("name", "snmp", "Graph name") 95 optGraphUnit := flag.String("unit", "float", "Graph unit") 96 97 optHost := flag.String("host", "localhost", "Hostname") 98 optPort := flag.Uint("port", 161, "Port") 99 optCommunity := flag.String("community", "public", "SNMP V2c Community") 100 101 optTempfile := flag.String("tempfile", "", "Temp file name") 102 flag.Parse() 103 104 var snmp SNMPPlugin 105 snmp.Host = *optHost 106 snmp.Port = uint16(*optPort) 107 snmp.Community = *optCommunity 108 snmp.GraphName = *optGraphName 109 snmp.GraphUnit = *optGraphUnit 110 111 sms := []SNMPMetrics{} 112 for _, arg := range flag.Args() { 113 vals := strings.Split(arg, ":") 114 if len(vals) < 2 { 115 continue 116 } 117 118 mpm := mp.Metrics{Name: vals[1], Label: vals[1]} 119 if len(vals) >= 3 { 120 mpm.Diff, _ = strconv.ParseBool(vals[2]) 121 } 122 if len(vals) >= 4 { 123 mpm.Stacked, _ = strconv.ParseBool(vals[3]) 124 } 125 if len(vals) >= 5 { 126 switch vals[4] { 127 case "uint64": 128 mpm.Type = "uint64" 129 case "uint32": 130 mpm.Type = "uint32" 131 default: 132 // do nothing 133 } 134 } 135 136 sms = append(sms, SNMPMetrics{OID: vals[0], Metrics: mpm}) 137 } 138 snmp.SNMPMetricsSlice = sms 139 140 helper := mp.NewMackerelPlugin(snmp) 141 helper.Tempfile = *optTempfile 142 143 helper.Run() 144 }