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  }