From: Amaury Denoyelle Date: Mon, 5 Oct 2020 09:49:37 +0000 (+0200) Subject: MINOR: stats: define the concept of domain for statistics X-Git-Tag: v2.3-dev6~104 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=072f97eddf3ea5d4b6293bd7185d7311e0744992;p=thirdparty%2Fhaproxy.git MINOR: stats: define the concept of domain for statistics The domain option will be used to have statistics attached to other objects than proxies/listeners/servers. At the moment, only the PROXY domain is available. Add an argument 'domain' on the 'show stats' cli command to specify the domain. Only 'domain proxy' is available now. If not specified, proxy will be considered the default domain. For HTML output, only proxy statistics will be displayed. --- diff --git a/doc/management.txt b/doc/management.txt index adbad95d34..9a749e48a3 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -944,6 +944,8 @@ mechanism is the HTTP statistics page. This page also exposes an alternative CSV output format for monitoring tools. The same format is provided on the Unix socket. +Statistics are regroup in categories labelled as domains, corresponding to the +multiple components of HAProxy. Only the proxy domain is available. 9.1. CSV format --------------- @@ -2423,12 +2425,13 @@ show sess The special id "all" dumps the states of all sessions, which must be avoided as much as possible as it is highly CPU intensive and can take a lot of time. -show stat [{|} ] [typed|json] [desc] - Dump statistics using the CSV format; using the extended typed output - format described in the section above if "typed" is passed after the - other arguments; or in JSON if "json" is passed after the other arguments - . By passing , and , it is possible to dump only selected - items : +show stat [domain ] [{|} ] [typed|json] [desc] + Dump statistics. The domain is used to select which statistics to print; only + proxy is available for now. By default, the CSV format is used; you can + activate the extended typed output format described in the section above if + "typed" is passed after the other arguments; or in JSON if "json" is passed + after the other arguments. By passing , and , it is possible + to dump only selected items : - is a proxy ID, -1 to dump everything. Alternatively, a proxy name may be specified. In this case, this proxy's ID will be used as the ID selector. diff --git a/include/haproxy/applet-t.h b/include/haproxy/applet-t.h index 7c97f19176..eca55c92af 100644 --- a/include/haproxy/applet-t.h +++ b/include/haproxy/applet-t.h @@ -120,6 +120,7 @@ struct appctx { struct { void *obj1; /* context pointer used in stats dump */ void *obj2; /* context pointer used in stats dump */ + uint32_t domain; /* set the stats to used, for now only proxy stats are supported */ int scope_str; /* limit scope to a frontend/backend substring */ int scope_len; /* length of the string above in the buffer */ int px_st; /* STAT_PX_ST* */ diff --git a/include/haproxy/stats-t.h b/include/haproxy/stats-t.h index 139b5468b1..be4c6865c0 100644 --- a/include/haproxy/stats-t.h +++ b/include/haproxy/stats-t.h @@ -50,6 +50,8 @@ #define STATS_TYPE_SV 2 #define STATS_TYPE_SO 3 +#define STATS_DOMAIN (0) /* used for bitshifting, type of statistics, for now only proxy is available */ + /* HTTP stats : applet.st0 */ enum { STAT_HTTP_INIT = 0, /* Initial state */ @@ -450,5 +452,12 @@ struct field { } u; }; +/* stats_domain is used in a flag as a 1 byte field */ +enum stats_domain { + STATS_DOMAIN_PROXY = 0, + STATS_DOMAIN_COUNT, + + STATS_DOMAIN_MASK = 0xff +}; #endif /* _HAPROXY_STATS_T_H */ diff --git a/src/stats.c b/src/stats.c index 66b8a49475..16e0c10fdf 100644 --- a/src/stats.c +++ b/src/stats.c @@ -257,6 +257,11 @@ static THREAD_LOCAL struct field info[INF_TOTAL_FIELDS]; /* one line of stats */ static THREAD_LOCAL struct field stats[ST_F_TOTAL_FIELDS]; +static inline uint8_t stats_get_domain(uint32_t domain) +{ + return domain >> STATS_DOMAIN & STATS_DOMAIN_MASK; +} + static void stats_dump_json_schema(struct buffer *out); int stats_putchk(struct channel *chn, struct htx *htx, struct buffer *chk) @@ -531,7 +536,8 @@ static int stats_dump_fields_csv(struct buffer *out, static int stats_dump_fields_typed(struct buffer *out, const struct field *stats, size_t stats_count, - unsigned int flags) + unsigned int flags, + enum stats_domain domain) { int field; @@ -539,14 +545,23 @@ static int stats_dump_fields_typed(struct buffer *out, if (!stats[field].type) continue; - chunk_appendf(out, "%c.%u.%u.%d.%s.%u:", - stats[ST_F_TYPE].u.u32 == STATS_TYPE_FE ? 'F' : - stats[ST_F_TYPE].u.u32 == STATS_TYPE_BE ? 'B' : - stats[ST_F_TYPE].u.u32 == STATS_TYPE_SO ? 'L' : - stats[ST_F_TYPE].u.u32 == STATS_TYPE_SV ? 'S' : - '?', - stats[ST_F_IID].u.u32, stats[ST_F_SID].u.u32, - field, stat_fields[field].name, stats[ST_F_PID].u.u32); + switch (domain) { + case STATS_DOMAIN_PROXY: + chunk_appendf(out, "%c.%u.%u.%d.%s.%u:", + stats[ST_F_TYPE].u.u32 == STATS_TYPE_FE ? 'F' : + stats[ST_F_TYPE].u.u32 == STATS_TYPE_BE ? 'B' : + stats[ST_F_TYPE].u.u32 == STATS_TYPE_SO ? 'L' : + stats[ST_F_TYPE].u.u32 == STATS_TYPE_SV ? 'S' : + '?', + stats[ST_F_IID].u.u32, stats[ST_F_SID].u.u32, + field, + stat_fields[field].name, + stats[ST_F_PID].u.u32); + break; + + default: + break; + } if (!stats_emit_field_tags(out, &stats[field], ':')) return 0; @@ -640,7 +655,8 @@ static void stats_print_proxy_field_json(struct buffer *out, /* Dump all fields from into using a typed "field:desc:type:value" format */ static int stats_dump_fields_json(struct buffer *out, const struct field *stats, size_t stats_count, - unsigned int flags) + unsigned int flags, + enum stats_domain domain) { int field; int started = 0; @@ -661,12 +677,14 @@ static int stats_dump_fields_json(struct buffer *out, started = 1; old_len = out->data; - stats_print_proxy_field_json(out, &stats[field], - stat_fields[field].name, field, - stats[ST_F_TYPE].u.u32, - stats[ST_F_IID].u.u32, - stats[ST_F_SID].u.u32, - stats[ST_F_PID].u.u32); + if (domain == STATS_DOMAIN_PROXY) { + stats_print_proxy_field_json(out, &stats[field], + stat_fields[field].name, field, + stats[ST_F_TYPE].u.u32, + stats[ST_F_IID].u.u32, + stats[ST_F_SID].u.u32, + stats[ST_F_PID].u.u32); + } if (old_len == out->data) goto err; @@ -1408,9 +1426,9 @@ int stats_dump_one_line(const struct field *stats, size_t stats_count, if (appctx->ctx.stats.flags & STAT_FMT_HTML) ret = stats_dump_fields_html(&trash, stats, appctx->ctx.stats.flags); else if (appctx->ctx.stats.flags & STAT_FMT_TYPED) - ret = stats_dump_fields_typed(&trash, stats, stats_count, appctx->ctx.stats.flags); + ret = stats_dump_fields_typed(&trash, stats, stats_count, appctx->ctx.stats.flags, appctx->ctx.stats.domain); else if (appctx->ctx.stats.flags & STAT_FMT_JSON) - ret = stats_dump_fields_json(&trash, stats, stats_count, appctx->ctx.stats.flags); + ret = stats_dump_fields_json(&trash, stats, stats_count, appctx->ctx.stats.flags, appctx->ctx.stats.domain); else ret = stats_dump_fields_csv(&trash, stats, stats_count, appctx->ctx.stats.flags); @@ -3339,6 +3357,9 @@ static void http_stats_io_handler(struct appctx *appctx) struct channel *res = si_ic(si); struct htx *req_htx, *res_htx; + /* only proxy stats are available via http */ + appctx->ctx.stats.domain = STATS_DOMAIN_PROXY; + res_htx = htx_from_buf(&res->buf); if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO)) @@ -3932,7 +3953,19 @@ static int cli_parse_show_stat(char **args, char *payload, struct appctx *appctx if ((strm_li(si_strm(appctx->owner))->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER) appctx->ctx.stats.flags |= STAT_SHLGNDS; - if (*args[arg] && *args[arg+1] && *args[arg+2]) { + /* proxy is the default domain */ + appctx->ctx.stats.domain = STATS_DOMAIN_PROXY; + if (!strcmp(args[arg], "domain")) { + ++args; + + if (!strcmp(args[arg], "proxy")) + ++args; + else + return cli_err(appctx, "Invalid statistics domain.\n"); + } + + if (appctx->ctx.stats.domain == STATS_DOMAIN_PROXY + && *args[arg] && *args[arg+1] && *args[arg+2]) { struct proxy *px; px = proxy_find_by_name(args[arg], 0, 0);