diff --git a/doc/management.txt b/doc/management.txt index f226d997b..2bac0e9c3 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -1511,6 +1511,18 @@ of hours, minutes and seconds on two digits each: [23:03:34:41]> quit +When the timed prompt is set on the master CLI, the prompt will display the +currently selected process' uptime, so this will work for the master, current +worker or an older worker: + + master> prompt timed + [0:00:00:50] master> show proc + (...) + [0:00:00:58] master> @!11955 <-- master, switch to current worker + [0:00:01:03] 11955> @!11942 <-- current worker, switch to older worker + [0:00:02:17] 11942> @ <-- older worker, switch back to master + [0:00:01:10] master> + Since multiple commands may be issued at once, haproxy uses the empty line as a delimiter to mark an end of output for each command, and takes care of ensuring that no command can emit an empty line on output. A script can thus easily diff --git a/include/haproxy/stream-t.h b/include/haproxy/stream-t.h index 14293d5b8..aa84ebf71 100644 --- a/include/haproxy/stream-t.h +++ b/include/haproxy/stream-t.h @@ -132,6 +132,7 @@ static forceinline char *strm_show_flags(char *buf, size_t len, const char *deli #define PCLI_F_PROMPT 0x10000 #define PCLI_F_PAYLOAD 0x20000 #define PCLI_F_RELOAD 0x40000 /* this is the "reload" stream, quits after displaying reload status */ +#define PCLI_F_TIMED 0x80000 /* the prompt shows the process' uptime */ /* error types reported on the streams for more accurate reporting. diff --git a/src/cli.c b/src/cli.c index f81cfa652..d8675e10f 100644 --- a/src/cli.c +++ b/src/cli.c @@ -2221,11 +2221,46 @@ void pcli_write_prompt(struct stream *s) if (s->pcli_flags & PCLI_F_PAYLOAD) { chunk_appendf(msg, "+ "); } else { - if (s->pcli_next_pid == 0) + if (s->pcli_next_pid == 0) { + /* master's prompt */ + if (s->pcli_flags & PCLI_F_TIMED) { + uint up = ns_to_sec(now_ns - start_time_ns); + chunk_appendf(msg, "[%u:%02u:%02u:%02u] ", + (up / 86400), (up / 3600) % 24, (up / 60) % 60, up % 60); + } + chunk_appendf(msg, "master%s", (proc_self->failedreloads > 0) ? "[ReloadFailed]" : ""); - else + } + else { + /* worker's prompt */ + if (s->pcli_flags & PCLI_F_TIMED) { + const struct mworker_proc *tmp, *proc; + uint up; + + /* set proc to the worker corresponding to pcli_next_pid or NULL */ + proc = NULL; + list_for_each_entry(tmp, &proc_list, list) { + if (!(tmp->options & PROC_O_TYPE_WORKER)) + continue; + if (tmp->pid == s->pcli_next_pid) { + proc = tmp; + break; + } + } + + if (!proc) + chunk_appendf(msg, "[gone] "); + else { + up = date.tv_sec - proc->timestamp; + if ((int)up < 0) /* must never be negative because of clock drift */ + up = 0; + chunk_appendf(msg, "[%u:%02u:%02u:%02u] ", + (up / 86400), (up / 3600) % 24, (up / 60) % 60, up % 60); + } + } chunk_appendf(msg, "%d", s->pcli_next_pid); + } if (s->pcli_flags & (ACCESS_EXPERIMENTAL|ACCESS_EXPERT|ACCESS_MCLI_DEBUG)) { chunk_appendf(msg, "("); @@ -2368,9 +2403,13 @@ int pcli_find_and_exec_kw(struct stream *s, char **args, int argl, char **errmsg *next_pid = target_pid; return 1; } else if (strcmp("prompt", args[0]) == 0) { - s->pcli_flags ^= PCLI_F_PROMPT; + if (argl >= 2 && strcmp(args[1], "timed") == 0) { + s->pcli_flags |= PCLI_F_PROMPT; + s->pcli_flags ^= PCLI_F_TIMED; + } + else + s->pcli_flags ^= PCLI_F_PROMPT; return argl; /* return the number of elements in the array */ - } else if (strcmp("quit", args[0]) == 0) { sc_schedule_abort(s->scf); sc_schedule_shutdown(s->scf);