aboutsummaryrefslogtreecommitdiff
path: root/node_exporter.go
diff options
context:
space:
mode:
authorbeorn7 <beorn@soundcloud.com>2018-11-08 16:26:21 +0100
committerbeorn7 <beorn@soundcloud.com>2018-11-13 14:22:25 +0100
commitcd2331a1852384263e75cf988aeabe39fe33ffe0 (patch)
treeb0cf2de989d15715fe485b6f8c2dcac73882b4f9 /node_exporter.go
parentb1eec66640af3d1940f74484fe1a3c0487204801 (diff)
downloadprometheus_node_collector-cd2331a1852384263e75cf988aeabe39fe33ffe0.tar.bz2
prometheus_node_collector-cd2331a1852384263e75cf988aeabe39fe33ffe0.tar.xz
prometheus_node_collector-cd2331a1852384263e75cf988aeabe39fe33ffe0.zip
Add --web.disable-exporter-metrics flag
If this flag is set, the metrics about the exporter itself (go_*, process_*, promhttp_*) will be excluded from /metrics. The Kingpin way of handling boolean flags makes the negative flag wording (_dis_able) the most reasonably one. This also refactors the flow in node_exporter.go quite a bit to avoid mixing up the global and a local registry and to avoid re-creating a registry even if no filtering is requested. Signed-off-by: beorn7 <beorn@soundcloud.com>
Diffstat (limited to 'node_exporter.go')
-rw-r--r--node_exporter.go139
1 files changed, 95 insertions, 44 deletions
diff --git a/node_exporter.go b/node_exporter.go
index 79863b9..0475a6a 100644
--- a/node_exporter.go
+++ b/node_exporter.go
@@ -27,51 +27,118 @@ import (
27 "gopkg.in/alecthomas/kingpin.v2" 27 "gopkg.in/alecthomas/kingpin.v2"
28) 28)
29 29
30func init() { 30// handler wraps an unfiltered http.Handler but uses a filtered handler,
31 prometheus.MustRegister(version.NewCollector("node_exporter")) 31// created on the fly, if filtering is requested. Create instances with
32// newHandler.
33type handler struct {
34 unfilteredHandler http.Handler
35 // exporterMetricsRegistry is a separate registry for the metrics about
36 // the exporter itself.
37 exporterMetricsRegistry *prometheus.Registry
38 includeExporterMetrics bool
32} 39}
33 40
34func handler(w http.ResponseWriter, r *http.Request) { 41func newHandler(includeExporterMetrics bool) *handler {
42 h := &handler{
43 exporterMetricsRegistry: prometheus.NewRegistry(),
44 includeExporterMetrics: includeExporterMetrics,
45 }
46 if h.includeExporterMetrics {
47 h.exporterMetricsRegistry.MustRegister(
48 prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}),
49 prometheus.NewGoCollector(),
50 )
51 }
52 if innerHandler, err := h.innerHandler(); err != nil {
53 log.Fatalf("Couldn't create metrics handler: %s", err)
54 } else {
55 h.unfilteredHandler = innerHandler
56 }
57 return h
58}
59
60// ServeHTTP implements http.Handler.
61func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
35 filters := r.URL.Query()["collect[]"] 62 filters := r.URL.Query()["collect[]"]
36 log.Debugln("collect query:", filters) 63 log.Debugln("collect query:", filters)
37 64
38 nc, err := collector.NewNodeCollector(filters...) 65 if len(filters) == 0 {
66 // No filters, use the prepared unfiltered handler.
67 h.unfilteredHandler.ServeHTTP(w, r)
68 return
69 }
70 // To serve filtered metrics, we create a filtering handler on the fly.
71 filteredHandler, err := h.innerHandler(filters...)
39 if err != nil { 72 if err != nil {
40 log.Warnln("Couldn't create", err) 73 log.Warnln("Couldn't create filtered metrics handler:", err)
41 w.WriteHeader(http.StatusBadRequest) 74 w.WriteHeader(http.StatusBadRequest)
42 w.Write([]byte(fmt.Sprintf("Couldn't create %s", err))) 75 w.Write([]byte(fmt.Sprintf("Couldn't create filtered metrics handler: %s", err)))
43 return 76 return
44 } 77 }
78 filteredHandler.ServeHTTP(w, r)
79}
45 80
46 registry := prometheus.NewRegistry() 81// innerHandler is used to create buth the one unfiltered http.Handler to be
47 err = registry.Register(nc) 82// wrapped by the outer handler and also the filtered handlers created on the
83// fly. The former is accomplished by calling innerHandler without any arguments
84// (in which case it will log all the collectors enabled via command-line
85// flags).
86func (h *handler) innerHandler(filters ...string) (http.Handler, error) {
87 nc, err := collector.NewNodeCollector(filters...)
48 if err != nil { 88 if err != nil {
49 log.Errorln("Couldn't register collector:", err) 89 return nil, fmt.Errorf("couldn't create collector: %s", err)
50 w.WriteHeader(http.StatusInternalServerError) 90 }
51 w.Write([]byte(fmt.Sprintf("Couldn't register collector: %s", err))) 91
52 return 92 // Only log the creation of an unfiltered handler, which should happen
93 // only once upon startup.
94 if len(filters) == 0 {
95 log.Infof("Enabled collectors:")
96 collectors := []string{}
97 for n := range nc.Collectors {
98 collectors = append(collectors, n)
99 }
100 sort.Strings(collectors)
101 for _, n := range collectors {
102 log.Infof(" - %s", n)
103 }
53 } 104 }
54 105
55 gatherers := prometheus.Gatherers{ 106 r := prometheus.NewRegistry()
56 prometheus.DefaultGatherer, 107 r.MustRegister(version.NewCollector("node_exporter"))
57 registry, 108 if err := r.Register(nc); err != nil {
109 return nil, fmt.Errorf("couldn't register node collector: %s", err)
58 } 110 }
59 // Delegate http serving to Prometheus client library, which will call collector.Collect. 111 handler := promhttp.HandlerFor(
60 h := promhttp.InstrumentMetricHandler( 112 prometheus.Gatherers{h.exporterMetricsRegistry, r},
61 registry, 113 promhttp.HandlerOpts{
62 promhttp.HandlerFor(gatherers, 114 ErrorLog: log.NewErrorLogger(),
63 promhttp.HandlerOpts{ 115 ErrorHandling: promhttp.ContinueOnError,
64 ErrorLog: log.NewErrorLogger(), 116 },
65 ErrorHandling: promhttp.ContinueOnError,
66 }),
67 ) 117 )
68 h.ServeHTTP(w, r) 118 if h.includeExporterMetrics {
119 // Note that we have to use h.exporterMetricsRegistry here to
120 // use the same promhttp metrics for all expositions.
121 handler = promhttp.InstrumentMetricHandler(
122 h.exporterMetricsRegistry, handler,
123 )
124 }
125 return handler, nil
69} 126}
70 127
71func main() { 128func main() {
72 var ( 129 var (
73 listenAddress = kingpin.Flag("web.listen-address", "Address on which to expose metrics and web interface.").Default(":9100").String() 130 listenAddress = kingpin.Flag(
74 metricsPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").String() 131 "web.listen-address",
132 "Address on which to expose metrics and web interface.",
133 ).Default(":9100").String()
134 metricsPath = kingpin.Flag(
135 "web.telemetry-path",
136 "Path under which to expose metrics.",
137 ).Default("/metrics").String()
138 disableExporterMetrics = kingpin.Flag(
139 "web.disable-exporter-metrics",
140 "Exclude metrics about the exporter itself (promhttp_*, process_*, go_*).",
141 ).Bool()
75 ) 142 )
76 143
77 log.AddFlags(kingpin.CommandLine) 144 log.AddFlags(kingpin.CommandLine)
@@ -82,22 +149,7 @@ func main() {
82 log.Infoln("Starting node_exporter", version.Info()) 149 log.Infoln("Starting node_exporter", version.Info())
83 log.Infoln("Build context", version.BuildContext()) 150 log.Infoln("Build context", version.BuildContext())
84 151
85 // This instance is only used to check collector creation and logging. 152 http.Handle(*metricsPath, newHandler(!*disableExporterMetrics))
86 nc, err := collector.NewNodeCollector()
87 if err != nil {
88 log.Fatalf("Couldn't create collector: %s", err)
89 }
90 log.Infof("Enabled collectors:")
91 collectors := []string{}
92 for n := range nc.Collectors {
93 collectors = append(collectors, n)
94 }
95 sort.Strings(collectors)
96 for _, n := range collectors {
97 log.Infof(" - %s", n)
98 }
99
100 http.HandleFunc(*metricsPath, handler)
101 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 153 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
102 w.Write([]byte(`<html> 154 w.Write([]byte(`<html>
103 <head><title>Node Exporter</title></head> 155 <head><title>Node Exporter</title></head>
@@ -109,8 +161,7 @@ func main() {
109 }) 161 })
110 162
111 log.Infoln("Listening on", *listenAddress) 163 log.Infoln("Listening on", *listenAddress)
112 err = http.ListenAndServe(*listenAddress, nil) 164 if err := http.ListenAndServe(*listenAddress, nil); err != nil {
113 if err != nil {
114 log.Fatal(err) 165 log.Fatal(err)
115 } 166 }
116} 167}