diff --git a/collector/collector.go b/collector/collector.go index e4046ffa..4bdb0e56 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -300,10 +300,22 @@ type Collector struct { metrics Metrics concurrency int snmpContext string + debugSNMP bool } -func New(ctx context.Context, target, authName, snmpContext string, auth *config.Auth, modules []*NamedModule, logger log.Logger, metrics Metrics, conc int) *Collector { - return &Collector{ctx: ctx, target: target, authName: authName, auth: auth, modules: modules, logger: logger, metrics: metrics, concurrency: conc, snmpContext: snmpContext} +func New(ctx context.Context, target, authName, snmpContext string, auth *config.Auth, modules []*NamedModule, logger log.Logger, metrics Metrics, conc int, debugSNMP bool) *Collector { + return &Collector{ + ctx: ctx, + target: target, + authName: authName, + auth: auth, + modules: modules, + snmpContxt: snmpContext, + logger: log.With(logger, "source_address", *srcAddress), + metrics: metrics, + concurrency: conc, + debugSNMP: debugSNMP, + } } // Describe implements Prometheus.Collector. @@ -420,7 +432,7 @@ func (c Collector) Collect(ch chan<- prometheus.Metric) { go func(i int) { defer wg.Done() logger := log.With(c.logger, "worker", i) - client, err := scraper.NewGoSNMP(logger, c.target, *srcAddress) + client, err := scraper.NewGoSNMP(logger, c.target, *srcAddress, c.debugSNMP) if err != nil { level.Info(logger).Log("msg", err) cancel() diff --git a/main.go b/main.go index f4cf5d32..9a6bd537 100644 --- a/main.go +++ b/main.go @@ -49,6 +49,7 @@ var ( configFile = kingpin.Flag("config.file", "Path to configuration file.").Default("snmp.yml").Strings() dryRun = kingpin.Flag("dry-run", "Only verify configuration is valid and exit.").Default("false").Bool() concurrency = kingpin.Flag("snmp.module-concurrency", "The number of modules to fetch concurrently per scrape").Default("1").Int() + debugSNMP = kingpin.Flag("snmp.debug-packets", "Include a full debug trace of SNMP packet traffics.").Default("false").Bool() expandEnvVars = kingpin.Flag("config.expand-environment-variables", "Expand environment variables to source secrets").Default("false").Bool() metricsPath = kingpin.Flag( "web.telemetry-path", @@ -86,6 +87,14 @@ const ( func handler(w http.ResponseWriter, r *http.Request, logger log.Logger, exporterMetrics collector.Metrics) { query := r.URL.Query() + debug := *debugSNMP + if query.Get("snmp_debug_packets") == "true" { + debug = true + // TODO: This doesn't work the way I want. + // logger = level.NewFilter(logger, level.AllowDebug()) + level.Debug(logger).Log("msg", "Debug query param enabled") + } + target := query.Get("target") if len(query["target"]) != 1 || target == "" { http.Error(w, "'target' parameter must be specified once", http.StatusBadRequest) @@ -149,7 +158,7 @@ func handler(w http.ResponseWriter, r *http.Request, logger log.Logger, exporter sc.RUnlock() logger = log.With(logger, "auth", authName, "target", target) registry := prometheus.NewRegistry() - c := collector.New(r.Context(), target, authName, snmpContext, auth, nmodules, logger, exporterMetrics, *concurrency) + c := collector.New(r.Context(), target, authName, snmpContext, auth, nmodules, logger, exporterMetrics, *concurrency, debug) registry.MustRegister(c) // Delegate http serving to Prometheus client library, which will call collector.Collect. h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{}) @@ -200,7 +209,7 @@ func main() { *concurrency = 1 } - level.Info(logger).Log("msg", "Starting snmp_exporter", "version", version.Info(), "concurrency", concurrency) + level.Info(logger).Log("msg", "Starting snmp_exporter", "version", version.Info(), "concurrency", concurrency, "debug_snmp", debugSNMP) level.Info(logger).Log("build_context", version.BuildContext()) prometheus.MustRegister(versioncollector.NewCollector("snmp_exporter")) diff --git a/scraper/gosnmp.go b/scraper/gosnmp.go index 83166898..3f56f8f6 100644 --- a/scraper/gosnmp.go +++ b/scraper/gosnmp.go @@ -16,6 +16,7 @@ package scraper import ( "context" "fmt" + stdlog "log" "net" "strconv" "strings" @@ -31,7 +32,7 @@ type GoSNMPWrapper struct { logger log.Logger } -func NewGoSNMP(logger log.Logger, target, srcAddress string) (*GoSNMPWrapper, error) { +func NewGoSNMP(logger log.Logger, target, srcAddress string, debug bool) (*GoSNMPWrapper, error) { transport := "udp" if s := strings.SplitN(target, "://", 2); len(s) == 2 { transport = s[0] @@ -52,6 +53,9 @@ func NewGoSNMP(logger log.Logger, target, srcAddress string) (*GoSNMPWrapper, er Port: port, LocalAddr: srcAddress, } + if debug { + g.Logger = gosnmp.NewLogger(stdlog.New(log.NewStdlibAdapter(level.Debug(logger)), "", 0)) + } return &GoSNMPWrapper{c: g, logger: logger}, nil }