*/
#define PROMEX_MAX_METRIC_LENGTH 512
-/* Some labels for build_info */
-#define PROMEX_VERSION_LABEL "version=\"" HAPROXY_VERSION "\""
-#define PROMEX_BUILDINFO_LABEL PROMEX_VERSION_LABEL
+/* The max number of labels per metric */
+#define PROMEX_MAX_LABELS 8
/* Describe a prometheus metric */
struct promex_metric {
unsigned int flags; /* PROMEX_FL_* flags */
};
+/* Describe a prometheus metric label. It is just a key/value pair */
+struct promex_label {
+ struct ist name;
+ struct ist value;
+};
+
/* Global metrics */
const struct promex_metric promex_global_metrics[INF_TOTAL_FIELDS] = {
//[INF_NAME] ignored
[ST_F_NEED_CONN_EST] = IST("Estimated needed number of connections."),
};
-/* Specific labels for all info fields. Empty by default. */
-const struct ist promex_inf_metric_labels[INF_TOTAL_FIELDS] = {
- [INF_BUILD_INFO] = IST(PROMEX_BUILDINFO_LABEL),
-};
-
-/* Specific labels for all stats fields. Empty by default. */
-const struct ist promex_st_metric_labels[ST_F_TOTAL_FIELDS] = {
- [ST_F_HRSP_1XX] = IST("code=\"1xx\""),
- [ST_F_HRSP_2XX] = IST("code=\"2xx\""),
- [ST_F_HRSP_3XX] = IST("code=\"3xx\""),
- [ST_F_HRSP_4XX] = IST("code=\"4xx\""),
- [ST_F_HRSP_5XX] = IST("code=\"5xx\""),
- [ST_F_HRSP_OTHER] = IST("code=\"other\""),
+/* Specific labels for all ST_F_HRSP_* fields */
+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_2XX - ST_F_HRSP_1XX] = IST("2xx"),
+ [ST_F_HRSP_3XX - ST_F_HRSP_1XX] = IST("3xx"),
+ [ST_F_HRSP_4XX - ST_F_HRSP_1XX] = IST("4xx"),
+ [ST_F_HRSP_5XX - ST_F_HRSP_1XX] = IST("5xx"),
+ [ST_F_HRSP_OTHER - ST_F_HRSP_1XX] = IST("other"),
};
enum promex_front_state {
*/
static int promex_dump_metric(struct appctx *appctx, struct htx *htx, struct ist prefix,
const struct promex_metric *metric, struct field *val,
- struct ist metric_label, struct ist *out, size_t max)
+ struct promex_label *labels, struct ist *out, size_t max)
{
struct ist name = { .ptr = (char[PROMEX_MAX_NAME_LEN]){ 0 }, .len = 0 };
size_t len = out->len;
!promex_dump_metric_header(appctx, htx, metric, name, out, max))
goto full;
- if (appctx->ctx.stats.flags & PROMEX_FL_INFO_METRIC) {
- const struct ist label = promex_inf_metric_labels[appctx->st2];
+ if (istcat(out, name, max) == -1)
+ goto full;
- if (istcat(out, name, max) == -1 ||
- (label.len && istcat(out, ist("{"), max) == -1) ||
- (label.len && istcat(out, label, max) == -1) ||
- (label.len && istcat(out, ist("}"), max) == -1) ||
- istcat(out, ist(" "), max) == -1)
+ if (isttest(labels[0].name)) {
+ int i;
+
+ if (istcat(out, ist("{"), max) == -1)
goto full;
- }
- else {
- struct proxy *px = appctx->ctx.stats.obj1;
- struct server *srv = appctx->ctx.stats.obj2;
- const struct ist label = promex_st_metric_labels[appctx->st2];
-
- if (istcat(out, name, max) == -1 ||
- istcat(out, ist("{proxy=\""), max) == -1 ||
- istcat(out, ist2(px->id, strlen(px->id)), max) == -1 ||
- istcat(out, ist("\""), max) == -1 ||
- (srv && istcat(out, ist(",server=\""), max) == -1) ||
- (srv && istcat(out, ist2(srv->id, strlen(srv->id)), max) == -1) ||
- (srv && istcat(out, ist("\""), max) == -1) ||
- (label.len && istcat(out, ist(","), max) == -1) ||
- (label.len && istcat(out, label, max) == -1) ||
- (metric_label.len && istcat(out, ist(","), max) == -1) ||
- (metric_label.len && istcat(out, metric_label, max) == -1) ||
- istcat(out, ist("} "), max) == -1)
+
+ for (i = 0; isttest(labels[i].name); i++) {
+ if (!isttest(labels[i].value))
+ continue;
+
+ if ((i && istcat(out, ist(","), max) == -1) ||
+ istcat(out, labels[i].name, max) == -1 ||
+ istcat(out, ist("=\""), max) == -1 ||
+ istcat(out, labels[i].value, max) == -1 ||
+ istcat(out, ist("\""), max) == -1)
+ goto full;
+ }
+
+ if (istcat(out, ist("}"), max) == -1)
goto full;
+
}
+ if (istcat(out, ist(" "), max) == -1)
+ goto full;
+
trash.data = out->len;
if (!promex_metric_to_str(&trash, val, max))
goto full;
return -1;
for (; appctx->st2 < INF_TOTAL_FIELDS; appctx->st2++) {
+ struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
+
if (!(promex_global_metrics[appctx->st2].flags & appctx->ctx.stats.flags))
continue;
switch (appctx->st2) {
case INF_BUILD_INFO:
+ labels[0].name = ist("version");
+ labels[0].value = ist(HAPROXY_VERSION);
val = mkf_u32(FN_GAUGE, 1);
break;
}
if (!promex_dump_metric(appctx, htx, prefix, &promex_global_metrics[appctx->st2],
- &val, IST_NULL, &out, max))
+ &val, labels, &out, max))
goto full;
appctx->ctx.stats.flags |= PROMEX_FL_METRIC_HDR;
goto end;
}
-/* Helper to generate state labels for ftd/bkd/srv */
-static int promex_state_label(struct ist *metric_label, struct ist state)
-{
- struct buffer *state_label = get_trash_chunk();
-
- *metric_label = ist2(state_label->area, 0);
- if (istcat(metric_label, ist("state=\""), state_label->size) == -1 ||
- istcat(metric_label, state, state_label->size) == -1 ||
- istcat(metric_label, ist("\""), state_label->size) == -1)
- return -1;
- return 1;
-}
-
/* Dump frontends metrics (prefixed by "haproxy_frontend_"). It returns 1 on success,
* 0 if <htx> is full and -1 in case of any error. */
static int promex_dump_front_metrics(struct appctx *appctx, struct htx *htx)
struct field *stats = stat_l[STATS_DOMAIN_PROXY];
int ret = 1;
enum promex_front_state state;
- struct ist metric_label;
int i;
for (;appctx->st2 < ST_F_TOTAL_FIELDS; appctx->st2++) {
continue;
while (appctx->ctx.stats.obj1) {
+ struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
+
px = appctx->ctx.stats.obj1;
+ labels[0].name = ist("proxy");
+ labels[0].value = ist2(px->id, strlen(px->id));
+
/* skip the disabled proxies, global frontend and non-networked ones */
if (px->disabled || px->uuid <= 0 || !(px->cap & PR_CAP_FE))
goto next_px;
case ST_F_STATUS:
state = !px->disabled;
for (i = 0; i < PROMEX_FRONT_STATE_COUNT; i++) {
+ labels[1].name = ist("state");
+ labels[1].value = promex_front_st[i];
val = mkf_u32(FO_STATUS, state == i);
- if (promex_state_label(&metric_label, promex_front_st[i]) == -1)
- goto full;
if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[appctx->st2],
- &val, metric_label, &out, max))
+ &val, labels, &out, max))
goto full;
}
goto next_px;
case ST_F_HRSP_OTHER:
if (px->mode != PR_MODE_HTTP)
goto next_px;
- val = stats[appctx->st2];
appctx->ctx.stats.flags &= ~PROMEX_FL_METRIC_HDR;
+ labels[1].name = ist("code");
+ labels[1].value = promex_hrsp_code[appctx->st2 - ST_F_HRSP_1XX];
+ val = stats[appctx->st2];
break;
default:
}
if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[appctx->st2],
- &val, IST_NULL, &out, max))
+ &val, labels, &out, max))
goto full;
next_px:
appctx->ctx.stats.obj1 = px->next;
int ret = 1;
double secs;
enum promex_back_state state;
- struct ist metric_label;
int i;
for (;appctx->st2 < ST_F_TOTAL_FIELDS; appctx->st2++) {
continue;
while (appctx->ctx.stats.obj1) {
+ struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
+
px = appctx->ctx.stats.obj1;
+ labels[0].name = ist("proxy");
+ labels[0].value = ist2(px->id, strlen(px->id));
+
/* skip the disabled proxies, global frontend and non-networked ones */
if (px->disabled || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
goto next_px;
case ST_F_STATUS:
state = ((px->lbprm.tot_weight > 0 || !px->srv) ? 1 : 0);
for (i = 0; i < PROMEX_BACK_STATE_COUNT; i++) {
+ labels[1].name = ist("state");
+ labels[1].value = promex_back_st[i];
val = mkf_u32(FO_STATUS, state == i);
- if (promex_state_label(&metric_label, promex_back_st[i]) == -1)
- goto full;
if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[appctx->st2],
- &val, metric_label, &out, max))
+ &val, labels, &out, max))
goto full;
}
goto next_px;
if (px->mode != PR_MODE_HTTP)
goto next_px;
appctx->ctx.stats.flags &= ~PROMEX_FL_METRIC_HDR;
+ labels[1].name = ist("code");
+ labels[1].value = promex_hrsp_code[appctx->st2 - ST_F_HRSP_1XX];
val = stats[appctx->st2];
break;
}
if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[appctx->st2],
- &val, IST_NULL, &out, max))
+ &val, labels, &out, max))
goto full;
next_px:
appctx->ctx.stats.obj1 = px->next;
int ret = 1;
double secs;
enum promex_srv_state state;
- struct ist metric_label;
int i;
for (;appctx->st2 < ST_F_TOTAL_FIELDS; appctx->st2++) {
continue;
while (appctx->ctx.stats.obj1) {
+ struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
+
px = appctx->ctx.stats.obj1;
+ labels[0].name = ist("proxy");
+ labels[0].value = ist2(px->id, strlen(px->id));
+
/* skip the disabled proxies, global frontend and non-networked ones */
if (px->disabled || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
goto next_px;
while (appctx->ctx.stats.obj2) {
sv = appctx->ctx.stats.obj2;
+ labels[1].name = ist("server");
+ labels[1].value = ist2(sv->id, strlen(sv->id));
+
if (!stats_fill_sv_stats(px, sv, 0, stats, ST_F_TOTAL_FIELDS, &(appctx->st2)))
return -1;
state = promex_srv_status(sv);
for (i = 0; i < PROMEX_SRV_STATE_COUNT; i++) {
val = mkf_u32(FO_STATUS, state == i);
- if (promex_state_label(&metric_label, promex_srv_st[i]) == -1)
- goto full;
+ labels[2].name = ist("state");
+ labels[2].value = promex_srv_st[i];
if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[appctx->st2],
- &val, metric_label, &out, max))
+ &val, labels, &out, max))
goto full;
}
goto next_sv;
if (px->mode != PR_MODE_HTTP)
goto next_px;
appctx->ctx.stats.flags &= ~PROMEX_FL_METRIC_HDR;
+ labels[2].name = ist("code");
+ labels[2].value = promex_hrsp_code[appctx->st2 - ST_F_HRSP_1XX];
val = stats[appctx->st2];
break;
}
if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[appctx->st2],
- &val, IST_NULL, &out, max))
+ &val, labels, &out, max))
goto full;
next_sv:
appctx->ctx.stats.obj2 = sv->next;