this patch is an attempt to permit parameters on the prometheus exporter
configuration: global, frontend, backend, listener, server.
This allows to avoid exporting metrics you don't necessary use. The
filtering can also be done on prometheus scraping configuration, but
general aim is to optimise the source of data to improve load and
scraping time. This is particularly true for huge configuration with
thousands of backends and servers.
Also note that this configuration was possible on the previous official
haproxy exporter but with even more parameters to select the needed
metrics. Here we thought it was sufficient to simply avoid a given type
of metric.
By default, everything is exported as before.

Signed-off-by: William Dauchy <w.dau...@criteo.com>
---
 contrib/prometheus-exporter/README            |   7 ++
 .../prometheus-exporter/service-prometheus.c  | 100 ++++++++++++++----
 2 files changed, 87 insertions(+), 20 deletions(-)

diff --git a/contrib/prometheus-exporter/README 
b/contrib/prometheus-exporter/README
index 915fc7f5..59c600ca 100644
--- a/contrib/prometheus-exporter/README
+++ b/contrib/prometheus-exporter/README
@@ -49,6 +49,13 @@ must loop on all proxies for each metric. Same for the 
servers. Thus, it will
 spend much more ressources to produce the Prometheus metrics than the CSV 
export
 through the stats page. To give a comparison order, quick benchmarks shown that
 a PROMEX dump is 5x slower and 20x more verbose than a CSV export.
+You may however select a given metric if you don't use all of them. The 
available
+keywords are: global, frontend, backend, listener, server.
+I can be used as argument with a space in between:
+
+    http-request use-service prometheus-exporter global frontend backend if { 
path /metrics }
+
+By default, all the metrics are activated.
 
 Exported metrics
 ------------------
diff --git a/contrib/prometheus-exporter/service-prometheus.c 
b/contrib/prometheus-exporter/service-prometheus.c
index 508e6b1f..ea341009 100644
--- a/contrib/prometheus-exporter/service-prometheus.c
+++ b/contrib/prometheus-exporter/service-prometheus.c
@@ -13,6 +13,8 @@
  *
  */
 
+#include <stdbool.h>
+
 #include <common/cfgparse.h>
 #include <common/config.h>
 #include <common/buffer.h>
@@ -60,6 +62,21 @@ enum {
        PROMEX_DUMPER_DONE,     /* finished */
 };
 
+typedef struct {
+       char *key;
+       int val;
+} t_promex_args;
+
+static const t_promex_args promex_args[] = {
+       { "global",   PROMEX_DUMPER_GLOBAL},
+       { "frontend", PROMEX_DUMPER_FRONT},
+       { "backend",  PROMEX_DUMPER_BACK},
+       { "listener", PROMEX_DUMPER_LI},
+       { "server",   PROMEX_DUMPER_SRV},
+};
+
+#define PROMEX_ARGS_LEN (sizeof(promex_args) / sizeof(t_promex_args))
+
 /* Prometheus exporter flags (appctx->ctx.stats.flags) */
 #define PROMEX_FL_METRIC_HDR    0x00000001
 #define PROMEX_FL_INFO_METRIC   0x00000002
@@ -2101,6 +2118,7 @@ static int promex_dump_srv_metrics(struct appctx *appctx, 
struct htx *htx)
  * -1 in case of any error. */
 static int promex_dump_metrics(struct appctx *appctx, struct stream_interface 
*si, struct htx *htx)
 {
+       bool *promex_settings = *appctx->rule->arg.act.p;
        int ret;
 
        switch (appctx->st1) {
@@ -2113,11 +2131,13 @@ static int promex_dump_metrics(struct appctx *appctx, 
struct stream_interface *s
                        /* fall through */
 
                case PROMEX_DUMPER_GLOBAL:
-                       ret = promex_dump_global_metrics(appctx, htx);
-                       if (ret <= 0) {
-                               if (ret == -1)
-                                       goto error;
-                               goto full;
+                       if (promex_settings[PROMEX_DUMPER_GLOBAL]) {
+                               ret = promex_dump_global_metrics(appctx, htx);
+                               if (ret <= 0) {
+                                       if (ret == -1)
+                                               goto error;
+                                       goto full;
+                               }
                        }
 
                        appctx->ctx.stats.px = proxies_list;
@@ -2128,11 +2148,13 @@ static int promex_dump_metrics(struct appctx *appctx, 
struct stream_interface *s
                        /* fall through */
 
                case PROMEX_DUMPER_FRONT:
-                       ret = promex_dump_front_metrics(appctx, htx);
-                       if (ret <= 0) {
-                               if (ret == -1)
-                                       goto error;
-                               goto full;
+                       if (promex_settings[PROMEX_DUMPER_FRONT]) {
+                               ret = promex_dump_front_metrics(appctx, htx);
+                               if (ret <= 0) {
+                                       if (ret == -1)
+                                               goto error;
+                                       goto full;
+                               }
                        }
 
                        appctx->ctx.stats.px = proxies_list;
@@ -2143,11 +2165,13 @@ static int promex_dump_metrics(struct appctx *appctx, 
struct stream_interface *s
                        /* fall through */
 
                case PROMEX_DUMPER_BACK:
-                       ret = promex_dump_back_metrics(appctx, htx);
-                       if (ret <= 0) {
-                               if (ret == -1)
-                                       goto error;
-                               goto full;
+                       if (promex_settings[PROMEX_DUMPER_BACK]) {
+                               ret = promex_dump_back_metrics(appctx, htx);
+                               if (ret <= 0) {
+                                       if (ret == -1)
+                                               goto error;
+                                       goto full;
+                               }
                        }
 
                        appctx->ctx.stats.px = proxies_list;
@@ -2158,11 +2182,13 @@ static int promex_dump_metrics(struct appctx *appctx, 
struct stream_interface *s
                        /* fall through */
 
                case PROMEX_DUMPER_SRV:
-                       ret = promex_dump_srv_metrics(appctx, htx);
-                       if (ret <= 0) {
-                               if (ret == -1)
-                                       goto error;
-                               goto full;
+                       if (promex_settings[PROMEX_DUMPER_SRV]) {
+                               ret = promex_dump_srv_metrics(appctx, htx);
+                               if (ret <= 0) {
+                                       if (ret == -1)
+                                               goto error;
+                                       goto full;
+                               }
                        }
 
                        appctx->ctx.stats.px = NULL;
@@ -2315,6 +2341,11 @@ struct applet promex_applet = {
 static enum act_parse_ret service_parse_prometheus_exporter(const char **args, 
int *cur_arg, struct proxy *px,
                                                            struct act_rule 
*rule, char **err)
 {
+       bool *promex_settings;
+       bool custom_settings;
+       int tmp_cur_arg;
+       int i;
+
        /* Prometheus exporter service is only available on "http-request" 
rulesets */
        if (rule->from != ACT_F_HTTP_REQ) {
                memprintf(err, "Prometheus exporter service only available on 
'http-request' rulesets");
@@ -2324,6 +2355,35 @@ static enum act_parse_ret 
service_parse_prometheus_exporter(const char **args, i
        /* Add applet pointer in the rule. */
        rule->applet = promex_applet;
 
+       /* init promex settings */
+       *rule->arg.act.p = calloc(PROMEX_DUMPER_DONE, sizeof(bool));
+       if (!*rule->arg.act.p) {
+               memprintf(err, "out of memory error");
+               return ACT_RET_PRS_ERR;
+       }
+       promex_settings = *rule->arg.act.p;
+       memset(promex_settings, false, PROMEX_DUMPER_DONE);
+       custom_settings = false;
+
+       /* parse promex settings */
+       while (*args[*cur_arg] != '\0') {
+               tmp_cur_arg = *cur_arg;
+               for (i = 0; i < PROMEX_ARGS_LEN; i++) {
+                       if (!strcmp(promex_args[i].key, args[*cur_arg])) {
+                               custom_settings = true;
+                               promex_settings[promex_args[i].val] = true;
+                               (*cur_arg)++;
+                       }
+               }
+               /* no successful parsing */
+               if (tmp_cur_arg == *cur_arg)
+                       break;
+       }
+
+       /* enable everything by default if no custom settings were found */
+       if (!custom_settings)
+               memset(promex_settings, true, PROMEX_DUMPER_DONE);
+
        return ACT_RET_PRS_OK;
 }
 static void promex_register_build_options(void)
-- 
2.24.0


Reply via email to