Skip to content

Commit 7fc81ff

Browse files
committed
Add discard[] parameter
This PR adds a `discard[]` URL parameter to discard specific enabled collectors. Compared to `collect[]` parameter, the `discard[]` parameter results in a filtered list which equals enabled collectors minus discarded ones. A small fix is applied to filtering related debug logs to print the actual slices instead of `unsupported value type`. Signed-off-by: Siavash Safi <[email protected]>
1 parent b9d0932 commit 7fc81ff

File tree

2 files changed

+45
-11
lines changed

2 files changed

+45
-11
lines changed

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,13 +339,21 @@ mv /path/to/directory/role.prom.$$ /path/to/directory/role.prom
339339

340340
The `node_exporter` will expose all metrics from enabled collectors by default. This is the recommended way to collect metrics to avoid errors when comparing metrics of different families.
341341

342-
For advanced use the `node_exporter` can be passed an optional list of collectors to filter metrics. The `collect[]` parameter may be used multiple times. In Prometheus configuration you can use this syntax under the [scrape config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#<scrape_config>).
342+
For advanced use the `node_exporter` can be passed an optional list of collectors to filter metrics. The parameters `collect[]` and `discard[]` can be used multiple times (but cannot be combined). In Prometheus configuration you can use this syntax under the [scrape config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#<scrape_config>).
343343

344+
Collect only `cpu` and `meminfo` collector metrics:
344345
```
345346
params:
346347
collect[]:
347-
- foo
348-
- bar
348+
- cpu
349+
- meminfo
350+
```
351+
352+
Collect all enabled collector metrics but discard `netdev`:
353+
```
354+
params:
355+
discard[]:
356+
- netdev
349357
```
350358

351359
This can be useful for having different Prometheus servers collect specific metrics from nodes.

node_exporter.go

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"os"
2222
"os/user"
2323
"runtime"
24+
"slices"
2425
"sort"
2526

2627
"github.com/prometheus/common/promlog"
@@ -39,6 +40,9 @@ import (
3940
"github.com/prometheus/node_exporter/collector"
4041
)
4142

43+
// list of enabled collectors used for logging and filtering.
44+
var enabledCollectors []string
45+
4246
// handler wraps an unfiltered http.Handler but uses a filtered handler,
4347
// created on the fly, if filtering is requested. Create instances with
4448
// newHandler.
@@ -75,16 +79,39 @@ func newHandler(includeExporterMetrics bool, maxRequests int, logger log.Logger)
7579

7680
// ServeHTTP implements http.Handler.
7781
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
78-
filters := r.URL.Query()["collect[]"]
79-
level.Debug(h.logger).Log("msg", "collect query:", "filters", filters)
82+
collects := r.URL.Query()["collect[]"]
83+
level.Debug(h.logger).Log("msg", "collect query:", "collects", fmt.Sprintf("%v", collects))
8084

81-
if len(filters) == 0 {
85+
discards := r.URL.Query()["discard[]"]
86+
level.Debug(h.logger).Log("msg", "discard query:", "discards", fmt.Sprintf("%v", discards))
87+
88+
if len(collects) == 0 && len(discards) == 0 {
8289
// No filters, use the prepared unfiltered handler.
8390
h.unfilteredHandler.ServeHTTP(w, r)
8491
return
8592
}
93+
94+
if len(collects) > 0 && len(discards) > 0 {
95+
level.Debug(h.logger).Log("msg", "rejecting combined collect and discard queries")
96+
w.WriteHeader(http.StatusBadRequest)
97+
w.Write([]byte("Combined collect and discard queries are not allowed."))
98+
return
99+
}
100+
101+
fileters := &collects
102+
if len(discards) > 0 {
103+
// In discard mode, filtered collectors = enabled - discarded.
104+
f := []string{}
105+
for _, c := range enabledCollectors {
106+
if (slices.Index(discards, c)) == -1 {
107+
f = append(f, c)
108+
}
109+
}
110+
fileters = &f
111+
}
112+
86113
// To serve filtered metrics, we create a filtering handler on the fly.
87-
filteredHandler, err := h.innerHandler(filters...)
114+
filteredHandler, err := h.innerHandler(*fileters...)
88115
if err != nil {
89116
level.Warn(h.logger).Log("msg", "Couldn't create filtered metrics handler:", "err", err)
90117
w.WriteHeader(http.StatusBadRequest)
@@ -109,12 +136,11 @@ func (h *handler) innerHandler(filters ...string) (http.Handler, error) {
109136
// only once upon startup.
110137
if len(filters) == 0 {
111138
level.Info(h.logger).Log("msg", "Enabled collectors")
112-
collectors := []string{}
113139
for n := range nc.Collectors {
114-
collectors = append(collectors, n)
140+
enabledCollectors = append(enabledCollectors, n)
115141
}
116-
sort.Strings(collectors)
117-
for _, c := range collectors {
142+
sort.Strings(enabledCollectors)
143+
for _, c := range enabledCollectors {
118144
level.Info(h.logger).Log("collector", c)
119145
}
120146
}

0 commit comments

Comments
 (0)