]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: promex: Simplify the context using generic pointers for restart points
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 30 Jan 2024 13:36:07 +0000 (14:36 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Thu, 1 Feb 2024 11:00:54 +0000 (12:00 +0100)
Instead of using typed pointers to save the restart points we know use
generic pointers. 4 pointers can be saved now. This replaces the 5 typed
pointers used before. So, we save 8-bytes but it is also more generic and
this will be used by the promex modules.

addons/promex/service-prometheus.c

index bf6fd7600114330e88f2e19157e67b800bb73d12..ca3e9a89ded1ed2484ec8f07656db27a3e6e0583 100644 (file)
@@ -83,11 +83,7 @@ enum {
 
 /* the context of the applet */
 struct promex_ctx {
-       struct proxy *px;          /* current proxy */
-       struct stktable *st;       /* current table */
-       struct listener *li;       /* current listener */
-       struct server *sv;         /* current server */
-       struct stats_module *mod;   /* current module for extra counters */
+       void *p[4];                /* generic pointers used to save context  */
        unsigned int flags;        /* PROMEX_FL_* */
        unsigned field_num;        /* current field number (ST_F_* etc) */
        unsigned mod_field_num;    /* first field number of the current module (ST_F_* etc) */
@@ -629,7 +625,8 @@ static int promex_dump_front_metrics(struct appctx *appctx, struct htx *htx)
 {
        static struct ist prefix = IST("haproxy_frontend_");
        struct promex_ctx *ctx = appctx->svcctx;
-       struct proxy *px;
+       struct proxy *px = ctx->p[0];
+       struct stats_module *mod = ctx->p[1];
        struct field val;
        struct channel *chn = sc_ic(appctx_sc(appctx));
        struct ist out = ist2(trash.area, 0);
@@ -642,10 +639,11 @@ static int promex_dump_front_metrics(struct appctx *appctx, struct htx *htx)
                if (!(promex_st_metrics[ctx->field_num].flags & ctx->flags))
                        continue;
 
-               while (ctx->px) {
-                       struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
+               if (!px)
+                       px = proxies_list;
 
-                       px = ctx->px;
+               while (px) {
+                       struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
 
                        labels[0].name  = ist("proxy");
                        labels[0].value = ist2(px->id, strlen(px->id));
@@ -713,79 +711,83 @@ static int promex_dump_front_metrics(struct appctx *appctx, struct htx *htx)
                                                &val, labels, &out, max))
                                goto full;
                  next_px:
-                       ctx->px = px->next;
+                       px = px->next;
                }
                ctx->flags |= PROMEX_FL_METRIC_HDR;
-               ctx->px = proxies_list;
        }
 
        /* Skip extra counters */
        if (!(ctx->flags & PROMEX_FL_EXTRA_COUNTERS))
                goto end;
 
-       if (!ctx->mod) {
-               /* no restart point, get the first module in the list */
-               ctx->mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(ctx->mod), list);
+       if (!mod) {
+               mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(mod), list);
                ctx->mod_field_num = 0;
        }
 
-       list_for_each_entry_from(ctx->mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
+       list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
                void *counters;
 
-               if (!(stats_px_get_cap(ctx->mod->domain_flags) & STATS_PX_CAP_FE)) {
-                       ctx->field_num += ctx->mod->stats_count;
+               if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_FE)) {
+                       ctx->field_num += mod->stats_count;
                        ctx->mod_field_num = 0;
                        continue;
                }
 
-               for (;ctx->mod_field_num < ctx->mod->stats_count; ctx->mod_field_num++) {
-                       while (ctx->px) {
+               for (;ctx->mod_field_num < mod->stats_count; ctx->mod_field_num++) {
+                       if (!px)
+                               px = proxies_list;
+
+                       while (px) {
                                struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
                                struct promex_metric metric;
 
-                               px = ctx->px;
-
                                labels[0].name  = ist("proxy");
                                labels[0].value = ist2(px->id, strlen(px->id));
 
                                labels[1].name  = ist("mod");
-                               labels[1].value = ist2(ctx->mod->name, strlen(ctx->mod->name));
+                               labels[1].value = ist2(mod->name, strlen(mod->name));
 
                                /* skip the disabled proxies, global frontend and non-networked ones */
                                if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_FE))
                                        goto next_px2;
 
-                               counters = EXTRA_COUNTERS_GET(px->extra_counters_fe, ctx->mod);
-                               if (!ctx->mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
+                               counters = EXTRA_COUNTERS_GET(px->extra_counters_fe, mod);
+                               if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
                                        return -1;
 
                                val = stats[ctx->field_num + ctx->mod_field_num];
                                metric.type = ((val.type == FN_GAUGE) ? PROMEX_MT_GAUGE : PROMEX_MT_COUNTER);
 
                                if (!promex_dump_metric(appctx, htx, prefix,
-                                                       ist2(ctx->mod->stats[ctx->mod_field_num].name, strlen(ctx->mod->stats[ctx->mod_field_num].name)),
-                                                       ist2(ctx->mod->stats[ctx->mod_field_num].desc, strlen(ctx->mod->stats[ctx->mod_field_num].desc)),
+                                                       ist2(mod->stats[ctx->mod_field_num].name, strlen(mod->stats[ctx->mod_field_num].name)),
+                                                       ist2(mod->stats[ctx->mod_field_num].desc, strlen(mod->stats[ctx->mod_field_num].desc)),
                                                        &metric, &val, labels, &out, max))
                                        goto full;
 
                        next_px2:
-                               ctx->px = px->next;
+                               px = px->next;
                        }
-
                        ctx->flags |= PROMEX_FL_METRIC_HDR;
-                       ctx->px = proxies_list;
                }
 
-               ctx->field_num += ctx->mod->stats_count;
+               ctx->field_num += mod->stats_count;
                ctx->mod_field_num = 0;
        }
 
+       px = NULL;
+       mod = NULL;
+
   end:
        if (out.len) {
                if (!htx_add_data_atonce(htx, out))
                        return -1; /* Unexpected and unrecoverable error */
                channel_add_input(chn, out.len);
        }
+
+       /* Save pointers (0=current proxy, 1=current stats module) of the current context */
+       ctx->p[0] = px;
+       ctx->p[1] = mod;
        return ret;
   full:
        ret = 0;
@@ -798,13 +800,14 @@ static int promex_dump_listener_metrics(struct appctx *appctx, struct htx *htx)
 {
        static struct ist prefix = IST("haproxy_listener_");
        struct promex_ctx *ctx = appctx->svcctx;
-       struct proxy *px;
+       struct proxy *px = ctx->p[0];
+       struct listener *li = ctx->p[1];
+       struct stats_module *mod = ctx->p[2];
        struct field val;
        struct channel *chn = sc_ic(appctx_sc(appctx));
        struct ist out = ist2(trash.area, 0);
        size_t max = htx_get_max_blksz(htx, channel_htx_recv_max(chn, htx));
        struct field *stats = stat_l[STATS_DOMAIN_PROXY];
-       struct listener *li;
        int ret = 1;
        enum li_status status;
 
@@ -812,10 +815,11 @@ static int promex_dump_listener_metrics(struct appctx *appctx, struct htx *htx)
                if (!(promex_st_metrics[ctx->field_num].flags & ctx->flags))
                        continue;
 
-               while (ctx->px) {
-                       struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
+               if (!px)
+                       px = proxies_list;
 
-                       px = ctx->px;
+               while (px) {
+                       struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
 
                        labels[0].name  = ist("proxy");
                        labels[0].value = ist2(px->id, strlen(px->id));
@@ -824,9 +828,10 @@ static int promex_dump_listener_metrics(struct appctx *appctx, struct htx *htx)
                        if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_FE))
                                goto next_px;
 
-                       li = ctx->li;
-                       list_for_each_entry_from(li, &px->conf.listeners, by_fe) {
+                       if (!li)
+                               li = LIST_NEXT(&px->conf.listeners, struct listener *, by_fe);
 
+                       list_for_each_entry_from(li, &px->conf.listeners, by_fe) {
                                if (!li->counters)
                                        continue;
 
@@ -864,43 +869,40 @@ static int promex_dump_listener_metrics(struct appctx *appctx, struct htx *htx)
                                                        &val, labels, &out, max))
                                        goto full;
                        }
+                       li = NULL;
 
                  next_px:
                        px = px->next;
-                       ctx->px = px;
-                       ctx->li = (px ? LIST_NEXT(&px->conf.listeners, struct listener *, by_fe) : NULL);
                }
                ctx->flags |= PROMEX_FL_METRIC_HDR;
-               ctx->px = proxies_list;
-               ctx->li =  LIST_NEXT(&proxies_list->conf.listeners, struct listener *, by_fe);
        }
 
        /* Skip extra counters */
        if (!(ctx->flags & PROMEX_FL_EXTRA_COUNTERS))
                goto end;
 
-       if (!ctx->mod) {
-               /* no restart point, get the first module in the list */
-               ctx->mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(ctx->mod), list);
+       if (!mod) {
+               mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(mod), list);
                ctx->mod_field_num = 0;
        }
 
-       list_for_each_entry_from(ctx->mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
+       list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
                void *counters;
 
-               if (!(stats_px_get_cap(ctx->mod->domain_flags) & STATS_PX_CAP_LI)) {
-                       ctx->field_num += ctx->mod->stats_count;
+               if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_LI)) {
+                       ctx->field_num += mod->stats_count;
                        ctx->mod_field_num = 0;
                        continue;
                }
 
-               for (;ctx->mod_field_num < ctx->mod->stats_count; ctx->mod_field_num++) {
-                       while (ctx->px) {
+               for (;ctx->mod_field_num < mod->stats_count; ctx->mod_field_num++) {
+                       if (!px)
+                               px = proxies_list;
+
+                       while (px) {
                                struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
                                struct promex_metric metric;
 
-                               px = ctx->px;
-
                                labels[0].name  = ist("proxy");
                                labels[0].value = ist2(px->id, strlen(px->id));
 
@@ -908,7 +910,9 @@ static int promex_dump_listener_metrics(struct appctx *appctx, struct htx *htx)
                                if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_FE))
                                        goto next_px2;
 
-                               li = ctx->li;
+                               if (!li)
+                                       li = LIST_NEXT(&px->conf.listeners, struct listener *, by_fe);
+
                                list_for_each_entry_from(li, &px->conf.listeners, by_fe) {
                                        if (!li->counters)
                                                continue;
@@ -917,45 +921,49 @@ static int promex_dump_listener_metrics(struct appctx *appctx, struct htx *htx)
                                        labels[1].value = ist2(li->name, strlen(li->name));
 
                                        labels[2].name  = ist("mod");
-                                       labels[2].value = ist2(ctx->mod->name, strlen(ctx->mod->name));
+                                       labels[2].value = ist2(mod->name, strlen(mod->name));
 
-                                       counters = EXTRA_COUNTERS_GET(li->extra_counters, ctx->mod);
-                                       if (!ctx->mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
+                                       counters = EXTRA_COUNTERS_GET(li->extra_counters, mod);
+                                       if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
                                                return -1;
 
                                        val = stats[ctx->field_num + ctx->mod_field_num];
                                        metric.type = ((val.type == FN_GAUGE) ? PROMEX_MT_GAUGE : PROMEX_MT_COUNTER);
 
                                        if (!promex_dump_metric(appctx, htx, prefix,
-                                                               ist2(ctx->mod->stats[ctx->mod_field_num].name, strlen(ctx->mod->stats[ctx->mod_field_num].name)),
-                                                               ist2(ctx->mod->stats[ctx->mod_field_num].desc, strlen(ctx->mod->stats[ctx->mod_field_num].desc)),
+                                                               ist2(mod->stats[ctx->mod_field_num].name, strlen(mod->stats[ctx->mod_field_num].name)),
+                                                               ist2(mod->stats[ctx->mod_field_num].desc, strlen(mod->stats[ctx->mod_field_num].desc)),
                                                                &metric, &val, labels, &out, max))
                                                goto full;
                                }
+                               li = NULL;
 
                        next_px2:
-                               ctx->px = px->next;
-                               ctx->li = (ctx->px ? LIST_NEXT(&ctx->px->conf.listeners, struct listener *, by_fe) : NULL);
+                               px = px->next;
                        }
-
                        ctx->flags |= PROMEX_FL_METRIC_HDR;
-                       ctx->px = proxies_list;
-                       ctx->li =  LIST_NEXT(&proxies_list->conf.listeners, struct listener *, by_fe);
                }
 
-               ctx->field_num += ctx->mod->stats_count;
+               ctx->field_num += mod->stats_count;
                ctx->mod_field_num = 0;
        }
 
+       px = NULL;
+       li = NULL;
+       mod = NULL;
+
   end:
        if (out.len) {
                if (!htx_add_data_atonce(htx, out))
                        return -1; /* Unexpected and unrecoverable error */
                channel_add_input(chn, out.len);
        }
+       /* Save pointers (0=current proxy, 1=current listener, 2=current stats module) of the current context */
+       ctx->p[0] = px;
+       ctx->p[1] = li;
+       ctx->p[2] = mod;
        return ret;
   full:
-       ctx->li = li;
        ret = 0;
        goto end;
 }
@@ -966,7 +974,8 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
 {
        static struct ist prefix = IST("haproxy_backend_");
        struct promex_ctx *ctx = appctx->svcctx;
-       struct proxy *px;
+       struct proxy *px = ctx->p[0];
+       struct stats_module *mod = ctx->p[2];
        struct server *sv;
        struct field val;
        struct channel *chn = sc_ic(appctx_sc(appctx));
@@ -983,14 +992,15 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
                if (!(promex_st_metrics[ctx->field_num].flags & ctx->flags))
                        continue;
 
-               while (ctx->px) {
+               if (!px)
+                       px = proxies_list;
+
+               while (px) {
                        struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
                        unsigned int srv_state_count[PROMEX_SRV_STATE_COUNT] = { 0 };
                        unsigned int srv_check_count[HCHK_STATUS_SIZE] = { 0 };
                        const char *check_state;
 
-                       px = ctx->px;
-
                        labels[0].name  = ist("proxy");
                        labels[0].value = ist2(px->id, strlen(px->id));
 
@@ -1136,79 +1146,82 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
                                                &val, labels, &out, max))
                                goto full;
                  next_px:
-                       ctx->px = px->next;
+                       px = px->next;
                }
                ctx->flags |= PROMEX_FL_METRIC_HDR;
-               ctx->px = proxies_list;
        }
 
        /* Skip extra counters */
        if (!(ctx->flags & PROMEX_FL_EXTRA_COUNTERS))
                goto end;
 
-       if (!ctx->mod) {
-               /* no restart point, get the first module in the list */
-               ctx->mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(ctx->mod), list);
+       if (!mod) {
+               mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(mod), list);
                ctx->mod_field_num = 0;
        }
 
-       list_for_each_entry_from(ctx->mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
+       list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
                void *counters;
 
-               if (!(stats_px_get_cap(ctx->mod->domain_flags) & STATS_PX_CAP_BE)) {
-                       ctx->field_num += ctx->mod->stats_count;
+               if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_BE)) {
+                       ctx->field_num += mod->stats_count;
                        ctx->mod_field_num = 0;
                        continue;
                }
 
-               for (;ctx->mod_field_num < ctx->mod->stats_count; ctx->mod_field_num++) {
-                       while (ctx->px) {
+               for (;ctx->mod_field_num < mod->stats_count; ctx->mod_field_num++) {
+                       if (!px)
+                               px = proxies_list;
+
+                       while (px) {
                                struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
                                struct promex_metric metric;
 
-                               px = ctx->px;
-
                                labels[0].name  = ist("proxy");
                                labels[0].value = ist2(px->id, strlen(px->id));
 
                                labels[1].name  = ist("mod");
-                               labels[1].value = ist2(ctx->mod->name, strlen(ctx->mod->name));
+                               labels[1].value = ist2(mod->name, strlen(mod->name));
 
                                /* skip the disabled proxies, global frontend and non-networked ones */
                                if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
                                        goto next_px2;
 
-                               counters = EXTRA_COUNTERS_GET(px->extra_counters_be, ctx->mod);
-                               if (!ctx->mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
+                               counters = EXTRA_COUNTERS_GET(px->extra_counters_be, mod);
+                               if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
                                        return -1;
 
                                val = stats[ctx->field_num + ctx->mod_field_num];
                                metric.type = ((val.type == FN_GAUGE) ? PROMEX_MT_GAUGE : PROMEX_MT_COUNTER);
 
                                if (!promex_dump_metric(appctx, htx, prefix,
-                                                       ist2(ctx->mod->stats[ctx->mod_field_num].name, strlen(ctx->mod->stats[ctx->mod_field_num].name)),
-                                                       ist2(ctx->mod->stats[ctx->mod_field_num].desc, strlen(ctx->mod->stats[ctx->mod_field_num].desc)),
+                                                       ist2(mod->stats[ctx->mod_field_num].name, strlen(mod->stats[ctx->mod_field_num].name)),
+                                                       ist2(mod->stats[ctx->mod_field_num].desc, strlen(mod->stats[ctx->mod_field_num].desc)),
                                                        &metric, &val, labels, &out, max))
                                        goto full;
 
                        next_px2:
-                               ctx->px = px->next;
+                               px = px->next;
                        }
-
                        ctx->flags |= PROMEX_FL_METRIC_HDR;
-                       ctx->px = proxies_list;
                }
 
-               ctx->field_num += ctx->mod->stats_count;
+               ctx->field_num += mod->stats_count;
                ctx->mod_field_num = 0;
        }
 
+       px = NULL;
+       mod = NULL;
+
   end:
        if (out.len) {
                if (!htx_add_data_atonce(htx, out))
                        return -1; /* Unexpected and unrecoverable error */
                channel_add_input(chn, out.len);
        }
+       /* Save pointers (0=current proxy, 1=current stats module) of the current context */
+       ctx->p[0] = px;
+       ctx->p[1] = mod;
        return ret;
   full:
        ret = 0;
@@ -1221,8 +1234,9 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
 {
        static struct ist prefix = IST("haproxy_server_");
        struct promex_ctx *ctx = appctx->svcctx;
-       struct proxy *px;
-       struct server *sv;
+       struct proxy *px = ctx->p[0];
+       struct server *sv = ctx->p[1];
+       struct stats_module *mod = ctx->p[2];
        struct field val;
        struct channel *chn = sc_ic(appctx_sc(appctx));
        struct ist out = ist2(trash.area, 0);
@@ -1237,10 +1251,11 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
                if (!(promex_st_metrics[ctx->field_num].flags & ctx->flags))
                        continue;
 
-               while (ctx->px) {
-                       struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
+               if (!px)
+                       px = proxies_list;
 
-                       px = ctx->px;
+               while (px) {
+                       struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
 
                        labels[0].name  = ist("proxy");
                        labels[0].value = ist2(px->id, strlen(px->id));
@@ -1249,9 +1264,10 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
                        if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
                                goto next_px;
 
-                       while (ctx->sv) {
-                               sv = ctx->sv;
+                       if (!sv)
+                               sv = px->srv;
 
+                       while (sv) {
                                labels[1].name  = ist("server");
                                labels[1].value = ist2(sv->id, strlen(sv->id));
 
@@ -1341,8 +1357,10 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
                                                val = mkf_flt(FN_DURATION, secs);
                                                break;
                                        case ST_F_REQ_TOT:
-                                               if (px->mode != PR_MODE_HTTP)
+                                               if (px->mode != PR_MODE_HTTP) {
+                                                       sv = NULL;
                                                        goto next_px;
+                                               }
                                                val = stats[ctx->field_num];
                                                break;
                                        case ST_F_HRSP_1XX:
@@ -1351,8 +1369,10 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
                                        case ST_F_HRSP_4XX:
                                        case ST_F_HRSP_5XX:
                                        case ST_F_HRSP_OTHER:
-                                               if (px->mode != PR_MODE_HTTP)
+                                               if (px->mode != PR_MODE_HTTP) {
+                                                       sv = NULL;
                                                        goto next_px;
+                                               }
                                                if (ctx->field_num != ST_F_HRSP_1XX)
                                                        ctx->flags &= ~PROMEX_FL_METRIC_HDR;
                                                labels[2].name = ist("code");
@@ -1371,44 +1391,41 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
                                                        &val, labels, &out, max))
                                        goto full;
                          next_sv:
-                               ctx->sv = sv->next;
+                               sv = sv->next;
                        }
 
                  next_px:
-                       ctx->px = px->next;
-                       ctx->sv = (ctx->px ? ctx->px->srv : NULL);
+                       px = px->next;
                }
                ctx->flags |= PROMEX_FL_METRIC_HDR;
-               ctx->px = proxies_list;
-               ctx->sv = (ctx->px ? ctx->px->srv : NULL);
        }
 
        /* Skip extra counters */
        if (!(ctx->flags & PROMEX_FL_EXTRA_COUNTERS))
                goto end;
 
-       if (!ctx->mod) {
-               /* no restart point, get the first module in the list */
-               ctx->mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(ctx->mod), list);
+       if (!mod) {
+               mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(mod), list);
                ctx->mod_field_num = 0;
        }
 
-       list_for_each_entry_from(ctx->mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
+       list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
                void *counters;
 
-               if (!(stats_px_get_cap(ctx->mod->domain_flags) & STATS_PX_CAP_SRV)) {
-                       ctx->field_num += ctx->mod->stats_count;
+               if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_SRV)) {
+                       ctx->field_num += mod->stats_count;
                        ctx->mod_field_num = 0;
                        continue;
                }
 
-               for (;ctx->mod_field_num < ctx->mod->stats_count; ctx->mod_field_num++) {
-                       while (ctx->px) {
+               for (;ctx->mod_field_num < mod->stats_count; ctx->mod_field_num++) {
+                       if (!px)
+                               px = proxies_list;
+
+                       while (px) {
                                struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
                                struct promex_metric metric;
 
-                               px = ctx->px;
-
                                labels[0].name  = ist("proxy");
                                labels[0].value = ist2(px->id, strlen(px->id));
 
@@ -1416,56 +1433,61 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
                                if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
                                        goto next_px2;
 
-                               while (ctx->sv) {
-                                       sv = ctx->sv;
+                               if (!sv)
+                                       sv = px->srv;
 
+                               while (sv) {
                                        labels[1].name  = ist("server");
                                        labels[1].value = ist2(sv->id, strlen(sv->id));
 
                                        labels[2].name  = ist("mod");
-                                       labels[2].value = ist2(ctx->mod->name, strlen(ctx->mod->name));
+                                       labels[2].value = ist2(mod->name, strlen(mod->name));
 
                                        if ((ctx->flags & PROMEX_FL_NO_MAINT_SRV) && (sv->cur_admin & SRV_ADMF_MAINT))
                                                goto next_sv2;
 
 
-                                       counters = EXTRA_COUNTERS_GET(sv->extra_counters, ctx->mod);
-                                       if (!ctx->mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
+                                       counters = EXTRA_COUNTERS_GET(sv->extra_counters, mod);
+                                       if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
                                                return -1;
 
                                        val = stats[ctx->field_num + ctx->mod_field_num];
                                        metric.type = ((val.type == FN_GAUGE) ? PROMEX_MT_GAUGE : PROMEX_MT_COUNTER);
 
                                        if (!promex_dump_metric(appctx, htx, prefix,
-                                                               ist2(ctx->mod->stats[ctx->mod_field_num].name, strlen(ctx->mod->stats[ctx->mod_field_num].name)),
-                                                               ist2(ctx->mod->stats[ctx->mod_field_num].desc, strlen(ctx->mod->stats[ctx->mod_field_num].desc)),
+                                                               ist2(mod->stats[ctx->mod_field_num].name, strlen(mod->stats[ctx->mod_field_num].name)),
+                                                               ist2(mod->stats[ctx->mod_field_num].desc, strlen(mod->stats[ctx->mod_field_num].desc)),
                                                                &metric, &val, labels, &out, max))
                                                goto full;
 
                                  next_sv2:
-                                       ctx->sv = sv->next;
+                                       sv = sv->next;
                                }
 
                          next_px2:
-                               ctx->px = px->next;
-                               ctx->sv = (ctx->px ? ctx->px->srv : NULL);
+                               px = px->next;
                        }
-
                        ctx->flags |= PROMEX_FL_METRIC_HDR;
-                       ctx->px = proxies_list;
-                       ctx->sv = (ctx->px ? ctx->px->srv : NULL);
                }
 
-               ctx->field_num += ctx->mod->stats_count;
+               ctx->field_num += mod->stats_count;
                ctx->mod_field_num = 0;
        }
 
+       px = NULL;
+       sv = NULL;
+       mod = NULL;
+
   end:
        if (out.len) {
                if (!htx_add_data_atonce(htx, out))
                        return -1; /* Unexpected and unrecoverable error */
                channel_add_input(chn, out.len);
        }
+       /* Save pointers (0=current proxy, 1=current server, 2=current stats module) of the current context */
+       ctx->p[0] = px;
+       ctx->p[1] = sv;
+       ctx->p[2] = mod;
        return ret;
   full:
        ret = 0;
@@ -1478,21 +1500,23 @@ static int promex_dump_sticktable_metrics(struct appctx *appctx, struct htx *htx
 {
        static struct ist prefix = IST("haproxy_sticktable_");
        struct promex_ctx *ctx = appctx->svcctx;
+       struct stktable *t = ctx->p[0];
        struct field val;
        struct channel *chn = sc_ic(appctx_sc(appctx));
        struct ist out = ist2(trash.area, 0);
        size_t max = htx_get_max_blksz(htx, channel_htx_recv_max(chn, htx));
        int ret = 1;
-       struct stktable *t;
 
        for (; ctx->field_num < STICKTABLE_TOTAL_FIELDS; ctx->field_num++) {
                if (!(promex_sticktable_metrics[ctx->field_num].flags & ctx->flags))
                        continue;
 
-               while (ctx->st) {
+               if (!t)
+                       t = stktables_list;
+
+               while (t) {
                        struct promex_label labels[PROMEX_MAX_LABELS - 1] = {};
 
-                       t = ctx->st;
                        if (!t->size)
                                goto next_px;
 
@@ -1518,18 +1542,21 @@ static int promex_dump_sticktable_metrics(struct appctx *appctx, struct htx *htx
                                goto full;
 
                  next_px:
-                       ctx->st = t->next;
+                       t = t->next;
                }
                ctx->flags |= PROMEX_FL_METRIC_HDR;
-               ctx->st = stktables_list;
        }
 
+       t = NULL;
+
   end:
        if (out.len) {
                if (!htx_add_data_atonce(htx, out))
                        return -1; /* Unexpected and unrecoverable error */
                channel_add_input(chn, out.len);
        }
+       /* Save pointers (0=current stick-table) of the current context */
+       ctx->p[0] = t;
        return ret;
   full:
        ret = 0;
@@ -1549,10 +1576,6 @@ static int promex_dump_metrics(struct appctx *appctx, struct stconn *sc, struct
 
        switch (appctx->st1) {
                case PROMEX_DUMPER_INIT:
-                       ctx->px = NULL;
-                       ctx->st = NULL;
-                       ctx->li = NULL;
-                       ctx->sv = NULL;
                        ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_INFO_METRIC);
                        ctx->obj_state = 0;
                        ctx->field_num = INF_NAME;
@@ -1569,11 +1592,6 @@ static int promex_dump_metrics(struct appctx *appctx, struct stconn *sc, struct
                                }
                        }
 
-                       ctx->px = proxies_list;
-                       ctx->st = NULL;
-                       ctx->li = NULL;
-                       ctx->sv = NULL;
-                       ctx->mod = NULL;
                        ctx->flags &= ~PROMEX_FL_INFO_METRIC;
                        ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_FRONT_METRIC);
                        ctx->obj_state = 0;
@@ -1592,11 +1610,6 @@ static int promex_dump_metrics(struct appctx *appctx, struct stconn *sc, struct
                                }
                        }
 
-                       ctx->px = proxies_list;
-                       ctx->st = NULL;
-                       ctx->li = LIST_NEXT(&proxies_list->conf.listeners, struct listener *, by_fe);
-                       ctx->sv = NULL;
-                       ctx->mod = NULL;
                        ctx->flags &= ~PROMEX_FL_FRONT_METRIC;
                        ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_LI_METRIC);
                        ctx->obj_state = 0;
@@ -1615,11 +1628,6 @@ static int promex_dump_metrics(struct appctx *appctx, struct stconn *sc, struct
                                }
                        }
 
-                       ctx->px = proxies_list;
-                       ctx->st = NULL;
-                       ctx->li = NULL;
-                       ctx->sv = NULL;
-                       ctx->mod = NULL;
                        ctx->flags &= ~PROMEX_FL_LI_METRIC;
                        ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_BACK_METRIC);
                        ctx->obj_state = 0;
@@ -1638,11 +1646,6 @@ static int promex_dump_metrics(struct appctx *appctx, struct stconn *sc, struct
                                }
                        }
 
-                       ctx->px = proxies_list;
-                       ctx->st = NULL;
-                       ctx->li = NULL;
-                       ctx->sv = ctx->px ? ctx->px->srv : NULL;
-                       ctx->mod = NULL;
                        ctx->flags &= ~PROMEX_FL_BACK_METRIC;
                        ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_SRV_METRIC);
                        ctx->obj_state = 0;
@@ -1661,11 +1664,6 @@ static int promex_dump_metrics(struct appctx *appctx, struct stconn *sc, struct
                                }
                        }
 
-                       ctx->px = NULL;
-                       ctx->st = stktables_list;
-                       ctx->li = NULL;
-                       ctx->sv = NULL;
-                       ctx->mod = NULL;
                        ctx->flags &= ~(PROMEX_FL_METRIC_HDR|PROMEX_FL_SRV_METRIC);
                        ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_STICKTABLE_METRIC);
                        ctx->field_num = STICKTABLE_SIZE;
@@ -1683,11 +1681,6 @@ static int promex_dump_metrics(struct appctx *appctx, struct stconn *sc, struct
                                }
                        }
 
-                       ctx->px = NULL;
-                       ctx->st = NULL;
-                       ctx->li = NULL;
-                       ctx->sv = NULL;
-                       ctx->mod = NULL;
                        ctx->flags &= ~(PROMEX_FL_METRIC_HDR|PROMEX_FL_STICKTABLE_METRIC);
                        ctx->field_num = 0;
                        ctx->mod_field_num = 0;
@@ -1706,11 +1699,6 @@ static int promex_dump_metrics(struct appctx *appctx, struct stconn *sc, struct
        return 0;
   error:
        /* unrecoverable error */
-       ctx->px = NULL;
-       ctx->st = NULL;
-       ctx->li = NULL;
-       ctx->sv = NULL;
-       ctx->mod = NULL;
        ctx->flags = 0;
        ctx->field_num = 0;
        ctx->mod_field_num = 0;