func (c collector) Describe(ch chan<- *prometheus.Desc) {
	ch <- prometheus.NewDesc("dummy", "dummy", nil, nil)
}
Describe implements Prometheus.Collector.
package collector
import (
	"context"
	"encoding/binary"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/gosnmp/gosnmp"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"gopkg.in/alecthomas/kingpin.v2"
	"github.com/prometheus/snmp_exporter/config"
)
const (
	namespace = "snmp"
)
var (
	buckets               = prometheus.ExponentialBuckets(0.0001, 2, 15)
	snmpUnexpectedPduType = promauto.NewCounter(
		prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "unexpected_pdu_type_total",
			Help:      "Unexpected Go types in a PDU.",
		},
	)
	snmpDuration = promauto.NewHistogram(
		prometheus.HistogramOpts{
			Namespace: namespace,
			Name:      "packet_duration_seconds",
			Help:      "A histogram of latencies for SNMP packets.",
			Buckets:   buckets,
		},
	)
	snmpPackets = promauto.NewCounter(
		prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "packets_total",
			Help:      "Number of SNMP packet sent, including retries.",
		},
	)
	snmpRetries = promauto.NewCounter(
		prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "packet_retries_total",
			Help:      "Number of SNMP packet retries.",
		},
	)
	float64Mantissa uint64 = 9007199254740992
	wrapCounters           = kingpin.Flag("snmp.wrap-large-counters", "Wrap 64-bit counters to avoid floating point rounding.").Default("true").Bool()
)
var combinedTypeMapping = map[string]map[int]string{
	"InetAddress": {
		1: "InetAddressIPv4",
		2: "InetAddressIPv6",
	},
	"InetAddressMissingSize": {
		1: "InetAddressIPv4",
		2: "InetAddressIPv6",
	},
	"LldpPortId": {
		1: "DisplayString",
		2: "DisplayString",
		3: "PhysAddress48",
		5: "DisplayString",
		7: "DisplayString",
	},
}
func oidToList(oid string) []int {
	result := []int{}
	for _, x := range strings.Split(oid, ".") {
		o, _ := strconv.Atoi(x)
		result = append(result, o)
	}
	return result
}
func listToOid(l []int) string {
	var result []string
	for _, o := range l {
		result = append(result, strconv.Itoa(o))
	}
	return strings.Join(result, ".")
}
type ScrapeResults struct {
	pdus    []gosnmp.SnmpPDU
	packets uint64
	retries uint64
}
func ScrapeTarget(ctx context.Context, target string, config *config.Module, logger log.Logger) (ScrapeResults, error) {
	results := ScrapeResults{}
	snmp := gosnmp.GoSNMP{}
	snmp.Context = ctx
	snmp.MaxRepetitions = config.WalkParams.MaxRepetitions
	snmp.Retries = config.WalkParams.Retries
	snmp.Timeout = config.WalkParams.Timeout
	var sent time.Time
	snmp.OnSent = func(x *gosnmp.GoSNMP) {
		sent = time.Now()
		snmpPackets.Inc()
		results.packets++
	}
	snmp.OnRecv = func(x *gosnmp.GoSNMP) {
		snmpDuration.Observe(time.Since(sent).Seconds())
	}
	snmp.OnRetry = func(x *gosnmp.GoSNMP) {
		snmpRetries.Inc()
		results.retries++
	}
	snmp.Target = target
	snmp.Port = 161
	if host, port, err := net.SplitHostPort(target); err == nil {
		snmp.Target = host
		p, err := strconv.Atoi(port)
		if err != nil {
			return results, fmt.Errorf("error converting port number to int for target %s: %s", target, err)
		}
		snmp.Port = uint16(p)
	}
	config.WalkParams.ConfigureSNMP(&snmp)
	err := snmp.Connect()
	if err != nil {
		if err == context.Canceled {
			return results, fmt.Errorf("scrape canceled (possible timeout) connecting to target %s", snmp.Target)
		}
		return results, fmt.Errorf("error connecting to target %s: %s", target, err)
	}
	defer snmp.Conn.Close()
	getOids := config.Get
	maxOids := int(config.WalkParams.MaxRepetitions)
	if maxOids == 0 || snmp.Version == gosnmp.Version1 {
		maxOids = 1
	}
	for len(getOids) > 0 {
		oids := len(getOids)
		if oids > maxOids {
			oids = maxOids
		}
		level.Debug(logger).Log("msg", "Getting OIDs", "oids", oids)
		getStart := time.Now()
		packet, err := snmp.Get(getOids[:oids])
		if err != nil {
			if err == context.Canceled {
				return results, fmt.Errorf("scrape canceled (possible timeout) getting target %s", snmp.Target)
			}
			return results, fmt.Errorf("error getting target %s: %s", snmp.Target, err)
		}
		level.Debug(logger).Log("msg", "Get of OIDs completed", "oids", oids, "duration_seconds", time.Since(getStart))
		if packet.Error == gosnmp.NoSuchName && snmp.Version == gosnmp.Version1 {
			level.Debug(logger).Log("msg", "OID not supported by target", "oids", getOids[0])
			getOids = getOids[oids:]
			continue
		}
		if packet.Error != gosnmp.NoError {
			return results, fmt.Errorf("error reported by target %s: Error Status %d", snmp.Target, packet.Error)
		}
		for _, v := range packet.Variables {
			if v.Type == gosnmp.NoSuchObject || v.Type == gosnmp.NoSuchInstance {
				level.Debug(logger).Log("msg", "OID not supported by target", "oids", v.Name)
				continue
			}
			results.pdus = append(results.pdus, v)
		}
		getOids = getOids[oids:]
	}
	for _, subtree := range config.Walk {
		var pdus []gosnmp.SnmpPDU
		level.Debug(logger).Log("msg", "Walking subtree", "oid", subtree)
		walkStart := time.Now()
		if snmp.Version == gosnmp.Version1 {
			pdus, err = snmp.WalkAll(subtree)
		} else {
			pdus, err = snmp.BulkWalkAll(subtree)
		}
		if err != nil {
			if err == context.Canceled {
				return results, fmt.Errorf("scrape canceled (possible timeout) walking target %s", snmp.Target)
			}
			return results, fmt.Errorf("error walking target %s: %s", snmp.Target, err)
		}
		level.Debug(logger).Log("msg", "Walk of subtree completed", "oid", subtree, "duration_seconds", time.Since(walkStart))
		results.pdus = append(results.pdus, pdus...)
	}
	return results, nil
}
type MetricNode struct {
	metric *config.Metric
	children map[int]*MetricNode
}
func buildMetricTree(metrics []*config.Metric) *MetricNode {
	metricTree := &MetricNode{children: map[int]*MetricNode{}}
	for _, metric := range metrics {
		head := metricTree
		for _, o := range oidToList(metric.Oid) {
			_, ok := head.children[o]
			if !ok {
				head.children[o] = &MetricNode{children: map[int]*MetricNode{}}
			}
			head = head.children[o]
		}
		head.metric = metric
	}
	return metricTree
}
type collector struct {
	ctx    context.Context
	target string
	module *config.Module
	logger log.Logger
}
func New(ctx context.Context, target string, module *config.Module, logger log.Logger) *collector {
	return &collector{ctx: ctx, target: target, module: module, logger: logger}
}