MEDIUM: stats: implement dump stats-file CLI
Define a new CLI command "dump stats-file" with its handler cli_parse_dump_stat_file(). It will loop twice on proxies_list to dump first frontend and then backend side. It reuses the common function stats_dump_stat_to_buffer(), using STAT_F_BOUND to restrict on the correct side. A new module stats-file.c is added to regroup function specifics to stats-file. It defines two main functions : * stats_dump_file_header() to generate the list of column list prefixed by the line context, either "#fe" or "#be" * stats_dump_fields_file() to generate each stat lines. Object without GUID are skipped. Each stat entry is separated by a comma. For the moment, stats-file does not support statistics modules. As such, stats_dump_*_line() functions are updated to prevent looping over stats module on stats-file output.
This commit is contained in:
parent
83281303f6
commit
e74148fb7c
2
Makefile
2
Makefile
|
@ -975,7 +975,7 @@ OBJS += src/mux_h2.o src/mux_fcgi.o src/mux_h1.o src/tcpcheck.o \
|
|||
src/dynbuf.o src/wdt.o src/pipe.o src/init.o src/http_acl.o \
|
||||
src/hpack-huff.o src/hpack-enc.o src/dict.o src/freq_ctr.o \
|
||||
src/ebtree.o src/hash.o src/dgram.o src/version.o src/proto_rhttp.o \
|
||||
src/guid.o src/stats-html.o src/stats-json.o
|
||||
src/guid.o src/stats-html.o src/stats-json.o src/stats-file.o
|
||||
|
||||
ifneq ($(TRACE),)
|
||||
OBJS += src/calltrace.o
|
||||
|
|
|
@ -32,6 +32,7 @@ Summary
|
|||
9.3. Unix Socket commands
|
||||
9.4. Master CLI
|
||||
9.4.1. Master CLI commands
|
||||
9.5. Stats-file
|
||||
10. Tricks for easier configuration management
|
||||
11. Well-known traps to avoid
|
||||
12. Debugging and performance issues
|
||||
|
@ -2067,6 +2068,10 @@ disable server <backend>/<server>
|
|||
This command is restricted and can only be issued on sockets configured for
|
||||
level "admin".
|
||||
|
||||
dump stats-file
|
||||
Generate a stats-file which can be used to preload haproxy counters values on
|
||||
startup. See "Stats-file" section for more detail.
|
||||
|
||||
enable agent <backend>/<server>
|
||||
Resume auxiliary agent check that was temporarily stopped.
|
||||
|
||||
|
@ -4235,6 +4240,29 @@ show startup-logs
|
|||
|
||||
Those messages are also dumped with the "reload" command.
|
||||
|
||||
|
||||
9.5. Stats-file
|
||||
--------------
|
||||
|
||||
A so-called stats-file can be used to preload internal haproxy counters on
|
||||
process startup with non-null values. Its main purpose is to preserve
|
||||
statistics for worker processes accross reloads. Only an excerpt of all the
|
||||
exposed haproxy statistics is present in a stats-file as it only makes sense to
|
||||
preload metric-type values.
|
||||
|
||||
For the moment, only proxy counters are supported in stats-file. This allows to
|
||||
preload values for frontends, backends, servers and listeners. However only
|
||||
objects instances with a non-empty GUID are stored in a stats-file. This
|
||||
guarantees that value will be preloaded for object with matching type and GUID,
|
||||
even if other parameters differ.
|
||||
|
||||
The CLI command "dump stats-file" purpose is to generate a stats-file. Format
|
||||
of the stats-file is internally defined and freely subject to future changes
|
||||
and extension. It is designed to be compatible at least accross adjacent
|
||||
haproxy stable branch releases, but may require optional extra configuration
|
||||
when loading a stats-file to a process running on an older version.
|
||||
|
||||
|
||||
10. Tricks for easier configuration management
|
||||
----------------------------------------------
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef _HAPROXY_STATS_FILE_H
|
||||
#define _HAPROXY_STATS_FILE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <haproxy/buf-t.h>
|
||||
#include <haproxy/stats-t.h>
|
||||
|
||||
int stats_dump_fields_file(struct buffer *out,
|
||||
const struct field *stats, size_t stats_count,
|
||||
struct show_stat_ctx *ctx);
|
||||
|
||||
void stats_dump_file_header(int type, struct buffer *out);
|
||||
|
||||
#endif /* _HAPROXY_STATS_FILE_H */
|
|
@ -0,0 +1,92 @@
|
|||
#include <haproxy/stats-file.h>
|
||||
|
||||
#include <haproxy/api.h>
|
||||
#include <haproxy/buf.h>
|
||||
#include <haproxy/chunk.h>
|
||||
#include <haproxy/guid-t.h>
|
||||
#include <haproxy/list.h>
|
||||
#include <haproxy/listener-t.h>
|
||||
#include <haproxy/obj_type.h>
|
||||
#include <haproxy/proxy-t.h>
|
||||
#include <haproxy/server-t.h>
|
||||
#include <haproxy/stats.h>
|
||||
|
||||
/* Dump all fields from <stats> into <out> for stats-file. */
|
||||
int stats_dump_fields_file(struct buffer *out,
|
||||
const struct field *line, size_t stats_count,
|
||||
struct show_stat_ctx *ctx)
|
||||
{
|
||||
struct guid_node *guid;
|
||||
struct listener *l;
|
||||
int i;
|
||||
|
||||
switch (ctx->px_st) {
|
||||
case STAT_PX_ST_FE:
|
||||
case STAT_PX_ST_BE:
|
||||
guid = &__objt_proxy(ctx->obj1)->guid;
|
||||
break;
|
||||
|
||||
case STAT_PX_ST_LI:
|
||||
l = LIST_ELEM(ctx->obj2, struct listener *, by_fe);
|
||||
guid = &l->guid;
|
||||
break;
|
||||
|
||||
case STAT_PX_ST_SV:
|
||||
guid = &__objt_server(ctx->obj2)->guid;
|
||||
break;
|
||||
|
||||
default:
|
||||
ABORT_NOW();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Skip objects without GUID. */
|
||||
if (!guid->node.key)
|
||||
return 1;
|
||||
|
||||
chunk_appendf(out, "%s,", (char *)guid->node.key);
|
||||
|
||||
for (i = 0; i < stats_count; ++i) {
|
||||
/* Empty field for stats-file is used to skip its output,
|
||||
* including any separator.
|
||||
*/
|
||||
if (field_format(line, i) == FF_EMPTY)
|
||||
continue;
|
||||
|
||||
if (!stats_emit_raw_data_field(out, &line[i]))
|
||||
return 0;
|
||||
if (!chunk_strcat(out, ","))
|
||||
return 0;
|
||||
}
|
||||
|
||||
chunk_strcat(out, "\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
void stats_dump_file_header(int type, struct buffer *out)
|
||||
{
|
||||
const struct stat_col *col;
|
||||
int i;
|
||||
|
||||
/* Caller must specified ither FE or BE. */
|
||||
BUG_ON(!(type & ((1 << STATS_TYPE_FE) | (1 << STATS_TYPE_BE))));
|
||||
|
||||
if (type & (1 << STATS_TYPE_FE)) {
|
||||
chunk_strcat(out, "#fe guid,");
|
||||
for (i = 0; i < ST_I_PX_MAX; ++i) {
|
||||
col = &stat_cols_px[i];
|
||||
if (stcol_nature(col) == FN_COUNTER && (col->cap & (STATS_PX_CAP_FE|STATS_PX_CAP_LI)))
|
||||
chunk_appendf(out, "%s,", col->name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
chunk_appendf(out, "#be guid,");
|
||||
for (i = 0; i < ST_I_PX_MAX; ++i) {
|
||||
col = &stat_cols_px[i];
|
||||
if (stcol_nature(col) == FN_COUNTER && (col->cap & (STATS_PX_CAP_BE|STATS_PX_CAP_SRV)))
|
||||
chunk_appendf(out, "%s,", col->name);
|
||||
}
|
||||
}
|
||||
|
||||
chunk_strcat(out, "\n");
|
||||
}
|
68
src/stats.c
68
src/stats.c
|
@ -57,6 +57,7 @@
|
|||
#include <haproxy/server.h>
|
||||
#include <haproxy/session.h>
|
||||
#include <haproxy/stats.h>
|
||||
#include <haproxy/stats-file.h>
|
||||
#include <haproxy/stats-html.h>
|
||||
#include <haproxy/stats-json.h>
|
||||
#include <haproxy/stconn.h>
|
||||
|
@ -631,6 +632,8 @@ int stats_dump_one_line(const struct field *line, size_t stats_count,
|
|||
ret = stats_dump_fields_typed(chk, line, stats_count, ctx);
|
||||
else if (ctx->flags & STAT_F_FMT_JSON)
|
||||
ret = stats_dump_fields_json(chk, line, stats_count, ctx);
|
||||
else if (ctx->flags & STAT_F_FMT_FILE)
|
||||
ret = stats_dump_fields_file(chk, line, stats_count, ctx);
|
||||
else
|
||||
ret = stats_dump_fields_csv(chk, line, stats_count, ctx);
|
||||
|
||||
|
@ -909,6 +912,9 @@ static int stats_dump_fe_line(struct stconn *sc, struct proxy *px)
|
|||
list_for_each_entry(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
||||
void *counters;
|
||||
|
||||
if (ctx->flags & STAT_F_FMT_FILE)
|
||||
continue;
|
||||
|
||||
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_FE)) {
|
||||
stats_count += mod->stats_count;
|
||||
continue;
|
||||
|
@ -1055,6 +1061,9 @@ static int stats_dump_li_line(struct stconn *sc, struct proxy *px, struct listen
|
|||
list_for_each_entry(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
||||
void *counters;
|
||||
|
||||
if (ctx->flags & STAT_F_FMT_FILE)
|
||||
continue;
|
||||
|
||||
if (!(stats_px_get_cap(mod->domain_flags) & STATS_PX_CAP_LI)) {
|
||||
stats_count += mod->stats_count;
|
||||
continue;
|
||||
|
@ -1498,6 +1507,9 @@ static int stats_dump_sv_line(struct stconn *sc, struct proxy *px, struct server
|
|||
list_for_each_entry(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
||||
void *counters;
|
||||
|
||||
if (ctx->flags & STAT_F_FMT_FILE)
|
||||
continue;
|
||||
|
||||
if (stats_get_domain(mod->domain_flags) != STATS_DOMAIN_PROXY)
|
||||
continue;
|
||||
|
||||
|
@ -1747,6 +1759,9 @@ static int stats_dump_be_line(struct stconn *sc, struct proxy *px)
|
|||
list_for_each_entry(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) {
|
||||
struct extra_counters *counters;
|
||||
|
||||
if (ctx->flags & STAT_F_FMT_FILE)
|
||||
continue;
|
||||
|
||||
if (stats_get_domain(mod->domain_flags) != STATS_DOMAIN_PROXY)
|
||||
continue;
|
||||
|
||||
|
@ -2070,6 +2085,8 @@ int stats_dump_stat_to_buffer(struct stconn *sc, struct buffer *buf, struct htx
|
|||
stats_dump_json_schema(chk);
|
||||
else if (ctx->flags & STAT_F_FMT_JSON)
|
||||
stats_dump_json_header(chk);
|
||||
else if (ctx->flags & STAT_F_FMT_FILE)
|
||||
stats_dump_file_header(ctx->type, chk);
|
||||
else if (!(ctx->flags & STAT_F_FMT_TYPED))
|
||||
stats_dump_csv_header(ctx->domain, chk);
|
||||
|
||||
|
@ -2611,6 +2628,56 @@ static int cli_io_handler_dump_json_schema(struct appctx *appctx)
|
|||
return stats_dump_json_schema_to_buffer(appctx);
|
||||
}
|
||||
|
||||
static int cli_parse_dump_stat_file(char **args, char *payload,
|
||||
struct appctx *appctx, void *private)
|
||||
{
|
||||
struct show_stat_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
|
||||
|
||||
ctx->chunk = b_make(trash.area, trash.size, 0, 0);
|
||||
ctx->domain = STATS_DOMAIN_PROXY;
|
||||
ctx->flags |= STAT_F_FMT_FILE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 1 on completion else 0. */
|
||||
static int cli_io_handler_dump_stat_file(struct appctx *appctx)
|
||||
{
|
||||
struct show_stat_ctx *ctx = appctx->svcctx;
|
||||
int ret;
|
||||
|
||||
/* Frontend and backend sides are ouputted separatedly on stats-file.
|
||||
* As such, use STAT_F_BOUND to restrict proxies looping over frontend
|
||||
* side first before first stats_dump_stat_to_buffer(). A second
|
||||
* iteration is conducted for backend side after.
|
||||
*/
|
||||
ctx->flags |= STAT_F_BOUND;
|
||||
|
||||
if (!(ctx->type & (1 << STATS_TYPE_BE))) {
|
||||
/* Restrict to frontend side. */
|
||||
ctx->type = (1 << STATS_TYPE_FE) | (1 << STATS_TYPE_SO);
|
||||
ctx->iid = ctx->sid = -1;
|
||||
|
||||
ret = stats_dump_stat_to_buffer(appctx_sc(appctx), NULL, NULL);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
chunk_strcat(&ctx->chunk, "\n");
|
||||
if (!stats_putchk(appctx, NULL, NULL))
|
||||
return 0;
|
||||
|
||||
/* Switch to backend side. */
|
||||
ctx->state = STAT_STATE_INIT;
|
||||
ctx->type = (1 << STATS_TYPE_BE) | (1 << STATS_TYPE_SV);
|
||||
}
|
||||
|
||||
return stats_dump_stat_to_buffer(appctx_sc(appctx), NULL, NULL);
|
||||
}
|
||||
|
||||
static void cli_io_handler_release_dump_stat_file(struct appctx *appctx)
|
||||
{
|
||||
}
|
||||
|
||||
int stats_allocate_proxy_counters_internal(struct extra_counters **counters,
|
||||
int type, int px_cap)
|
||||
{
|
||||
|
@ -2854,6 +2921,7 @@ static struct cli_kw_list cli_kws = {{ },{
|
|||
{ { "show", "info", NULL }, "show info [desc|json|typed|float]* : report information about the running process", cli_parse_show_info, cli_io_handler_dump_info, NULL },
|
||||
{ { "show", "stat", NULL }, "show stat [desc|json|no-maint|typed|up]*: report counters for each proxy and server", cli_parse_show_stat, cli_io_handler_dump_stat, cli_io_handler_release_stat },
|
||||
{ { "show", "schema", "json", NULL }, "show schema json : report schema used for stats", NULL, cli_io_handler_dump_json_schema, NULL },
|
||||
{ { "dump", "stats-file", NULL }, "dump stats-file : dump stats for restore", cli_parse_dump_stat_file, cli_io_handler_dump_stat_file, cli_io_handler_release_dump_stat_file },
|
||||
{{},}
|
||||
}};
|
||||
|
||||
|
|
Loading…
Reference in New Issue