@@ -16,6 +16,7 @@ package collector
1616import (
1717 "context"
1818 "encoding/binary"
19+ "encoding/hex"
1920 "fmt"
2021 "log/slog"
2122 "net"
@@ -62,7 +63,7 @@ var combinedTypeMapping = map[string]map[int]string{
6263
6364func oidToList (oid string ) []int {
6465 result := []int {}
65- for _ , x := range strings .Split (oid , "." ) {
66+ for x := range strings .SplitSeq (oid , "." ) {
6667 o , _ := strconv .Atoi (x )
6768 result = append (result , o )
6869 }
@@ -117,10 +118,7 @@ func ScrapeTarget(snmp scraper.SNMPScraper, target string, auth *config.Auth, mo
117118 maxOids = 1
118119 }
119120 for len (getOids ) > 0 {
120- oids := len (getOids )
121- if oids > maxOids {
122- oids = maxOids
123- }
121+ oids := min (len (getOids ), maxOids )
124122
125123 packet , err := snmp .Get (getOids [:oids ])
126124 if err != nil {
@@ -291,30 +289,32 @@ func NewNamedModule(name string, module *config.Module) *NamedModule {
291289}
292290
293291type Collector struct {
294- ctx context.Context
295- target string
296- auth * config.Auth
297- authName string
298- modules []* NamedModule
299- logger * slog.Logger
300- metrics Metrics
301- concurrency int
302- snmpContext string
303- debugSNMP bool
304- }
305-
306- func New (ctx context.Context , target , authName , snmpContext string , auth * config.Auth , modules []* NamedModule , logger * slog.Logger , metrics Metrics , conc int , debugSNMP bool ) * Collector {
292+ ctx context.Context
293+ target string
294+ auth * config.Auth
295+ authName string
296+ modules []* NamedModule
297+ logger * slog.Logger
298+ metrics Metrics
299+ concurrency int
300+ snmpContext string
301+ snmpEngineID string
302+ debugSNMP bool
303+ }
304+
305+ func New (ctx context.Context , target , authName , snmpContext , snmpEngineID string , auth * config.Auth , modules []* NamedModule , logger * slog.Logger , metrics Metrics , conc int , debugSNMP bool ) * Collector {
307306 return & Collector {
308- ctx : ctx ,
309- target : target ,
310- authName : authName ,
311- auth : auth ,
312- modules : modules ,
313- snmpContext : snmpContext ,
314- logger : logger .With ("source_address" , * srcAddress ),
315- metrics : metrics ,
316- concurrency : conc ,
317- debugSNMP : debugSNMP ,
307+ ctx : ctx ,
308+ target : target ,
309+ authName : authName ,
310+ auth : auth ,
311+ modules : modules ,
312+ snmpContext : snmpContext ,
313+ snmpEngineID : snmpEngineID ,
314+ logger : logger .With ("source_address" , * srcAddress ),
315+ metrics : metrics ,
316+ concurrency : conc ,
317+ debugSNMP : debugSNMP ,
318318 }
319319}
320320
@@ -352,7 +352,7 @@ func (c Collector) collect(ch chan<- prometheus.Metric, logger *slog.Logger, cli
352352 g .MaxRepetitions = module .WalkParams .MaxRepetitions
353353 g .UseUnconnectedUDPSocket = module .WalkParams .UseUnconnectedUDPSocket
354354 if module .WalkParams .AllowNonIncreasingOIDs {
355- g .AppOpts = map [string ]interface {} {
355+ g .AppOpts = map [string ]any {
356356 "c" : true ,
357357 }
358358 }
@@ -420,10 +420,7 @@ func (c Collector) collect(ch chan<- prometheus.Metric, logger *slog.Logger, cli
420420// Collect implements Prometheus.Collector.
421421func (c Collector ) Collect (ch chan <- prometheus.Metric ) {
422422 wg := sync.WaitGroup {}
423- workerCount := c .concurrency
424- if workerCount < 1 {
425- workerCount = 1
426- }
423+ workerCount := max (c .concurrency , 1 )
427424 ctx , cancel := context .WithCancel (c .ctx )
428425 defer cancel ()
429426 workerChan := make (chan * NamedModule )
@@ -447,6 +444,15 @@ func (c Collector) Collect(ch chan<- prometheus.Metric) {
447444 break
448445 }
449446 }
447+ // Set EngineID option if one is configured and we're using SNMPv3
448+ if c .snmpEngineID != "" && c .auth .Version == 3 {
449+ // Convert the SNMP Engine ID to a byte string
450+ sEID , _ := hex .DecodeString (c .snmpEngineID )
451+ // Set the options.
452+ client .SetOptions (func (g * gosnmp.GoSNMP ) {
453+ g .ContextEngineID = string (sEID )
454+ })
455+ }
450456 // Set the options.
451457 client .SetOptions (func (g * gosnmp.GoSNMP ) {
452458 g .Context = ctx
@@ -531,14 +537,14 @@ func parseDateAndTime(pdu *gosnmp.SnmpPDU) (float64, error) {
531537 locString := fmt .Sprintf ("%s%02d%02d" , string (v [8 ]), v [9 ], v [10 ])
532538 loc , err := time .Parse ("-0700" , locString )
533539 if err != nil {
534- return 0 , fmt .Errorf ("error parsing location string: %q, error: %s " , locString , err )
540+ return 0 , fmt .Errorf ("error parsing location string: %q, error: %w " , locString , err )
535541 }
536542 tz = loc .Location ()
537543 default :
538544 return 0 , fmt .Errorf ("invalid DateAndTime length %v" , pduLength )
539545 }
540546 if err != nil {
541- return 0 , fmt .Errorf ("unable to parse DateAndTime %q, error: %s " , v , err )
547+ return 0 , fmt .Errorf ("unable to parse DateAndTime %q, error: %w " , v , err )
542548 }
543549 // Build the date from the various fields and time zone.
544550 t := time .Date (
@@ -557,13 +563,13 @@ func parseDateAndTimeWithPattern(metric *config.Metric, pdu *gosnmp.SnmpPDU, met
557563 pduValue := pduValueAsString (pdu , "DisplayString" , metrics )
558564 t , err := timefmt .Parse (pduValue , metric .DateTimePattern )
559565 if err != nil {
560- return 0 , fmt .Errorf ("error parsing date and time %q " , err )
566+ return 0 , fmt .Errorf ("error parsing date and time %w " , err )
561567 }
562568 return float64 (t .Unix ()), nil
563569}
564570
565571func parseNtpTimestamp (pdu * gosnmp.SnmpPDU ) (float64 , error ) {
566- var data = pdu .Value .([]byte )
572+ data : = pdu .Value .([]byte )
567573
568574 // Prometheus uses the Unix time epoch (seconds since 1970).
569575 // NTP seconds are counted since 1900 and must be corrected
@@ -668,7 +674,7 @@ func pduToSamples(indexOids []int, pdu *gosnmp.SnmpPDU, metric *config.Metric, o
668674 t , value , labelvalues ... )
669675 if err != nil {
670676 sample = prometheus .NewInvalidMetric (prometheus .NewDesc ("snmp_error" , "Error calling NewConstMetric" , nil , nil ),
671- fmt .Errorf ("error for metric %s with labels %v from indexOids %v: %v " , metric .Name , labelvalues , indexOids , err ))
677+ fmt .Errorf ("error for metric %s with labels %v from indexOids %v: %w " , metric .Name , labelvalues , indexOids , err ))
672678 }
673679
674680 return []prometheus.Metric {sample }
@@ -693,7 +699,7 @@ func applyRegexExtracts(metric *config.Metric, pduValue string, labelnames, labe
693699 prometheus .GaugeValue , v , labelvalues ... )
694700 if err != nil {
695701 newMetric = prometheus .NewInvalidMetric (prometheus .NewDesc ("snmp_error" , "Error calling NewConstMetric for regex_extract" , nil , nil ),
696- fmt .Errorf ("error for metric %s with labels %v: %v " , metric .Name + name , labelvalues , err ))
702+ fmt .Errorf ("error for metric %s with labels %v: %w " , metric .Name + name , labelvalues , err ))
697703 }
698704 results = append (results , newMetric )
699705 break
@@ -715,7 +721,7 @@ func enumAsInfo(metric *config.Metric, value int, labelnames, labelvalues []stri
715721 prometheus .GaugeValue , 1.0 , labelvalues ... )
716722 if err != nil {
717723 newMetric = prometheus .NewInvalidMetric (prometheus .NewDesc ("snmp_error" , "Error calling NewConstMetric for EnumAsInfo" , nil , nil ),
718- fmt .Errorf ("error for metric %s with labels %v: %v " , metric .Name , labelvalues , err ))
724+ fmt .Errorf ("error for metric %s with labels %v: %w " , metric .Name , labelvalues , err ))
719725 }
720726 return []prometheus.Metric {newMetric }
721727}
@@ -733,7 +739,7 @@ func enumAsStateSet(metric *config.Metric, value int, labelnames, labelvalues []
733739 prometheus .GaugeValue , 1.0 , append (labelvalues , state )... )
734740 if err != nil {
735741 newMetric = prometheus .NewInvalidMetric (prometheus .NewDesc ("snmp_error" , "Error calling NewConstMetric for EnumAsStateSet" , nil , nil ),
736- fmt .Errorf ("error for metric %s with labels %v: %v " , metric .Name , labelvalues , err ))
742+ fmt .Errorf ("error for metric %s with labels %v: %w " , metric .Name , labelvalues , err ))
737743 }
738744 results = append (results , newMetric )
739745
@@ -745,14 +751,14 @@ func enumAsStateSet(metric *config.Metric, value int, labelnames, labelvalues []
745751 prometheus .GaugeValue , 0.0 , append (labelvalues , v )... )
746752 if err != nil {
747753 newMetric = prometheus .NewInvalidMetric (prometheus .NewDesc ("snmp_error" , "Error calling NewConstMetric for EnumAsStateSet" , nil , nil ),
748- fmt .Errorf ("error for metric %s with labels %v: %v " , metric .Name , labelvalues , err ))
754+ fmt .Errorf ("error for metric %s with labels %v: %w " , metric .Name , labelvalues , err ))
749755 }
750756 results = append (results , newMetric )
751757 }
752758 return results
753759}
754760
755- func bits (metric * config.Metric , value interface {} , labelnames , labelvalues []string ) []prometheus.Metric {
761+ func bits (metric * config.Metric , value any , labelnames , labelvalues []string ) []prometheus.Metric {
756762 bytes , ok := value .([]byte )
757763 if ! ok {
758764 return []prometheus.Metric {prometheus .NewInvalidMetric (prometheus .NewDesc ("snmp_error" , "BITS type was not a BISTRING on the wire." , nil , nil ),
@@ -773,7 +779,7 @@ func bits(metric *config.Metric, value interface{}, labelnames, labelvalues []st
773779 prometheus .GaugeValue , bit , append (labelvalues , v )... )
774780 if err != nil {
775781 newMetric = prometheus .NewInvalidMetric (prometheus .NewDesc ("snmp_error" , "Error calling NewConstMetric for Bits" , nil , nil ),
776- fmt .Errorf ("error for metric %s with labels %v: %v " , metric .Name , labelvalues , err ))
782+ fmt .Errorf ("error for metric %s with labels %v: %w " , metric .Name , labelvalues , err ))
777783 }
778784 results = append (results , newMetric )
779785 }
@@ -797,36 +803,36 @@ func splitOid(oid []int, count int) ([]int, []int) {
797803
798804// This mirrors decodeValue in gosnmp's helper.go.
799805func pduValueAsString (pdu * gosnmp.SnmpPDU , typ string , metrics Metrics ) string {
800- switch pdu .Value .(type ) {
806+ switch v := pdu .Value .(type ) {
801807 case int :
802- return strconv .Itoa (pdu . Value .( int ) )
808+ return strconv .Itoa (v )
803809 case uint :
804- return strconv .FormatUint (uint64 (pdu . Value .( uint ) ), 10 )
810+ return strconv .FormatUint (uint64 (v ), 10 )
805811 case uint64 :
806- return strconv .FormatUint (pdu . Value .( uint64 ) , 10 )
812+ return strconv .FormatUint (v , 10 )
807813 case float32 :
808- return strconv .FormatFloat (float64 (pdu . Value .( float32 ) ), 'f' , - 1 , 32 )
814+ return strconv .FormatFloat (float64 (v ), 'f' , - 1 , 32 )
809815 case float64 :
810- return strconv .FormatFloat (pdu . Value .( float64 ) , 'f' , - 1 , 64 )
816+ return strconv .FormatFloat (v , 'f' , - 1 , 64 )
811817 case string :
812818 if pdu .Type == gosnmp .ObjectIdentifier {
813819 // Trim leading period.
814- return pdu . Value .( string ) [1 :]
820+ return v [1 :]
815821 }
816822 // DisplayString.
817- return strings .ToValidUTF8 (pdu . Value .( string ) , "�" )
823+ return strings .ToValidUTF8 (v , "�" )
818824 case []byte :
819825 if typ == "" || typ == "Bits" {
820826 typ = "OctetString"
821827 }
822828 // Reuse the OID index parsing code.
823- parts := make ([]int , len (pdu . Value .([] byte ) ))
824- for i , o := range pdu . Value .([] byte ) {
829+ parts := make ([]int , len (v ))
830+ for i , o := range v {
825831 parts [i ] = int (o )
826832 }
827833 if typ == "OctetString" || typ == "DisplayString" {
828834 // Prepend the length, as it is explicit in an index.
829- parts = append ([]int {len (pdu . Value .([] byte ) )}, parts ... )
835+ parts = append ([]int {len (v )}, parts ... )
830836 }
831837 str , _ , _ := indexOidsAsString (parts , typ , 0 , false , nil )
832838 return strings .ToValidUTF8 (str , "�" )
@@ -924,7 +930,7 @@ func indexOidsAsString(indexOids []int, typ string, fixedSize int, implied bool,
924930 return strings .Join (parts , "." ), subOid , indexOids
925931 case "InetAddressIPv6" :
926932 subOid , indexOids := splitOid (indexOids , 16 )
927- parts := make ([]interface {} , 16 )
933+ parts := make ([]any , 16 )
928934 for i , o := range subOid {
929935 parts [i ] = o
930936 }
0 commit comments