mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 07:07:04 +02:00
MEDIUM: contrib/prometheus-exporter: export base stick table stats
I saw some people falling back to unix socket to collect some data they could not find in prometheus exporter. One of them is base info from stick tables (used/size). I do not plan to extend it more for now; keys are quite a mess to handle. This should resolve github issue #1008. Signed-off-by: William Dauchy <wdauchy@gmail.com>
This commit is contained in:
parent
486e5117b5
commit
69164228b8
@ -72,6 +72,7 @@ exported. Here are examples:
|
|||||||
/metrics?scope=frontend&scope=backend # ==> Frontend and backend metrics will be exported
|
/metrics?scope=frontend&scope=backend # ==> Frontend and backend metrics will be exported
|
||||||
/metrics?scope=*&scope= # ==> no metrics will be exported
|
/metrics?scope=*&scope= # ==> no metrics will be exported
|
||||||
/metrics?scope=&scope=global # ==> global metrics will be exported
|
/metrics?scope=&scope=global # ==> global metrics will be exported
|
||||||
|
/metrics?scope=sticktable # ==> stick tables metrics will be exported
|
||||||
|
|
||||||
* How do I prevent my prometheus instance to explode?
|
* How do I prevent my prometheus instance to explode?
|
||||||
|
|
||||||
@ -320,3 +321,12 @@ See prometheus export for the description of each field.
|
|||||||
| haproxy_server_need_connections_current |
|
| haproxy_server_need_connections_current |
|
||||||
| haproxy_server_uweight |
|
| haproxy_server_uweight |
|
||||||
+----------------------------------------------------+
|
+----------------------------------------------------+
|
||||||
|
|
||||||
|
* Stick table metrics
|
||||||
|
|
||||||
|
+----------------------------------------------------+
|
||||||
|
| Metric name |
|
||||||
|
+----------------------------------------------------+
|
||||||
|
| haproxy_sticktable_size |
|
||||||
|
| haproxy_sticktable_used |
|
||||||
|
+----------------------------------------------------+
|
||||||
|
@ -47,28 +47,33 @@ enum {
|
|||||||
|
|
||||||
/* Prometheus exporter dumper states (appctx->st1) */
|
/* Prometheus exporter dumper states (appctx->st1) */
|
||||||
enum {
|
enum {
|
||||||
PROMEX_DUMPER_INIT = 0, /* initialized */
|
PROMEX_DUMPER_INIT = 0, /* initialized */
|
||||||
PROMEX_DUMPER_GLOBAL, /* dump metrics of globals */
|
PROMEX_DUMPER_GLOBAL, /* dump metrics of globals */
|
||||||
PROMEX_DUMPER_FRONT, /* dump metrics of frontend proxies */
|
PROMEX_DUMPER_FRONT, /* dump metrics of frontend proxies */
|
||||||
PROMEX_DUMPER_BACK, /* dump metrics of backend proxies */
|
PROMEX_DUMPER_BACK, /* dump metrics of backend proxies */
|
||||||
PROMEX_DUMPER_LI, /* dump metrics of listeners */
|
PROMEX_DUMPER_LI, /* dump metrics of listeners */
|
||||||
PROMEX_DUMPER_SRV, /* dump metrics of servers */
|
PROMEX_DUMPER_SRV, /* dump metrics of servers */
|
||||||
PROMEX_DUMPER_DONE, /* finished */
|
PROMEX_DUMPER_STICKTABLE, /* dump metrics of stick tables */
|
||||||
|
PROMEX_DUMPER_DONE, /* finished */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Prometheus exporter flags (appctx->ctx.stats.flags) */
|
/* Prometheus exporter flags (appctx->ctx.stats.flags) */
|
||||||
#define PROMEX_FL_METRIC_HDR 0x00000001
|
#define PROMEX_FL_METRIC_HDR 0x00000001
|
||||||
#define PROMEX_FL_INFO_METRIC 0x00000002
|
#define PROMEX_FL_INFO_METRIC 0x00000002
|
||||||
#define PROMEX_FL_FRONT_METRIC 0x00000004
|
#define PROMEX_FL_FRONT_METRIC 0x00000004
|
||||||
#define PROMEX_FL_BACK_METRIC 0x00000008
|
#define PROMEX_FL_BACK_METRIC 0x00000008
|
||||||
#define PROMEX_FL_SRV_METRIC 0x00000010
|
#define PROMEX_FL_SRV_METRIC 0x00000010
|
||||||
#define PROMEX_FL_SCOPE_GLOBAL 0x00000020
|
#define PROMEX_FL_SCOPE_GLOBAL 0x00000020
|
||||||
#define PROMEX_FL_SCOPE_FRONT 0x00000040
|
#define PROMEX_FL_SCOPE_FRONT 0x00000040
|
||||||
#define PROMEX_FL_SCOPE_BACK 0x00000080
|
#define PROMEX_FL_SCOPE_BACK 0x00000080
|
||||||
#define PROMEX_FL_SCOPE_SERVER 0x00000100
|
#define PROMEX_FL_SCOPE_SERVER 0x00000100
|
||||||
#define PROMEX_FL_NO_MAINT_SRV 0x00000200
|
#define PROMEX_FL_NO_MAINT_SRV 0x00000200
|
||||||
|
#define PROMEX_FL_STICKTABLE_METRIC 0x00000400
|
||||||
|
#define PROMEX_FL_SCOPE_STICKTABLE 0x00000800
|
||||||
|
|
||||||
#define PROMEX_FL_SCOPE_ALL (PROMEX_FL_SCOPE_GLOBAL|PROMEX_FL_SCOPE_FRONT|PROMEX_FL_SCOPE_BACK|PROMEX_FL_SCOPE_SERVER)
|
#define PROMEX_FL_SCOPE_ALL (PROMEX_FL_SCOPE_GLOBAL | PROMEX_FL_SCOPE_FRONT | \
|
||||||
|
PROMEX_FL_SCOPE_BACK | PROMEX_FL_SCOPE_SERVER | \
|
||||||
|
PROMEX_FL_SCOPE_STICKTABLE)
|
||||||
|
|
||||||
/* Promtheus metric type (gauge or counter) */
|
/* Promtheus metric type (gauge or counter) */
|
||||||
enum promex_mt_type {
|
enum promex_mt_type {
|
||||||
@ -298,6 +303,25 @@ const struct ist promex_st_metric_desc[ST_F_TOTAL_FIELDS] = {
|
|||||||
[ST_F_TT_MAX] = IST("Maximum observed total request+response time (request+queue+connect+response+processing)"),
|
[ST_F_TT_MAX] = IST("Maximum observed total request+response time (request+queue+connect+response+processing)"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* stick table base fields */
|
||||||
|
enum sticktable_field {
|
||||||
|
STICKTABLE_SIZE = 0,
|
||||||
|
STICKTABLE_USED,
|
||||||
|
/* must always be the last one */
|
||||||
|
STICKTABLE_TOTAL_FIELDS
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct promex_metric promex_sticktable_metrics[STICKTABLE_TOTAL_FIELDS] = {
|
||||||
|
[STICKTABLE_SIZE] = { .n = IST("size"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_STICKTABLE_METRIC },
|
||||||
|
[STICKTABLE_USED] = { .n = IST("used"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_STICKTABLE_METRIC },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* stick table base description */
|
||||||
|
const struct ist promex_sticktable_metric_desc[STICKTABLE_TOTAL_FIELDS] = {
|
||||||
|
[STICKTABLE_SIZE] = IST("Stick table size."),
|
||||||
|
[STICKTABLE_USED] = IST("Number of entries used in this stick table."),
|
||||||
|
};
|
||||||
|
|
||||||
/* Specific labels for all ST_F_HRSP_* fields */
|
/* Specific labels for all ST_F_HRSP_* fields */
|
||||||
const struct ist promex_hrsp_code[1 + ST_F_HRSP_OTHER - ST_F_HRSP_1XX] = {
|
const struct ist promex_hrsp_code[1 + ST_F_HRSP_OTHER - ST_F_HRSP_1XX] = {
|
||||||
[ST_F_HRSP_1XX - ST_F_HRSP_1XX] = IST("1xx"),
|
[ST_F_HRSP_1XX - ST_F_HRSP_1XX] = IST("1xx"),
|
||||||
@ -419,6 +443,8 @@ static int promex_dump_metric_header(struct appctx *appctx, struct htx *htx,
|
|||||||
|
|
||||||
if (metric->flags & PROMEX_FL_INFO_METRIC)
|
if (metric->flags & PROMEX_FL_INFO_METRIC)
|
||||||
desc = ist(info_fields[appctx->st2].desc);
|
desc = ist(info_fields[appctx->st2].desc);
|
||||||
|
else if (metric->flags & PROMEX_FL_STICKTABLE_METRIC)
|
||||||
|
desc = promex_sticktable_metric_desc[appctx->st2];
|
||||||
else if (!isttest(promex_st_metric_desc[appctx->st2]))
|
else if (!isttest(promex_st_metric_desc[appctx->st2]))
|
||||||
desc = ist(stat_fields[appctx->st2].desc);
|
desc = ist(stat_fields[appctx->st2].desc);
|
||||||
else
|
else
|
||||||
@ -958,6 +984,68 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dump stick table metrics (prefixed by "haproxy_sticktable_"). It returns 1 on success,
|
||||||
|
* 0 if <htx> is full and -1 in case of any error. */
|
||||||
|
static int promex_dump_sticktable_metrics(struct appctx *appctx, struct htx *htx)
|
||||||
|
{
|
||||||
|
static struct ist prefix = IST("haproxy_sticktable_");
|
||||||
|
struct field val;
|
||||||
|
struct channel *chn = si_ic(appctx->owner);
|
||||||
|
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 (; appctx->st2 < STICKTABLE_TOTAL_FIELDS; appctx->st2++) {
|
||||||
|
if (!(promex_sticktable_metrics[appctx->st2].flags & appctx->ctx.stats.flags))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
while (appctx->ctx.stats.obj1) {
|
||||||
|
struct promex_label labels[PROMEX_MAX_LABELS - 1] = {};
|
||||||
|
|
||||||
|
t = appctx->ctx.stats.obj1;
|
||||||
|
if (!t->size)
|
||||||
|
goto next_px;
|
||||||
|
|
||||||
|
labels[0].name = ist("name");
|
||||||
|
labels[0].value = ist2(t->id, strlen(t->id));
|
||||||
|
labels[1].name = ist("type");
|
||||||
|
labels[1].value = ist2(stktable_types[t->type].kw, strlen(stktable_types[t->type].kw));
|
||||||
|
switch (appctx->st2) {
|
||||||
|
case STICKTABLE_SIZE:
|
||||||
|
val = mkf_u32(FN_GAUGE, t->size);
|
||||||
|
break;
|
||||||
|
case STICKTABLE_USED:
|
||||||
|
val = mkf_u32(FN_GAUGE, t->current);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto next_px;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!promex_dump_metric(appctx, htx, prefix,
|
||||||
|
&promex_sticktable_metrics[appctx->st2],
|
||||||
|
&val, labels, &out, max))
|
||||||
|
goto full;
|
||||||
|
|
||||||
|
next_px:
|
||||||
|
appctx->ctx.stats.obj1 = t->next;
|
||||||
|
}
|
||||||
|
appctx->ctx.stats.flags |= PROMEX_FL_METRIC_HDR;
|
||||||
|
appctx->ctx.stats.obj1 = stktables_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (out.len) {
|
||||||
|
if (!htx_add_data_atonce(htx, out))
|
||||||
|
return -1; /* Unexpected and unrecoverable error */
|
||||||
|
channel_add_input(chn, out.len);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
full:
|
||||||
|
ret = 0;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
/* Dump all metrics (global, frontends, backends and servers) depending on the
|
/* Dump all metrics (global, frontends, backends and servers) depending on the
|
||||||
* dumper state (appctx->st1). It returns 1 on success, 0 if <htx> is full and
|
* dumper state (appctx->st1). It returns 1 on success, 0 if <htx> is full and
|
||||||
* -1 in case of any error.
|
* -1 in case of any error.
|
||||||
@ -1044,9 +1132,27 @@ static int promex_dump_metrics(struct appctx *appctx, struct stream_interface *s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
appctx->ctx.stats.obj1 = NULL;
|
appctx->ctx.stats.obj1 = stktables_list;
|
||||||
appctx->ctx.stats.obj2 = NULL;
|
appctx->ctx.stats.obj2 = NULL;
|
||||||
appctx->ctx.stats.flags &= ~(PROMEX_FL_METRIC_HDR|PROMEX_FL_SRV_METRIC);
|
appctx->ctx.stats.flags &= ~(PROMEX_FL_METRIC_HDR|PROMEX_FL_SRV_METRIC);
|
||||||
|
appctx->ctx.stats.flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_STICKTABLE_METRIC);
|
||||||
|
appctx->st2 = STICKTABLE_SIZE;
|
||||||
|
appctx->st1 = PROMEX_DUMPER_STICKTABLE;
|
||||||
|
/* fall through */
|
||||||
|
|
||||||
|
case PROMEX_DUMPER_STICKTABLE:
|
||||||
|
if (appctx->ctx.stats.flags & PROMEX_FL_SCOPE_STICKTABLE) {
|
||||||
|
ret = promex_dump_sticktable_metrics(appctx, htx);
|
||||||
|
if (ret <= 0) {
|
||||||
|
if (ret == -1)
|
||||||
|
goto error;
|
||||||
|
goto full;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appctx->ctx.stats.obj1 = NULL;
|
||||||
|
appctx->ctx.stats.obj2 = NULL;
|
||||||
|
appctx->ctx.stats.flags &= ~(PROMEX_FL_METRIC_HDR|PROMEX_FL_STICKTABLE_METRIC);
|
||||||
appctx->st2 = 0;
|
appctx->st2 = 0;
|
||||||
appctx->st1 = PROMEX_DUMPER_DONE;
|
appctx->st1 = PROMEX_DUMPER_DONE;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
@ -1155,6 +1261,8 @@ static int promex_parse_uri(struct appctx *appctx, struct stream_interface *si)
|
|||||||
appctx->ctx.stats.flags |= PROMEX_FL_SCOPE_BACK;
|
appctx->ctx.stats.flags |= PROMEX_FL_SCOPE_BACK;
|
||||||
else if (strcmp(value, "frontend") == 0)
|
else if (strcmp(value, "frontend") == 0)
|
||||||
appctx->ctx.stats.flags |= PROMEX_FL_SCOPE_FRONT;
|
appctx->ctx.stats.flags |= PROMEX_FL_SCOPE_FRONT;
|
||||||
|
else if (strcmp(value, "sticktable") == 0)
|
||||||
|
appctx->ctx.stats.flags |= PROMEX_FL_SCOPE_STICKTABLE;
|
||||||
else
|
else
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
varnishtest "prometheus exporter test"
|
varnishtest "prometheus exporter test"
|
||||||
|
|
||||||
#REQUIRE_VERSION=2.0
|
#REQUIRE_VERSION=2.4
|
||||||
#REQUIRE_SERVICES=prometheus-exporter
|
#REQUIRE_SERVICES=prometheus-exporter
|
||||||
|
|
||||||
feature ignore_unknown_macro
|
feature ignore_unknown_macro
|
||||||
@ -26,6 +26,7 @@ haproxy h1 -conf {
|
|||||||
default_backend be
|
default_backend be
|
||||||
|
|
||||||
backend be
|
backend be
|
||||||
|
stick-table type ip size 1m expire 10s store http_req_rate(10s)
|
||||||
server s1 ${s1_addr}:${s1_port}
|
server s1 ${s1_addr}:${s1_port}
|
||||||
} -start
|
} -start
|
||||||
|
|
||||||
@ -37,6 +38,7 @@ client c1 -connect ${h1_stats_sock} {
|
|||||||
expect resp.body ~ ".*haproxy_frontend.*"
|
expect resp.body ~ ".*haproxy_frontend.*"
|
||||||
expect resp.body ~ ".*haproxy_backend.*"
|
expect resp.body ~ ".*haproxy_backend.*"
|
||||||
expect resp.body ~ ".*haproxy_server.*"
|
expect resp.body ~ ".*haproxy_server.*"
|
||||||
|
expect resp.body ~ ".*haproxy_sticktable.*"
|
||||||
|
|
||||||
txreq -url "/metrics?scope="
|
txreq -url "/metrics?scope="
|
||||||
rxresp
|
rxresp
|
||||||
@ -50,6 +52,7 @@ client c1 -connect ${h1_stats_sock} {
|
|||||||
expect resp.body !~ ".*haproxy_frontend.*"
|
expect resp.body !~ ".*haproxy_frontend.*"
|
||||||
expect resp.body !~ ".*haproxy_backend.*"
|
expect resp.body !~ ".*haproxy_backend.*"
|
||||||
expect resp.body ~ ".*haproxy_server.*"
|
expect resp.body ~ ".*haproxy_server.*"
|
||||||
|
expect resp.body !~ ".*haproxy_sticktable.*"
|
||||||
|
|
||||||
txreq -url "/metrics?scope=frontend&scope=backend"
|
txreq -url "/metrics?scope=frontend&scope=backend"
|
||||||
rxresp
|
rxresp
|
||||||
@ -58,6 +61,7 @@ client c1 -connect ${h1_stats_sock} {
|
|||||||
expect resp.body ~ ".*haproxy_frontend.*"
|
expect resp.body ~ ".*haproxy_frontend.*"
|
||||||
expect resp.body ~ ".*haproxy_backend.*"
|
expect resp.body ~ ".*haproxy_backend.*"
|
||||||
expect resp.body !~ ".*haproxy_server.*"
|
expect resp.body !~ ".*haproxy_server.*"
|
||||||
|
expect resp.body !~ ".*haproxy_sticktable.*"
|
||||||
|
|
||||||
txreq -url "/metrics?scope"
|
txreq -url "/metrics?scope"
|
||||||
rxresp
|
rxresp
|
||||||
|
Loading…
Reference in New Issue
Block a user