Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD))
MACH ?= $(shell uname -m)
DOCKERFILE ?= Dockerfile

# TODO: Remove deprecated and problematic InstrumentHandlerFunc usage.
STATICCHECK_IGNORE = \
github.com/prometheus/node_exporter/node_exporter.go:SA1019

ifeq ($(GOHOSTARCH),amd64)
# Only supported on amd64
test-flags := -race
Expand Down Expand Up @@ -99,7 +103,7 @@ vet:

staticcheck: $(STATICCHECK)
@echo ">> running staticcheck"
@$(STATICCHECK) $(pkgs)
@$(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" $(pkgs)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't introduce staticcheck violations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was discussed on IRC with @beorn7 and @SuperQ
Without this we will get:

node_exporter.go:86:32: prometheus.InstrumentHandlerFunc is deprecated: InstrumentHandlerFunc is deprecated for the same reasons as InstrumentHandler is. Use the tooling provided in package promhttp instead.  (SA1019)

Another solution is to use prometheus@v0.8.0 instead of v0.9.0-pre1

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Please add a comment mentioning InstrumentHandlerFunc and when that ignoring can be removed again.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently this will also warn in client_golang v0.8.0 as well. :(


build: $(PROMU)
@echo ">> building binaries"
Expand Down
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,39 @@ echo 'role{role="application_server"} 1' > /path/to/directory/role.prom.$$
mv /path/to/directory/role.prom.$$ /path/to/directory/role.prom
```

### Filtering enabled collectors

The node_exporter will expose all metrics from enabled collectors by default, but it can be passed an optional list of collectors to filter metrics. The `collect[]` parameter accepts values matching enabled collector names.

This can be useful for specifying different scrape intervals for different collectors in Prometheus:

```yaml
scrape_configs:
- job_name: 'node resources'
scrape_interval: 15s
static_configs:
- targets:
- '192.168.1.2:9100'
params:
collect[]:
- cpu
- meminfo
- diskstats
- netdev
- netstat

- job_name: 'node storage'
scrape_interval: 1m
static_configs:
- targets:
- '192.168.1.2:9100'
params:
collect[]:
- filefd
- filesystem
- xfs
```

## Building and running

Prerequisites:
Expand Down
17 changes: 15 additions & 2 deletions collector/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,28 @@ type nodeCollector struct {
}

// NewNodeCollector creates a new NodeCollector
func NewNodeCollector() (*nodeCollector, error) {
func NewNodeCollector(filters ...string) (*nodeCollector, error) {
f := make(map[string]bool)
for _, filter := range filters {
enabled, exist := collectorState[filter]
if !exist {
return nil, fmt.Errorf("missing collector: %s", filter)
}
if !*enabled {
return nil, fmt.Errorf("disabled collector: %s", filter)
}
f[filter] = true
}
collectors := make(map[string]Collector)
for key, enabled := range collectorState {
if *enabled {
collector, err := factories[key]()
if err != nil {
return nil, err
}
collectors[key] = collector
if len(f) == 0 || f[key] {
collectors[key] = collector
}
}
}
return &nodeCollector{Collectors: collectors}, nil
Expand Down
49 changes: 38 additions & 11 deletions node_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package main

import (
"fmt"
"net/http"
_ "net/http/pprof"

Expand All @@ -29,6 +30,40 @@ func init() {
prometheus.MustRegister(version.NewCollector("node_exporter"))
}

func handler(w http.ResponseWriter, r *http.Request) {
filters := r.URL.Query()["collect[]"]
log.Debugln("collect query:", filters)

nc, err := collector.NewNodeCollector(filters...)
if err != nil {
log.Warnln("Couldn't create", err)
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(fmt.Sprintf("Couldn't create %s", err)))
return
}

registry := prometheus.NewRegistry()
err = registry.Register(nc)
if err != nil {
log.Errorln("Couldn't register collector:", err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't register collector: %s", err)))
return
}

gatherers := prometheus.Gatherers{
prometheus.DefaultGatherer,
registry,
}
// Delegate http serving to Prometheus client library, which will call collector.Collect.
h := promhttp.HandlerFor(gatherers,
promhttp.HandlerOpts{
ErrorLog: log.NewErrorLogger(),
ErrorHandling: promhttp.ContinueOnError,
})
h.ServeHTTP(w, r)
}

func main() {
var (
listenAddress = kingpin.Flag("web.listen-address", "Address on which to expose metrics and web interface.").Default(":9100").String()
Expand All @@ -43,6 +78,7 @@ func main() {
log.Infoln("Starting node_exporter", version.Info())
log.Infoln("Build context", version.BuildContext())

// This instance is only used to check collector creation and logging.
nc, err := collector.NewNodeCollector()
if err != nil {
log.Fatalf("Couldn't create collector: %s", err)
Expand All @@ -52,17 +88,8 @@ func main() {
log.Infof(" - %s", n)
}

if err := prometheus.Register(nc); err != nil {
log.Fatalf("Couldn't register collector: %s", err)
}
handler := promhttp.HandlerFor(prometheus.DefaultGatherer,
promhttp.HandlerOpts{
ErrorLog: log.NewErrorLogger(),
ErrorHandling: promhttp.ContinueOnError,
})

// TODO(ts): Remove deprecated and problematic InstrumentHandler usage.
http.Handle(*metricsPath, prometheus.InstrumentHandler("prometheus", handler))
// TODO(ts): Remove deprecated and problematic InstrumentHandlerFunc usage.
http.HandleFunc(*metricsPath, prometheus.InstrumentHandlerFunc("prometheus", handler))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`<html>
<head><title>Node Exporter</title></head>
Expand Down