diff --git a/doc/management.txt b/doc/management.txt index e65ac471ad..6aeb08d38b 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -2488,7 +2488,7 @@ user increased. It also drops expert and experimental mode. See also "show cli level". -show activity +show activity [-1 | 0 | thread_num] Reports some counters about internal events that will help developers and more generally people who know haproxy well enough to narrow down the causes of reports of abnormal behaviours. A typical example would be a properly @@ -2498,7 +2498,14 @@ show activity is not a problem since calls to this command will typically be performed twice. The fields are purposely not documented so that their exact meaning is verified in the code where the counters are fed. These values are also reset - by the "clear counters" command. + by the "clear counters" command. On multi-threaded deployments, the first + column will indicate the total (or average depending on the nature of the + metric) for all threads, and the list of all threads' values will be + represented between square brackets in the thread order. Optionally the + thread number to be dumped may be specified in argument. The special value + "0" will report the aggregated value (first column), and "-1", which is the + default, will display all the columns. Note that just like in single-threaded + mode, there will be no brackets when a single column is requested. show cli sockets List CLI sockets. The output format is composed of 3 fields separated by diff --git a/src/cli.c b/src/cli.c index bd77418fe5..419466524b 100644 --- a/src/cli.c +++ b/src/cli.c @@ -86,6 +86,11 @@ extern const char *stat_status_codes[]; struct proxy *mworker_proxy; /* CLI proxy of the master */ +/* CLI context for the "show activity" command */ +struct show_activity_ctx { + int thr; /* thread ID to show or -1 for all */ +}; + /* CLI context for the "show env" command */ struct show_env_ctx { char **var; /* first variable to show */ @@ -1463,6 +1468,8 @@ static int cli_io_handler_show_fd(struct appctx *appctx) static int cli_io_handler_show_activity(struct appctx *appctx) { struct stconn *sc = appctx_sc(appctx); + struct show_activity_ctx *actctx = appctx->svcctx; + int tgt = actctx->thr; // target thread, -1 for all, 0 for total only int thr; if (unlikely(sc_ic(sc)->flags & (CF_WRITE_ERROR|CF_SHUTW))) @@ -1484,10 +1491,15 @@ static int cli_io_handler_show_activity(struct appctx *appctx) chunk_appendf(&trash, " %u\n", _tot); \ break; \ } \ - chunk_appendf(&trash, " %u [", _tot); \ - for (t = 0; t < _nbt; t++) \ - chunk_appendf(&trash, " %u", _v[t]); \ - chunk_appendf(&trash, " ]\n"); \ + if (tgt == -1) { \ + chunk_appendf(&trash, " %u [", _tot); \ + for (t = 0; t < _nbt; t++) \ + chunk_appendf(&trash, " %u", _v[t]); \ + chunk_appendf(&trash, " ]\n"); \ + } else if (tgt == 0) \ + chunk_appendf(&trash, " %u\n", _tot); \ + else \ + chunk_appendf(&trash, " %u\n", _v[tgt-1]);\ } while (0) #undef SHOW_AVG @@ -1504,10 +1516,15 @@ static int cli_io_handler_show_activity(struct appctx *appctx) chunk_appendf(&trash, " %u\n", _tot); \ break; \ } \ - chunk_appendf(&trash, " %u [", (_tot + _nbt/2) / _nbt); \ - for (t = 0; t < _nbt; t++) \ - chunk_appendf(&trash, " %u", _v[t]); \ - chunk_appendf(&trash, " ]\n"); \ + if (tgt == -1) { \ + chunk_appendf(&trash, " %u [", (_tot + _nbt/2) / _nbt); \ + for (t = 0; t < _nbt; t++) \ + chunk_appendf(&trash, " %u", _v[t]); \ + chunk_appendf(&trash, " ]\n"); \ + } else if (tgt == 0) \ + chunk_appendf(&trash, " %u\n", (_tot + _nbt/2) / _nbt); \ + else \ + chunk_appendf(&trash, " %u\n", _v[tgt-1]);\ } while (0) chunk_appendf(&trash, "thread_id: %u (%u..%u)\n", tid + 1, 1, global.nbthread); @@ -1636,6 +1653,28 @@ static int cli_io_handler_show_cli_sock(struct appctx *appctx) } +/* parse a "show activity" CLI request. Returns 0 if it needs to continue, 1 if it + * wants to stop here. It sets a show_activity_ctx context where, if a specific + * thread is requested, it puts the thread number into ->thr otherwise sets it to + * -1. + */ +static int cli_parse_show_activity(char **args, char *payload, struct appctx *appctx, void *private) +{ + struct show_activity_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx)); + + if (!cli_has_level(appctx, ACCESS_LVL_OPER)) + return 1; + + ctx->thr = -1; // show all by default + if (*args[2]) + ctx->thr = atoi(args[2]); + + if (ctx->thr < -1 || ctx->thr > global.nbthread) + return cli_err(appctx, "Thread ID number must be between -1 and nbthread\n"); + + return 0; +} + /* parse a "show env" CLI request. Returns 0 if it needs to continue, 1 if it * wants to stop here. It reserves a sohw_env_ctx where it puts the variable to * be dumped as well as a flag if a single variable is requested, otherwise puts @@ -3164,7 +3203,7 @@ static struct cli_kw_list cli_kws = {{ },{ { { "show", "cli", "sockets", NULL }, "show cli sockets : dump list of cli sockets", cli_parse_default, cli_io_handler_show_cli_sock, NULL, NULL, ACCESS_MASTER }, { { "show", "cli", "level", NULL }, "show cli level : display the level of the current CLI session", cli_parse_show_lvl, NULL, NULL, NULL, ACCESS_MASTER}, { { "show", "fd", NULL }, "show fd [num] : dump list of file descriptors in use or a specific one", cli_parse_show_fd, cli_io_handler_show_fd, NULL }, - { { "show", "activity", NULL }, "show activity : show per-thread activity stats (for support/developers)", cli_parse_default, cli_io_handler_show_activity, NULL }, + { { "show", "activity", NULL }, "show activity [-1|0|thread_num] : show per-thread activity stats (for support/developers)", cli_parse_show_activity, cli_io_handler_show_activity, NULL }, { { "show", "version", NULL }, "show version : show version of the current process", cli_parse_show_version, NULL, NULL, NULL, ACCESS_MASTER }, { { "operator", NULL }, "operator : lower the level of the current CLI session to operator", cli_parse_set_lvl, NULL, NULL, NULL, ACCESS_MASTER}, { { "user", NULL }, "user : lower the level of the current CLI session to user", cli_parse_set_lvl, NULL, NULL, NULL, ACCESS_MASTER},