From bc18b73dab0e6454285d29150a7bcd99578da8d5 Mon Sep 17 00:00:00 2001 From: Ben Rottke Date: Mon, 11 Mar 2024 16:54:50 -0400 Subject: [PATCH] Add feature to filter project ID at call-time (#164) Signed-off-by: Ben Kochie --- README.md | 15 +++++++++++++-- stackdriver_exporter.go | 34 +++++++++++++++++++--------------- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 2103dd72..629cfcf7 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/prometheus-community/stackdriver_exporter) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -A [Prometheus][prometheus] exporter for [Google Stackdriver Monitoring][stackdriver] metrics. It acts as a proxy that requests Stackdriver API for the metric's time-series everytime prometheus scrapes it. +A [Prometheus][prometheus] exporter for [Google Stackdriver Monitoring][stackdriver] metrics. It acts as a proxy that requests Stackdriver API for the metric's time-series every time prometheus scrapes it. ## Installation @@ -167,7 +167,7 @@ stackdriver_exporter \ The `stackdriver_exporter` collects all metrics type prefixes by default. -For advanced uses, the collection can be filtered by using a repeatable URL param called `collect`. In the Prometheus configuration you can use you can use this syntax under the [scrape config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#). +For advanced uses, the metric prefixes can be filtered by using a repeatable URL param called `collect`. In the Prometheus configuration you can use this syntax under the [scrape config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#). ```yaml @@ -177,6 +177,17 @@ params: - compute.googleapis.com/instance/disk ``` +The GCP projects to collect metrics from can also be filtered, using the `project_ids` URL param: +```yaml +params: + project_ids: + - project-a + - project-b + collect: + - compute.googleapis.com/instance/cpu + - compute.googleapis.com/instance/disk +``` + ### What to know about Aggregating DELTA Metrics Treating DELTA Metrics as a gauge produces data which is wildly inaccurate/not very useful (see https://github.com/prometheus-community/stackdriver_exporter/issues/116). However, aggregating the DELTA metrics overtime is not a perfect solution and is intended to produce data which mirrors GCP's data as close as possible. diff --git a/stackdriver_exporter.go b/stackdriver_exporter.go index f71c4f43..30761691 100644 --- a/stackdriver_exporter.go +++ b/stackdriver_exporter.go @@ -180,17 +180,14 @@ type handler struct { func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { collectParams := r.URL.Query()["collect"] - filters := make(map[string]bool) - for _, param := range collectParams { - filters[param] = true - } + projectIDsParam := r.URL.Query()["project_ids"] - if len(filters) > 0 { - h.innerHandler(filters).ServeHTTP(w, r) - return + projectFilters := make(map[string]bool) + for _, projID := range projectIDsParam { + projectFilters[projID] = true } - h.handler.ServeHTTP(w, r) + h.innerHandler(collectParams, projectFilters).ServeHTTP(w, r) } func newHandler(projectIDs []string, metricPrefixes []string, metricExtraFilters []collectors.MetricFilter, m *monitoring.Service, logger log.Logger, additionalGatherer prometheus.Gatherer) *handler { @@ -203,16 +200,20 @@ func newHandler(projectIDs []string, metricPrefixes []string, metricExtraFilters m: m, } - h.handler = h.innerHandler(nil) + h.handler = h.innerHandler(nil, nil) return h } -func (h *handler) innerHandler(filters map[string]bool) http.Handler { +func (h *handler) innerHandler(metricFilters []string, projectFilters map[string]bool) http.Handler { registry := prometheus.NewRegistry() for _, project := range h.projectIDs { + if len(projectFilters) > 0 && !projectFilters[project] { + continue + } + monitoringCollector, err := collectors.NewMonitoringCollector(project, h.m, collectors.MonitoringCollectorOptions{ - MetricTypePrefixes: h.filterMetricTypePrefixes(filters), + MetricTypePrefixes: h.filterMetricTypePrefixes(metricFilters), ExtraFilters: h.metricsExtraFilters, RequestInterval: *monitoringMetricsInterval, RequestOffset: *monitoringMetricsOffset, @@ -243,13 +244,16 @@ func (h *handler) innerHandler(filters map[string]bool) http.Handler { // filterMetricTypePrefixes filters the initial list of metric type prefixes, with the ones coming from an individual // prometheus collect request. -func (h *handler) filterMetricTypePrefixes(filters map[string]bool) []string { +func (h *handler) filterMetricTypePrefixes(filters []string) []string { filteredPrefixes := h.metricsPrefixes if len(filters) > 0 { filteredPrefixes = nil - for _, prefix := range h.metricsPrefixes { - if filters[prefix] { - filteredPrefixes = append(filteredPrefixes, prefix) + for _, calltimePrefix := range filters { + for _, preconfiguredPrefix := range h.metricsPrefixes { + if strings.HasPrefix(calltimePrefix, preconfiguredPrefix) { + filteredPrefixes = append(filteredPrefixes, calltimePrefix) + break + } } } }