@@ -135,7 +135,7 @@ type Snmp struct {
135
135
Name string
136
136
Fields []Field `toml:"field"`
137
137
138
- connectionCache map [ string ]snmpConnection
138
+ connectionCache [ ]snmpConnection
139
139
initialized bool
140
140
}
141
141
@@ -144,6 +144,8 @@ func (s *Snmp) init() error {
144
144
return nil
145
145
}
146
146
147
+ s .connectionCache = make ([]snmpConnection , len (s .Agents ))
148
+
147
149
for i := range s .Tables {
148
150
if err := s .Tables [i ].init (); err != nil {
149
151
return Errorf (err , "initializing table %s" , s .Tables [i ].Name )
@@ -342,30 +344,36 @@ func (s *Snmp) Gather(acc telegraf.Accumulator) error {
342
344
return err
343
345
}
344
346
345
- for _ , agent := range s .Agents {
346
- gs , err := s .getConnection (agent )
347
- if err != nil {
348
- acc .AddError (Errorf (err , "agent %s" , agent ))
349
- continue
350
- }
347
+ var wg sync.WaitGroup
348
+ for i , agent := range s .Agents {
349
+ wg .Add (1 )
350
+ go func (i int , agent string ) {
351
+ defer wg .Done ()
352
+ gs , err := s .getConnection (i )
353
+ if err != nil {
354
+ acc .AddError (Errorf (err , "agent %s" , agent ))
355
+ return
356
+ }
351
357
352
- // First is the top-level fields. We treat the fields as table prefixes with an empty index.
353
- t := Table {
354
- Name : s .Name ,
355
- Fields : s .Fields ,
356
- }
357
- topTags := map [string ]string {}
358
- if err := s .gatherTable (acc , gs , t , topTags , false ); err != nil {
359
- acc .AddError (Errorf (err , "agent %s" , agent ))
360
- }
358
+ // First is the top-level fields. We treat the fields as table prefixes with an empty index.
359
+ t := Table {
360
+ Name : s .Name ,
361
+ Fields : s .Fields ,
362
+ }
363
+ topTags := map [string ]string {}
364
+ if err := s .gatherTable (acc , gs , t , topTags , false ); err != nil {
365
+ acc .AddError (Errorf (err , "agent %s" , agent ))
366
+ }
361
367
362
- // Now is the real tables.
363
- for _ , t := range s .Tables {
364
- if err := s .gatherTable (acc , gs , t , topTags , true ); err != nil {
365
- acc .AddError (Errorf (err , "agent %s: gathering table %s" , agent , t .Name ))
368
+ // Now is the real tables.
369
+ for _ , t := range s .Tables {
370
+ if err := s .gatherTable (acc , gs , t , topTags , true ); err != nil {
371
+ acc .AddError (Errorf (err , "agent %s: gathering table %s" , agent , t .Name ))
372
+ }
366
373
}
367
- }
374
+ }( i , agent )
368
375
}
376
+ wg .Wait ()
369
377
370
378
return nil
371
379
}
@@ -568,16 +576,18 @@ func (gsw gosnmpWrapper) Get(oids []string) (*gosnmp.SnmpPacket, error) {
568
576
}
569
577
570
578
// getConnection creates a snmpConnection (*gosnmp.GoSNMP) object and caches the
571
- // result using `agent` as the cache key.
572
- func (s * Snmp ) getConnection (agent string ) (snmpConnection , error ) {
573
- if s .connectionCache == nil {
574
- s .connectionCache = map [string ]snmpConnection {}
575
- }
576
- if gs , ok := s .connectionCache [agent ]; ok {
579
+ // result using `agentIndex` as the cache key. This is done to allow multiple
580
+ // connections to a single address. It is an error to use a connection in
581
+ // more than one goroutine.
582
+ func (s * Snmp ) getConnection (idx int ) (snmpConnection , error ) {
583
+ if gs := s .connectionCache [idx ]; gs != nil {
577
584
return gs , nil
578
585
}
579
586
587
+ agent := s .Agents [idx ]
588
+
580
589
gs := gosnmpWrapper {& gosnmp.GoSNMP {}}
590
+ s .connectionCache [idx ] = gs
581
591
582
592
host , portStr , err := net .SplitHostPort (agent )
583
593
if err != nil {
@@ -677,7 +687,6 @@ func (s *Snmp) getConnection(agent string) (snmpConnection, error) {
677
687
return nil , Errorf (err , "setting up connection" )
678
688
}
679
689
680
- s .connectionCache [agent ] = gs
681
690
return gs , nil
682
691
}
683
692
0 commit comments