MINOR: stream/cli: add an optional "older" filter for "show sess"

It's often needed to be able to refine "show sess" when debugging, and
very often a first glance at old streams is performed, but that's a
difficult task in large dumps, and it takes lots of resources to dump
everything.

This commit adds "older <age>" to "show sess" in order to specify the
minimum age of streams that will be dumped. This should simplify the
identification of blocked ones.
This commit is contained in:
Willy Tarreau 2023-11-17 18:32:59 +01:00
parent ec76e0138b
commit 3ffcf7beb1
2 changed files with 44 additions and 18 deletions

View File

@ -3144,17 +3144,20 @@ show sess
the last one that was created before the command was entered; those which
die in the mean time will not appear.
show sess <id>
Display a lot of internal information about the specified session identifier.
This identifier is the first field at the beginning of the lines in the dumps
of "show sess" (it corresponds to the session pointer). Those information are
useless to most users but may be used by haproxy developers to troubleshoot a
complex bug. The output format is intentionally not documented so that it can
freely evolve depending on demands. You may find a description of all fields
returned in src/dumpstats.c
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 sess <id> | older <age> | all
Display a lot of internal information about the matching sessions. In the
first form, only the session matching the specified session identifier will
be shown. This identifier is the first field at the beginning of the lines in
the dumps of "show sess" (it corresponds to the session pointer). In the
second form, only sessions older than <age> (in seconds by default) will be
shown. If "all" is used instead, then all sessions will be dumped. Dumping
many sessions can produce a huge output, take a lot of time and be CPU
intensive, so it's always better to only dump the minimum needed. Those
information are useless to most users but may be used by haproxy developers
to troubleshoot a complex bug. The output format is intentionally not
documented so that it can freely evolve depending on demands. This output
is meant to be interpreted while checking function strm_dump_to_buffer() in
src/stream.c to figure the exact meaning of certain fields.
show stat [domain <dns|proxy>] [{<iid>|<proxy>} <type> <sid>] [typed|json] \
[desc] [up|no-maint]

View File

@ -3115,6 +3115,7 @@ struct show_sess_ctx {
void *target; /* session we want to dump, or NULL for all */
unsigned int thr; /* the thread number being explored (0..MAX_THREADS-1) */
unsigned int uid; /* if non-null, the uniq_id of the session being dumped */
unsigned int min_age; /* minimum age of streams to dump */
int section; /* section of the session being dumped */
int pos; /* last position of the current session's buffer */
};
@ -3510,16 +3511,32 @@ static int cli_parse_show_sess(char **args, char *payload, struct appctx *appctx
if (!cli_has_level(appctx, ACCESS_LVL_OPER))
return 1;
if (*args[2] && strcmp(args[2], "all") == 0)
ctx->target = (void *)-1;
else if (*args[2])
ctx->target = (void *)strtoul(args[2], NULL, 0);
else
ctx->target = NULL;
/* now all sessions by default */
ctx->target = NULL;
ctx->min_age = 0;
ctx->section = 0; /* start with stream status */
ctx->pos = 0;
ctx->thr = 0;
if (*args[2] && strcmp(args[2], "older") == 0) {
unsigned timeout;
const char *res;
if (!*args[3])
return cli_err(appctx, "Expects a minimum age (in seconds by default).\n");
res = parse_time_err(args[3], &timeout, TIME_UNIT_S);
if (res != 0)
return cli_err(appctx, "Invalid age.\n");
ctx->min_age = timeout;
ctx->target = (void *)-1; /* show all matching entries */
}
else if (*args[2] && strcmp(args[2], "all") == 0)
ctx->target = (void *)-1;
else if (*args[2])
ctx->target = (void *)strtoul(args[2], NULL, 0);
/* The back-ref must be reset, it will be detected and set by
* the dump code upon first invocation.
*/
@ -3596,6 +3613,12 @@ static int cli_io_handler_dump_sess(struct appctx *appctx)
continue;
}
if (ctx->min_age) {
uint age = ns_to_sec(now_ns) - ns_to_sec(curr_strm->logs.request_ts);
if (age < ctx->min_age)
goto next_sess;
}
if (ctx->target) {
if (ctx->target != (void *)-1 && ctx->target != curr_strm)
goto next_sess;
@ -3822,7 +3845,7 @@ static int cli_parse_shutdown_sessions_server(char **args, char *payload, struct
/* register cli keywords */
static struct cli_kw_list cli_kws = {{ },{
{ { "show", "sess", NULL }, "show sess [id] : report the list of current sessions or dump this exact session", cli_parse_show_sess, cli_io_handler_dump_sess, cli_release_show_sess },
{ { "show", "sess", NULL }, "show sess [<id>|all|older <age>] : report the list of current sessions or dump this exact session", cli_parse_show_sess, cli_io_handler_dump_sess, cli_release_show_sess },
{ { "shutdown", "session", NULL }, "shutdown session [id] : kill a specific session", cli_parse_shutdown_session, NULL, NULL },
{ { "shutdown", "sessions", "server" }, "shutdown sessions server <bk>/<srv> : kill sessions on a server", cli_parse_shutdown_sessions_server, NULL, NULL },
{{},}