Skip to content

Commit 65766f8

Browse files
authored
PMM-9973 Resolutions fix #2 (percona#73)
* PMM-9973 resolutions filtering fix
1 parent dcd699d commit 65766f8

File tree

2 files changed

+100
-5
lines changed

2 files changed

+100
-5
lines changed

cmd/postgres_exporter/main.go

+98-3
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
package main
1515

1616
import (
17+
"fmt"
1718
"net/http"
1819
"os"
1920

2021
"github.com/go-kit/log"
2122
"github.com/go-kit/log/level"
2223
"github.com/prometheus-community/postgres_exporter/collector"
2324
"github.com/prometheus/client_golang/prometheus"
25+
"github.com/prometheus/client_golang/prometheus/collectors"
2426
"github.com/prometheus/client_golang/prometheus/promhttp"
2527
"github.com/prometheus/common/promlog"
2628
"github.com/prometheus/common/promlog/flag"
@@ -113,11 +115,12 @@ func main() {
113115
exporter.servers.Close()
114116
}()
115117

116-
prometheus.MustRegister(version.NewCollector(exporterName))
118+
versionCollector := version.NewCollector(exporterName)
119+
prometheus.MustRegister(versionCollector)
117120

118121
prometheus.MustRegister(exporter)
119122

120-
cleanup := initializePerconaExporters(dsn, opts)
123+
cleanup, hr, mr, lr := initializePerconaExporters(dsn, opts)
121124
defer cleanup()
122125

123126
pe, err := collector.NewPostgresCollector(
@@ -131,7 +134,22 @@ func main() {
131134
}
132135
prometheus.MustRegister(pe)
133136

134-
http.Handle(*metricPath, promhttp.Handler())
137+
psCollector := collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})
138+
goCollector := collectors.NewGoCollector()
139+
140+
promHandler := newHandler(map[string]prometheus.Collector{
141+
"exporter": exporter,
142+
"custom_query.hr": hr,
143+
"custom_query.mr": mr,
144+
"custom_query.lr": lr,
145+
"standard.process": psCollector,
146+
"standard.go": goCollector,
147+
"version": versionCollector,
148+
"postgres": pe,
149+
})
150+
151+
http.Handle(*metricPath, promHandler)
152+
135153
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
136154
w.Header().Set("Content-Type", "text/html; charset=UTF-8") // nolint: errcheck
137155
w.Write(landingPage) // nolint: errcheck
@@ -152,3 +170,80 @@ func main() {
152170
os.Exit(1)
153171
}
154172
}
173+
174+
// handler wraps an unfiltered http.Handler but uses a filtered handler,
175+
// created on the fly, if filtering is requested. Create instances with
176+
// newHandler. It used for collectors filtering.
177+
type handler struct {
178+
unfilteredHandler http.Handler
179+
collectors map[string]prometheus.Collector
180+
}
181+
182+
func newHandler(collectors map[string]prometheus.Collector) *handler {
183+
h := &handler{collectors: collectors}
184+
185+
innerHandler, err := h.innerHandler()
186+
if err != nil {
187+
level.Error(logger).Log("msg", "Couldn't create metrics handler", "error", err)
188+
os.Exit(1)
189+
}
190+
191+
h.unfilteredHandler = innerHandler
192+
return h
193+
}
194+
195+
// ServeHTTP implements http.Handler.
196+
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
197+
filters := r.URL.Query()["collect[]"]
198+
level.Debug(logger).Log("msg", "Collect query", "filters", filters)
199+
200+
if len(filters) == 0 {
201+
// No filters, use the prepared unfiltered handler.
202+
h.unfilteredHandler.ServeHTTP(w, r)
203+
return
204+
}
205+
206+
filteredHandler, err := h.innerHandler(filters...)
207+
if err != nil {
208+
level.Warn(logger).Log("msg", "Couldn't create filtered metrics handler", "error", err)
209+
w.WriteHeader(http.StatusBadRequest)
210+
w.Write([]byte(fmt.Sprintf("Couldn't create filtered metrics handler: %s", err))) // nolint: errcheck
211+
return
212+
}
213+
214+
filteredHandler.ServeHTTP(w, r)
215+
}
216+
217+
func (h *handler) innerHandler(filters ...string) (http.Handler, error) {
218+
registry := prometheus.NewRegistry()
219+
220+
// register all collectors by default.
221+
if len(filters) == 0 {
222+
for name, c := range h.collectors {
223+
if err := registry.Register(c); err != nil {
224+
return nil, err
225+
}
226+
level.Debug(logger).Log("msg", "Collector was registered", "collector", name)
227+
}
228+
}
229+
230+
// register only filtered collectors.
231+
for _, name := range filters {
232+
if c, ok := h.collectors[name]; ok {
233+
if err := registry.Register(c); err != nil {
234+
return nil, err
235+
}
236+
level.Debug(logger).Log("msg", "Collector was registered", "collector", name)
237+
}
238+
}
239+
240+
handler := promhttp.HandlerFor(
241+
registry,
242+
promhttp.HandlerOpts{
243+
//ErrorLog: log.NewNopLogger() .NewErrorLogger(),
244+
ErrorHandling: promhttp.ContinueOnError,
245+
},
246+
)
247+
248+
return handler, nil
249+
}

cmd/postgres_exporter/percona_exporter.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ var (
2828
collectCustomQueryHrDirectory = kingpin.Flag("collect.custom_query.hr.directory", "Path to custom queries with high resolution directory.").Envar("PG_EXPORTER_EXTEND_QUERY_HR_PATH").String()
2929
)
3030

31-
func initializePerconaExporters(dsn []string, opts []ExporterOpt) func() {
31+
func initializePerconaExporters(dsn []string, opts []ExporterOpt) (func(), *Exporter, *Exporter, *Exporter) {
3232
queriesPath := map[MetricResolution]string{
3333
HR: *collectCustomQueryHrDirectory,
3434
MR: *collectCustomQueryMrDirectory,
@@ -96,7 +96,7 @@ func initializePerconaExporters(dsn []string, opts []ExporterOpt) func() {
9696
hrExporter.servers.Close()
9797
mrExporter.servers.Close()
9898
lrExporter.servers.Close()
99-
}
99+
}, hrExporter, mrExporter, lrExporter
100100
}
101101

102102
func (e *Exporter) loadCustomQueries(res MetricResolution, version semver.Version, server *Server) {

0 commit comments

Comments
 (0)