2019-02-07 14:38:42 +00:00
|
|
|
/*
|
|
|
|
* Promex is a Prometheus exporter for HAProxy
|
|
|
|
*
|
|
|
|
* It is highly inspired by the official Prometheus exporter.
|
|
|
|
* See: https://github.com/prometheus/haproxy_exporter
|
|
|
|
*
|
|
|
|
* Copyright 2019 Christopher Faulet <cfaulet@haproxy.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2020-06-04 08:15:32 +00:00
|
|
|
#include <haproxy/action-t.h>
|
2020-06-09 07:07:15 +00:00
|
|
|
#include <haproxy/api.h>
|
2020-06-04 17:42:41 +00:00
|
|
|
#include <haproxy/applet.h>
|
2020-06-04 20:50:02 +00:00
|
|
|
#include <haproxy/backend.h>
|
2020-06-04 22:00:29 +00:00
|
|
|
#include <haproxy/cfgparse.h>
|
2021-02-01 12:11:51 +00:00
|
|
|
#include <haproxy/check.h>
|
2020-06-04 09:23:07 +00:00
|
|
|
#include <haproxy/frontend.h>
|
2020-06-04 15:05:57 +00:00
|
|
|
#include <haproxy/global.h>
|
2020-06-02 17:11:26 +00:00
|
|
|
#include <haproxy/http.h>
|
2021-10-06 16:56:42 +00:00
|
|
|
#include <haproxy/http_ana.h>
|
2020-06-04 07:08:41 +00:00
|
|
|
#include <haproxy/http_htx.h>
|
2020-06-03 06:44:35 +00:00
|
|
|
#include <haproxy/htx.h>
|
2020-06-05 15:27:29 +00:00
|
|
|
#include <haproxy/list.h>
|
2020-06-04 12:58:24 +00:00
|
|
|
#include <haproxy/listener.h>
|
2020-06-05 15:27:29 +00:00
|
|
|
#include <haproxy/log.h>
|
2024-01-30 14:58:31 +00:00
|
|
|
#include <haproxy/pool.h>
|
2020-06-04 20:29:18 +00:00
|
|
|
#include <haproxy/proxy.h>
|
2020-06-04 13:33:47 +00:00
|
|
|
#include <haproxy/sample.h>
|
2022-05-27 07:25:10 +00:00
|
|
|
#include <haproxy/sc_strm.h>
|
2020-06-04 21:20:13 +00:00
|
|
|
#include <haproxy/server.h>
|
2020-06-04 17:58:55 +00:00
|
|
|
#include <haproxy/stats.h>
|
2022-05-27 07:47:12 +00:00
|
|
|
#include <haproxy/stconn.h>
|
2020-06-04 21:46:14 +00:00
|
|
|
#include <haproxy/stream.h>
|
2020-06-04 15:25:40 +00:00
|
|
|
#include <haproxy/task.h>
|
2021-05-08 10:58:12 +00:00
|
|
|
#include <haproxy/tools.h>
|
2021-01-08 12:18:06 +00:00
|
|
|
#include <haproxy/version.h>
|
2024-01-31 16:15:49 +00:00
|
|
|
#include <haproxy/xxhash.h>
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2024-01-30 06:34:54 +00:00
|
|
|
#include <promex/promex.h>
|
|
|
|
|
2019-02-07 14:38:42 +00:00
|
|
|
/* Prometheus exporter applet states (appctx->st0) */
|
|
|
|
enum {
|
|
|
|
PROMEX_ST_INIT = 0, /* initialized */
|
|
|
|
PROMEX_ST_HEAD, /* send headers before dump */
|
|
|
|
PROMEX_ST_DUMP, /* dumping stats */
|
|
|
|
PROMEX_ST_DONE, /* finished */
|
2019-03-27 14:48:53 +00:00
|
|
|
PROMEX_ST_END, /* treatment terminated */
|
2019-02-07 14:38:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Prometheus exporter dumper states (appctx->st1) */
|
|
|
|
enum {
|
2021-02-07 19:42:38 +00:00
|
|
|
PROMEX_DUMPER_INIT = 0, /* initialized */
|
|
|
|
PROMEX_DUMPER_GLOBAL, /* dump metrics of globals */
|
|
|
|
PROMEX_DUMPER_FRONT, /* dump metrics of frontend proxies */
|
|
|
|
PROMEX_DUMPER_BACK, /* dump metrics of backend proxies */
|
|
|
|
PROMEX_DUMPER_LI, /* dump metrics of listeners */
|
|
|
|
PROMEX_DUMPER_SRV, /* dump metrics of servers */
|
2024-01-31 09:33:55 +00:00
|
|
|
PROMEX_DUMPER_MODULES, /* dump metrics of modules */
|
2021-02-07 19:42:38 +00:00
|
|
|
PROMEX_DUMPER_DONE, /* finished */
|
2019-02-07 14:38:42 +00:00
|
|
|
};
|
|
|
|
|
2024-01-30 14:58:31 +00:00
|
|
|
struct promex_module_ref {
|
|
|
|
struct promex_module *mod;
|
|
|
|
struct list list;
|
|
|
|
};
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2024-01-31 16:15:49 +00:00
|
|
|
/* An entry in a headers map */
|
|
|
|
struct promex_metric_filter {
|
|
|
|
int exclude;
|
|
|
|
struct eb32_node node;
|
|
|
|
};
|
|
|
|
|
2022-05-03 15:33:00 +00:00
|
|
|
/* the context of the applet */
|
|
|
|
struct promex_ctx {
|
2024-01-30 13:36:07 +00:00
|
|
|
void *p[4]; /* generic pointers used to save context */
|
2022-05-03 15:33:00 +00:00
|
|
|
unsigned int flags; /* PROMEX_FL_* */
|
2024-04-19 16:03:45 +00:00
|
|
|
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) */
|
2022-05-03 15:33:00 +00:00
|
|
|
int obj_state; /* current state among PROMEX_{FRONT|BACK|SRV|LI}_STATE_* */
|
2024-01-30 14:58:31 +00:00
|
|
|
struct list modules; /* list of promex modules to export */
|
2024-01-31 16:15:49 +00:00
|
|
|
struct eb_root filters; /* list of filters to apply on metrics name */
|
2022-05-03 15:33:00 +00:00
|
|
|
};
|
|
|
|
|
2019-02-07 14:38:42 +00:00
|
|
|
/* The max length for metrics name. It is a hard limit but it should be
|
2020-03-23 17:28:40 +00:00
|
|
|
* enough.
|
2019-02-07 14:38:42 +00:00
|
|
|
*/
|
|
|
|
#define PROMEX_MAX_NAME_LEN 128
|
|
|
|
|
|
|
|
/* The expected max length for a metric dump, including its header lines. It is
|
|
|
|
* just a soft limit to avoid extra work. We don't try to dump a metric if less
|
|
|
|
* than this size is available in the HTX.
|
|
|
|
*/
|
|
|
|
#define PROMEX_MAX_METRIC_LENGTH 512
|
|
|
|
|
2021-01-20 14:20:53 +00:00
|
|
|
/* Global metrics */
|
2024-04-22 07:41:15 +00:00
|
|
|
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 },
|
2019-02-07 14:38:42 +00:00
|
|
|
};
|
|
|
|
|
2021-01-20 14:20:53 +00:00
|
|
|
/* frontend/backend/server fields */
|
2024-04-19 16:03:45 +00:00
|
|
|
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 ) },
|
2019-02-07 14:38:42 +00:00
|
|
|
};
|
|
|
|
|
2023-12-04 08:00:18 +00:00
|
|
|
/* Specialized frontend metric names, to override default ones */
|
2024-04-19 16:03:45 +00:00
|
|
|
const struct ist promex_st_front_metrics_names[ST_I_PX_MAX] = {
|
2023-12-04 08:00:18 +00:00
|
|
|
};
|
|
|
|
|
2023-12-29 19:05:20 +00:00
|
|
|
/* Specialized backend metric names, to override default ones */
|
2024-04-19 16:03:45 +00:00
|
|
|
const struct ist promex_st_back_metrics_names[ST_I_PX_MAX] = {
|
2023-12-04 08:00:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Specialized listener metric names, to override default ones */
|
2024-04-19 16:03:45 +00:00
|
|
|
const struct ist promex_st_li_metrics_names[ST_I_PX_MAX] = {
|
2023-12-04 08:00:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Specialized server metric names, to override default ones */
|
2024-04-19 16:03:45 +00:00
|
|
|
const struct ist promex_st_srv_metrics_names[ST_I_PX_MAX] = {
|
|
|
|
[ST_I_PX_ACT] = IST("active"),
|
|
|
|
[ST_I_PX_BCK] = IST("backup"),
|
2023-12-04 08:00:18 +00:00
|
|
|
};
|
|
|
|
|
2021-02-06 17:29:08 +00:00
|
|
|
/* Description of overridden stats fields */
|
2024-04-19 16:03:45 +00:00
|
|
|
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)"),
|
2019-02-07 14:38:42 +00:00
|
|
|
};
|
|
|
|
|
2024-04-19 16:03:45 +00:00
|
|
|
/* 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"),
|
2019-02-07 14:38:42 +00:00
|
|
|
};
|
|
|
|
|
2021-01-27 21:40:16 +00:00
|
|
|
enum promex_front_state {
|
|
|
|
PROMEX_FRONT_STATE_DOWN = 0,
|
|
|
|
PROMEX_FRONT_STATE_UP,
|
|
|
|
|
|
|
|
PROMEX_FRONT_STATE_COUNT /* must be last */
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct ist promex_front_st[PROMEX_FRONT_STATE_COUNT] = {
|
|
|
|
[PROMEX_FRONT_STATE_DOWN] = IST("DOWN"),
|
|
|
|
[PROMEX_FRONT_STATE_UP] = IST("UP"),
|
|
|
|
};
|
|
|
|
|
|
|
|
enum promex_back_state {
|
|
|
|
PROMEX_BACK_STATE_DOWN = 0,
|
|
|
|
PROMEX_BACK_STATE_UP,
|
|
|
|
|
|
|
|
PROMEX_BACK_STATE_COUNT /* must be last */
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct ist promex_back_st[PROMEX_BACK_STATE_COUNT] = {
|
|
|
|
[PROMEX_BACK_STATE_DOWN] = IST("DOWN"),
|
|
|
|
[PROMEX_BACK_STATE_UP] = IST("UP"),
|
|
|
|
};
|
|
|
|
|
|
|
|
enum promex_srv_state {
|
|
|
|
PROMEX_SRV_STATE_DOWN = 0,
|
|
|
|
PROMEX_SRV_STATE_UP,
|
|
|
|
PROMEX_SRV_STATE_MAINT,
|
|
|
|
PROMEX_SRV_STATE_DRAIN,
|
|
|
|
PROMEX_SRV_STATE_NOLB,
|
|
|
|
|
|
|
|
PROMEX_SRV_STATE_COUNT /* must be last */
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct ist promex_srv_st[PROMEX_SRV_STATE_COUNT] = {
|
|
|
|
[PROMEX_SRV_STATE_DOWN] = IST("DOWN"),
|
|
|
|
[PROMEX_SRV_STATE_UP] = IST("UP"),
|
|
|
|
[PROMEX_SRV_STATE_MAINT] = IST("MAINT"),
|
|
|
|
[PROMEX_SRV_STATE_DRAIN] = IST("DRAIN"),
|
|
|
|
[PROMEX_SRV_STATE_NOLB] = IST("NOLB"),
|
|
|
|
};
|
|
|
|
|
2024-01-30 06:34:54 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2024-01-31 16:15:49 +00:00
|
|
|
/* 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));
|
2024-01-30 14:58:31 +00:00
|
|
|
|
2021-01-27 21:40:16 +00:00
|
|
|
/* Return the server status. */
|
|
|
|
enum promex_srv_state promex_srv_status(struct server *sv)
|
2019-02-07 14:38:42 +00:00
|
|
|
{
|
2021-01-27 21:40:16 +00:00
|
|
|
int state = PROMEX_SRV_STATE_DOWN;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
|
|
|
if (sv->cur_state == SRV_ST_RUNNING || sv->cur_state == SRV_ST_STARTING) {
|
2021-01-27 21:40:16 +00:00
|
|
|
state = PROMEX_SRV_STATE_UP;
|
2019-02-07 14:38:42 +00:00
|
|
|
if (sv->cur_admin & SRV_ADMF_DRAIN)
|
2021-01-27 21:40:16 +00:00
|
|
|
state = PROMEX_SRV_STATE_DRAIN;
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
2019-09-06 14:10:19 +00:00
|
|
|
else if (sv->cur_state == SRV_ST_STOPPING)
|
2021-01-27 21:40:16 +00:00
|
|
|
state = PROMEX_SRV_STATE_NOLB;
|
2019-09-06 14:10:19 +00:00
|
|
|
|
|
|
|
if (sv->cur_admin & SRV_ADMF_MAINT)
|
2021-01-27 21:40:16 +00:00
|
|
|
state = PROMEX_SRV_STATE_MAINT;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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
|
2021-01-22 20:09:47 +00:00
|
|
|
* "NaN" because Prometheus only support numerical values (but it is unexepceted
|
2019-02-07 14:38:42 +00:00
|
|
|
* to process this kind of value). It returns 1 on success. Otherwise, it
|
|
|
|
* returns 0. The buffer's length must not exceed <max> value.
|
|
|
|
*/
|
2024-01-31 09:42:10 +00:00
|
|
|
static int promex_ts_val_to_str(struct buffer *out, struct field *f, size_t max)
|
2019-02-07 14:38:42 +00:00
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
switch (field_format(f, 0)) {
|
2021-01-22 20:09:47 +00:00
|
|
|
case FF_EMPTY: ret = chunk_strcat(out, "NaN\n"); break;
|
2019-02-07 14:38:42 +00:00
|
|
|
case FF_S32: ret = chunk_appendf(out, "%d\n", f->u.s32); break;
|
|
|
|
case FF_U32: ret = chunk_appendf(out, "%u\n", f->u.u32); break;
|
|
|
|
case FF_S64: ret = chunk_appendf(out, "%lld\n", (long long)f->u.s64); break;
|
|
|
|
case FF_U64: ret = chunk_appendf(out, "%llu\n", (unsigned long long)f->u.u64); break;
|
2019-09-24 14:35:19 +00:00
|
|
|
case FF_FLT: ret = chunk_appendf(out, "%f\n", f->u.flt); break;
|
2021-01-22 20:09:47 +00:00
|
|
|
case FF_STR: ret = chunk_strcat(out, "NaN\n"); break;
|
|
|
|
default: ret = chunk_strcat(out, "NaN\n"); break;
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
if (!ret || out->data > max)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
/* Dump the time series header lines for the metric <name>. It is its #HELP and #TYPE
|
2024-01-31 09:42:10 +00:00
|
|
|
* strings. It returns 1 on success. Otherwise, if <out> length exceeds <max>,
|
|
|
|
* it returns 0.
|
2019-02-07 14:38:42 +00:00
|
|
|
*/
|
2024-01-31 10:54:58 +00:00
|
|
|
static int promex_dump_ts_header(const struct ist name, const struct ist desc, enum promex_mt_type type,
|
2024-01-31 09:42:10 +00:00
|
|
|
struct ist *out, size_t max)
|
2019-02-07 14:38:42 +00:00
|
|
|
{
|
2024-01-31 10:54:58 +00:00
|
|
|
struct ist t;
|
2021-01-20 14:20:53 +00:00
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
switch (type) {
|
2021-01-20 14:20:53 +00:00
|
|
|
case PROMEX_MT_COUNTER:
|
2024-01-31 10:54:58 +00:00
|
|
|
t = ist("counter");
|
2021-01-20 14:20:53 +00:00
|
|
|
break;
|
|
|
|
default:
|
2024-01-31 10:54:58 +00:00
|
|
|
t = ist("gauge");
|
2021-01-20 14:20:53 +00:00
|
|
|
}
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2021-01-15 21:41:39 +00:00
|
|
|
if (istcat(out, ist("# HELP "), max) == -1 ||
|
|
|
|
istcat(out, name, max) == -1 ||
|
|
|
|
istcat(out, ist(" "), max) == -1)
|
|
|
|
goto full;
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
if (istcat(out, ist("# HELP "), max) == -1 ||
|
|
|
|
istcat(out, name, max) == -1 ||
|
|
|
|
istcat(out, ist(" "), max) == -1 ||
|
|
|
|
istcat(out, desc, max) == -1)
|
|
|
|
goto full;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
if (istcat(out, ist("\n# TYPE "), max) == -1 ||
|
2019-02-07 14:38:42 +00:00
|
|
|
istcat(out, name, max) == -1 ||
|
|
|
|
istcat(out, ist(" "), max) == -1 ||
|
2024-01-31 10:54:58 +00:00
|
|
|
istcat(out, t, max) == -1 ||
|
2019-02-07 14:38:42 +00:00
|
|
|
istcat(out, ist("\n"), max) == -1)
|
|
|
|
goto full;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
full:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
/* Dump the time series for the metric <name>. It starts by the metric name followed by
|
2024-01-31 09:42:10 +00:00
|
|
|
* 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.
|
2019-02-07 14:38:42 +00:00
|
|
|
*/
|
2024-01-31 09:42:10 +00:00
|
|
|
static int promex_dump_ts(struct appctx *appctx, struct ist prefix,
|
2024-01-31 10:54:58 +00:00
|
|
|
const struct ist name, const struct ist desc, enum promex_mt_type type,
|
2024-01-31 09:42:10 +00:00
|
|
|
struct field *val, struct promex_label *labels, struct ist *out, size_t max)
|
2019-02-07 14:38:42 +00:00
|
|
|
{
|
2024-01-31 10:54:58 +00:00
|
|
|
struct ist n = { .ptr = (char[PROMEX_MAX_NAME_LEN]){ 0 }, .len = 0 };
|
2022-05-03 15:33:00 +00:00
|
|
|
struct promex_ctx *ctx = appctx->svcctx;
|
2019-02-07 14:38:42 +00:00
|
|
|
size_t len = out->len;
|
|
|
|
|
|
|
|
if (out->len + PROMEX_MAX_METRIC_LENGTH > max)
|
|
|
|
return 0;
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
|
2021-01-20 14:20:53 +00:00
|
|
|
/* Fill the metric name */
|
2024-01-31 10:54:58 +00:00
|
|
|
istcat(&n, prefix, PROMEX_MAX_NAME_LEN);
|
|
|
|
istcat(&n, name, PROMEX_MAX_NAME_LEN);
|
2021-01-20 14:20:53 +00:00
|
|
|
|
2022-05-03 15:33:00 +00:00
|
|
|
if ((ctx->flags & PROMEX_FL_METRIC_HDR) &&
|
2024-01-31 10:54:58 +00:00
|
|
|
!promex_dump_ts_header(n, desc, type, out, max))
|
2019-02-07 14:38:42 +00:00
|
|
|
goto full;
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
if (istcat(out, n, max) == -1)
|
2021-01-28 10:24:17 +00:00
|
|
|
goto full;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2021-01-28 10:24:17 +00:00
|
|
|
if (isttest(labels[0].name)) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (istcat(out, ist("{"), max) == -1)
|
2019-02-07 14:38:42 +00:00
|
|
|
goto full;
|
2021-01-28 10:24:17 +00:00
|
|
|
|
2024-01-29 16:19:28 +00:00
|
|
|
for (i = 0; i < PROMEX_MAX_LABELS && isttest(labels[i].name); i++) {
|
2021-01-28 10:24:17 +00:00
|
|
|
if (!isttest(labels[i].value))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((i && istcat(out, ist(","), max) == -1) ||
|
|
|
|
istcat(out, labels[i].name, max) == -1 ||
|
|
|
|
istcat(out, ist("=\""), max) == -1 ||
|
|
|
|
istcat(out, labels[i].value, max) == -1 ||
|
|
|
|
istcat(out, ist("\""), max) == -1)
|
|
|
|
goto full;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (istcat(out, ist("}"), max) == -1)
|
2019-02-07 14:38:42 +00:00
|
|
|
goto full;
|
2021-01-28 10:24:17 +00:00
|
|
|
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
2021-01-28 10:24:17 +00:00
|
|
|
if (istcat(out, ist(" "), max) == -1)
|
|
|
|
goto full;
|
|
|
|
|
2019-02-07 14:38:42 +00:00
|
|
|
trash.data = out->len;
|
2024-01-31 09:42:10 +00:00
|
|
|
if (!promex_ts_val_to_str(&trash, val, max))
|
2019-02-07 14:38:42 +00:00
|
|
|
goto full;
|
|
|
|
out->len = trash.data;
|
|
|
|
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags &= ~PROMEX_FL_METRIC_HDR;
|
2019-02-07 14:38:42 +00:00
|
|
|
return 1;
|
|
|
|
full:
|
|
|
|
// Restore previous length
|
|
|
|
out->len = len;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2024-01-31 16:15:49 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2020-03-23 17:28:40 +00:00
|
|
|
/* Dump global metrics (prefixed by "haproxy_process_"). It returns 1 on success,
|
2019-02-07 14:38:42 +00:00
|
|
|
* 0 if <htx> is full and -1 in case of any error. */
|
|
|
|
static int promex_dump_global_metrics(struct appctx *appctx, struct htx *htx)
|
|
|
|
{
|
|
|
|
static struct ist prefix = IST("haproxy_process_");
|
2022-05-03 15:33:00 +00:00
|
|
|
struct promex_ctx *ctx = appctx->svcctx;
|
2021-01-20 14:20:53 +00:00
|
|
|
struct field val;
|
2022-05-27 09:08:15 +00:00
|
|
|
struct channel *chn = sc_ic(appctx_sc(appctx));
|
2024-01-31 10:54:58 +00:00
|
|
|
struct ist name, desc, out = ist2(trash.area, 0);
|
2019-07-03 09:43:17 +00:00
|
|
|
size_t max = htx_get_max_blksz(htx, channel_htx_recv_max(chn, htx));
|
2019-02-07 14:38:42 +00:00
|
|
|
int ret = 1;
|
|
|
|
|
2024-04-22 07:41:15 +00:00
|
|
|
if (!stats_fill_info(stat_line_info, ST_I_INF_MAX, 0))
|
2021-01-11 19:07:49 +00:00
|
|
|
return -1;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2024-04-22 07:41:15 +00:00
|
|
|
for (; ctx->field_num < ST_I_INF_MAX; ctx->field_num++) {
|
2021-01-28 10:24:17 +00:00
|
|
|
struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
|
|
|
|
|
2022-05-03 16:05:23 +00:00
|
|
|
if (!(promex_global_metrics[ctx->field_num].flags & ctx->flags))
|
2021-01-20 14:20:53 +00:00
|
|
|
continue;
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
name = promex_global_metrics[ctx->field_num].n;
|
2024-04-23 09:06:00 +00:00
|
|
|
desc = ist(stat_cols_info[ctx->field_num].desc);
|
2024-01-31 10:54:58 +00:00
|
|
|
|
2024-01-31 16:15:49 +00:00
|
|
|
if (promex_filter_metric(appctx, prefix, name))
|
|
|
|
continue;
|
|
|
|
|
2022-05-03 16:05:23 +00:00
|
|
|
switch (ctx->field_num) {
|
2024-04-22 07:41:15 +00:00
|
|
|
case ST_I_INF_BUILD_INFO:
|
2021-01-28 10:24:17 +00:00
|
|
|
labels[0].name = ist("version");
|
|
|
|
labels[0].value = ist(HAPROXY_VERSION);
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_u32(FN_GAUGE, 1);
|
2021-01-08 12:18:06 +00:00
|
|
|
break;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
|
|
|
default:
|
2024-04-22 07:41:15 +00:00
|
|
|
val = stat_line_info[ctx->field_num];
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc,
|
|
|
|
promex_global_metrics[ctx->field_num].type,
|
2024-01-31 09:42:10 +00:00
|
|
|
&val, labels, &out, max))
|
2019-02-07 14:38:42 +00:00
|
|
|
goto full;
|
|
|
|
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
2019-07-04 08:03:28 +00:00
|
|
|
if (out.len) {
|
|
|
|
if (!htx_add_data_atonce(htx, out))
|
|
|
|
return -1; /* Unexpected and unrecoverable error */
|
|
|
|
channel_add_input(chn, out.len);
|
|
|
|
}
|
2019-02-07 14:38:42 +00:00
|
|
|
return ret;
|
|
|
|
full:
|
|
|
|
ret = 0;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2020-03-23 17:28:40 +00:00
|
|
|
/* Dump frontends metrics (prefixed by "haproxy_frontend_"). It returns 1 on success,
|
2019-02-07 14:38:42 +00:00
|
|
|
* 0 if <htx> is full and -1 in case of any error. */
|
|
|
|
static int promex_dump_front_metrics(struct appctx *appctx, struct htx *htx)
|
|
|
|
{
|
|
|
|
static struct ist prefix = IST("haproxy_frontend_");
|
2022-05-03 15:33:00 +00:00
|
|
|
struct promex_ctx *ctx = appctx->svcctx;
|
2024-01-30 13:36:07 +00:00
|
|
|
struct proxy *px = ctx->p[0];
|
|
|
|
struct stats_module *mod = ctx->p[1];
|
2021-01-20 14:20:53 +00:00
|
|
|
struct field val;
|
2022-05-27 09:08:15 +00:00
|
|
|
struct channel *chn = sc_ic(appctx_sc(appctx));
|
2024-01-31 10:54:58 +00:00
|
|
|
struct ist name, desc, out = ist2(trash.area, 0);
|
2019-07-03 09:43:17 +00:00
|
|
|
size_t max = htx_get_max_blksz(htx, channel_htx_recv_max(chn, htx));
|
2024-04-22 09:19:17 +00:00
|
|
|
struct field *stats = stat_lines[STATS_DOMAIN_PROXY];
|
2019-02-07 14:38:42 +00:00
|
|
|
int ret = 1;
|
2021-01-27 21:40:17 +00:00
|
|
|
enum promex_front_state state;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2024-04-19 16:03:45 +00:00
|
|
|
for (;ctx->field_num < ST_I_PX_MAX; ctx->field_num++) {
|
2022-05-03 16:05:23 +00:00
|
|
|
if (!(promex_st_metrics[ctx->field_num].flags & ctx->flags))
|
2021-01-20 14:20:53 +00:00
|
|
|
continue;
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
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))
|
2024-04-23 09:06:00 +00:00
|
|
|
desc = ist(stat_cols_px[ctx->field_num].desc);
|
2024-01-31 10:54:58 +00:00
|
|
|
|
2024-01-31 16:15:49 +00:00
|
|
|
if (promex_filter_metric(appctx, prefix, name))
|
|
|
|
continue;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!px)
|
|
|
|
px = proxies_list;
|
2021-01-28 10:24:17 +00:00
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
while (px) {
|
|
|
|
struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2021-01-28 10:24:17 +00:00
|
|
|
labels[0].name = ist("proxy");
|
|
|
|
labels[0].value = ist2(px->id, strlen(px->id));
|
|
|
|
|
2019-02-07 14:38:42 +00:00
|
|
|
/* skip the disabled proxies, global frontend and non-networked ones */
|
2021-10-06 12:24:19 +00:00
|
|
|
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_FE))
|
2019-02-07 14:38:42 +00:00
|
|
|
goto next_px;
|
|
|
|
|
2024-04-16 16:17:48 +00:00
|
|
|
if (!stats_fill_fe_line(px, 0, stats, ST_I_PX_MAX, &(ctx->field_num)))
|
2021-01-17 17:27:46 +00:00
|
|
|
return -1;
|
|
|
|
|
2022-05-03 16:05:23 +00:00
|
|
|
switch (ctx->field_num) {
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_STATUS:
|
2021-10-06 12:24:19 +00:00
|
|
|
state = !(px->flags & PR_FL_STOPPED);
|
2022-05-03 15:33:00 +00:00
|
|
|
for (; ctx->obj_state < PROMEX_FRONT_STATE_COUNT; ctx->obj_state++) {
|
2021-01-28 10:24:17 +00:00
|
|
|
labels[1].name = ist("state");
|
2022-05-03 15:33:00 +00:00
|
|
|
labels[1].value = promex_front_st[ctx->obj_state];
|
|
|
|
val = mkf_u32(FO_STATUS, state == ctx->obj_state);
|
2024-01-29 15:37:35 +00:00
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc,
|
|
|
|
promex_st_metrics[ctx->field_num].type,
|
2024-01-31 09:42:10 +00:00
|
|
|
&val, labels, &out, max))
|
2021-01-27 21:40:17 +00:00
|
|
|
goto full;
|
|
|
|
}
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->obj_state = 0;
|
2021-01-27 21:40:17 +00:00
|
|
|
goto next_px;
|
2024-04-19 16:03:45 +00:00
|
|
|
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:
|
2019-02-07 14:38:42 +00:00
|
|
|
if (px->mode != PR_MODE_HTTP)
|
|
|
|
goto next_px;
|
2022-05-03 16:05:23 +00:00
|
|
|
val = stats[ctx->field_num];
|
2019-02-07 14:38:42 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
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:
|
2019-02-07 14:38:42 +00:00
|
|
|
if (px->mode != PR_MODE_HTTP)
|
|
|
|
goto next_px;
|
2024-04-19 16:03:45 +00:00
|
|
|
if (ctx->field_num != ST_I_PX_HRSP_1XX)
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags &= ~PROMEX_FL_METRIC_HDR;
|
2021-01-28 10:24:17 +00:00
|
|
|
labels[1].name = ist("code");
|
2024-04-19 16:03:45 +00:00
|
|
|
labels[1].value = promex_hrsp_code[ctx->field_num - ST_I_PX_HRSP_1XX];
|
2022-05-03 16:05:23 +00:00
|
|
|
val = stats[ctx->field_num];
|
2019-02-07 14:38:42 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2022-05-03 16:05:23 +00:00
|
|
|
val = stats[ctx->field_num];
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc,
|
|
|
|
promex_st_metrics[ctx->field_num].type,
|
2024-01-31 09:42:10 +00:00
|
|
|
&val, labels, &out, max))
|
2019-02-07 14:38:42 +00:00
|
|
|
goto full;
|
|
|
|
next_px:
|
2024-01-30 13:36:07 +00:00
|
|
|
px = px->next;
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
2024-01-29 15:41:24 +00:00
|
|
|
/* Skip extra counters */
|
|
|
|
if (!(ctx->flags & PROMEX_FL_EXTRA_COUNTERS))
|
|
|
|
goto end;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!mod) {
|
|
|
|
mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(mod), list);
|
2024-01-29 15:41:24 +00:00
|
|
|
ctx->mod_field_num = 0;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
2024-01-29 15:41:24 +00:00
|
|
|
void *counters;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_FE)) {
|
|
|
|
ctx->field_num += mod->stats_count;
|
2024-01-29 15:41:24 +00:00
|
|
|
ctx->mod_field_num = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
for (;ctx->mod_field_num < mod->stats_count; ctx->mod_field_num++) {
|
2024-01-31 10:54:58 +00:00
|
|
|
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));
|
|
|
|
|
2024-01-31 16:15:49 +00:00
|
|
|
if (promex_filter_metric(appctx, prefix, name))
|
|
|
|
continue;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!px)
|
|
|
|
px = proxies_list;
|
|
|
|
|
|
|
|
while (px) {
|
2024-01-29 15:41:24 +00:00
|
|
|
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");
|
2024-01-30 13:36:07 +00:00
|
|
|
labels[1].value = ist2(mod->name, strlen(mod->name));
|
2024-01-29 15:41:24 +00:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
counters = EXTRA_COUNTERS_GET(px->extra_counters_fe, mod);
|
|
|
|
if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
|
2024-01-29 15:41:24 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
val = stats[ctx->field_num + ctx->mod_field_num];
|
|
|
|
metric.type = ((val.type == FN_GAUGE) ? PROMEX_MT_GAUGE : PROMEX_MT_COUNTER);
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc, metric.type,
|
|
|
|
&val, labels, &out, max))
|
2024-01-29 15:41:24 +00:00
|
|
|
goto full;
|
|
|
|
|
|
|
|
next_px2:
|
2024-01-30 13:36:07 +00:00
|
|
|
px = px->next;
|
2024-01-29 15:41:24 +00:00
|
|
|
}
|
|
|
|
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
ctx->field_num += mod->stats_count;
|
2024-01-29 15:41:24 +00:00
|
|
|
ctx->mod_field_num = 0;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
px = NULL;
|
|
|
|
mod = NULL;
|
|
|
|
|
2019-02-07 14:38:42 +00:00
|
|
|
end:
|
2019-07-04 08:03:28 +00:00
|
|
|
if (out.len) {
|
|
|
|
if (!htx_add_data_atonce(htx, out))
|
|
|
|
return -1; /* Unexpected and unrecoverable error */
|
|
|
|
channel_add_input(chn, out.len);
|
|
|
|
}
|
2024-01-30 13:36:07 +00:00
|
|
|
|
|
|
|
/* Save pointers (0=current proxy, 1=current stats module) of the current context */
|
|
|
|
ctx->p[0] = px;
|
|
|
|
ctx->p[1] = mod;
|
2019-02-07 14:38:42 +00:00
|
|
|
return ret;
|
|
|
|
full:
|
|
|
|
ret = 0;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2021-02-14 22:22:56 +00:00
|
|
|
/* Dump listener metrics (prefixed by "haproxy_listen_"). It returns 1 on
|
|
|
|
* success, 0 if <htx> is full and -1 in case of any error. */
|
|
|
|
static int promex_dump_listener_metrics(struct appctx *appctx, struct htx *htx)
|
|
|
|
{
|
|
|
|
static struct ist prefix = IST("haproxy_listener_");
|
2022-05-03 15:33:00 +00:00
|
|
|
struct promex_ctx *ctx = appctx->svcctx;
|
2024-01-30 13:36:07 +00:00
|
|
|
struct proxy *px = ctx->p[0];
|
|
|
|
struct listener *li = ctx->p[1];
|
|
|
|
struct stats_module *mod = ctx->p[2];
|
2021-02-14 22:22:56 +00:00
|
|
|
struct field val;
|
2022-05-27 09:08:15 +00:00
|
|
|
struct channel *chn = sc_ic(appctx_sc(appctx));
|
2024-01-31 10:54:58 +00:00
|
|
|
struct ist name, desc, out = ist2(trash.area, 0);
|
2021-02-14 22:22:56 +00:00
|
|
|
size_t max = htx_get_max_blksz(htx, channel_htx_recv_max(chn, htx));
|
2024-04-22 09:19:17 +00:00
|
|
|
struct field *stats = stat_lines[STATS_DOMAIN_PROXY];
|
2021-02-14 22:22:56 +00:00
|
|
|
int ret = 1;
|
|
|
|
enum li_status status;
|
|
|
|
|
2024-04-19 16:03:45 +00:00
|
|
|
for (;ctx->field_num < ST_I_PX_MAX; ctx->field_num++) {
|
2022-05-03 16:05:23 +00:00
|
|
|
if (!(promex_st_metrics[ctx->field_num].flags & ctx->flags))
|
2021-02-14 22:22:56 +00:00
|
|
|
continue;
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
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))
|
2024-04-23 09:06:00 +00:00
|
|
|
desc = ist(stat_cols_px[ctx->field_num].desc);
|
2024-01-31 10:54:58 +00:00
|
|
|
|
2024-01-31 16:15:49 +00:00
|
|
|
if (promex_filter_metric(appctx, prefix, name))
|
|
|
|
continue;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!px)
|
|
|
|
px = proxies_list;
|
2021-02-14 22:22:56 +00:00
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
while (px) {
|
|
|
|
struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
|
2021-02-14 22:22:56 +00:00
|
|
|
|
|
|
|
labels[0].name = ist("proxy");
|
|
|
|
labels[0].value = ist2(px->id, strlen(px->id));
|
|
|
|
|
|
|
|
/* skip the disabled proxies, global frontend and non-networked ones */
|
2021-10-06 12:24:19 +00:00
|
|
|
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_FE))
|
2021-02-14 22:22:56 +00:00
|
|
|
goto next_px;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!li)
|
|
|
|
li = LIST_NEXT(&px->conf.listeners, struct listener *, by_fe);
|
2021-02-14 22:22:56 +00:00
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
list_for_each_entry_from(li, &px->conf.listeners, by_fe) {
|
2021-02-14 22:22:56 +00:00
|
|
|
if (!li->counters)
|
|
|
|
continue;
|
|
|
|
|
BUG/MEDIUM: contrib/prometheus-exporter: fix segfault in listener name dump
We need to check whether listener is empty before doing anything; in
that case, we were trying to dump listerner name while name is null. So
simply move the counters check above, which validate all possible cases
when the listener is empty. This is very similar to what is done in
stats.c
see also the trace:
Thread 1 "haproxy" received signal SIGSEGV, Segmentation fault.
__strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:120
120 ../sysdeps/x86_64/multiarch/../strlen.S: No such file or directory.
(gdb) bt
#0 __strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:120
#1 0x00005555555b716b in promex_dump_listener_metrics (htx=0x5555558fadf0, appctx=0x555555926070) at contrib/prometheus-exporter/service-prometheus.c:722
#2 promex_dump_metrics (htx=0x5555558fadf0, si=0x555555925920, appctx=0x555555926070) at contrib/prometheus-exporter/service-prometheus.c:1200
#3 promex_appctx_handle_io (appctx=0x555555926070) at contrib/prometheus-exporter/service-prometheus.c:1477
#4 0x00005555556f0c94 in task_run_applet (t=0x555555926180, context=0x555555926070, state=<optimized out>) at src/applet.c:88
#5 0x00005555556bc6d8 in run_tasks_from_lists (budgets=budgets@entry=0x7fffffffe374) at src/task.c:548
#6 0x00005555556bd1a0 in process_runnable_tasks () at src/task.c:750
#7 0x0000555555696cdd in run_poll_loop () at src/haproxy.c:2870
#8 0x0000555555697025 in run_thread_poll_loop (data=data@entry=0x0) at src/haproxy.c:3035
#9 0x0000555555596c90 in main (argc=<optimized out>, argv=0x7fffffffe818) at src/haproxy.c:3723
quit)
this bug was introduced by commit
e3f7bd5ae9e969cbfe87e4130d06bff7a3e814c6 ("MEDIUM:
contrib/prometheus-exporter: add listen stats"), which is present for
2.4 only, so no backport needed.
Signed-off-by: William Dauchy <wdauchy@gmail.com>
2021-02-24 23:53:13 +00:00
|
|
|
labels[1].name = ist("listener");
|
|
|
|
labels[1].value = ist2(li->name, strlen(li->name));
|
|
|
|
|
2024-04-22 08:26:23 +00:00
|
|
|
if (!stats_fill_li_line(px, li, 0, stats,
|
|
|
|
ST_I_PX_MAX, &(ctx->field_num)))
|
2021-02-14 22:22:56 +00:00
|
|
|
return -1;
|
|
|
|
|
2022-05-03 16:05:23 +00:00
|
|
|
switch (ctx->field_num) {
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_STATUS:
|
2021-02-14 22:22:56 +00:00
|
|
|
status = get_li_status(li);
|
2022-05-03 15:33:00 +00:00
|
|
|
for (; ctx->obj_state < LI_STATE_COUNT; ctx->obj_state++) {
|
|
|
|
val = mkf_u32(FO_STATUS, status == ctx->obj_state);
|
2021-02-14 22:22:56 +00:00
|
|
|
labels[2].name = ist("state");
|
2022-05-03 15:33:00 +00:00
|
|
|
labels[2].value = ist(li_status_st[ctx->obj_state]);
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc,
|
|
|
|
promex_st_metrics[ctx->field_num].type,
|
2024-01-31 09:42:10 +00:00
|
|
|
&val, labels, &out, max))
|
2021-02-14 22:22:56 +00:00
|
|
|
goto full;
|
|
|
|
}
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->obj_state = 0;
|
2021-02-14 22:22:56 +00:00
|
|
|
continue;
|
|
|
|
default:
|
2022-05-03 16:05:23 +00:00
|
|
|
val = stats[ctx->field_num];
|
2021-02-14 22:22:56 +00:00
|
|
|
}
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc,
|
|
|
|
promex_st_metrics[ctx->field_num].type,
|
2024-01-31 09:42:10 +00:00
|
|
|
&val, labels, &out, max))
|
2021-02-14 22:22:56 +00:00
|
|
|
goto full;
|
|
|
|
}
|
2024-01-30 13:36:07 +00:00
|
|
|
li = NULL;
|
2021-02-14 22:22:56 +00:00
|
|
|
|
|
|
|
next_px:
|
|
|
|
px = px->next;
|
|
|
|
}
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
2021-02-14 22:22:56 +00:00
|
|
|
}
|
|
|
|
|
2024-01-29 15:42:02 +00:00
|
|
|
/* Skip extra counters */
|
|
|
|
if (!(ctx->flags & PROMEX_FL_EXTRA_COUNTERS))
|
|
|
|
goto end;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!mod) {
|
|
|
|
mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(mod), list);
|
2024-01-29 15:42:02 +00:00
|
|
|
ctx->mod_field_num = 0;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
2024-01-29 15:42:02 +00:00
|
|
|
void *counters;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_LI)) {
|
|
|
|
ctx->field_num += mod->stats_count;
|
2024-01-29 15:42:02 +00:00
|
|
|
ctx->mod_field_num = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
for (;ctx->mod_field_num < mod->stats_count; ctx->mod_field_num++) {
|
2024-01-31 10:54:58 +00:00
|
|
|
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));
|
|
|
|
|
2024-01-31 16:15:49 +00:00
|
|
|
if (promex_filter_metric(appctx, prefix, name))
|
|
|
|
continue;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!px)
|
|
|
|
px = proxies_list;
|
|
|
|
|
|
|
|
while (px) {
|
2024-01-29 15:42:02 +00:00
|
|
|
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;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!li)
|
|
|
|
li = LIST_NEXT(&px->conf.listeners, struct listener *, by_fe);
|
|
|
|
|
2024-01-29 15:42:02 +00:00
|
|
|
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");
|
2024-01-30 13:36:07 +00:00
|
|
|
labels[2].value = ist2(mod->name, strlen(mod->name));
|
2024-01-29 15:42:02 +00:00
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
counters = EXTRA_COUNTERS_GET(li->extra_counters, mod);
|
|
|
|
if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
|
2024-01-29 15:42:02 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
val = stats[ctx->field_num + ctx->mod_field_num];
|
|
|
|
metric.type = ((val.type == FN_GAUGE) ? PROMEX_MT_GAUGE : PROMEX_MT_COUNTER);
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc, metric.type,
|
|
|
|
&val, labels, &out, max))
|
2024-01-29 15:42:02 +00:00
|
|
|
goto full;
|
|
|
|
}
|
2024-01-30 13:36:07 +00:00
|
|
|
li = NULL;
|
2024-01-29 15:42:02 +00:00
|
|
|
|
|
|
|
next_px2:
|
2024-01-30 13:36:07 +00:00
|
|
|
px = px->next;
|
2024-01-29 15:42:02 +00:00
|
|
|
}
|
|
|
|
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
ctx->field_num += mod->stats_count;
|
2024-01-29 15:42:02 +00:00
|
|
|
ctx->mod_field_num = 0;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
px = NULL;
|
|
|
|
li = NULL;
|
|
|
|
mod = NULL;
|
|
|
|
|
2021-02-14 22:22:56 +00:00
|
|
|
end:
|
|
|
|
if (out.len) {
|
|
|
|
if (!htx_add_data_atonce(htx, out))
|
|
|
|
return -1; /* Unexpected and unrecoverable error */
|
|
|
|
channel_add_input(chn, out.len);
|
|
|
|
}
|
2024-01-30 13:36:07 +00:00
|
|
|
/* 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;
|
2021-02-14 22:22:56 +00:00
|
|
|
return ret;
|
|
|
|
full:
|
|
|
|
ret = 0;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2020-03-23 17:28:40 +00:00
|
|
|
/* Dump backends metrics (prefixed by "haproxy_backend_"). It returns 1 on success,
|
2019-02-07 14:38:42 +00:00
|
|
|
* 0 if <htx> is full and -1 in case of any error. */
|
|
|
|
static int promex_dump_back_metrics(struct appctx *appctx, struct htx *htx)
|
|
|
|
{
|
|
|
|
static struct ist prefix = IST("haproxy_backend_");
|
2022-05-03 15:33:00 +00:00
|
|
|
struct promex_ctx *ctx = appctx->svcctx;
|
2024-01-30 13:36:07 +00:00
|
|
|
struct proxy *px = ctx->p[0];
|
|
|
|
struct stats_module *mod = ctx->p[2];
|
2021-11-07 09:18:47 +00:00
|
|
|
struct server *sv;
|
2021-01-20 14:20:53 +00:00
|
|
|
struct field val;
|
2022-05-27 09:08:15 +00:00
|
|
|
struct channel *chn = sc_ic(appctx_sc(appctx));
|
2024-01-31 10:54:58 +00:00
|
|
|
struct ist name, desc, out = ist2(trash.area, 0);
|
2019-07-03 09:43:17 +00:00
|
|
|
size_t max = htx_get_max_blksz(htx, channel_htx_recv_max(chn, htx));
|
2024-04-22 09:19:17 +00:00
|
|
|
struct field *stats = stat_lines[STATS_DOMAIN_PROXY];
|
2019-02-07 14:38:42 +00:00
|
|
|
int ret = 1;
|
2019-09-24 14:35:19 +00:00
|
|
|
double secs;
|
2021-11-07 09:18:47 +00:00
|
|
|
enum promex_back_state bkd_state;
|
|
|
|
enum promex_srv_state srv_state;
|
2022-12-08 09:17:01 +00:00
|
|
|
enum healthcheck_status srv_check_status;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2024-04-19 16:03:45 +00:00
|
|
|
for (;ctx->field_num < ST_I_PX_MAX; ctx->field_num++) {
|
2022-05-03 16:05:23 +00:00
|
|
|
if (!(promex_st_metrics[ctx->field_num].flags & ctx->flags))
|
2021-01-20 14:20:53 +00:00
|
|
|
continue;
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
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))
|
2024-04-23 09:06:00 +00:00
|
|
|
desc = ist(stat_cols_px[ctx->field_num].desc);
|
2024-01-31 10:54:58 +00:00
|
|
|
|
2024-01-31 16:15:49 +00:00
|
|
|
if (promex_filter_metric(appctx, prefix, name))
|
|
|
|
continue;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!px)
|
|
|
|
px = proxies_list;
|
|
|
|
|
|
|
|
while (px) {
|
2021-01-28 10:24:17 +00:00
|
|
|
struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
|
2021-11-07 09:18:47 +00:00
|
|
|
unsigned int srv_state_count[PROMEX_SRV_STATE_COUNT] = { 0 };
|
2022-12-08 09:17:01 +00:00
|
|
|
unsigned int srv_check_count[HCHK_STATUS_SIZE] = { 0 };
|
|
|
|
const char *check_state;
|
2021-01-28 10:24:17 +00:00
|
|
|
|
|
|
|
labels[0].name = ist("proxy");
|
|
|
|
labels[0].value = ist2(px->id, strlen(px->id));
|
|
|
|
|
2019-02-07 14:38:42 +00:00
|
|
|
/* skip the disabled proxies, global frontend and non-networked ones */
|
2021-10-06 12:24:19 +00:00
|
|
|
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
|
2019-02-07 14:38:42 +00:00
|
|
|
goto next_px;
|
|
|
|
|
2024-04-22 08:26:23 +00:00
|
|
|
if (!stats_fill_be_line(px, 0, stats, ST_I_PX_MAX, &(ctx->field_num)))
|
2021-01-25 16:29:02 +00:00
|
|
|
return -1;
|
|
|
|
|
2022-05-03 16:05:23 +00:00
|
|
|
switch (ctx->field_num) {
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_AGG_SRV_CHECK_STATUS: // DEPRECATED
|
|
|
|
case ST_I_PX_AGG_SRV_STATUS:
|
2021-11-07 09:18:47 +00:00
|
|
|
if (!px->srv)
|
|
|
|
goto next_px;
|
|
|
|
sv = px->srv;
|
|
|
|
while (sv) {
|
|
|
|
srv_state = promex_srv_status(sv);
|
|
|
|
srv_state_count[srv_state] += 1;
|
|
|
|
sv = sv->next;
|
|
|
|
}
|
2022-05-03 15:33:00 +00:00
|
|
|
for (; ctx->obj_state < PROMEX_SRV_STATE_COUNT; ctx->obj_state++) {
|
|
|
|
val = mkf_u32(FN_GAUGE, srv_state_count[ctx->obj_state]);
|
2021-11-07 09:18:47 +00:00
|
|
|
labels[1].name = ist("state");
|
2022-05-03 15:33:00 +00:00
|
|
|
labels[1].value = promex_srv_st[ctx->obj_state];
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc,
|
|
|
|
promex_st_metrics[ctx->field_num].type,
|
2024-01-31 09:42:10 +00:00
|
|
|
&val, labels, &out, max))
|
2022-12-08 09:17:01 +00:00
|
|
|
goto full;
|
|
|
|
}
|
|
|
|
ctx->obj_state = 0;
|
|
|
|
goto next_px;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_AGG_CHECK_STATUS:
|
2022-12-08 09:17:01 +00:00
|
|
|
if (!px->srv)
|
|
|
|
goto next_px;
|
|
|
|
sv = px->srv;
|
|
|
|
while (sv) {
|
2023-09-12 09:37:55 +00:00
|
|
|
if ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED) {
|
|
|
|
srv_check_status = sv->check.status;
|
|
|
|
srv_check_count[srv_check_status] += 1;
|
|
|
|
}
|
2022-12-08 09:17:01 +00:00
|
|
|
sv = sv->next;
|
|
|
|
}
|
|
|
|
for (; ctx->obj_state < HCHK_STATUS_SIZE; ctx->obj_state++) {
|
|
|
|
if (get_check_status_result(ctx->obj_state) < CHK_RES_FAILED)
|
|
|
|
continue;
|
|
|
|
val = mkf_u32(FO_STATUS, srv_check_count[ctx->obj_state]);
|
|
|
|
check_state = get_check_status_info(ctx->obj_state);
|
|
|
|
labels[1].name = ist("state");
|
|
|
|
labels[1].value = ist(check_state);
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc,
|
|
|
|
promex_st_metrics[ctx->field_num].type,
|
2024-01-31 09:42:10 +00:00
|
|
|
&val, labels, &out, max))
|
2021-11-07 09:18:47 +00:00
|
|
|
goto full;
|
|
|
|
}
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->obj_state = 0;
|
2021-11-07 09:18:47 +00:00
|
|
|
goto next_px;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_STATUS:
|
2021-11-07 09:18:47 +00:00
|
|
|
bkd_state = ((px->lbprm.tot_weight > 0 || !px->srv) ? 1 : 0);
|
2022-05-03 15:33:00 +00:00
|
|
|
for (; ctx->obj_state < PROMEX_BACK_STATE_COUNT; ctx->obj_state++) {
|
2021-01-28 10:24:17 +00:00
|
|
|
labels[1].name = ist("state");
|
2022-05-03 15:33:00 +00:00
|
|
|
labels[1].value = promex_back_st[ctx->obj_state];
|
|
|
|
val = mkf_u32(FO_STATUS, bkd_state == ctx->obj_state);
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc,
|
|
|
|
promex_st_metrics[ctx->field_num].type,
|
2024-01-31 09:42:10 +00:00
|
|
|
&val, labels, &out, max))
|
2021-01-27 21:40:17 +00:00
|
|
|
goto full;
|
|
|
|
}
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->obj_state = 0;
|
2021-01-27 21:40:17 +00:00
|
|
|
goto next_px;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_QTIME:
|
2019-09-24 14:35:19 +00:00
|
|
|
secs = (double)swrate_avg(px->be_counters.q_time, TIME_STATS_SAMPLES) / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_AVG, secs);
|
2019-02-07 14:38:42 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_CTIME:
|
2019-09-24 14:35:19 +00:00
|
|
|
secs = (double)swrate_avg(px->be_counters.c_time, TIME_STATS_SAMPLES) / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_AVG, secs);
|
2019-02-07 14:38:42 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_RTIME:
|
2019-09-24 14:35:19 +00:00
|
|
|
secs = (double)swrate_avg(px->be_counters.d_time, TIME_STATS_SAMPLES) / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_AVG, secs);
|
2019-02-07 14:38:42 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_TTIME:
|
2019-09-24 14:35:19 +00:00
|
|
|
secs = (double)swrate_avg(px->be_counters.t_time, TIME_STATS_SAMPLES) / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_AVG, secs);
|
2019-02-07 14:38:42 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_QT_MAX:
|
2019-11-08 14:05:31 +00:00
|
|
|
secs = (double)px->be_counters.qtime_max / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_MAX, secs);
|
2019-11-08 14:05:31 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_CT_MAX:
|
2019-11-08 14:05:31 +00:00
|
|
|
secs = (double)px->be_counters.ctime_max / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_MAX, secs);
|
2019-11-08 14:05:31 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_RT_MAX:
|
2019-11-08 14:05:31 +00:00
|
|
|
secs = (double)px->be_counters.dtime_max / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_MAX, secs);
|
2019-11-08 14:05:31 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_TT_MAX:
|
2019-11-08 14:05:31 +00:00
|
|
|
secs = (double)px->be_counters.ttime_max / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_MAX, secs);
|
2019-11-08 14:05:31 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
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:
|
2019-02-07 14:38:42 +00:00
|
|
|
if (px->mode != PR_MODE_HTTP)
|
|
|
|
goto next_px;
|
2022-05-03 16:05:23 +00:00
|
|
|
val = stats[ctx->field_num];
|
2019-02-07 14:38:42 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
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:
|
2019-02-07 14:38:42 +00:00
|
|
|
if (px->mode != PR_MODE_HTTP)
|
|
|
|
goto next_px;
|
2024-04-19 16:03:45 +00:00
|
|
|
if (ctx->field_num != ST_I_PX_HRSP_1XX)
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags &= ~PROMEX_FL_METRIC_HDR;
|
2021-01-28 10:24:17 +00:00
|
|
|
labels[1].name = ist("code");
|
2024-04-19 16:03:45 +00:00
|
|
|
labels[1].value = promex_hrsp_code[ctx->field_num - ST_I_PX_HRSP_1XX];
|
2022-05-03 16:05:23 +00:00
|
|
|
val = stats[ctx->field_num];
|
2019-02-07 14:38:42 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2022-05-03 16:05:23 +00:00
|
|
|
val = stats[ctx->field_num];
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc,
|
|
|
|
promex_st_metrics[ctx->field_num].type,
|
2024-01-31 09:42:10 +00:00
|
|
|
&val, labels, &out, max))
|
2019-02-07 14:38:42 +00:00
|
|
|
goto full;
|
|
|
|
next_px:
|
2024-01-30 13:36:07 +00:00
|
|
|
px = px->next;
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
2024-01-29 15:41:42 +00:00
|
|
|
/* Skip extra counters */
|
|
|
|
if (!(ctx->flags & PROMEX_FL_EXTRA_COUNTERS))
|
|
|
|
goto end;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!mod) {
|
|
|
|
mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(mod), list);
|
2024-01-29 15:41:42 +00:00
|
|
|
ctx->mod_field_num = 0;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
2024-01-29 15:41:42 +00:00
|
|
|
void *counters;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_BE)) {
|
|
|
|
ctx->field_num += mod->stats_count;
|
2024-01-29 15:41:42 +00:00
|
|
|
ctx->mod_field_num = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
for (;ctx->mod_field_num < mod->stats_count; ctx->mod_field_num++) {
|
2024-01-31 10:54:58 +00:00
|
|
|
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));
|
|
|
|
|
2024-01-31 16:15:49 +00:00
|
|
|
if (promex_filter_metric(appctx, prefix, name))
|
|
|
|
continue;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!px)
|
|
|
|
px = proxies_list;
|
|
|
|
|
|
|
|
while (px) {
|
2024-01-29 15:41:42 +00:00
|
|
|
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");
|
2024-01-30 13:36:07 +00:00
|
|
|
labels[1].value = ist2(mod->name, strlen(mod->name));
|
2024-01-29 15:41:42 +00:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
counters = EXTRA_COUNTERS_GET(px->extra_counters_be, mod);
|
|
|
|
if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
|
2024-01-29 15:41:42 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
val = stats[ctx->field_num + ctx->mod_field_num];
|
|
|
|
metric.type = ((val.type == FN_GAUGE) ? PROMEX_MT_GAUGE : PROMEX_MT_COUNTER);
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc, metric.type,
|
|
|
|
&val, labels, &out, max))
|
2024-01-29 15:41:42 +00:00
|
|
|
goto full;
|
|
|
|
|
|
|
|
next_px2:
|
2024-01-30 13:36:07 +00:00
|
|
|
px = px->next;
|
2024-01-29 15:41:42 +00:00
|
|
|
}
|
|
|
|
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
ctx->field_num += mod->stats_count;
|
2024-01-29 15:41:42 +00:00
|
|
|
ctx->mod_field_num = 0;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
px = NULL;
|
|
|
|
mod = NULL;
|
|
|
|
|
2019-02-07 14:38:42 +00:00
|
|
|
end:
|
2019-07-04 08:03:28 +00:00
|
|
|
if (out.len) {
|
|
|
|
if (!htx_add_data_atonce(htx, out))
|
|
|
|
return -1; /* Unexpected and unrecoverable error */
|
|
|
|
channel_add_input(chn, out.len);
|
|
|
|
}
|
2024-01-30 13:36:07 +00:00
|
|
|
/* Save pointers (0=current proxy, 1=current stats module) of the current context */
|
|
|
|
ctx->p[0] = px;
|
|
|
|
ctx->p[1] = mod;
|
2019-02-07 14:38:42 +00:00
|
|
|
return ret;
|
|
|
|
full:
|
|
|
|
ret = 0;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2020-03-23 17:28:40 +00:00
|
|
|
/* Dump servers metrics (prefixed by "haproxy_server_"). It returns 1 on success,
|
2019-02-07 14:38:42 +00:00
|
|
|
* 0 if <htx> is full and -1 in case of any error. */
|
|
|
|
static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
|
|
|
|
{
|
|
|
|
static struct ist prefix = IST("haproxy_server_");
|
2022-05-03 15:33:00 +00:00
|
|
|
struct promex_ctx *ctx = appctx->svcctx;
|
2024-01-30 13:36:07 +00:00
|
|
|
struct proxy *px = ctx->p[0];
|
|
|
|
struct server *sv = ctx->p[1];
|
|
|
|
struct stats_module *mod = ctx->p[2];
|
2021-01-20 14:20:53 +00:00
|
|
|
struct field val;
|
2022-05-27 09:08:15 +00:00
|
|
|
struct channel *chn = sc_ic(appctx_sc(appctx));
|
2024-01-31 10:54:58 +00:00
|
|
|
struct ist name, desc, out = ist2(trash.area, 0);
|
2019-07-03 09:43:17 +00:00
|
|
|
size_t max = htx_get_max_blksz(htx, channel_htx_recv_max(chn, htx));
|
2024-04-22 09:19:17 +00:00
|
|
|
struct field *stats = stat_lines[STATS_DOMAIN_PROXY];
|
2019-02-07 14:38:42 +00:00
|
|
|
int ret = 1;
|
2019-09-24 14:35:19 +00:00
|
|
|
double secs;
|
2021-01-27 21:40:17 +00:00
|
|
|
enum promex_srv_state state;
|
2021-02-01 12:11:51 +00:00
|
|
|
const char *check_state;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2024-04-19 16:03:45 +00:00
|
|
|
for (;ctx->field_num < ST_I_PX_MAX; ctx->field_num++) {
|
2022-05-03 16:05:23 +00:00
|
|
|
if (!(promex_st_metrics[ctx->field_num].flags & ctx->flags))
|
2021-01-20 14:20:53 +00:00
|
|
|
continue;
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
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))
|
2024-04-23 09:06:00 +00:00
|
|
|
desc = ist(stat_cols_px[ctx->field_num].desc);
|
2024-01-31 10:54:58 +00:00
|
|
|
|
2024-01-31 16:15:49 +00:00
|
|
|
if (promex_filter_metric(appctx, prefix, name))
|
|
|
|
continue;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!px)
|
|
|
|
px = proxies_list;
|
2021-01-28 10:24:17 +00:00
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
while (px) {
|
|
|
|
struct promex_label labels[PROMEX_MAX_LABELS-1] = {};
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2021-01-28 10:24:17 +00:00
|
|
|
labels[0].name = ist("proxy");
|
|
|
|
labels[0].value = ist2(px->id, strlen(px->id));
|
|
|
|
|
2019-02-07 14:38:42 +00:00
|
|
|
/* skip the disabled proxies, global frontend and non-networked ones */
|
2021-10-06 12:24:19 +00:00
|
|
|
if ((px->flags & PR_FL_DISABLED) || px->uuid <= 0 || !(px->cap & PR_CAP_BE))
|
2019-02-07 14:38:42 +00:00
|
|
|
goto next_px;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!sv)
|
|
|
|
sv = px->srv;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
while (sv) {
|
2021-01-28 10:24:17 +00:00
|
|
|
labels[1].name = ist("server");
|
|
|
|
labels[1].value = ist2(sv->id, strlen(sv->id));
|
|
|
|
|
2024-04-22 08:26:23 +00:00
|
|
|
if (!stats_fill_sv_line(px, sv, 0, stats, ST_I_PX_MAX, &(ctx->field_num)))
|
2021-01-25 16:29:04 +00:00
|
|
|
return -1;
|
|
|
|
|
2022-05-03 15:33:00 +00:00
|
|
|
if ((ctx->flags & PROMEX_FL_NO_MAINT_SRV) && (sv->cur_admin & SRV_ADMF_MAINT))
|
2019-11-19 13:18:24 +00:00
|
|
|
goto next_sv;
|
|
|
|
|
2022-05-03 16:05:23 +00:00
|
|
|
switch (ctx->field_num) {
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_STATUS:
|
2021-01-27 21:40:17 +00:00
|
|
|
state = promex_srv_status(sv);
|
2022-05-03 15:33:00 +00:00
|
|
|
for (; ctx->obj_state < PROMEX_SRV_STATE_COUNT; ctx->obj_state++) {
|
|
|
|
val = mkf_u32(FO_STATUS, state == ctx->obj_state);
|
2021-01-28 10:24:17 +00:00
|
|
|
labels[2].name = ist("state");
|
2022-05-03 15:33:00 +00:00
|
|
|
labels[2].value = promex_srv_st[ctx->obj_state];
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc,
|
|
|
|
promex_st_metrics[ctx->field_num].type,
|
2024-01-31 09:42:10 +00:00
|
|
|
&val, labels, &out, max))
|
2021-01-27 21:40:17 +00:00
|
|
|
goto full;
|
|
|
|
}
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->obj_state = 0;
|
2021-01-27 21:40:17 +00:00
|
|
|
goto next_sv;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_QTIME:
|
2019-09-24 14:35:19 +00:00
|
|
|
secs = (double)swrate_avg(sv->counters.q_time, TIME_STATS_SAMPLES) / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_AVG, secs);
|
2019-02-07 14:38:42 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_CTIME:
|
2019-09-24 14:35:19 +00:00
|
|
|
secs = (double)swrate_avg(sv->counters.c_time, TIME_STATS_SAMPLES) / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_AVG, secs);
|
2019-02-07 14:38:42 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_RTIME:
|
2019-09-24 14:35:19 +00:00
|
|
|
secs = (double)swrate_avg(sv->counters.d_time, TIME_STATS_SAMPLES) / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_AVG, secs);
|
2019-02-07 14:38:42 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_TTIME:
|
2019-09-24 14:35:19 +00:00
|
|
|
secs = (double)swrate_avg(sv->counters.t_time, TIME_STATS_SAMPLES) / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_AVG, secs);
|
2019-02-07 14:38:42 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_QT_MAX:
|
2019-11-08 14:05:31 +00:00
|
|
|
secs = (double)sv->counters.qtime_max / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_MAX, secs);
|
2019-11-08 14:05:31 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_CT_MAX:
|
2019-11-08 14:05:31 +00:00
|
|
|
secs = (double)sv->counters.ctime_max / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_MAX, secs);
|
2019-11-08 14:05:31 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_RT_MAX:
|
2019-11-08 14:05:31 +00:00
|
|
|
secs = (double)sv->counters.dtime_max / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_MAX, secs);
|
2019-11-08 14:05:31 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_TT_MAX:
|
2019-11-08 14:05:31 +00:00
|
|
|
secs = (double)sv->counters.ttime_max / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_MAX, secs);
|
2019-11-08 14:05:31 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_CHECK_STATUS:
|
2019-11-21 13:35:46 +00:00
|
|
|
if ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) != CHK_ST_ENABLED)
|
|
|
|
goto next_sv;
|
2021-02-01 12:11:51 +00:00
|
|
|
|
2022-05-03 15:33:00 +00:00
|
|
|
for (; ctx->obj_state < HCHK_STATUS_SIZE; ctx->obj_state++) {
|
|
|
|
if (get_check_status_result(ctx->obj_state) < CHK_RES_FAILED)
|
2021-02-01 12:11:51 +00:00
|
|
|
continue;
|
2022-05-03 15:33:00 +00:00
|
|
|
val = mkf_u32(FO_STATUS, sv->check.status == ctx->obj_state);
|
|
|
|
check_state = get_check_status_info(ctx->obj_state);
|
2021-02-01 12:11:51 +00:00
|
|
|
labels[2].name = ist("state");
|
2021-09-15 11:58:44 +00:00
|
|
|
labels[2].value = ist(check_state);
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc,
|
|
|
|
promex_st_metrics[ctx->field_num].type,
|
2024-01-31 09:42:10 +00:00
|
|
|
&val, labels, &out, max))
|
2021-02-01 12:11:51 +00:00
|
|
|
goto full;
|
|
|
|
}
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->obj_state = 0;
|
2021-02-01 12:11:51 +00:00
|
|
|
goto next_sv;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_CHECK_CODE:
|
2019-11-21 13:35:46 +00:00
|
|
|
if ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) != CHK_ST_ENABLED)
|
|
|
|
goto next_sv;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_u32(FN_OUTPUT, (sv->check.status < HCHK_STATUS_L57DATA) ? 0 : sv->check.code);
|
2019-11-21 13:35:46 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_CHECK_DURATION:
|
2020-02-27 15:12:07 +00:00
|
|
|
if (sv->check.status < HCHK_STATUS_CHECKED)
|
|
|
|
goto next_sv;
|
|
|
|
secs = (double)sv->check.duration / 1000.0;
|
2021-01-20 14:20:53 +00:00
|
|
|
val = mkf_flt(FN_DURATION, secs);
|
2020-02-27 15:12:07 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
case ST_I_PX_REQ_TOT:
|
2024-01-30 13:36:07 +00:00
|
|
|
if (px->mode != PR_MODE_HTTP) {
|
|
|
|
sv = NULL;
|
2019-02-07 14:38:42 +00:00
|
|
|
goto next_px;
|
2024-01-30 13:36:07 +00:00
|
|
|
}
|
2022-05-03 16:05:23 +00:00
|
|
|
val = stats[ctx->field_num];
|
2019-02-07 14:38:42 +00:00
|
|
|
break;
|
2024-04-19 16:03:45 +00:00
|
|
|
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:
|
2024-01-30 13:36:07 +00:00
|
|
|
if (px->mode != PR_MODE_HTTP) {
|
|
|
|
sv = NULL;
|
2019-02-07 14:38:42 +00:00
|
|
|
goto next_px;
|
2024-01-30 13:36:07 +00:00
|
|
|
}
|
2024-04-19 16:03:45 +00:00
|
|
|
if (ctx->field_num != ST_I_PX_HRSP_1XX)
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags &= ~PROMEX_FL_METRIC_HDR;
|
2021-01-28 10:24:17 +00:00
|
|
|
labels[2].name = ist("code");
|
2024-04-19 16:03:45 +00:00
|
|
|
labels[2].value = promex_hrsp_code[ctx->field_num - ST_I_PX_HRSP_1XX];
|
2022-05-03 16:05:23 +00:00
|
|
|
val = stats[ctx->field_num];
|
2020-07-10 13:39:39 +00:00
|
|
|
break;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
|
|
|
default:
|
2022-05-03 16:05:23 +00:00
|
|
|
val = stats[ctx->field_num];
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc,
|
|
|
|
promex_st_metrics[ctx->field_num].type,
|
2024-01-31 09:42:10 +00:00
|
|
|
&val, labels, &out, max))
|
2019-02-07 14:38:42 +00:00
|
|
|
goto full;
|
2019-11-19 13:18:24 +00:00
|
|
|
next_sv:
|
2024-01-30 13:36:07 +00:00
|
|
|
sv = sv->next;
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
next_px:
|
2024-01-30 13:36:07 +00:00
|
|
|
px = px->next;
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
2024-01-29 15:41:56 +00:00
|
|
|
/* Skip extra counters */
|
|
|
|
if (!(ctx->flags & PROMEX_FL_EXTRA_COUNTERS))
|
|
|
|
goto end;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!mod) {
|
|
|
|
mod = LIST_NEXT(&stats_module_list[STATS_DOMAIN_PROXY], typeof(mod), list);
|
2024-01-29 15:41:56 +00:00
|
|
|
ctx->mod_field_num = 0;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
list_for_each_entry_from(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
2024-01-29 15:41:56 +00:00
|
|
|
void *counters;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_SRV)) {
|
|
|
|
ctx->field_num += mod->stats_count;
|
2024-01-29 15:41:56 +00:00
|
|
|
ctx->mod_field_num = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
for (;ctx->mod_field_num < mod->stats_count; ctx->mod_field_num++) {
|
2024-01-31 10:54:58 +00:00
|
|
|
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));
|
|
|
|
|
2024-01-31 16:15:49 +00:00
|
|
|
if (promex_filter_metric(appctx, prefix, name))
|
|
|
|
continue;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!px)
|
|
|
|
px = proxies_list;
|
|
|
|
|
|
|
|
while (px) {
|
2024-01-29 15:41:56 +00:00
|
|
|
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;
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
if (!sv)
|
|
|
|
sv = px->srv;
|
2024-01-29 15:41:56 +00:00
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
while (sv) {
|
2024-01-29 15:41:56 +00:00
|
|
|
labels[1].name = ist("server");
|
|
|
|
labels[1].value = ist2(sv->id, strlen(sv->id));
|
|
|
|
|
|
|
|
labels[2].name = ist("mod");
|
2024-01-30 13:36:07 +00:00
|
|
|
labels[2].value = ist2(mod->name, strlen(mod->name));
|
2024-01-29 15:41:56 +00:00
|
|
|
|
|
|
|
if ((ctx->flags & PROMEX_FL_NO_MAINT_SRV) && (sv->cur_admin & SRV_ADMF_MAINT))
|
|
|
|
goto next_sv2;
|
|
|
|
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
counters = EXTRA_COUNTERS_GET(sv->extra_counters, mod);
|
|
|
|
if (!mod->fill_stats(counters, stats + ctx->field_num, &ctx->mod_field_num))
|
2024-01-29 15:41:56 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
val = stats[ctx->field_num + ctx->mod_field_num];
|
|
|
|
metric.type = ((val.type == FN_GAUGE) ? PROMEX_MT_GAUGE : PROMEX_MT_COUNTER);
|
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, name, desc, metric.type,
|
|
|
|
&val, labels, &out, max))
|
2024-01-29 15:41:56 +00:00
|
|
|
goto full;
|
|
|
|
|
|
|
|
next_sv2:
|
2024-01-30 13:36:07 +00:00
|
|
|
sv = sv->next;
|
2024-01-29 15:41:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
next_px2:
|
2024-01-30 13:36:07 +00:00
|
|
|
px = px->next;
|
2024-01-29 15:41:56 +00:00
|
|
|
}
|
|
|
|
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
|
|
|
}
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
ctx->field_num += mod->stats_count;
|
2024-01-29 15:41:56 +00:00
|
|
|
ctx->mod_field_num = 0;
|
|
|
|
}
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
px = NULL;
|
|
|
|
sv = NULL;
|
|
|
|
mod = NULL;
|
|
|
|
|
2019-02-07 14:38:42 +00:00
|
|
|
end:
|
2019-07-04 08:03:28 +00:00
|
|
|
if (out.len) {
|
|
|
|
if (!htx_add_data_atonce(htx, out))
|
|
|
|
return -1; /* Unexpected and unrecoverable error */
|
|
|
|
channel_add_input(chn, out.len);
|
|
|
|
}
|
2024-02-22 13:16:37 +00:00
|
|
|
|
|
|
|
/* Decrement server refcount if it was saved through ctx.p[1]. */
|
|
|
|
srv_drop(ctx->p[1]);
|
|
|
|
if (sv)
|
|
|
|
srv_take(sv);
|
|
|
|
|
2024-01-30 13:36:07 +00:00
|
|
|
/* 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;
|
2019-02-07 14:38:42 +00:00
|
|
|
return ret;
|
|
|
|
full:
|
|
|
|
ret = 0;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2024-01-30 14:58:31 +00:00
|
|
|
/* 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)
|
2021-02-07 19:42:38 +00:00
|
|
|
{
|
2024-01-30 14:58:31 +00:00
|
|
|
struct ist prefix = { .ptr = (char[PROMEX_MAX_NAME_LEN]){ 0 }, .len = 0 };
|
2022-05-03 15:33:00 +00:00
|
|
|
struct promex_ctx *ctx = appctx->svcctx;
|
2021-02-07 19:42:38 +00:00
|
|
|
int ret = 1;
|
|
|
|
|
2024-01-30 14:58:31 +00:00
|
|
|
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;
|
|
|
|
|
2024-01-31 16:15:49 +00:00
|
|
|
|
2024-01-30 14:58:31 +00:00
|
|
|
ret = mod->metric_info(ctx->mod_field_num, &metric, &desc);
|
|
|
|
if (!ret)
|
2021-02-07 19:42:38 +00:00
|
|
|
continue;
|
2024-01-30 14:58:31 +00:00
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
2021-02-07 19:42:38 +00:00
|
|
|
|
2024-01-31 16:15:49 +00:00
|
|
|
if (promex_filter_metric(appctx, prefix, metric.n))
|
|
|
|
continue;
|
|
|
|
|
2024-01-30 14:58:31 +00:00
|
|
|
if (!ctx->p[2])
|
|
|
|
ctx->p[2] = mod->start_ts(ctx->p[1], ctx->mod_field_num);
|
2024-01-30 13:36:07 +00:00
|
|
|
|
2024-01-30 14:58:31 +00:00
|
|
|
while (ctx->p[2]) {
|
2021-02-07 19:42:38 +00:00
|
|
|
struct promex_label labels[PROMEX_MAX_LABELS - 1] = {};
|
2024-01-30 14:58:31 +00:00
|
|
|
struct field val;
|
2021-02-07 19:42:38 +00:00
|
|
|
|
2024-01-30 14:58:31 +00:00
|
|
|
ret = mod->fill_ts(ctx->p[1], ctx->p[2], ctx->mod_field_num, labels, &val);
|
|
|
|
if (!ret)
|
|
|
|
continue;
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
2021-02-07 19:42:38 +00:00
|
|
|
|
2024-01-31 10:54:58 +00:00
|
|
|
if (!promex_dump_ts(appctx, prefix, metric.n, desc, metric.type,
|
2024-01-31 09:42:10 +00:00
|
|
|
&val, labels, out, max))
|
2021-02-07 19:42:38 +00:00
|
|
|
goto full;
|
|
|
|
|
2024-01-30 14:58:31 +00:00
|
|
|
next:
|
|
|
|
ctx->p[2] = mod->next_ts(ctx->p[1], ctx->p[2], ctx->mod_field_num);
|
2021-02-07 19:42:38 +00:00
|
|
|
}
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags |= PROMEX_FL_METRIC_HDR;
|
2021-02-07 19:42:38 +00:00
|
|
|
}
|
2024-01-30 14:58:31 +00:00
|
|
|
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;
|
|
|
|
}
|
2021-02-07 19:42:38 +00:00
|
|
|
|
2024-01-30 14:58:31 +00:00
|
|
|
/* 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;
|
2024-01-30 13:36:07 +00:00
|
|
|
|
2021-02-07 19:42:38 +00:00
|
|
|
end:
|
|
|
|
if (out.len) {
|
|
|
|
if (!htx_add_data_atonce(htx, out))
|
|
|
|
return -1; /* Unexpected and unrecoverable error */
|
|
|
|
channel_add_input(chn, out.len);
|
|
|
|
}
|
2024-01-30 14:58:31 +00:00
|
|
|
ctx->p[0] = mod;
|
2021-02-07 19:42:38 +00:00
|
|
|
return ret;
|
|
|
|
full:
|
|
|
|
ret = 0;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2019-02-07 14:38:42 +00:00
|
|
|
/* Dump all metrics (global, frontends, backends and servers) depending on the
|
|
|
|
* dumper state (appctx->st1). It returns 1 on success, 0 if <htx> is full and
|
2020-10-02 16:32:02 +00:00
|
|
|
* -1 in case of any error.
|
2022-05-03 15:33:00 +00:00
|
|
|
* Uses <appctx.ctx.stats.px> as a pointer to the current proxy and <sv>/<li>
|
|
|
|
* as pointers to the current server/listener respectively.
|
|
|
|
*/
|
2022-05-27 08:16:15 +00:00
|
|
|
static int promex_dump_metrics(struct appctx *appctx, struct stconn *sc, struct htx *htx)
|
2019-02-07 14:38:42 +00:00
|
|
|
{
|
2022-05-03 15:33:00 +00:00
|
|
|
struct promex_ctx *ctx = appctx->svcctx;
|
2019-02-07 14:38:42 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
switch (appctx->st1) {
|
|
|
|
case PROMEX_DUMPER_INIT:
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_INFO_METRIC);
|
|
|
|
ctx->obj_state = 0;
|
2024-04-22 07:41:15 +00:00
|
|
|
ctx->field_num = ST_I_INF_NAME;
|
2019-02-07 14:38:42 +00:00
|
|
|
appctx->st1 = PROMEX_DUMPER_GLOBAL;
|
2022-11-14 06:37:45 +00:00
|
|
|
__fallthrough;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
|
|
|
case PROMEX_DUMPER_GLOBAL:
|
2022-05-03 15:33:00 +00:00
|
|
|
if (ctx->flags & PROMEX_FL_SCOPE_GLOBAL) {
|
2019-11-18 13:47:08 +00:00
|
|
|
ret = promex_dump_global_metrics(appctx, htx);
|
|
|
|
if (ret <= 0) {
|
|
|
|
if (ret == -1)
|
|
|
|
goto error;
|
|
|
|
goto full;
|
|
|
|
}
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags &= ~PROMEX_FL_INFO_METRIC;
|
|
|
|
ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_FRONT_METRIC);
|
|
|
|
ctx->obj_state = 0;
|
2024-04-19 16:03:45 +00:00
|
|
|
ctx->field_num = ST_I_PX_PXNAME;
|
2024-01-29 15:40:41 +00:00
|
|
|
ctx->mod_field_num = 0;
|
2019-02-07 14:38:42 +00:00
|
|
|
appctx->st1 = PROMEX_DUMPER_FRONT;
|
2022-11-14 06:37:45 +00:00
|
|
|
__fallthrough;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
|
|
|
case PROMEX_DUMPER_FRONT:
|
2022-05-03 15:33:00 +00:00
|
|
|
if (ctx->flags & PROMEX_FL_SCOPE_FRONT) {
|
2019-11-18 13:47:08 +00:00
|
|
|
ret = promex_dump_front_metrics(appctx, htx);
|
|
|
|
if (ret <= 0) {
|
|
|
|
if (ret == -1)
|
|
|
|
goto error;
|
|
|
|
goto full;
|
|
|
|
}
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags &= ~PROMEX_FL_FRONT_METRIC;
|
|
|
|
ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_LI_METRIC);
|
|
|
|
ctx->obj_state = 0;
|
2024-04-19 16:03:45 +00:00
|
|
|
ctx->field_num = ST_I_PX_PXNAME;
|
2024-01-29 15:40:41 +00:00
|
|
|
ctx->mod_field_num = 0;
|
2021-02-14 22:22:56 +00:00
|
|
|
appctx->st1 = PROMEX_DUMPER_LI;
|
2022-11-14 06:37:45 +00:00
|
|
|
__fallthrough;
|
2021-02-14 22:22:56 +00:00
|
|
|
|
|
|
|
case PROMEX_DUMPER_LI:
|
2022-05-03 15:33:00 +00:00
|
|
|
if (ctx->flags & PROMEX_FL_SCOPE_LI) {
|
2021-02-14 22:22:56 +00:00
|
|
|
ret = promex_dump_listener_metrics(appctx, htx);
|
|
|
|
if (ret <= 0) {
|
|
|
|
if (ret == -1)
|
|
|
|
goto error;
|
|
|
|
goto full;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags &= ~PROMEX_FL_LI_METRIC;
|
|
|
|
ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_BACK_METRIC);
|
|
|
|
ctx->obj_state = 0;
|
2024-04-19 16:03:45 +00:00
|
|
|
ctx->field_num = ST_I_PX_PXNAME;
|
2024-01-29 15:40:41 +00:00
|
|
|
ctx->mod_field_num = 0;
|
2019-02-07 14:38:42 +00:00
|
|
|
appctx->st1 = PROMEX_DUMPER_BACK;
|
2022-11-14 06:37:45 +00:00
|
|
|
__fallthrough;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
|
|
|
case PROMEX_DUMPER_BACK:
|
2022-05-03 15:33:00 +00:00
|
|
|
if (ctx->flags & PROMEX_FL_SCOPE_BACK) {
|
2019-11-18 13:47:08 +00:00
|
|
|
ret = promex_dump_back_metrics(appctx, htx);
|
|
|
|
if (ret <= 0) {
|
|
|
|
if (ret == -1)
|
|
|
|
goto error;
|
|
|
|
goto full;
|
|
|
|
}
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags &= ~PROMEX_FL_BACK_METRIC;
|
|
|
|
ctx->flags |= (PROMEX_FL_METRIC_HDR|PROMEX_FL_SRV_METRIC);
|
|
|
|
ctx->obj_state = 0;
|
2024-04-19 16:03:45 +00:00
|
|
|
ctx->field_num = ST_I_PX_PXNAME;
|
2024-01-29 15:40:41 +00:00
|
|
|
ctx->mod_field_num = 0;
|
2019-02-07 14:38:42 +00:00
|
|
|
appctx->st1 = PROMEX_DUMPER_SRV;
|
2022-11-14 06:37:45 +00:00
|
|
|
__fallthrough;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
|
|
|
case PROMEX_DUMPER_SRV:
|
2022-05-03 15:33:00 +00:00
|
|
|
if (ctx->flags & PROMEX_FL_SCOPE_SERVER) {
|
2019-11-18 13:47:08 +00:00
|
|
|
ret = promex_dump_srv_metrics(appctx, htx);
|
|
|
|
if (ret <= 0) {
|
|
|
|
if (ret == -1)
|
|
|
|
goto error;
|
|
|
|
goto full;
|
|
|
|
}
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags &= ~(PROMEX_FL_METRIC_HDR|PROMEX_FL_SRV_METRIC);
|
2024-01-30 14:58:31 +00:00
|
|
|
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_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;
|
|
|
|
goto full;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->flags &= ~(PROMEX_FL_METRIC_HDR|PROMEX_FL_MODULE_METRIC);
|
2022-05-03 16:05:23 +00:00
|
|
|
ctx->field_num = 0;
|
2024-01-29 15:40:41 +00:00
|
|
|
ctx->mod_field_num = 0;
|
2019-02-07 14:38:42 +00:00
|
|
|
appctx->st1 = PROMEX_DUMPER_DONE;
|
2022-11-14 06:37:45 +00:00
|
|
|
__fallthrough;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
|
|
|
case PROMEX_DUMPER_DONE:
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
full:
|
2023-05-05 09:28:45 +00:00
|
|
|
sc_need_room(sc, channel_htx_recv_max(sc_ic(appctx_sc(appctx)), htx) + 1);
|
2019-02-07 14:38:42 +00:00
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
/* unrecoverable error */
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags = 0;
|
2022-05-03 16:05:23 +00:00
|
|
|
ctx->field_num = 0;
|
2024-01-29 15:40:41 +00:00
|
|
|
ctx->mod_field_num = 0;
|
2019-02-07 14:38:42 +00:00
|
|
|
appctx->st1 = PROMEX_DUMPER_DONE;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-03-23 17:28:40 +00:00
|
|
|
/* Parse the query string of request URI to filter the metrics. It returns 1 on
|
2019-11-18 13:47:08 +00:00
|
|
|
* success and -1 on error. */
|
2022-05-27 08:16:15 +00:00
|
|
|
static int promex_parse_uri(struct appctx *appctx, struct stconn *sc)
|
2019-11-18 13:47:08 +00:00
|
|
|
{
|
2022-05-03 15:33:00 +00:00
|
|
|
struct promex_ctx *ctx = appctx->svcctx;
|
2022-05-27 08:16:15 +00:00
|
|
|
struct channel *req = sc_oc(sc);
|
|
|
|
struct channel *res = sc_ic(sc);
|
2019-11-18 13:47:08 +00:00
|
|
|
struct htx *req_htx, *res_htx;
|
|
|
|
struct htx_sl *sl;
|
2019-11-26 11:56:26 +00:00
|
|
|
char *p, *key, *value;
|
|
|
|
const char *end;
|
2019-11-18 13:47:08 +00:00
|
|
|
struct buffer *err;
|
|
|
|
int default_scopes = PROMEX_FL_SCOPE_ALL;
|
2024-01-31 16:15:49 +00:00
|
|
|
int default_metrics_filter = PROMEX_FL_INC_METRIC_BY_DEFAULT;
|
2019-11-18 13:47:08 +00:00
|
|
|
int len;
|
|
|
|
|
|
|
|
/* Get the query-string */
|
|
|
|
req_htx = htxbuf(&req->buf);
|
|
|
|
sl = http_get_stline(req_htx);
|
|
|
|
if (!sl)
|
|
|
|
goto error;
|
|
|
|
p = http_find_param_list(HTX_SL_REQ_UPTR(sl), HTX_SL_REQ_ULEN(sl), '?');
|
|
|
|
if (!p)
|
|
|
|
goto end;
|
|
|
|
end = HTX_SL_REQ_UPTR(sl) + HTX_SL_REQ_ULEN(sl);
|
|
|
|
|
2019-11-26 11:56:26 +00:00
|
|
|
/* copy the query-string */
|
|
|
|
len = end - p;
|
2019-11-18 13:47:08 +00:00
|
|
|
chunk_reset(&trash);
|
|
|
|
memcpy(trash.area, p, len);
|
|
|
|
trash.area[len] = 0;
|
|
|
|
p = trash.area;
|
2019-11-26 11:56:26 +00:00
|
|
|
end = trash.area + len;
|
2019-11-18 13:47:08 +00:00
|
|
|
|
|
|
|
/* Parse the query-string */
|
2019-11-26 11:56:26 +00:00
|
|
|
while (p < end && *p && *p != '#') {
|
|
|
|
value = NULL;
|
|
|
|
|
|
|
|
/* decode parameter name */
|
|
|
|
key = p;
|
|
|
|
while (p < end && *p != '=' && *p != '&' && *p != '#')
|
2019-11-18 13:47:08 +00:00
|
|
|
++p;
|
2019-11-26 11:56:26 +00:00
|
|
|
/* found a value */
|
|
|
|
if (*p == '=') {
|
|
|
|
*(p++) = 0;
|
|
|
|
value = p;
|
|
|
|
}
|
|
|
|
else if (*p == '&')
|
|
|
|
*(p++) = 0;
|
|
|
|
else if (*p == '#')
|
|
|
|
*p = 0;
|
2020-04-23 15:54:47 +00:00
|
|
|
len = url_decode(key, 1);
|
2019-11-26 11:56:26 +00:00
|
|
|
if (len == -1)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* decode value */
|
|
|
|
if (value) {
|
|
|
|
while (p < end && *p != '=' && *p != '&' && *p != '#')
|
|
|
|
++p;
|
|
|
|
if (*p == '=')
|
|
|
|
goto error;
|
|
|
|
if (*p == '&')
|
|
|
|
*(p++) = 0;
|
|
|
|
else if (*p == '#')
|
|
|
|
*p = 0;
|
2020-04-23 15:54:47 +00:00
|
|
|
len = url_decode(value, 1);
|
2019-11-26 11:56:26 +00:00
|
|
|
if (len == -1)
|
|
|
|
goto error;
|
|
|
|
}
|
2019-11-18 13:47:08 +00:00
|
|
|
|
2021-01-02 21:31:55 +00:00
|
|
|
if (strcmp(key, "scope") == 0) {
|
2019-11-26 11:56:26 +00:00
|
|
|
default_scopes = 0; /* at least a scope defined, unset default scopes */
|
|
|
|
if (!value)
|
|
|
|
goto error;
|
|
|
|
else if (*value == 0)
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags &= ~PROMEX_FL_SCOPE_ALL;
|
2024-01-31 16:15:49 +00:00
|
|
|
else if (*value == '*' && *(value+1) == 0)
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags |= PROMEX_FL_SCOPE_ALL;
|
2021-01-02 21:31:55 +00:00
|
|
|
else if (strcmp(value, "global") == 0)
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags |= PROMEX_FL_SCOPE_GLOBAL;
|
2021-01-02 21:31:55 +00:00
|
|
|
else if (strcmp(value, "server") == 0)
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags |= PROMEX_FL_SCOPE_SERVER;
|
2021-01-02 21:31:55 +00:00
|
|
|
else if (strcmp(value, "backend") == 0)
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags |= PROMEX_FL_SCOPE_BACK;
|
2021-01-02 21:31:55 +00:00
|
|
|
else if (strcmp(value, "frontend") == 0)
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags |= PROMEX_FL_SCOPE_FRONT;
|
2021-02-14 22:22:56 +00:00
|
|
|
else if (strcmp(value, "listener") == 0)
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags |= PROMEX_FL_SCOPE_LI;
|
2024-01-30 14:58:31 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-11-18 13:47:08 +00:00
|
|
|
}
|
2024-01-31 16:15:49 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2024-01-29 15:40:41 +00:00
|
|
|
else if (strcmp(key, "extra-counters") == 0) {
|
|
|
|
ctx->flags |= PROMEX_FL_EXTRA_COUNTERS;
|
|
|
|
}
|
2021-01-02 21:31:55 +00:00
|
|
|
else if (strcmp(key, "no-maint") == 0)
|
2022-05-03 15:33:00 +00:00
|
|
|
ctx->flags |= PROMEX_FL_NO_MAINT_SRV;
|
2019-11-18 13:47:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
2024-01-31 16:15:49 +00:00
|
|
|
ctx->flags |= (default_scopes | default_metrics_filter);
|
2019-11-18 13:47:08 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
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;
|
2024-01-30 14:58:31 +00:00
|
|
|
|
|
|
|
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;
|
2019-11-18 13:47:08 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 14:38:42 +00:00
|
|
|
/* Send HTTP headers of the response. It returns 1 on success and 0 if <htx> is
|
|
|
|
* full. */
|
2022-05-27 08:16:15 +00:00
|
|
|
static int promex_send_headers(struct appctx *appctx, struct stconn *sc, struct htx *htx)
|
2019-02-07 14:38:42 +00:00
|
|
|
{
|
2022-05-27 08:16:15 +00:00
|
|
|
struct channel *chn = sc_ic(sc);
|
2019-02-07 14:38:42 +00:00
|
|
|
struct htx_sl *sl;
|
|
|
|
unsigned int flags;
|
|
|
|
|
|
|
|
flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11|HTX_SL_F_XFER_ENC|HTX_SL_F_XFER_LEN|HTX_SL_F_CHNK);
|
|
|
|
sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"), ist("200"), ist("OK"));
|
|
|
|
if (!sl)
|
|
|
|
goto full;
|
|
|
|
sl->info.res.status = 200;
|
|
|
|
if (!htx_add_header(htx, ist("Cache-Control"), ist("no-cache")) ||
|
|
|
|
!htx_add_header(htx, ist("Content-Type"), ist("text/plain; version=0.0.4")) ||
|
|
|
|
!htx_add_header(htx, ist("Transfer-Encoding"), ist("chunked")) ||
|
|
|
|
!htx_add_endof(htx, HTX_BLK_EOH))
|
|
|
|
goto full;
|
|
|
|
|
2019-03-27 14:48:53 +00:00
|
|
|
channel_add_input(chn, htx->data);
|
2019-02-07 14:38:42 +00:00
|
|
|
return 1;
|
|
|
|
full:
|
|
|
|
htx_reset(htx);
|
2023-05-05 09:28:45 +00:00
|
|
|
sc_need_room(sc, 0);
|
2019-02-07 14:38:42 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The function returns 1 if the initialisation is complete, 0 if
|
|
|
|
* an errors occurs and -1 if more data are required for initializing
|
|
|
|
* the applet.
|
|
|
|
*/
|
2022-01-13 15:01:35 +00:00
|
|
|
static int promex_appctx_init(struct appctx *appctx)
|
2019-02-07 14:38:42 +00:00
|
|
|
{
|
2024-01-30 14:58:31 +00:00
|
|
|
struct promex_ctx *ctx;
|
|
|
|
|
2022-05-03 15:33:00 +00:00
|
|
|
applet_reserve_svcctx(appctx, sizeof(struct promex_ctx));
|
2024-01-30 14:58:31 +00:00
|
|
|
ctx = appctx->svcctx;
|
|
|
|
memset(ctx->p, 0, sizeof(ctx->p));
|
|
|
|
LIST_INIT(&ctx->modules);
|
2024-01-31 16:15:49 +00:00
|
|
|
ctx->filters = EB_ROOT;
|
2019-02-07 14:38:42 +00:00
|
|
|
appctx->st0 = PROMEX_ST_INIT;
|
2022-05-12 09:52:27 +00:00
|
|
|
return 0;
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
2024-01-30 14:58:31 +00:00
|
|
|
|
|
|
|
/* 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;
|
2024-01-31 16:15:49 +00:00
|
|
|
struct promex_metric_filter *flt;
|
|
|
|
struct eb32_node *node, *next;
|
2024-01-30 14:58:31 +00:00
|
|
|
|
2024-02-22 13:16:37 +00:00
|
|
|
if (appctx->st1 == PROMEX_DUMPER_SRV) {
|
|
|
|
struct server *srv = objt_server(ctx->p[1]);
|
|
|
|
srv_drop(srv);
|
|
|
|
}
|
|
|
|
|
2024-01-30 14:58:31 +00:00
|
|
|
list_for_each_entry_safe(ref, back, &ctx->modules, list) {
|
|
|
|
LIST_DELETE(&ref->list);
|
|
|
|
pool_free(pool_head_promex_mod_ref, ref);
|
|
|
|
}
|
2024-01-31 16:15:49 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2024-01-30 14:58:31 +00:00
|
|
|
}
|
|
|
|
|
2019-02-07 14:38:42 +00:00
|
|
|
/* The main I/O handler for the promex applet. */
|
|
|
|
static void promex_appctx_handle_io(struct appctx *appctx)
|
|
|
|
{
|
2022-05-27 09:08:15 +00:00
|
|
|
struct stconn *sc = appctx_sc(appctx);
|
2022-05-27 08:16:15 +00:00
|
|
|
struct stream *s = __sc_strm(sc);
|
|
|
|
struct channel *req = sc_oc(sc);
|
|
|
|
struct channel *res = sc_ic(sc);
|
2019-02-07 14:38:42 +00:00
|
|
|
struct htx *req_htx, *res_htx;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
res_htx = htx_from_buf(&res->buf);
|
2023-03-31 09:29:54 +00:00
|
|
|
|
|
|
|
if (unlikely(se_fl_test(appctx->sedesc, (SE_FL_EOS|SE_FL_ERROR|SE_FL_SHR|SE_FL_SHW))))
|
2019-02-07 14:38:42 +00:00
|
|
|
goto out;
|
|
|
|
|
2020-03-23 17:28:40 +00:00
|
|
|
/* Check if the input buffer is available. */
|
2019-02-07 14:38:42 +00:00
|
|
|
if (!b_size(&res->buf)) {
|
2023-05-05 09:28:45 +00:00
|
|
|
sc_need_room(sc, 0);
|
2019-02-07 14:38:42 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (appctx->st0) {
|
|
|
|
case PROMEX_ST_INIT:
|
2022-05-27 08:16:15 +00:00
|
|
|
ret = promex_parse_uri(appctx, sc);
|
2019-11-18 13:47:08 +00:00
|
|
|
if (ret <= 0) {
|
|
|
|
if (ret == -1)
|
|
|
|
goto error;
|
|
|
|
goto out;
|
|
|
|
}
|
2019-02-07 14:38:42 +00:00
|
|
|
appctx->st0 = PROMEX_ST_HEAD;
|
|
|
|
appctx->st1 = PROMEX_DUMPER_INIT;
|
2022-11-14 06:37:45 +00:00
|
|
|
__fallthrough;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
|
|
|
case PROMEX_ST_HEAD:
|
2022-05-27 08:16:15 +00:00
|
|
|
if (!promex_send_headers(appctx, sc, res_htx))
|
2019-02-07 14:38:42 +00:00
|
|
|
goto out;
|
|
|
|
appctx->st0 = ((s->txn->meth == HTTP_METH_HEAD) ? PROMEX_ST_DONE : PROMEX_ST_DUMP);
|
2022-11-14 06:37:45 +00:00
|
|
|
__fallthrough;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
|
|
|
case PROMEX_ST_DUMP:
|
2022-05-27 08:16:15 +00:00
|
|
|
ret = promex_dump_metrics(appctx, sc, res_htx);
|
2019-02-07 14:38:42 +00:00
|
|
|
if (ret <= 0) {
|
|
|
|
if (ret == -1)
|
|
|
|
goto error;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
appctx->st0 = PROMEX_ST_DONE;
|
2022-11-14 06:37:45 +00:00
|
|
|
__fallthrough;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
|
|
|
case PROMEX_ST_DONE:
|
2022-04-07 08:19:46 +00:00
|
|
|
/* no more data are expected. If the response buffer is
|
|
|
|
* empty, be sure to add something (EOT block in this
|
|
|
|
* case) to have something to send. It is important to
|
|
|
|
* be sure the EOM flags will be handled by the
|
|
|
|
* endpoint.
|
|
|
|
*/
|
|
|
|
if (htx_is_empty(res_htx)) {
|
|
|
|
if (!htx_add_endof(res_htx, HTX_BLK_EOT)) {
|
2023-05-05 09:28:45 +00:00
|
|
|
sc_need_room(sc, sizeof(struct htx_blk) + 1);
|
2022-04-07 08:19:46 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
channel_add_input(res, 1);
|
|
|
|
}
|
|
|
|
res_htx->flags |= HTX_FL_EOM;
|
2022-05-17 16:05:31 +00:00
|
|
|
se_fl_set(appctx->sedesc, SE_FL_EOI);
|
2019-03-27 14:48:53 +00:00
|
|
|
appctx->st0 = PROMEX_ST_END;
|
2022-11-14 06:37:45 +00:00
|
|
|
__fallthrough;
|
2019-02-07 14:38:42 +00:00
|
|
|
|
2019-03-27 14:48:53 +00:00
|
|
|
case PROMEX_ST_END:
|
2023-03-31 09:29:54 +00:00
|
|
|
se_fl_set(appctx->sedesc, SE_FL_EOS);
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
htx_to_buf(res_htx, &res->buf);
|
2019-03-27 14:48:53 +00:00
|
|
|
|
|
|
|
/* eat the whole request */
|
|
|
|
if (co_data(req)) {
|
|
|
|
req_htx = htx_from_buf(&req->buf);
|
|
|
|
co_htx_skip(req, req_htx, co_data(req));
|
|
|
|
}
|
2019-02-07 14:38:42 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
error:
|
2023-03-31 09:29:54 +00:00
|
|
|
se_fl_set(appctx->sedesc, SE_FL_ERROR);
|
2023-01-13 07:53:23 +00:00
|
|
|
goto out;
|
2019-02-07 14:38:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct applet promex_applet = {
|
|
|
|
.obj_type = OBJ_TYPE_APPLET,
|
|
|
|
.name = "<PROMEX>", /* used for logging */
|
|
|
|
.init = promex_appctx_init,
|
2024-01-30 14:58:31 +00:00
|
|
|
.release = promex_appctx_release,
|
2019-02-07 14:38:42 +00:00
|
|
|
.fct = promex_appctx_handle_io,
|
|
|
|
};
|
|
|
|
|
|
|
|
static enum act_parse_ret service_parse_prometheus_exporter(const char **args, int *cur_arg, struct proxy *px,
|
|
|
|
struct act_rule *rule, char **err)
|
|
|
|
{
|
|
|
|
/* Prometheus exporter service is only available on "http-request" rulesets */
|
|
|
|
if (rule->from != ACT_F_HTTP_REQ) {
|
|
|
|
memprintf(err, "Prometheus exporter service only available on 'http-request' rulesets");
|
|
|
|
return ACT_RET_PRS_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add applet pointer in the rule. */
|
|
|
|
rule->applet = promex_applet;
|
|
|
|
|
|
|
|
return ACT_RET_PRS_OK;
|
|
|
|
}
|
|
|
|
static void promex_register_build_options(void)
|
|
|
|
{
|
|
|
|
char *ptr = NULL;
|
|
|
|
|
|
|
|
memprintf(&ptr, "Built with the Prometheus exporter as a service");
|
|
|
|
hap_register_build_opts(ptr, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct action_kw_list service_actions = { ILH, {
|
|
|
|
{ "prometheus-exporter", service_parse_prometheus_exporter },
|
|
|
|
{ /* END */ }
|
|
|
|
}};
|
|
|
|
|
|
|
|
INITCALL1(STG_REGISTER, service_keywords_register, &service_actions);
|
|
|
|
INITCALL0(STG_REGISTER, promex_register_build_options);
|