#include <haproxy/task.h>
#include <haproxy/tools.h>
#include <haproxy/version.h>
+#include <haproxy/xxhash.h>
#include <promex/promex.h>
struct list list;
};
+/* An entry in a headers map */
+struct promex_metric_filter {
+ int exclude;
+ struct eb32_node node;
+};
+
/* the context of the applet */
struct promex_ctx {
void *p[4]; /* generic pointers used to save context */
unsigned mod_field_num; /* first field number of the current module (ST_F_* etc) */
int obj_state; /* current state among PROMEX_{FRONT|BACK|SRV|LI}_STATE_* */
struct list modules; /* list of promex modules to export */
+ struct eb_root filters; /* list of filters to apply on metrics name */
};
/* The max length for metrics name. It is a hard limit but it should be
LIST_APPEND(&promex_module_list, &m->list);
}
-/* Pools used to allocate ref on Promex modules */
-DECLARE_STATIC_POOL(pool_head_promex_mod_ref, "promex_module_ref", sizeof(struct promex_module_ref));
+/* Pools used to allocate ref on Promex modules and filters */
+DECLARE_STATIC_POOL(pool_head_promex_mod_ref, "promex_module_ref", sizeof(struct promex_module_ref));
+DECLARE_STATIC_POOL(pool_head_promex_metric_flt, "promex_metric_filter", sizeof(struct promex_metric_filter));
/* Return the server status. */
enum promex_srv_state promex_srv_status(struct server *sv)
}
+static int promex_filter_metric(struct appctx *appctx, struct ist prefix, struct ist name)
+{
+ struct promex_ctx *ctx = appctx->svcctx;
+ struct eb32_node *node;
+ struct promex_metric_filter *flt;
+ unsigned int hash;
+ XXH32_state_t state;
+
+ if (!eb_is_empty(&ctx->filters)) {
+ XXH32_reset(&state, 0);
+ XXH32_update(&state, istptr(prefix), istlen(prefix));
+ XXH32_update(&state, istptr(name), istlen(name));
+ hash = XXH32_digest(&state);
+
+ node = eb32_lookup(&ctx->filters, hash);
+ if (node) {
+ flt = container_of(node, typeof(*flt), node);
+ if (flt->exclude)
+ return 1;
+ }
+ else if (!(ctx->flags & PROMEX_FL_INC_METRIC_BY_DEFAULT))
+ return 1;
+ }
+
+ return 0;
+}
/* Dump global metrics (prefixed by "haproxy_process_"). It returns 1 on success,
* 0 if <htx> is full and -1 in case of any error. */
name = promex_global_metrics[ctx->field_num].n;
desc = ist(info_fields[ctx->field_num].desc);
+ if (promex_filter_metric(appctx, prefix, name))
+ continue;
+
switch (ctx->field_num) {
case INF_BUILD_INFO:
labels[0].name = ist("version");
if (!isttest(desc))
desc = ist(stat_fields[ctx->field_num].desc);
+ if (promex_filter_metric(appctx, prefix, name))
+ continue;
+
if (!px)
px = proxies_list;
name = ist2(mod->stats[ctx->mod_field_num].name, strlen(mod->stats[ctx->mod_field_num].name));
desc = ist2(mod->stats[ctx->mod_field_num].desc, strlen(mod->stats[ctx->mod_field_num].desc));
+ if (promex_filter_metric(appctx, prefix, name))
+ continue;
+
if (!px)
px = proxies_list;
if (!isttest(desc))
desc = ist(stat_fields[ctx->field_num].desc);
+ if (promex_filter_metric(appctx, prefix, name))
+ continue;
+
if (!px)
px = proxies_list;
name = ist2(mod->stats[ctx->mod_field_num].name, strlen(mod->stats[ctx->mod_field_num].name));
desc = ist2(mod->stats[ctx->mod_field_num].desc, strlen(mod->stats[ctx->mod_field_num].desc));
+ if (promex_filter_metric(appctx, prefix, name))
+ continue;
+
if (!px)
px = proxies_list;
if (!isttest(desc))
desc = ist(stat_fields[ctx->field_num].desc);
+ if (promex_filter_metric(appctx, prefix, name))
+ continue;
+
if (!px)
px = proxies_list;
name = ist2(mod->stats[ctx->mod_field_num].name, strlen(mod->stats[ctx->mod_field_num].name));
desc = ist2(mod->stats[ctx->mod_field_num].desc, strlen(mod->stats[ctx->mod_field_num].desc));
+ if (promex_filter_metric(appctx, prefix, name))
+ continue;
+
if (!px)
px = proxies_list;
if (!isttest(desc))
desc = ist(stat_fields[ctx->field_num].desc);
+ if (promex_filter_metric(appctx, prefix, name))
+ continue;
+
if (!px)
px = proxies_list;
name = ist2(mod->stats[ctx->mod_field_num].name, strlen(mod->stats[ctx->mod_field_num].name));
desc = ist2(mod->stats[ctx->mod_field_num].desc, strlen(mod->stats[ctx->mod_field_num].desc));
+ if (promex_filter_metric(appctx, prefix, name))
+ continue;
+
if (!px)
px = proxies_list;
struct promex_metric metric;
struct ist desc;
+
ret = mod->metric_info(ctx->mod_field_num, &metric, &desc);
if (!ret)
continue;
if (ret < 0)
goto error;
+ if (promex_filter_metric(appctx, prefix, metric.n))
+ continue;
+
if (!ctx->p[2])
ctx->p[2] = mod->start_ts(ctx->p[1], ctx->mod_field_num);
const char *end;
struct buffer *err;
int default_scopes = PROMEX_FL_SCOPE_ALL;
+ int default_metrics_filter = PROMEX_FL_INC_METRIC_BY_DEFAULT;
int len;
/* Get the query-string */
goto error;
else if (*value == 0)
ctx->flags &= ~PROMEX_FL_SCOPE_ALL;
- else if (*value == '*')
+ else if (*value == '*' && *(value+1) == 0)
ctx->flags |= PROMEX_FL_SCOPE_ALL;
else if (strcmp(value, "global") == 0)
ctx->flags |= PROMEX_FL_SCOPE_GLOBAL;
goto error;
}
}
+ else if (strcmp(key, "metrics") == 0) {
+ struct ist args;
+
+ if (!value)
+ goto error;
+
+ for (args = ist(value); istlen(args); args = istadv(istfind(args, ','), 1)) {
+ struct eb32_node *node;
+ struct promex_metric_filter *flt;
+ struct ist m = iststop(args, ',');
+ unsigned int hash;
+ int exclude = 0;
+
+ if (!istlen(m))
+ continue;
+
+ if (*istptr(m) == '-') {
+ m = istnext(m);
+ if (!istlen(m))
+ continue;
+ exclude = 1;
+ }
+ else
+ default_metrics_filter &= ~PROMEX_FL_INC_METRIC_BY_DEFAULT;
+
+
+ hash = XXH32(istptr(m), istlen(m), 0);
+ node = eb32_lookup(&ctx->filters, hash);
+ if (node) {
+ flt = container_of(node, typeof(*flt), node);
+ flt->exclude = exclude;
+ continue;
+ }
+
+ flt = pool_alloc(pool_head_promex_metric_flt);
+ if (!flt)
+ goto internal_error;
+ flt->node.key = hash;
+ flt->exclude = exclude;
+ eb32_insert(&ctx->filters, &flt->node);
+ }
+ }
else if (strcmp(key, "extra-counters") == 0) {
ctx->flags |= PROMEX_FL_EXTRA_COUNTERS;
}
}
end:
- ctx->flags |= default_scopes;
+ ctx->flags |= (default_scopes | default_metrics_filter);
return 1;
error:
ctx = appctx->svcctx;
memset(ctx->p, 0, sizeof(ctx->p));
LIST_INIT(&ctx->modules);
+ ctx->filters = EB_ROOT;
appctx->st0 = PROMEX_ST_INIT;
return 0;
}
{
struct promex_ctx *ctx = appctx->svcctx;
struct promex_module_ref *ref, *back;
+ struct promex_metric_filter *flt;
+ struct eb32_node *node, *next;
list_for_each_entry_safe(ref, back, &ctx->modules, list) {
LIST_DELETE(&ref->list);
pool_free(pool_head_promex_mod_ref, ref);
}
+
+ node = eb32_first(&ctx->filters);
+ while (node) {
+ next = eb32_next(node);
+ eb32_delete(node);
+ flt = container_of(node, typeof(*flt), node);
+ pool_free(pool_head_promex_metric_flt, flt);
+ node = next;
+ }
}
/* The main I/O handler for the promex applet. */