diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-03 05:11:11 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-03 05:11:11 +0000 |
commit | 669c3ea68099b330943d5c3215f0cf381880c3ad (patch) | |
tree | b5fbb97171c91fb994c2c3744dd33073f8f07407 /addons/promex | |
parent | Releasing progress-linux version 2.9.7-1~progress7.99u1. (diff) | |
download | haproxy-669c3ea68099b330943d5c3215f0cf381880c3ad.tar.xz haproxy-669c3ea68099b330943d5c3215f0cf381880c3ad.zip |
Merging upstream version 3.0.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'addons/promex')
-rw-r--r-- | addons/promex/README | 60 | ||||
-rw-r--r-- | addons/promex/include/promex/promex.h | 127 | ||||
-rw-r--r-- | addons/promex/service-prometheus.c | 1629 |
3 files changed, 1270 insertions, 546 deletions
diff --git a/addons/promex/README b/addons/promex/README index 4e29e23..8c2266f 100644 --- a/addons/promex/README +++ b/addons/promex/README @@ -75,6 +75,40 @@ exported. Here are examples: /metrics?scope=&scope=global # ==> global metrics will be exported /metrics?scope=sticktable # ==> stick tables metrics will be exported +* Filtering on metrics name + +It is possible to filter metrics dumped by the exporter. To to so, multiple +"metrics" parameters may be passed to specify all metrics to include or exclude, +as a comma-separated list of filter. By default, there is no filter and all +metrics are dumped. By specifying at least one metric to be included in the +dump, this disables the default behavior and only explicitly mentioned metrics +are dumped. To include a metric, its name must be specified. To exclude it, its +name must be preceded by a minus character ('-'). Here are examples: + + # Dumped all metrics, except "haproxy_server_check_status" + /metrics?metrics=-haproxy_server_check_status + + # Only dump frontends, backends and servers status + /metrics?metrics=haproxy_frontend_status,haproxy_backend_status,haproxy_server_status + + +* Dump extra counters + +Internally, some modules can register to frontends, backends, servers or +listeners to export extra counters. For instance, some multiplexers do so on +frontends or backends. To display extra counters for all regiestered modules, +"extra-counters" parameter must be pass. It can be cumulated with "scope" +parameters: + + /metrics?extra-counters # ==> export all extra counters in + # addition to main ones, for all + # scopes + /metrics?scope=frontend&extra-counters # ==> export extra counters for + # frontends + +There are extra counters are only for frontends, backends, servers and +listeners. + * How do I prevent my prometheus instance to explode? ** Filtering on servers state @@ -109,7 +143,8 @@ except the server_check_status, you may configure prometheus that way: Exported metrics ------------------ -See prometheus export for the description of each field. +See prometheus export for the description of each field. Only main metrics are +listed below. Metrics from extra counters are not listed. * Globals metrics @@ -310,6 +345,8 @@ See prometheus export for the description of each field. | haproxy_server_redispatch_warnings_total | | haproxy_server_status | | haproxy_server_weight | +| haproxy_server_active | +| haproxy_server_backup | | haproxy_server_check_failures_total | | haproxy_server_check_up_down_total | | haproxy_server_check_last_change_seconds | @@ -354,3 +391,24 @@ See prometheus export for the description of each field. | haproxy_sticktable_size | | haproxy_sticktable_used | +----------------------------------------------------+ + +* Resolvers metrics + ++----------------------------------------------------+ +| Metric name | ++----------------------------------------------------+ +| haproxy_resolver_sent | +| haproxy_resolver_send_error | +| haproxy_resolver_valid | +| haproxy_resolver_update | +| haproxy_resolver_cname | +| haproxy_resolver_cname_error | +| haproxy_resolver_any_err | +| haproxy_resolver_nx | +| haproxy_resolver_timeout | +| haproxy_resolver_refused | +| haproxy_resolver_other | +| haproxy_resolver_invalid | +| haproxy_resolver_too_big | +| haproxy_resolver_outdated | ++----------------------------------------------------+ diff --git a/addons/promex/include/promex/promex.h b/addons/promex/include/promex/promex.h new file mode 100644 index 0000000..74ea2f1 --- /dev/null +++ b/addons/promex/include/promex/promex.h @@ -0,0 +1,127 @@ +/* + * include/promex/promex.h + * This file contains definitions, macros and inline functions dedicated to + * the prometheus exporter for HAProxy. + * + * Copyright 2024 Christopher Faulet <cfaulet@haproxy.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, version 2.1 + * exclusively. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _PROMEX_PROMEX_H +#define _PROMEX_PROMEX_H + +#include <import/ist.h> + +#include <haproxy/api-t.h> +#include <haproxy/list-t.h> + +#include <haproxy/stats.h> + +/* Prometheus exporter flags (ctx->flags) */ +#define PROMEX_FL_METRIC_HDR 0x00000001 +#define PROMEX_FL_INFO_METRIC 0x00000002 +#define PROMEX_FL_FRONT_METRIC 0x00000004 +#define PROMEX_FL_BACK_METRIC 0x00000008 +#define PROMEX_FL_SRV_METRIC 0x00000010 +#define PROMEX_FL_LI_METRIC 0x00000020 +#define PROMEX_FL_MODULE_METRIC 0x00000040 +#define PROMEX_FL_SCOPE_GLOBAL 0x00000080 +#define PROMEX_FL_SCOPE_FRONT 0x00000100 +#define PROMEX_FL_SCOPE_BACK 0x00000200 +#define PROMEX_FL_SCOPE_SERVER 0x00000400 +#define PROMEX_FL_SCOPE_LI 0x00000800 +#define PROMEX_FL_SCOPE_MODULE 0x00001000 +#define PROMEX_FL_NO_MAINT_SRV 0x00002000 +#define PROMEX_FL_EXTRA_COUNTERS 0x00004000 +#define PROMEX_FL_INC_METRIC_BY_DEFAULT 0x00008000 + +#define PROMEX_FL_SCOPE_ALL (PROMEX_FL_SCOPE_GLOBAL | PROMEX_FL_SCOPE_FRONT | \ + PROMEX_FL_SCOPE_LI | PROMEX_FL_SCOPE_BACK | \ + PROMEX_FL_SCOPE_SERVER | PROMEX_FL_SCOPE_MODULE) + +/* The max number of labels per metric */ +#define PROMEX_MAX_LABELS 8 + +/* Promtheus metric type (gauge or counter) */ +enum promex_mt_type { + PROMEX_MT_GAUGE = 1, + PROMEX_MT_COUNTER = 2, +}; + +/* Describe a prometheus metric */ +struct promex_metric { + struct ist n; /* The metric name */ + enum promex_mt_type type; /* The metric type (gauge or counter) */ + 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; +}; + +/* Entity used to expose custom metrics on HAProxy. + * + * * start_metric_dump(): It is an optional callback function. If defined, it + * is responsible to initialize the dump context use + * as the first restart point. + * + * * stop_metric_dump(): It is an optional callback function. If defined, it + * is responsible to deinit the dump context. + * + * * metric_info(): This one is mandatory. It returns the info about the + * metric: name, type and flags and description. + * + * * start_ts(): This one is mandatory, it initializes the context for a time + * series for a given metric. This context is the second + * restart point. + * + * * next_ts(): This one is mandatory. It iterates on time series for a + * given metrics. It is also responsible to handle end of a + * time series and deinit the context. + * + * * fill_ts(): It fills info on the time series for a given metric : the + * labels and the value. + */ +struct promex_module { + struct list list; + struct ist name; /* The promex module name */ + int (*metric_info)(unsigned int id, /* Return info for the given id */ + struct promex_metric *metric, + struct ist *desc); + void *(*start_metrics_dump)(); /* Start a dump (may be NULL) */ + void (*stop_metrics_dump)(void *ctx); /* Stop a dump (may be NULL) */ + void *(*start_ts)(void *ctx, unsigned int id); /* Start a time series for the given metric */ + void *(*next_ts)(void *ctx, void *ts_ctx, unsigned int id); /* move to the next time series for the given metric */ + int (*fill_ts)(void *ctx, void *ts_ctx, unsigned int id, /* fill the time series for the given metric */ + struct promex_label *labels, struct field *field); + + size_t nb_metrics; /* # of metrics */ +}; + +extern struct list promex_module_list; + +void promex_register_module(struct promex_module *m); + +#endif /* _PROMEX_PROMEX_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */ diff --git a/addons/promex/service-prometheus.c b/addons/promex/service-prometheus.c index e9ad44e..4e0bc68 100644 --- a/addons/promex/service-prometheus.c +++ b/addons/promex/service-prometheus.c @@ -28,6 +28,7 @@ #include <haproxy/list.h> #include <haproxy/listener.h> #include <haproxy/log.h> +#include <haproxy/pool.h> #include <haproxy/proxy.h> #include <haproxy/sample.h> #include <haproxy/sc_strm.h> @@ -38,6 +39,9 @@ #include <haproxy/task.h> #include <haproxy/tools.h> #include <haproxy/version.h> +#include <haproxy/xxhash.h> + +#include <promex/promex.h> /* Prometheus exporter applet states (appctx->st0) */ enum { @@ -56,45 +60,30 @@ enum { PROMEX_DUMPER_BACK, /* dump metrics of backend proxies */ PROMEX_DUMPER_LI, /* dump metrics of listeners */ PROMEX_DUMPER_SRV, /* dump metrics of servers */ - PROMEX_DUMPER_STICKTABLE, /* dump metrics of stick tables */ + PROMEX_DUMPER_MODULES, /* dump metrics of modules */ PROMEX_DUMPER_DONE, /* finished */ }; -/* Prometheus exporter flags (ctx->flags) */ -#define PROMEX_FL_METRIC_HDR 0x00000001 -#define PROMEX_FL_INFO_METRIC 0x00000002 -#define PROMEX_FL_FRONT_METRIC 0x00000004 -#define PROMEX_FL_BACK_METRIC 0x00000008 -#define PROMEX_FL_SRV_METRIC 0x00000010 -#define PROMEX_FL_LI_METRIC 0x00000020 -#define PROMEX_FL_STICKTABLE_METRIC 0x00000040 -#define PROMEX_FL_SCOPE_GLOBAL 0x00000080 -#define PROMEX_FL_SCOPE_FRONT 0x00000100 -#define PROMEX_FL_SCOPE_BACK 0x00000200 -#define PROMEX_FL_SCOPE_SERVER 0x00000400 -#define PROMEX_FL_SCOPE_LI 0x00000800 -#define PROMEX_FL_SCOPE_STICKTABLE 0x00001000 -#define PROMEX_FL_NO_MAINT_SRV 0x00002000 - -#define PROMEX_FL_SCOPE_ALL (PROMEX_FL_SCOPE_GLOBAL | PROMEX_FL_SCOPE_FRONT | \ - PROMEX_FL_SCOPE_LI | PROMEX_FL_SCOPE_BACK | \ - PROMEX_FL_SCOPE_SERVER | PROMEX_FL_SCOPE_STICKTABLE) +struct promex_module_ref { + struct promex_module *mod; + 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 { - struct proxy *px; /* current proxy */ - struct stktable *st; /* current table */ - struct listener *li; /* current listener */ - struct server *sv; /* current server */ + void *p[4]; /* generic pointers used to save context */ unsigned int flags; /* PROMEX_FL_* */ - unsigned field_num; /* current field number (ST_F_* etc) */ + unsigned field_num; /* current field number (ST_I_PX_* etc) */ + unsigned mod_field_num; /* first field number of the current module (ST_I_PX_* etc) */ int obj_state; /* current state among PROMEX_{FRONT|BACK|SRV|LI}_STATE_* */ -}; - -/* Promtheus metric type (gauge or counter) */ -enum promex_mt_type { - PROMEX_MT_GAUGE = 1, - PROMEX_MT_COUNTER = 2, + 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 @@ -108,247 +97,230 @@ enum promex_mt_type { */ #define PROMEX_MAX_METRIC_LENGTH 512 -/* The max number of labels per metric */ -#define PROMEX_MAX_LABELS 8 - -/* Describe a prometheus metric */ -struct promex_metric { - const struct ist n; /* The metric name */ - enum promex_mt_type type; /* The metric type (gauge or counter) */ - 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 - //[INF_VERSION], ignored - //[INF_RELEASE_DATE] ignored - [INF_NBTHREAD] = { .n = IST("nbthread"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_NBPROC] = { .n = IST("nbproc"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_PROCESS_NUM] = { .n = IST("relative_process_id"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - //[INF_PID] ignored - //[INF_UPTIME] ignored - [INF_UPTIME_SEC] = { .n = IST("uptime_seconds"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_START_TIME_SEC] = { .n = IST("start_time_seconds"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - //[INF_MEMMAX_MB] ignored - [INF_MEMMAX_BYTES] = { .n = IST("max_memory_bytes"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - //[INF_POOL_ALLOC_MB] ignored - [INF_POOL_ALLOC_BYTES] = { .n = IST("pool_allocated_bytes"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - //[INF_POOL_USED_MB] ignored - [INF_POOL_USED_BYTES] = { .n = IST("pool_used_bytes"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_POOL_FAILED] = { .n = IST("pool_failures_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_ULIMIT_N] = { .n = IST("max_fds"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_MAXSOCK] = { .n = IST("max_sockets"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_MAXCONN] = { .n = IST("max_connections"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_HARD_MAXCONN] = { .n = IST("hard_max_connections"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_CURR_CONN] = { .n = IST("current_connections"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_CUM_CONN] = { .n = IST("connections_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_CUM_REQ] = { .n = IST("requests_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_MAX_SSL_CONNS] = { .n = IST("max_ssl_connections"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_CURR_SSL_CONNS] = { .n = IST("current_ssl_connections"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_CUM_SSL_CONNS] = { .n = IST("ssl_connections_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_MAXPIPES] = { .n = IST("max_pipes"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_PIPES_USED] = { .n = IST("pipes_used_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_PIPES_FREE] = { .n = IST("pipes_free_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_CONN_RATE] = { .n = IST("current_connection_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_CONN_RATE_LIMIT] = { .n = IST("limit_connection_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_MAX_CONN_RATE] = { .n = IST("max_connection_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_SESS_RATE] = { .n = IST("current_session_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_SESS_RATE_LIMIT] = { .n = IST("limit_session_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_MAX_SESS_RATE] = { .n = IST("max_session_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_SSL_RATE] = { .n = IST("current_ssl_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_SSL_RATE_LIMIT] = { .n = IST("limit_ssl_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_MAX_SSL_RATE] = { .n = IST("max_ssl_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_SSL_FRONTEND_KEY_RATE] = { .n = IST("current_frontend_ssl_key_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_SSL_FRONTEND_MAX_KEY_RATE] = { .n = IST("max_frontend_ssl_key_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_SSL_FRONTEND_SESSION_REUSE_PCT] = { .n = IST("frontend_ssl_reuse"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_SSL_BACKEND_KEY_RATE] = { .n = IST("current_backend_ssl_key_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_SSL_BACKEND_MAX_KEY_RATE] = { .n = IST("max_backend_ssl_key_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_SSL_CACHE_LOOKUPS] = { .n = IST("ssl_cache_lookups_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_SSL_CACHE_MISSES] = { .n = IST("ssl_cache_misses_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_COMPRESS_BPS_IN] = { .n = IST("http_comp_bytes_in_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_COMPRESS_BPS_OUT] = { .n = IST("http_comp_bytes_out_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_COMPRESS_BPS_RATE_LIM] = { .n = IST("limit_http_comp"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_ZLIB_MEM_USAGE] = { .n = IST("current_zlib_memory"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_MAX_ZLIB_MEM_USAGE] = { .n = IST("max_zlib_memory"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_TASKS] = { .n = IST("current_tasks"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_RUN_QUEUE] = { .n = IST("current_run_queue"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_IDLE_PCT] = { .n = IST("idle_time_percent"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - //[INF_NODE] ignored - //[INF_DESCRIPTION] ignored - [INF_STOPPING] = { .n = IST("stopping"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_JOBS] = { .n = IST("jobs"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_UNSTOPPABLE_JOBS] = { .n = IST("unstoppable_jobs"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_LISTENERS] = { .n = IST("listeners"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_ACTIVE_PEERS] = { .n = IST("active_peers"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_CONNECTED_PEERS] = { .n = IST("connected_peers"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_DROPPED_LOGS] = { .n = IST("dropped_logs_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_BUSY_POLLING] = { .n = IST("busy_polling_enabled"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - [INF_FAILED_RESOLUTIONS] = { .n = IST("failed_resolutions"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_TOTAL_BYTES_OUT] = { .n = IST("bytes_out_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_TOTAL_SPLICED_BYTES_OUT] = { .n = IST("spliced_bytes_out_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_BYTES_OUT_RATE] = { .n = IST("bytes_out_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, - //[INF_DEBUG_COMMANDS_ISSUED] ignored - [INF_CUM_LOG_MSGS] = { .n = IST("recv_logs_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, - [INF_BUILD_INFO] = { .n = IST("build_info"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, +const struct promex_metric promex_global_metrics[ST_I_INF_MAX] = { + //[ST_I_INF_NAME] ignored + //[ST_I_INF_VERSION], ignored + //[ST_I_INF_RELEASE_DATE] ignored + [ST_I_INF_NBTHREAD] = { .n = IST("nbthread"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_NBPROC] = { .n = IST("nbproc"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_PROCESS_NUM] = { .n = IST("relative_process_id"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + //[ST_I_INF_PID] ignored + //[ST_I_INF_UPTIME] ignored + [ST_I_INF_UPTIME_SEC] = { .n = IST("uptime_seconds"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_START_TIME_SEC] = { .n = IST("start_time_seconds"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + //[ST_I_INF_MEMMAX_MB] ignored + [ST_I_INF_MEMMAX_BYTES] = { .n = IST("max_memory_bytes"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + //[ST_I_INF_POOL_ALLOC_MB] ignored + [ST_I_INF_POOL_ALLOC_BYTES] = { .n = IST("pool_allocated_bytes"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + //[ST_I_INF_POOL_USED_MB] ignored + [ST_I_INF_POOL_USED_BYTES] = { .n = IST("pool_used_bytes"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_POOL_FAILED] = { .n = IST("pool_failures_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_ULIMIT_N] = { .n = IST("max_fds"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_MAXSOCK] = { .n = IST("max_sockets"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_MAXCONN] = { .n = IST("max_connections"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_HARD_MAXCONN] = { .n = IST("hard_max_connections"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_CURR_CONN] = { .n = IST("current_connections"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_CUM_CONN] = { .n = IST("connections_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_CUM_REQ] = { .n = IST("requests_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_MAX_SSL_CONNS] = { .n = IST("max_ssl_connections"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_CURR_SSL_CONNS] = { .n = IST("current_ssl_connections"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_CUM_SSL_CONNS] = { .n = IST("ssl_connections_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_MAXPIPES] = { .n = IST("max_pipes"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_PIPES_USED] = { .n = IST("pipes_used_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_PIPES_FREE] = { .n = IST("pipes_free_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_CONN_RATE] = { .n = IST("current_connection_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_CONN_RATE_LIMIT] = { .n = IST("limit_connection_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_MAX_CONN_RATE] = { .n = IST("max_connection_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_SESS_RATE] = { .n = IST("current_session_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_SESS_RATE_LIMIT] = { .n = IST("limit_session_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_MAX_SESS_RATE] = { .n = IST("max_session_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_SSL_RATE] = { .n = IST("current_ssl_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_SSL_RATE_LIMIT] = { .n = IST("limit_ssl_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_MAX_SSL_RATE] = { .n = IST("max_ssl_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_SSL_FRONTEND_KEY_RATE] = { .n = IST("current_frontend_ssl_key_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_SSL_FRONTEND_MAX_KEY_RATE] = { .n = IST("max_frontend_ssl_key_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_SSL_FRONTEND_SESSION_REUSE_PCT] = { .n = IST("frontend_ssl_reuse"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_SSL_BACKEND_KEY_RATE] = { .n = IST("current_backend_ssl_key_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_SSL_BACKEND_MAX_KEY_RATE] = { .n = IST("max_backend_ssl_key_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_SSL_CACHE_LOOKUPS] = { .n = IST("ssl_cache_lookups_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_SSL_CACHE_MISSES] = { .n = IST("ssl_cache_misses_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_COMPRESS_BPS_IN] = { .n = IST("http_comp_bytes_in_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_COMPRESS_BPS_OUT] = { .n = IST("http_comp_bytes_out_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_COMPRESS_BPS_RATE_LIM] = { .n = IST("limit_http_comp"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_ZLIB_MEM_USAGE] = { .n = IST("current_zlib_memory"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_MAX_ZLIB_MEM_USAGE] = { .n = IST("max_zlib_memory"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_TASKS] = { .n = IST("current_tasks"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_RUN_QUEUE] = { .n = IST("current_run_queue"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_IDLE_PCT] = { .n = IST("idle_time_percent"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + //[ST_I_INF_NODE] ignored + //[ST_I_INF_DESCRIPTION] ignored + [ST_I_INF_STOPPING] = { .n = IST("stopping"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_JOBS] = { .n = IST("jobs"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_UNSTOPPABLE_JOBS] = { .n = IST("unstoppable_jobs"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_LISTENERS] = { .n = IST("listeners"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_ACTIVE_PEERS] = { .n = IST("active_peers"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_CONNECTED_PEERS] = { .n = IST("connected_peers"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_DROPPED_LOGS] = { .n = IST("dropped_logs_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_BUSY_POLLING] = { .n = IST("busy_polling_enabled"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_FAILED_RESOLUTIONS] = { .n = IST("failed_resolutions"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_TOTAL_BYTES_OUT] = { .n = IST("bytes_out_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_TOTAL_SPLICED_BYTES_OUT] = { .n = IST("spliced_bytes_out_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_BYTES_OUT_RATE] = { .n = IST("bytes_out_rate"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, + //[ST_I_INF_DEBUG_COMMANDS_ISSUED] ignored + [ST_I_INF_CUM_LOG_MSGS] = { .n = IST("recv_logs_total"), .type = PROMEX_MT_COUNTER, .flags = PROMEX_FL_INFO_METRIC }, + [ST_I_INF_BUILD_INFO] = { .n = IST("build_info"), .type = PROMEX_MT_GAUGE, .flags = PROMEX_FL_INFO_METRIC }, }; /* frontend/backend/server fields */ -const struct promex_metric promex_st_metrics[ST_F_TOTAL_FIELDS] = { - //[ST_F_PXNAME] ignored - //[ST_F_SVNAME] ignored - [ST_F_QCUR] = { .n = IST("current_queue"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_QMAX] = { .n = IST("max_queue"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_SCUR] = { .n = IST("current_sessions"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_SMAX] = { .n = IST("max_sessions"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_SLIM] = { .n = IST("limit_sessions"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_STOT] = { .n = IST("sessions_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_BIN] = { .n = IST("bytes_in_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_BOUT] = { .n = IST("bytes_out_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_DREQ] = { .n = IST("requests_denied_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC ) }, - [ST_F_DRESP] = { .n = IST("responses_denied_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_EREQ] = { .n = IST("request_errors_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC ) }, - [ST_F_ECON] = { .n = IST("connection_errors_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_ERESP] = { .n = IST("response_errors_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_WRETR] = { .n = IST("retry_warnings_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_WREDIS] = { .n = IST("redispatch_warnings_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_STATUS] = { .n = IST("status"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_WEIGHT] = { .n = IST("weight"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_ACT] = { .n = IST("active_servers"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC ) }, - [ST_F_BCK] = { .n = IST("backup_servers"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC ) }, - [ST_F_CHKFAIL] = { .n = IST("check_failures_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_SRV_METRIC) }, - [ST_F_CHKDOWN] = { .n = IST("check_up_down_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_LASTCHG] = { .n = IST("check_last_change_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_DOWNTIME] = { .n = IST("downtime_seconds_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_QLIMIT] = { .n = IST("queue_limit"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, - //[ST_F_PID] ignored - //[ST_F_IID] ignored - //[ST_F_SID] ignored - [ST_F_THROTTLE] = { .n = IST("current_throttle"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, - [ST_F_LBTOT] = { .n = IST("loadbalanced_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - //[ST_F_TRACKED] ignored - //[ST_F_TYPE] ignored - //[ST_F_RATE] ignored - [ST_F_RATE_LIM] = { .n = IST("limit_session_rate"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC ) }, - [ST_F_RATE_MAX] = { .n = IST("max_session_rate"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_CHECK_STATUS] = { .n = IST("check_status"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, - [ST_F_CHECK_CODE] = { .n = IST("check_code"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, - [ST_F_CHECK_DURATION] = { .n = IST("check_duration_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, - [ST_F_HRSP_1XX] = { .n = IST("http_responses_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_HRSP_2XX] = { .n = IST("http_responses_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_HRSP_3XX] = { .n = IST("http_responses_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_HRSP_4XX] = { .n = IST("http_responses_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_HRSP_5XX] = { .n = IST("http_responses_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_HRSP_OTHER] = { .n = IST("http_responses_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - //[ST_F_HANAFAIL] ignored - //[ST_F_REQ_RATE] ignored - [ST_F_REQ_RATE_MAX] = { .n = IST("http_requests_rate_max"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC ) }, - [ST_F_REQ_TOT] = { .n = IST("http_requests_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC ) }, - [ST_F_CLI_ABRT] = { .n = IST("client_aborts_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_SRV_ABRT] = { .n = IST("server_aborts_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_COMP_IN] = { .n = IST("http_comp_bytes_in_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC ) }, - [ST_F_COMP_OUT] = { .n = IST("http_comp_bytes_out_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC ) }, - [ST_F_COMP_BYP] = { .n = IST("http_comp_bytes_bypassed_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC ) }, - [ST_F_COMP_RSP] = { .n = IST("http_comp_responses_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC ) }, - [ST_F_LASTSESS] = { .n = IST("last_session_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - //[ST_F_LAST_CHK] ignored - //[ST_F_LAST_AGT] ignored - [ST_F_QTIME] = { .n = IST("queue_time_average_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_CTIME] = { .n = IST("connect_time_average_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_RTIME] = { .n = IST("response_time_average_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_TTIME] = { .n = IST("total_time_average_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - //[ST_F_AGENT_STATUS] ignored - //[ST_F_AGENT_CODE] ignored - //[ST_F_AGENT_DURATION] ignored - //[ST_F_CHECK_DESC] ignored - //[ST_F_AGENT_DESC] ignored - //[ST_F_CHECK_RISE] ignored - //[ST_F_CHECK_FALL] ignored - //[ST_F_CHECK_HEALTH] ignored - //[ST_F_AGENT_RISE] ignored - //[ST_F_AGENT_FALL] ignored - //[ST_F_AGENT_HEALTH] ignored - //[ST_F_ADDR] ignored - //[ST_F_COOKIE] ignored - //[ST_F_MODE] ignored - //[ST_F_ALGO] ignored - //[ST_F_CONN_RATE] ignored - [ST_F_CONN_RATE_MAX] = { .n = IST("connections_rate_max"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC ) }, - [ST_F_CONN_TOT] = { .n = IST("connections_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC ) }, - [ST_F_INTERCEPTED] = { .n = IST("intercepted_requests_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC ) }, - [ST_F_DCON] = { .n = IST("denied_connections_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC ) }, - [ST_F_DSES] = { .n = IST("denied_sessions_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC ) }, - [ST_F_WREW] = { .n = IST("failed_header_rewriting_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_CONNECT] = { .n = IST("connection_attempts_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_REUSE] = { .n = IST("connection_reuses_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_CACHE_LOOKUPS] = { .n = IST("http_cache_lookups_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC ) }, - [ST_F_CACHE_HITS] = { .n = IST("http_cache_hits_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC ) }, - [ST_F_SRV_ICUR] = { .n = IST("idle_connections_current"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, - [ST_F_SRV_ILIM] = { .n = IST("idle_connections_limit"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, - [ST_F_QT_MAX] = { .n = IST("max_queue_time_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_CT_MAX] = { .n = IST("max_connect_time_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_RT_MAX] = { .n = IST("max_response_time_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_TT_MAX] = { .n = IST("max_total_time_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_EINT] = { .n = IST("internal_errors_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_IDLE_CONN_CUR] = { .n = IST("unsafe_idle_connections_current"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, - [ST_F_SAFE_CONN_CUR] = { .n = IST("safe_idle_connections_current"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, - [ST_F_USED_CONN_CUR] = { .n = IST("used_connections_current"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, - [ST_F_NEED_CONN_EST] = { .n = IST("need_connections_current"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, - [ST_F_UWEIGHT] = { .n = IST("uweight"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, - [ST_F_AGG_SRV_CHECK_STATUS] = { .n = IST("agg_server_check_status"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC ) }, - [ST_F_AGG_SRV_STATUS ] = { .n = IST("agg_server_status"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC ) }, - [ST_F_AGG_CHECK_STATUS] = { .n = IST("agg_check_status"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC ) }, +const struct promex_metric promex_st_metrics[ST_I_PX_MAX] = { + //[ST_I_PX_PXNAME] ignored + //[ST_I_PX_SVNAME] ignored + [ST_I_PX_QCUR] = { .n = IST("current_queue"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_QMAX] = { .n = IST("max_queue"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_SCUR] = { .n = IST("current_sessions"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_SMAX] = { .n = IST("max_sessions"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_SLIM] = { .n = IST("limit_sessions"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_STOT] = { .n = IST("sessions_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_BIN] = { .n = IST("bytes_in_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_BOUT] = { .n = IST("bytes_out_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_DREQ] = { .n = IST("requests_denied_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC ) }, + [ST_I_PX_DRESP] = { .n = IST("responses_denied_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_EREQ] = { .n = IST("request_errors_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC ) }, + [ST_I_PX_ECON] = { .n = IST("connection_errors_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_ERESP] = { .n = IST("response_errors_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_WRETR] = { .n = IST("retry_warnings_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_WREDIS] = { .n = IST("redispatch_warnings_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_STATUS] = { .n = IST("status"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_WEIGHT] = { .n = IST("weight"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_ACT] = { .n = IST("active_servers"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_BCK] = { .n = IST("backup_servers"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_CHKFAIL] = { .n = IST("check_failures_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_CHKDOWN] = { .n = IST("check_up_down_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_LASTCHG] = { .n = IST("check_last_change_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_DOWNTIME] = { .n = IST("downtime_seconds_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_QLIMIT] = { .n = IST("queue_limit"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, + //[ST_I_PX_PID] ignored + //[ST_I_PX_IID] ignored + //[ST_I_PX_SID] ignored + [ST_I_PX_THROTTLE] = { .n = IST("current_throttle"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_LBTOT] = { .n = IST("loadbalanced_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + //[ST_I_PX_TRACKED] ignored + //[ST_I_PX_TYPE] ignored + //[ST_I_PX_RATE] ignored + [ST_I_PX_RATE_LIM] = { .n = IST("limit_session_rate"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC ) }, + [ST_I_PX_RATE_MAX] = { .n = IST("max_session_rate"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_CHECK_STATUS] = { .n = IST("check_status"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_CHECK_CODE] = { .n = IST("check_code"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_CHECK_DURATION] = { .n = IST("check_duration_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_HRSP_1XX] = { .n = IST("http_responses_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_HRSP_2XX] = { .n = IST("http_responses_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_HRSP_3XX] = { .n = IST("http_responses_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_HRSP_4XX] = { .n = IST("http_responses_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_HRSP_5XX] = { .n = IST("http_responses_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_HRSP_OTHER] = { .n = IST("http_responses_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + //[ST_I_PX_HANAFAIL] ignored + //[ST_I_PX_REQ_RATE] ignored + [ST_I_PX_REQ_RATE_MAX] = { .n = IST("http_requests_rate_max"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC ) }, + [ST_I_PX_REQ_TOT] = { .n = IST("http_requests_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC ) }, + [ST_I_PX_CLI_ABRT] = { .n = IST("client_aborts_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_SRV_ABRT] = { .n = IST("server_aborts_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_COMP_IN] = { .n = IST("http_comp_bytes_in_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC ) }, + [ST_I_PX_COMP_OUT] = { .n = IST("http_comp_bytes_out_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC ) }, + [ST_I_PX_COMP_BYP] = { .n = IST("http_comp_bytes_bypassed_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC ) }, + [ST_I_PX_COMP_RSP] = { .n = IST("http_comp_responses_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC ) }, + [ST_I_PX_LASTSESS] = { .n = IST("last_session_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + //[ST_I_PX_LAST_CHK] ignored + //[ST_I_PX_LAST_AGT] ignored + [ST_I_PX_QTIME] = { .n = IST("queue_time_average_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_CTIME] = { .n = IST("connect_time_average_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_RTIME] = { .n = IST("response_time_average_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_TTIME] = { .n = IST("total_time_average_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + //[ST_I_PX_AGENT_STATUS] ignored + //[ST_I_PX_AGENT_CODE] ignored + //[ST_I_PX_AGENT_DURATION] ignored + //[ST_I_PX_CHECK_DESC] ignored + //[ST_I_PX_AGENT_DESC] ignored + //[ST_I_PX_CHECK_RISE] ignored + //[ST_I_PX_CHECK_FALL] ignored + //[ST_I_PX_CHECK_HEALTH] ignored + //[ST_I_PX_AGENT_RISE] ignored + //[ST_I_PX_AGENT_FALL] ignored + //[ST_I_PX_AGENT_HEALTH] ignored + //[ST_I_PX_ADDR] ignored + //[ST_I_PX_COOKIE] ignored + //[ST_I_PX_MODE] ignored + //[ST_I_PX_ALGO] ignored + //[ST_I_PX_CONN_RATE] ignored + [ST_I_PX_CONN_RATE_MAX] = { .n = IST("connections_rate_max"), .type = PROMEX_MT_GAUGE, .flags = (PROMEX_FL_FRONT_METRIC ) }, + [ST_I_PX_CONN_TOT] = { .n = IST("connections_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC ) }, + [ST_I_PX_INTERCEPTED] = { .n = IST("intercepted_requests_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC ) }, + [ST_I_PX_DCON] = { .n = IST("denied_connections_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC ) }, + [ST_I_PX_DSES] = { .n = IST("denied_sessions_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC ) }, + [ST_I_PX_WREW] = { .n = IST("failed_header_rewriting_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_CONNECT] = { .n = IST("connection_attempts_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_REUSE] = { .n = IST("connection_reuses_total"), .type = PROMEX_MT_COUNTER, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_CACHE_LOOKUPS] = { .n = IST("http_cache_lookups_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC ) }, + [ST_I_PX_CACHE_HITS] = { .n = IST("http_cache_hits_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_BACK_METRIC ) }, + [ST_I_PX_SRV_ICUR] = { .n = IST("idle_connections_current"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_SRV_ILIM] = { .n = IST("idle_connections_limit"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_QT_MAX] = { .n = IST("max_queue_time_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_CT_MAX] = { .n = IST("max_connect_time_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_RT_MAX] = { .n = IST("max_response_time_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_TT_MAX] = { .n = IST("max_total_time_seconds"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_EINT] = { .n = IST("internal_errors_total"), .type = PROMEX_MT_COUNTER, .flags = (PROMEX_FL_FRONT_METRIC | PROMEX_FL_LI_METRIC | PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_IDLE_CONN_CUR] = { .n = IST("unsafe_idle_connections_current"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_SAFE_CONN_CUR] = { .n = IST("safe_idle_connections_current"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_USED_CONN_CUR] = { .n = IST("used_connections_current"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_NEED_CONN_EST] = { .n = IST("need_connections_current"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_UWEIGHT] = { .n = IST("uweight"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC | PROMEX_FL_SRV_METRIC) }, + [ST_I_PX_AGG_SRV_CHECK_STATUS] = { .n = IST("agg_server_check_status"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC ) }, + [ST_I_PX_AGG_SRV_STATUS ] = { .n = IST("agg_server_status"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC ) }, + [ST_I_PX_AGG_CHECK_STATUS] = { .n = IST("agg_check_status"), .type = PROMEX_MT_GAUGE, .flags = ( PROMEX_FL_BACK_METRIC ) }, }; -/* Description of overridden stats fields */ -const struct ist promex_st_metric_desc[ST_F_TOTAL_FIELDS] = { - [ST_F_STATUS] = IST("Current status of the service, per state label value."), - [ST_F_CHECK_STATUS] = IST("Status of last health check, per state label value."), - [ST_F_CHECK_CODE] = IST("layer5-7 code, if available of the last health check."), - [ST_F_CHECK_DURATION] = IST("Total duration of the latest server health check, in seconds."), - [ST_F_QTIME] = IST("Avg. queue time for last 1024 successful connections."), - [ST_F_CTIME] = IST("Avg. connect time for last 1024 successful connections."), - [ST_F_RTIME] = IST("Avg. response time for last 1024 successful connections."), - [ST_F_TTIME] = IST("Avg. total time for last 1024 successful connections."), - [ST_F_QT_MAX] = IST("Maximum observed time spent in the queue"), - [ST_F_CT_MAX] = IST("Maximum observed time spent waiting for a connection to complete"), - [ST_F_RT_MAX] = IST("Maximum observed time spent waiting for a server response"), - [ST_F_TT_MAX] = IST("Maximum observed total request+response time (request+queue+connect+response+processing)"), +/* Specialized frontend metric names, to override default ones */ +const struct ist promex_st_front_metrics_names[ST_I_PX_MAX] = { }; -/* stick table base fields */ -enum sticktable_field { - STICKTABLE_SIZE = 0, - STICKTABLE_USED, - /* must always be the last one */ - STICKTABLE_TOTAL_FIELDS +/* Specialized backend metric names, to override default ones */ +const struct ist promex_st_back_metrics_names[ST_I_PX_MAX] = { }; -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 }, +/* Specialized listener metric names, to override default ones */ +const struct ist promex_st_li_metrics_names[ST_I_PX_MAX] = { }; -/* 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."), +/* Specialized server metric names, to override default ones */ +const struct ist promex_st_srv_metrics_names[ST_I_PX_MAX] = { + [ST_I_PX_ACT] = IST("active"), + [ST_I_PX_BCK] = IST("backup"), +}; + +/* Description of overridden stats fields */ +const struct ist promex_st_metric_desc[ST_I_PX_MAX] = { + [ST_I_PX_STATUS] = IST("Current status of the service, per state label value."), + [ST_I_PX_CHECK_STATUS] = IST("Status of last health check, per state label value."), + [ST_I_PX_CHECK_CODE] = IST("layer5-7 code, if available of the last health check."), + [ST_I_PX_CHECK_DURATION] = IST("Total duration of the latest server health check, in seconds."), + [ST_I_PX_QTIME] = IST("Avg. queue time for last 1024 successful connections."), + [ST_I_PX_CTIME] = IST("Avg. connect time for last 1024 successful connections."), + [ST_I_PX_RTIME] = IST("Avg. response time for last 1024 successful connections."), + [ST_I_PX_TTIME] = IST("Avg. total time for last 1024 successful connections."), + [ST_I_PX_QT_MAX] = IST("Maximum observed time spent in the queue"), + [ST_I_PX_CT_MAX] = IST("Maximum observed time spent waiting for a connection to complete"), + [ST_I_PX_RT_MAX] = IST("Maximum observed time spent waiting for a server response"), + [ST_I_PX_TT_MAX] = IST("Maximum observed total request+response time (request+queue+connect+response+processing)"), }; -/* 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"), +/* Specific labels for all ST_I_PX_HRSP_* fields */ +const struct ist promex_hrsp_code[1 + ST_I_PX_HRSP_OTHER - ST_I_PX_HRSP_1XX] = { + [ST_I_PX_HRSP_1XX - ST_I_PX_HRSP_1XX] = IST("1xx"), + [ST_I_PX_HRSP_2XX - ST_I_PX_HRSP_1XX] = IST("2xx"), + [ST_I_PX_HRSP_3XX - ST_I_PX_HRSP_1XX] = IST("3xx"), + [ST_I_PX_HRSP_4XX - ST_I_PX_HRSP_1XX] = IST("4xx"), + [ST_I_PX_HRSP_5XX - ST_I_PX_HRSP_1XX] = IST("5xx"), + [ST_I_PX_HRSP_OTHER - ST_I_PX_HRSP_1XX] = IST("other"), }; enum promex_front_state { @@ -393,6 +365,18 @@ const struct ist promex_srv_st[PROMEX_SRV_STATE_COUNT] = { [PROMEX_SRV_STATE_NOLB] = IST("NOLB"), }; +struct list promex_module_list = LIST_HEAD_INIT(promex_module_list); + + +void promex_register_module(struct promex_module *m) +{ + LIST_APPEND(&promex_module_list, &m->list); +} + +/* 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) { @@ -412,22 +396,13 @@ enum promex_srv_state promex_srv_status(struct server *sv) return state; } -/* Store <sv> in <ctx> safely by using refcount to prevent server deletion. */ -static void promex_set_ctx_sv(struct promex_ctx *ctx, struct server *sv) -{ - srv_drop(ctx->sv); - ctx->sv = sv; - if (ctx->sv) - srv_take(ctx->sv); -} - /* Convert a field to its string representation and write it in <out>, followed * by a newline, if there is enough space. non-numeric value are converted in * "NaN" because Prometheus only support numerical values (but it is unexepceted * to process this kind of value). It returns 1 on success. Otherwise, it * returns 0. The buffer's length must not exceed <max> value. */ -static int promex_metric_to_str(struct buffer *out, struct field *f, size_t max) +static int promex_ts_val_to_str(struct buffer *out, struct field *f, size_t max) { int ret = 0; @@ -446,23 +421,21 @@ static int promex_metric_to_str(struct buffer *out, struct field *f, size_t max) return 1; } -/* Dump the header lines for <metric>. It is its #HELP and #TYPE strings. It - * returns 1 on success. Otherwise, if <out> length exceeds <max>, it returns 0. +/* Dump the time series header lines for the metric <name>. It is its #HELP and #TYPE + * strings. It returns 1 on success. Otherwise, if <out> length exceeds <max>, + * it returns 0. */ -static int promex_dump_metric_header(struct appctx *appctx, struct htx *htx, - const struct promex_metric *metric, const struct ist name, - struct ist *out, size_t max) +static int promex_dump_ts_header(const struct ist name, const struct ist desc, enum promex_mt_type type, + struct ist *out, size_t max) { - struct promex_ctx *ctx = appctx->svcctx; - struct ist type; - struct ist desc; + struct ist t; - switch (metric->type) { + switch (type) { case PROMEX_MT_COUNTER: - type = ist("counter"); + t = ist("counter"); break; default: - type = ist("gauge"); + t = ist("gauge"); } if (istcat(out, ist("# HELP "), max) == -1 || @@ -470,20 +443,16 @@ static int promex_dump_metric_header(struct appctx *appctx, struct htx *htx, istcat(out, ist(" "), max) == -1) goto full; - if (metric->flags & PROMEX_FL_INFO_METRIC) - desc = ist(info_fields[ctx->field_num].desc); - else if (metric->flags & PROMEX_FL_STICKTABLE_METRIC) - desc = promex_sticktable_metric_desc[ctx->field_num]; - else if (!isttest(promex_st_metric_desc[ctx->field_num])) - desc = ist(stat_fields[ctx->field_num].desc); - else - desc = promex_st_metric_desc[ctx->field_num]; + if (istcat(out, ist("# HELP "), max) == -1 || + istcat(out, name, max) == -1 || + istcat(out, ist(" "), max) == -1 || + istcat(out, desc, max) == -1) + goto full; - if (istcat(out, desc, max) == -1 || - istcat(out, ist("\n# TYPE "), max) == -1 || + if (istcat(out, ist("\n# TYPE "), max) == -1 || istcat(out, name, max) == -1 || istcat(out, ist(" "), max) == -1 || - istcat(out, type, max) == -1 || + istcat(out, t, max) == -1 || istcat(out, ist("\n"), max) == -1) goto full; @@ -493,32 +462,32 @@ static int promex_dump_metric_header(struct appctx *appctx, struct htx *htx, return 0; } -/* Dump the line for <metric>. It starts by the metric name followed by its - * labels (proxy name, server name...) between braces and finally its value. If - * not already done, the header lines are dumped first. It returns 1 on - * success. Otherwise if <out> length exceeds <max>, it returns 0. +/* Dump the time series for the metric <name>. It starts by the metric name followed by + * its labels (proxy name, server name...) between braces and finally its + * value. If not already done, the header lines are dumped first. It returns 1 + * on success. Otherwise if <out> length exceeds <max>, it returns 0. */ -static int promex_dump_metric(struct appctx *appctx, struct htx *htx, struct ist prefix, - const struct promex_metric *metric, struct field *val, - struct promex_label *labels, struct ist *out, size_t max) +static int promex_dump_ts(struct appctx *appctx, struct ist prefix, + const struct ist name, const struct ist desc, enum promex_mt_type type, + struct field *val, struct promex_label *labels, struct ist *out, size_t max) { - struct ist name = { .ptr = (char[PROMEX_MAX_NAME_LEN]){ 0 }, .len = 0 }; + struct ist n = { .ptr = (char[PROMEX_MAX_NAME_LEN]){ 0 }, .len = 0 }; struct promex_ctx *ctx = appctx->svcctx; size_t len = out->len; if (out->len + PROMEX_MAX_METRIC_LENGTH > max) return 0; - /* Fill the metric name */ - istcat(&name, prefix, PROMEX_MAX_NAME_LEN); - istcat(&name, metric->n, PROMEX_MAX_NAME_LEN); + /* Fill the metric name */ + istcat(&n, prefix, PROMEX_MAX_NAME_LEN); + istcat(&n, name, PROMEX_MAX_NAME_LEN); if ((ctx->flags & PROMEX_FL_METRIC_HDR) && - !promex_dump_metric_header(appctx, htx, metric, name, out, max)) + !promex_dump_ts_header(n, desc, type, out, max)) goto full; - if (istcat(out, name, max) == -1) + if (istcat(out, n, max) == -1) goto full; if (isttest(labels[0].name)) { @@ -527,7 +496,7 @@ static int promex_dump_metric(struct appctx *appctx, struct htx *htx, struct ist if (istcat(out, ist("{"), max) == -1) goto full; - for (i = 0; isttest(labels[i].name); i++) { + for (i = 0; i < PROMEX_MAX_LABELS && isttest(labels[i].name); i++) { if (!isttest(labels[i].value)) continue; @@ -548,7 +517,7 @@ static int promex_dump_metric(struct appctx *appctx, struct htx *htx, struct ist goto full; trash.data = out->len; - if (!promex_metric_to_str(&trash, val, max)) + if (!promex_ts_val_to_str(&trash, val, max)) goto full; out->len = trash.data; @@ -561,6 +530,32 @@ static int promex_dump_metric(struct appctx *appctx, struct htx *htx, struct ist } +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. */ @@ -570,32 +565,39 @@ static int promex_dump_global_metrics(struct appctx *appctx, struct htx *htx) struct promex_ctx *ctx = appctx->svcctx; struct field val; struct channel *chn = sc_ic(appctx_sc(appctx)); - struct ist out = ist2(trash.area, 0); + struct ist name, desc, out = ist2(trash.area, 0); size_t max = htx_get_max_blksz(htx, channel_htx_recv_max(chn, htx)); int ret = 1; - if (!stats_fill_info(info, INF_TOTAL_FIELDS, 0)) + if (!stats_fill_info(stat_line_info, ST_I_INF_MAX, 0)) return -1; - for (; ctx->field_num < INF_TOTAL_FIELDS; ctx->field_num++) { + for (; ctx->field_num < ST_I_INF_MAX; ctx->field_num++) { struct promex_label labels[PROMEX_MAX_LABELS-1] = {}; if (!(promex_global_metrics[ctx->field_num].flags & ctx->flags)) continue; + name = promex_global_metrics[ctx->field_num].n; + desc = ist(stat_cols_info[ctx->field_num].desc); + + if (promex_filter_metric(appctx, prefix, name)) + continue; + switch (ctx->field_num) { - case INF_BUILD_INFO: + case ST_I_INF_BUILD_INFO: labels[0].name = ist("version"); labels[0].value = ist(HAPROXY_VERSION); val = mkf_u32(FN_GAUGE, 1); break; default: - val = info[ctx->field_num]; + val = stat_line_info[ctx->field_num]; } - if (!promex_dump_metric(appctx, htx, prefix, &promex_global_metrics[ctx->field_num], - &val, labels, &out, max)) + if (!promex_dump_ts(appctx, prefix, name, desc, + promex_global_metrics[ctx->field_num].type, + &val, labels, &out, max)) goto full; ctx->flags |= PROMEX_FL_METRIC_HDR; @@ -619,23 +621,36 @@ 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); + struct ist name, desc, 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 field *stats = stat_lines[STATS_DOMAIN_PROXY]; int ret = 1; enum promex_front_state state; - for (;ctx->field_num < ST_F_TOTAL_FIELDS; ctx->field_num++) { + for (;ctx->field_num < ST_I_PX_MAX; ctx->field_num++) { if (!(promex_st_metrics[ctx->field_num].flags & ctx->flags)) continue; - while (ctx->px) { - struct promex_label labels[PROMEX_MAX_LABELS-1] = {}; + name = promex_st_front_metrics_names[ctx->field_num]; + desc = promex_st_metric_desc[ctx->field_num]; + + if (!isttest(name)) + name = promex_st_metrics[ctx->field_num].n; + if (!isttest(desc)) + desc = ist(stat_cols_px[ctx->field_num].desc); + + if (promex_filter_metric(appctx, prefix, name)) + continue; + + 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)); @@ -644,47 +659,49 @@ static int promex_dump_front_metrics(struct appctx *appctx, struct htx *htx) if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_FE)) goto next_px; - if (!stats_fill_fe_stats(px, stats, ST_F_TOTAL_FIELDS, &(ctx->field_num))) + if (!stats_fill_fe_line(px, 0, stats, ST_I_PX_MAX, &(ctx->field_num))) return -1; switch (ctx->field_num) { - case ST_F_STATUS: + case ST_I_PX_STATUS: state = !(px->flags & PR_FL_STOPPED); for (; ctx->obj_state < PROMEX_FRONT_STATE_COUNT; ctx->obj_state++) { labels[1].name = ist("state"); labels[1].value = promex_front_st[ctx->obj_state]; val = mkf_u32(FO_STATUS, state == ctx->obj_state); - if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[ctx->field_num], - &val, labels, &out, max)) + + if (!promex_dump_ts(appctx, prefix, name, desc, + promex_st_metrics[ctx->field_num].type, + &val, labels, &out, max)) goto full; } ctx->obj_state = 0; goto next_px; - case ST_F_REQ_RATE_MAX: - case ST_F_REQ_TOT: - case ST_F_INTERCEPTED: - case ST_F_CACHE_LOOKUPS: - case ST_F_CACHE_HITS: - case ST_F_COMP_IN: - case ST_F_COMP_OUT: - case ST_F_COMP_BYP: - case ST_F_COMP_RSP: + case ST_I_PX_REQ_RATE_MAX: + case ST_I_PX_REQ_TOT: + case ST_I_PX_INTERCEPTED: + case ST_I_PX_CACHE_LOOKUPS: + case ST_I_PX_CACHE_HITS: + case ST_I_PX_COMP_IN: + case ST_I_PX_COMP_OUT: + case ST_I_PX_COMP_BYP: + case ST_I_PX_COMP_RSP: if (px->mode != PR_MODE_HTTP) goto next_px; val = stats[ctx->field_num]; break; - case ST_F_HRSP_1XX: - case ST_F_HRSP_2XX: - case ST_F_HRSP_3XX: - case ST_F_HRSP_4XX: - case ST_F_HRSP_5XX: - case ST_F_HRSP_OTHER: + case ST_I_PX_HRSP_1XX: + case ST_I_PX_HRSP_2XX: + case ST_I_PX_HRSP_3XX: + case ST_I_PX_HRSP_4XX: + case ST_I_PX_HRSP_5XX: + case ST_I_PX_HRSP_OTHER: if (px->mode != PR_MODE_HTTP) goto next_px; - if (ctx->field_num != ST_F_HRSP_1XX) + if (ctx->field_num != ST_I_PX_HRSP_1XX) ctx->flags &= ~PROMEX_FL_METRIC_HDR; labels[1].name = ist("code"); - labels[1].value = promex_hrsp_code[ctx->field_num - ST_F_HRSP_1XX]; + labels[1].value = promex_hrsp_code[ctx->field_num - ST_I_PX_HRSP_1XX]; val = stats[ctx->field_num]; break; @@ -692,22 +709,92 @@ static int promex_dump_front_metrics(struct appctx *appctx, struct htx *htx) val = stats[ctx->field_num]; } - if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[ctx->field_num], - &val, labels, &out, max)) + if (!promex_dump_ts(appctx, prefix, name, desc, + promex_st_metrics[ctx->field_num].type, + &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 (!mod) { + mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(mod), list); + ctx->mod_field_num = 0; + } + + list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) { + void *counters; + + 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 < mod->stats_count; ctx->mod_field_num++) { + 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; + + while (px) { + struct promex_label labels[PROMEX_MAX_LABELS-1] = {}; + struct promex_metric metric; + + labels[0].name = ist("proxy"); + labels[0].value = ist2(px->id, strlen(px->id)); + + labels[1].name = ist("mod"); + 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, 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_ts(appctx, prefix, name, desc, metric.type, + &val, labels, &out, max)) + goto full; + + next_px2: + px = px->next; + } + ctx->flags |= PROMEX_FL_METRIC_HDR; + } + + 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; @@ -720,24 +807,37 @@ 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); + struct ist name, desc, 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; + struct field *stats = stat_lines[STATS_DOMAIN_PROXY]; int ret = 1; enum li_status status; - for (;ctx->field_num < ST_F_TOTAL_FIELDS; ctx->field_num++) { + for (;ctx->field_num < ST_I_PX_MAX; ctx->field_num++) { if (!(promex_st_metrics[ctx->field_num].flags & ctx->flags)) continue; - while (ctx->px) { - struct promex_label labels[PROMEX_MAX_LABELS-1] = {}; + name = promex_st_li_metrics_names[ctx->field_num]; + desc = promex_st_metric_desc[ctx->field_num]; + + if (!isttest(name)) + name = promex_st_metrics[ctx->field_num].n; + if (!isttest(desc)) + desc = ist(stat_cols_px[ctx->field_num].desc); - px = ctx->px; + if (promex_filter_metric(appctx, prefix, name)) + continue; + + if (!px) + px = proxies_list; + + while (px) { + struct promex_label labels[PROMEX_MAX_LABELS-1] = {}; labels[0].name = ist("proxy"); labels[0].value = ist2(px->id, strlen(px->id)); @@ -746,28 +846,30 @@ 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; labels[1].name = ist("listener"); labels[1].value = ist2(li->name, strlen(li->name)); - if (!stats_fill_li_stats(px, li, 0, stats, - ST_F_TOTAL_FIELDS, &(ctx->field_num))) + if (!stats_fill_li_line(px, li, 0, stats, + ST_I_PX_MAX, &(ctx->field_num))) return -1; switch (ctx->field_num) { - case ST_F_STATUS: + case ST_I_PX_STATUS: status = get_li_status(li); for (; ctx->obj_state < LI_STATE_COUNT; ctx->obj_state++) { val = mkf_u32(FO_STATUS, status == ctx->obj_state); labels[2].name = ist("state"); labels[2].value = ist(li_status_st[ctx->obj_state]); - if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[ctx->field_num], - &val, labels, &out, max)) + if (!promex_dump_ts(appctx, prefix, name, desc, + promex_st_metrics[ctx->field_num].type, + &val, labels, &out, max)) goto full; } ctx->obj_state = 0; @@ -776,31 +878,110 @@ static int promex_dump_listener_metrics(struct appctx *appctx, struct htx *htx) val = stats[ctx->field_num]; } - if (!promex_dump_metric(appctx, htx, prefix, - &promex_st_metrics[ctx->field_num], - &val, labels, &out, max)) + if (!promex_dump_ts(appctx, prefix, name, desc, + promex_st_metrics[ctx->field_num].type, + &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 (!mod) { + mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(mod), list); + ctx->mod_field_num = 0; + } + + list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) { + void *counters; + + 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 < mod->stats_count; ctx->mod_field_num++) { + 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; + + while (px) { + struct promex_label labels[PROMEX_MAX_LABELS-1] = {}; + struct promex_metric metric; + + 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->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_FE)) + goto next_px2; + + 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; + + labels[1].name = ist("listener"); + labels[1].value = ist2(li->name, strlen(li->name)); + + labels[2].name = ist("mod"); + labels[2].value = ist2(mod->name, strlen(mod->name)); + + 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_ts(appctx, prefix, name, desc, metric.type, + &val, labels, &out, max)) + goto full; + } + li = NULL; + + next_px2: + px = px->next; + } + ctx->flags |= PROMEX_FL_METRIC_HDR; + } + + 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; } @@ -811,31 +992,44 @@ 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)); - struct ist out = ist2(trash.area, 0); + struct ist name, desc, 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 field *stats = stat_lines[STATS_DOMAIN_PROXY]; int ret = 1; double secs; enum promex_back_state bkd_state; enum promex_srv_state srv_state; enum healthcheck_status srv_check_status; - for (;ctx->field_num < ST_F_TOTAL_FIELDS; ctx->field_num++) { + for (;ctx->field_num < ST_I_PX_MAX; ctx->field_num++) { if (!(promex_st_metrics[ctx->field_num].flags & ctx->flags)) continue; - while (ctx->px) { + name = promex_st_back_metrics_names[ctx->field_num]; + desc = promex_st_metric_desc[ctx->field_num]; + + if (!isttest(name)) + name = promex_st_metrics[ctx->field_num].n; + if (!isttest(desc)) + desc = ist(stat_cols_px[ctx->field_num].desc); + + if (promex_filter_metric(appctx, prefix, name)) + continue; + + 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)); @@ -843,12 +1037,12 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx) if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE)) goto next_px; - if (!stats_fill_be_stats(px, 0, stats, ST_F_TOTAL_FIELDS, &(ctx->field_num))) + if (!stats_fill_be_line(px, 0, stats, ST_I_PX_MAX, &(ctx->field_num))) return -1; switch (ctx->field_num) { - case ST_F_AGG_SRV_CHECK_STATUS: // DEPRECATED - case ST_F_AGG_SRV_STATUS: + case ST_I_PX_AGG_SRV_CHECK_STATUS: // DEPRECATED + case ST_I_PX_AGG_SRV_STATUS: if (!px->srv) goto next_px; sv = px->srv; @@ -861,13 +1055,14 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx) val = mkf_u32(FN_GAUGE, srv_state_count[ctx->obj_state]); labels[1].name = ist("state"); labels[1].value = promex_srv_st[ctx->obj_state]; - if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[ctx->field_num], - &val, labels, &out, max)) + if (!promex_dump_ts(appctx, prefix, name, desc, + promex_st_metrics[ctx->field_num].type, + &val, labels, &out, max)) goto full; } ctx->obj_state = 0; goto next_px; - case ST_F_AGG_CHECK_STATUS: + case ST_I_PX_AGG_CHECK_STATUS: if (!px->srv) goto next_px; sv = px->srv; @@ -885,79 +1080,81 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx) check_state = get_check_status_info(ctx->obj_state); labels[1].name = ist("state"); labels[1].value = ist(check_state); - if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[ctx->field_num], - &val, labels, &out, max)) + if (!promex_dump_ts(appctx, prefix, name, desc, + promex_st_metrics[ctx->field_num].type, + &val, labels, &out, max)) goto full; } ctx->obj_state = 0; goto next_px; - case ST_F_STATUS: + case ST_I_PX_STATUS: bkd_state = ((px->lbprm.tot_weight > 0 || !px->srv) ? 1 : 0); for (; ctx->obj_state < PROMEX_BACK_STATE_COUNT; ctx->obj_state++) { labels[1].name = ist("state"); labels[1].value = promex_back_st[ctx->obj_state]; val = mkf_u32(FO_STATUS, bkd_state == ctx->obj_state); - if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[ctx->field_num], - &val, labels, &out, max)) + if (!promex_dump_ts(appctx, prefix, name, desc, + promex_st_metrics[ctx->field_num].type, + &val, labels, &out, max)) goto full; } ctx->obj_state = 0; goto next_px; - case ST_F_QTIME: + case ST_I_PX_QTIME: secs = (double)swrate_avg(px->be_counters.q_time, TIME_STATS_SAMPLES) / 1000.0; val = mkf_flt(FN_AVG, secs); break; - case ST_F_CTIME: + case ST_I_PX_CTIME: secs = (double)swrate_avg(px->be_counters.c_time, TIME_STATS_SAMPLES) / 1000.0; val = mkf_flt(FN_AVG, secs); break; - case ST_F_RTIME: + case ST_I_PX_RTIME: secs = (double)swrate_avg(px->be_counters.d_time, TIME_STATS_SAMPLES) / 1000.0; val = mkf_flt(FN_AVG, secs); break; - case ST_F_TTIME: + case ST_I_PX_TTIME: secs = (double)swrate_avg(px->be_counters.t_time, TIME_STATS_SAMPLES) / 1000.0; val = mkf_flt(FN_AVG, secs); break; - case ST_F_QT_MAX: + case ST_I_PX_QT_MAX: secs = (double)px->be_counters.qtime_max / 1000.0; val = mkf_flt(FN_MAX, secs); break; - case ST_F_CT_MAX: + case ST_I_PX_CT_MAX: secs = (double)px->be_counters.ctime_max / 1000.0; val = mkf_flt(FN_MAX, secs); break; - case ST_F_RT_MAX: + case ST_I_PX_RT_MAX: secs = (double)px->be_counters.dtime_max / 1000.0; val = mkf_flt(FN_MAX, secs); break; - case ST_F_TT_MAX: + case ST_I_PX_TT_MAX: secs = (double)px->be_counters.ttime_max / 1000.0; val = mkf_flt(FN_MAX, secs); break; - case ST_F_REQ_TOT: - case ST_F_CACHE_LOOKUPS: - case ST_F_CACHE_HITS: - case ST_F_COMP_IN: - case ST_F_COMP_OUT: - case ST_F_COMP_BYP: - case ST_F_COMP_RSP: + case ST_I_PX_REQ_TOT: + case ST_I_PX_CACHE_LOOKUPS: + case ST_I_PX_CACHE_HITS: + case ST_I_PX_COMP_IN: + case ST_I_PX_COMP_OUT: + case ST_I_PX_COMP_BYP: + case ST_I_PX_COMP_RSP: if (px->mode != PR_MODE_HTTP) goto next_px; val = stats[ctx->field_num]; break; - case ST_F_HRSP_1XX: - case ST_F_HRSP_2XX: - case ST_F_HRSP_3XX: - case ST_F_HRSP_4XX: - case ST_F_HRSP_5XX: - case ST_F_HRSP_OTHER: + case ST_I_PX_HRSP_1XX: + case ST_I_PX_HRSP_2XX: + case ST_I_PX_HRSP_3XX: + case ST_I_PX_HRSP_4XX: + case ST_I_PX_HRSP_5XX: + case ST_I_PX_HRSP_OTHER: if (px->mode != PR_MODE_HTTP) goto next_px; - if (ctx->field_num != ST_F_HRSP_1XX) + if (ctx->field_num != ST_I_PX_HRSP_1XX) ctx->flags &= ~PROMEX_FL_METRIC_HDR; labels[1].name = ist("code"); - labels[1].value = promex_hrsp_code[ctx->field_num - ST_F_HRSP_1XX]; + labels[1].value = promex_hrsp_code[ctx->field_num - ST_I_PX_HRSP_1XX]; val = stats[ctx->field_num]; break; @@ -965,22 +1162,91 @@ static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx) val = stats[ctx->field_num]; } - if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[ctx->field_num], - &val, labels, &out, max)) + if (!promex_dump_ts(appctx, prefix, name, desc, + promex_st_metrics[ctx->field_num].type, + &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 (!mod) { + mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(mod), list); + ctx->mod_field_num = 0; + } + + list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) { + void *counters; + + 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 < mod->stats_count; ctx->mod_field_num++) { + 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; + + while (px) { + struct promex_label labels[PROMEX_MAX_LABELS-1] = {}; + struct promex_metric metric; + + labels[0].name = ist("proxy"); + labels[0].value = ist2(px->id, strlen(px->id)); + + labels[1].name = ist("mod"); + 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, 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_ts(appctx, prefix, name, desc, metric.type, + &val, labels, &out, max)) + goto full; + + next_px2: + px = px->next; + } + ctx->flags |= PROMEX_FL_METRIC_HDR; + } + + 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; @@ -993,26 +1259,39 @@ 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); + struct ist name, desc, 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 field *stats = stat_lines[STATS_DOMAIN_PROXY]; int ret = 1; double secs; enum promex_srv_state state; const char *check_state; - for (;ctx->field_num < ST_F_TOTAL_FIELDS; ctx->field_num++) { + for (;ctx->field_num < ST_I_PX_MAX; ctx->field_num++) { if (!(promex_st_metrics[ctx->field_num].flags & ctx->flags)) continue; - while (ctx->px) { - struct promex_label labels[PROMEX_MAX_LABELS-1] = {}; + name = promex_st_srv_metrics_names[ctx->field_num]; + desc = promex_st_metric_desc[ctx->field_num]; + + if (!isttest(name)) + name = promex_st_metrics[ctx->field_num].n; + if (!isttest(desc)) + desc = ist(stat_cols_px[ctx->field_num].desc); + + if (promex_filter_metric(appctx, prefix, name)) + continue; - px = ctx->px; + if (!px) + px = proxies_list; + + while (px) { + struct promex_label labels[PROMEX_MAX_LABELS-1] = {}; labels[0].name = ist("proxy"); labels[0].value = ist2(px->id, strlen(px->id)); @@ -1021,64 +1300,66 @@ 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)); - if (!stats_fill_sv_stats(px, sv, 0, stats, ST_F_TOTAL_FIELDS, &(ctx->field_num))) + if (!stats_fill_sv_line(px, sv, 0, stats, ST_I_PX_MAX, &(ctx->field_num))) return -1; if ((ctx->flags & PROMEX_FL_NO_MAINT_SRV) && (sv->cur_admin & SRV_ADMF_MAINT)) goto next_sv; switch (ctx->field_num) { - case ST_F_STATUS: + case ST_I_PX_STATUS: state = promex_srv_status(sv); for (; ctx->obj_state < PROMEX_SRV_STATE_COUNT; ctx->obj_state++) { val = mkf_u32(FO_STATUS, state == ctx->obj_state); labels[2].name = ist("state"); labels[2].value = promex_srv_st[ctx->obj_state]; - if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[ctx->field_num], - &val, labels, &out, max)) + if (!promex_dump_ts(appctx, prefix, name, desc, + promex_st_metrics[ctx->field_num].type, + &val, labels, &out, max)) goto full; } ctx->obj_state = 0; goto next_sv; - case ST_F_QTIME: + case ST_I_PX_QTIME: secs = (double)swrate_avg(sv->counters.q_time, TIME_STATS_SAMPLES) / 1000.0; val = mkf_flt(FN_AVG, secs); break; - case ST_F_CTIME: + case ST_I_PX_CTIME: secs = (double)swrate_avg(sv->counters.c_time, TIME_STATS_SAMPLES) / 1000.0; val = mkf_flt(FN_AVG, secs); break; - case ST_F_RTIME: + case ST_I_PX_RTIME: secs = (double)swrate_avg(sv->counters.d_time, TIME_STATS_SAMPLES) / 1000.0; val = mkf_flt(FN_AVG, secs); break; - case ST_F_TTIME: + case ST_I_PX_TTIME: secs = (double)swrate_avg(sv->counters.t_time, TIME_STATS_SAMPLES) / 1000.0; val = mkf_flt(FN_AVG, secs); break; - case ST_F_QT_MAX: + case ST_I_PX_QT_MAX: secs = (double)sv->counters.qtime_max / 1000.0; val = mkf_flt(FN_MAX, secs); break; - case ST_F_CT_MAX: + case ST_I_PX_CT_MAX: secs = (double)sv->counters.ctime_max / 1000.0; val = mkf_flt(FN_MAX, secs); break; - case ST_F_RT_MAX: + case ST_I_PX_RT_MAX: secs = (double)sv->counters.dtime_max / 1000.0; val = mkf_flt(FN_MAX, secs); break; - case ST_F_TT_MAX: + case ST_I_PX_TT_MAX: secs = (double)sv->counters.ttime_max / 1000.0; val = mkf_flt(FN_MAX, secs); break; - case ST_F_CHECK_STATUS: + case ST_I_PX_CHECK_STATUS: if ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) != CHK_ST_ENABLED) goto next_sv; @@ -1089,40 +1370,45 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx) check_state = get_check_status_info(ctx->obj_state); labels[2].name = ist("state"); labels[2].value = ist(check_state); - if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[ctx->field_num], - &val, labels, &out, max)) + if (!promex_dump_ts(appctx, prefix, name, desc, + promex_st_metrics[ctx->field_num].type, + &val, labels, &out, max)) goto full; } ctx->obj_state = 0; goto next_sv; - case ST_F_CHECK_CODE: + case ST_I_PX_CHECK_CODE: if ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) != CHK_ST_ENABLED) goto next_sv; val = mkf_u32(FN_OUTPUT, (sv->check.status < HCHK_STATUS_L57DATA) ? 0 : sv->check.code); break; - case ST_F_CHECK_DURATION: + case ST_I_PX_CHECK_DURATION: if (sv->check.status < HCHK_STATUS_CHECKED) goto next_sv; secs = (double)sv->check.duration / 1000.0; val = mkf_flt(FN_DURATION, secs); break; - case ST_F_REQ_TOT: - if (px->mode != PR_MODE_HTTP) + case ST_I_PX_REQ_TOT: + if (px->mode != PR_MODE_HTTP) { + sv = NULL; goto next_px; + } val = stats[ctx->field_num]; break; - case ST_F_HRSP_1XX: - case ST_F_HRSP_2XX: - case ST_F_HRSP_3XX: - case ST_F_HRSP_4XX: - case ST_F_HRSP_5XX: - case ST_F_HRSP_OTHER: - if (px->mode != PR_MODE_HTTP) + case ST_I_PX_HRSP_1XX: + case ST_I_PX_HRSP_2XX: + case ST_I_PX_HRSP_3XX: + case ST_I_PX_HRSP_4XX: + case ST_I_PX_HRSP_5XX: + case ST_I_PX_HRSP_OTHER: + if (px->mode != PR_MODE_HTTP) { + sv = NULL; goto next_px; - if (ctx->field_num != ST_F_HRSP_1XX) + } + if (ctx->field_num != ST_I_PX_HRSP_1XX) ctx->flags &= ~PROMEX_FL_METRIC_HDR; labels[2].name = ist("code"); - labels[2].value = promex_hrsp_code[ctx->field_num - ST_F_HRSP_1XX]; + labels[2].value = promex_hrsp_code[ctx->field_num - ST_I_PX_HRSP_1XX]; val = stats[ctx->field_num]; break; @@ -1130,22 +1416,101 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx) val = stats[ctx->field_num]; } - if (!promex_dump_metric(appctx, htx, prefix, &promex_st_metrics[ctx->field_num], - &val, labels, &out, max)) + if (!promex_dump_ts(appctx, prefix, name, desc, + promex_st_metrics[ctx->field_num].type, + &val, labels, &out, max)) goto full; next_sv: - promex_set_ctx_sv(ctx, sv->next); + sv = sv->next; } next_px: - ctx->px = px->next; - promex_set_ctx_sv(ctx, ctx->px ? ctx->px->srv : NULL); + px = px->next; } ctx->flags |= PROMEX_FL_METRIC_HDR; - ctx->px = proxies_list; - promex_set_ctx_sv(ctx, ctx->px ? ctx->px->srv : NULL); } + /* Skip extra counters */ + if (!(ctx->flags & PROMEX_FL_EXTRA_COUNTERS)) + goto end; + + if (!mod) { + mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(mod), list); + ctx->mod_field_num = 0; + } + + list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) { + void *counters; + + 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 < mod->stats_count; ctx->mod_field_num++) { + 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; + + while (px) { + struct promex_label labels[PROMEX_MAX_LABELS-1] = {}; + struct promex_metric metric; + + 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->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE)) + goto next_px2; + + 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(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, 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_ts(appctx, prefix, name, desc, metric.type, + &val, labels, &out, max)) + goto full; + + next_sv2: + sv = sv->next; + } + + next_px2: + px = px->next; + } + ctx->flags |= PROMEX_FL_METRIC_HDR; + } + + ctx->field_num += mod->stats_count; + ctx->mod_field_num = 0; + } + + px = NULL; + sv = NULL; + mod = NULL; end: if (out.len) { @@ -1153,62 +1518,162 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx) return -1; /* Unexpected and unrecoverable error */ channel_add_input(chn, out.len); } + + /* Decrement server refcount if it was saved through ctx.p[1]. */ + srv_drop(ctx->p[1]); + if (sv) + srv_take(sv); + + /* 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; 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) +/* Dump metrics of module <mod>. It returns 1 on success, 0 if <out> is full and + * -1 on error. */ +static int promex_dump_module_metrics(struct appctx *appctx, struct promex_module *mod, + struct ist *out, size_t max) { - static struct ist prefix = IST("haproxy_sticktable_"); + struct ist prefix = { .ptr = (char[PROMEX_MAX_NAME_LEN]){ 0 }, .len = 0 }; struct promex_ctx *ctx = appctx->svcctx; - 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)) + istcat(&prefix, ist("haproxy_"), PROMEX_MAX_NAME_LEN); + istcat(&prefix, mod->name, PROMEX_MAX_NAME_LEN); + istcat(&prefix, ist("_"), PROMEX_MAX_NAME_LEN); + + if (!ctx->p[1] && mod->start_metrics_dump) { + ctx->p[1] = mod->start_metrics_dump(); + if (!ctx->p[1]) + goto end; + } + + for (; ctx->mod_field_num < mod->nb_metrics; ctx->mod_field_num++) { + 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; - while (ctx->st) { - struct promex_label labels[PROMEX_MAX_LABELS - 1] = {}; + if (promex_filter_metric(appctx, prefix, metric.n)) + continue; - t = ctx->st; - if (!t->size) - goto next_px; + if (!ctx->p[2]) + ctx->p[2] = mod->start_ts(ctx->p[1], ctx->mod_field_num); - 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 (ctx->field_num) { - 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; - } + while (ctx->p[2]) { + struct promex_label labels[PROMEX_MAX_LABELS - 1] = {}; + struct field val; + + ret = mod->fill_ts(ctx->p[1], ctx->p[2], ctx->mod_field_num, labels, &val); + if (!ret) + continue; + if (ret < 0) + goto error; - if (!promex_dump_metric(appctx, htx, prefix, - &promex_sticktable_metrics[ctx->field_num], - &val, labels, &out, max)) + if (!promex_dump_ts(appctx, prefix, metric.n, desc, metric.type, + &val, labels, out, max)) goto full; - next_px: - ctx->st = t->next; + next: + ctx->p[2] = mod->next_ts(ctx->p[1], ctx->p[2], ctx->mod_field_num); } ctx->flags |= PROMEX_FL_METRIC_HDR; - ctx->st = stktables_list; } + ret = 1; + + end: + if (ctx->p[1] && mod->stop_metrics_dump) + mod->stop_metrics_dump(ctx->p[1]); + ctx->p[1] = NULL; + ctx->p[2] = NULL; + return ret; + + full: + return 0; + error: + ret = -1; + goto end; + +} + +/* Dump metrics of referenced modules. It returns 1 on success, 0 if <htx> is + * full and -1 in case of any error. */ +static int promex_dump_ref_modules_metrics(struct appctx *appctx, struct htx *htx) +{ + struct promex_ctx *ctx = appctx->svcctx; + struct promex_module_ref *ref = ctx->p[0]; + 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; + + if (!ref) { + ref = LIST_NEXT(&ctx->modules, typeof(ref), list); + ctx->mod_field_num = 0; + } + + list_for_each_entry_from(ref, &ctx->modules, list) { + ret = promex_dump_module_metrics(appctx, ref->mod, &out, max); + if (ret <= 0) { + if (ret == -1) + return -1; + goto full; + } + ctx->mod_field_num = 0; + } + + ref = NULL; + + end: + if (out.len) { + if (!htx_add_data_atonce(htx, out)) + return -1; /* Unexpected and unrecoverable error */ + channel_add_input(chn, out.len); + } + ctx->p[0] = ref; + return ret; + full: + ret = 0; + goto end; +} + +/* Dump metrics of all registered modules. It returns 1 on success, 0 if <htx> is + * full and -1 in case of any error. */ +static int promex_dump_all_modules_metrics(struct appctx *appctx, struct htx *htx) +{ + struct promex_ctx *ctx = appctx->svcctx; + struct promex_module *mod = ctx->p[0]; + 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; + + if (!mod) { + mod = LIST_NEXT(&promex_module_list, typeof(mod), list); + ctx->mod_field_num = 0; + } + + list_for_each_entry_from(mod, &promex_module_list, list) { + ret = promex_dump_module_metrics(appctx, mod, &out, max); + if (ret <= 0) { + if (ret == -1) + return -1; + goto full; + } + ctx->mod_field_num = 0; + } + + mod = NULL; end: if (out.len) { @@ -1216,6 +1681,7 @@ static int promex_dump_sticktable_metrics(struct appctx *appctx, struct htx *htx return -1; /* Unexpected and unrecoverable error */ channel_add_input(chn, out.len); } + ctx->p[0] = mod; return ret; full: ret = 0; @@ -1235,13 +1701,9 @@ 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; - promex_set_ctx_sv(ctx, NULL); ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_INFO_METRIC); ctx->obj_state = 0; - ctx->field_num = INF_NAME; + ctx->field_num = ST_I_INF_NAME; appctx->st1 = PROMEX_DUMPER_GLOBAL; __fallthrough; @@ -1255,14 +1717,11 @@ static int promex_dump_metrics(struct appctx *appctx, struct stconn *sc, struct } } - ctx->px = proxies_list; - ctx->st = NULL; - ctx->li = NULL; - promex_set_ctx_sv(ctx, NULL); ctx->flags &= ~PROMEX_FL_INFO_METRIC; ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_FRONT_METRIC); ctx->obj_state = 0; - ctx->field_num = ST_F_PXNAME; + ctx->field_num = ST_I_PX_PXNAME; + ctx->mod_field_num = 0; appctx->st1 = PROMEX_DUMPER_FRONT; __fallthrough; @@ -1276,14 +1735,11 @@ 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); - promex_set_ctx_sv(ctx, NULL); ctx->flags &= ~PROMEX_FL_FRONT_METRIC; ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_LI_METRIC); ctx->obj_state = 0; - ctx->field_num = ST_F_PXNAME; + ctx->field_num = ST_I_PX_PXNAME; + ctx->mod_field_num = 0; appctx->st1 = PROMEX_DUMPER_LI; __fallthrough; @@ -1297,14 +1753,11 @@ static int promex_dump_metrics(struct appctx *appctx, struct stconn *sc, struct } } - ctx->px = proxies_list; - ctx->st = NULL; - ctx->li = NULL; - promex_set_ctx_sv(ctx, NULL); ctx->flags &= ~PROMEX_FL_LI_METRIC; ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_BACK_METRIC); ctx->obj_state = 0; - ctx->field_num = ST_F_PXNAME; + ctx->field_num = ST_I_PX_PXNAME; + ctx->mod_field_num = 0; appctx->st1 = PROMEX_DUMPER_BACK; __fallthrough; @@ -1318,14 +1771,11 @@ static int promex_dump_metrics(struct appctx *appctx, struct stconn *sc, struct } } - ctx->px = proxies_list; - ctx->st = NULL; - ctx->li = NULL; - promex_set_ctx_sv(ctx, ctx->px ? ctx->px->srv : NULL); ctx->flags &= ~PROMEX_FL_BACK_METRIC; ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_SRV_METRIC); ctx->obj_state = 0; - ctx->field_num = ST_F_PXNAME; + ctx->field_num = ST_I_PX_PXNAME; + ctx->mod_field_num = 0; appctx->st1 = PROMEX_DUMPER_SRV; __fallthrough; @@ -1339,19 +1789,19 @@ static int promex_dump_metrics(struct appctx *appctx, struct stconn *sc, struct } } - ctx->px = NULL; - ctx->st = stktables_list; - ctx->li = NULL; - promex_set_ctx_sv(ctx, 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; - appctx->st1 = PROMEX_DUMPER_STICKTABLE; + ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_MODULE_METRIC); + ctx->field_num = 0; + ctx->mod_field_num = 0; + appctx->st1 = PROMEX_DUMPER_MODULES; __fallthrough; - case PROMEX_DUMPER_STICKTABLE: - if (ctx->flags & PROMEX_FL_SCOPE_STICKTABLE) { - ret = promex_dump_sticktable_metrics(appctx, htx); + case PROMEX_DUMPER_MODULES: + if (ctx->flags & PROMEX_FL_SCOPE_MODULE) { + if (LIST_ISEMPTY(&ctx->modules)) + ret = promex_dump_all_modules_metrics(appctx, htx); + else + ret = promex_dump_ref_modules_metrics(appctx, htx); if (ret <= 0) { if (ret == -1) goto error; @@ -1359,12 +1809,9 @@ static int promex_dump_metrics(struct appctx *appctx, struct stconn *sc, struct } } - ctx->px = NULL; - ctx->st = NULL; - ctx->li = NULL; - promex_set_ctx_sv(ctx, NULL); - ctx->flags &= ~(PROMEX_FL_METRIC_HDR|PROMEX_FL_STICKTABLE_METRIC); + ctx->flags &= ~(PROMEX_FL_METRIC_HDR|PROMEX_FL_MODULE_METRIC); ctx->field_num = 0; + ctx->mod_field_num = 0; appctx->st1 = PROMEX_DUMPER_DONE; __fallthrough; @@ -1380,12 +1827,9 @@ 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; - promex_set_ctx_sv(ctx, NULL); ctx->flags = 0; ctx->field_num = 0; + ctx->mod_field_num = 0; appctx->st1 = PROMEX_DUMPER_DONE; return -1; } @@ -1403,6 +1847,7 @@ static int promex_parse_uri(struct appctx *appctx, struct stconn *sc) 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 */ @@ -1465,7 +1910,7 @@ static int promex_parse_uri(struct appctx *appctx, struct stconn *sc) 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; @@ -1477,17 +1922,76 @@ static int promex_parse_uri(struct appctx *appctx, struct stconn *sc) ctx->flags |= PROMEX_FL_SCOPE_FRONT; else if (strcmp(value, "listener") == 0) ctx->flags |= PROMEX_FL_SCOPE_LI; - else if (strcmp(value, "sticktable") == 0) - ctx->flags |= PROMEX_FL_SCOPE_STICKTABLE; - else + else { + struct promex_module *mod; + struct promex_module_ref *ref; + + list_for_each_entry(mod, &promex_module_list, list) { + if (strncmp(value, istptr(mod->name), istlen(mod->name)) == 0) { + ref = pool_alloc(pool_head_promex_mod_ref); + if (!ref) + goto internal_error; + ctx->flags |= PROMEX_FL_SCOPE_MODULE; + ref->mod = mod; + LIST_APPEND(&ctx->modules, &ref->list); + break; + } + } + if (!(ctx->flags & PROMEX_FL_SCOPE_MODULE)) + 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; } else if (strcmp(key, "no-maint") == 0) ctx->flags |= PROMEX_FL_NO_MAINT_SRV; } end: - ctx->flags |= default_scopes; + ctx->flags |= (default_scopes | default_metrics_filter); return 1; error: @@ -1498,6 +2002,15 @@ static int promex_parse_uri(struct appctx *appctx, struct stconn *sc) res_htx = htx_from_buf(&res->buf); channel_add_input(res, res_htx->data); return -1; + + internal_error: + err = &http_err_chunks[HTTP_ERR_400]; + channel_erase(res); + res->buf.data = b_data(err); + memcpy(res->buf.area, b_head(err), b_data(err)); + res_htx = htx_from_buf(&res->buf); + channel_add_input(res, res_htx->data); + return -1; } /* Send HTTP headers of the response. It returns 1 on success and 0 if <htx> is @@ -1533,19 +2046,45 @@ static int promex_send_headers(struct appctx *appctx, struct stconn *sc, struct */ static int promex_appctx_init(struct appctx *appctx) { + struct promex_ctx *ctx; + applet_reserve_svcctx(appctx, sizeof(struct promex_ctx)); + 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; } + /* Callback function that releases a promex applet. This happens when the * connection with the agent is closed. */ static void promex_appctx_release(struct appctx *appctx) { struct promex_ctx *ctx = appctx->svcctx; + struct promex_module_ref *ref, *back; + struct promex_metric_filter *flt; + struct eb32_node *node, *next; - if (appctx->st1 == PROMEX_DUMPER_SRV) - srv_drop(ctx->sv); + if (appctx->st1 == PROMEX_DUMPER_SRV) { + struct server *srv = objt_server(ctx->p[1]); + srv_drop(srv); + } + + 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. */ @@ -1639,8 +2178,8 @@ struct applet promex_applet = { .obj_type = OBJ_TYPE_APPLET, .name = "<PROMEX>", /* used for logging */ .init = promex_appctx_init, - .fct = promex_appctx_handle_io, .release = promex_appctx_release, + .fct = promex_appctx_handle_io, }; static enum act_parse_ret service_parse_prometheus_exporter(const char **args, int *cur_arg, struct proxy *px, |