Download raw body.
relayctl: rework output and add -v flag
On Thu, 27 Aug 2026 15:05:30 +0200,
Rafael Sadowski <rafael@sizeofvoid.org> wrote:
>
> Any feeback or better ideas?
>
I don't use relactl that much to actually have an opinion on this, but your
code reads OK kirill@
So, if it makes your life a bit easy, I see no objection.
> On Sat Aug 01, 2026 at 11:54:43AM +0200, Rafael Sadowski wrote:
> > I find the current output: 1. Pointless by default, the keyword "imsg"
> > appears in the monitor mode. 2. Unreadable with long names. 3. Inconsistent.
> > The diff attempts to improve this.
> >
> > "relayctl show sessions" is a different story. Even using "watch -s 0.2
> > 'doas relayctl show sessions'" is of no use, as sessions are really
> > short-lived. In my view, this would need to be a monitor. But that would
> > involve more work.
> >
> > See the commit message below for impl details.
> >
> >
> > Current:
> >
> > $ doas relayctl monitor
> > sync: imsg type 38 len 0 peerid 4294967295 pid 1
> > timestamp: 1785577221, Sat Aug 1 11:40:21 2026
> > host_status: imsg type 37 len 32 peerid 4294967295 pid 1
> > timestamp: 1785577221, Sat Aug 1 11:40:21 2026
> > id: 3
> > state: down
> > host_status: imsg type 37 len 32 peerid 4294967295 pid 1
> > timestamp: 1785577221, Sat Aug 1 11:40:21 2026
> > id: 1
> > state: up
> >
> > (Why someone should be interested in imsg?).
> >
> > $ doas relayctl show summary
> > Id Type Name Avlblty Status
> > 1 redirect db-redirect down
> > 6 table db:5432 empty
> > 8 host 10.0.23.9 0.00% down
> > 9 host 10.0.23.10 0.00% down
> > 2 redirect cache-redirect down
> > 7 table cache2:11211 empty
> > 10 host 10.0.23.11 0.00% down
> > 3 redirect api-redirect down
> > 8 table api:9000 empty
> > 11 host 10.0.23.8 0.00% down
> > 1 relay https-gateway-way-to-long-name-for-testing active
> > 1 table ap:6443 active (1 hosts)
> > 1 host 10.0.23.6 100.00% up
> > 2 relay https-api-gateway active
> >
> > $ doas relayctl show hosts
> > Id Type Name Avlblty Status
> > 6 table db:5432 empty
> > 8 host 10.0.23.9 0.00% down
> > total: 0/3 checks, error: tcp connect timeout
> > 9 host 10.0.23.10 0.00% down
> > total: 0/3 checks, error: tcp connect timeout
> > 7 table cache2:11211 empty
> > 10 host 10.0.23.11 0.00% down
> > total: 0/3 checks, error: tcp connect timeout
> > 8 table api:9000 empty
> > 11 host 10.0.23.8 0.00% down
> > total: 0/3 checks, error: tcp connect timeout
> > 1 table ap:6443 active (1 hosts)
> > 1 host 10.0.23.6 100.00% up
> > total: 3/3 checks
> > 2 table api:8443 empty
> > 2 host 10.0.23.8 0.00% down
> > total: 0/3 checks, error: tcp connect timeout
> >
> > $ doas relayctl show relays
> > Id Type Name Avlblty Status
> > 1 relay https-gateway-way-to-long-name-for-testing active
> >
> > $ doas relayctl show hosts
> > Id Type Name Avlblty Status
> > 6 table db:5432 empty
> > 8 host 10.0.23.9 0.00% down
> > total: 0/10 checks, error: tcp connect timeout
> > 9 host 10.0.23.10 0.00% down
> > total: 0/10 checks, error: tcp connect timeout
> > 7 table cache2:11211 empty
> > 10 host 10.0.23.11 0.00% down
> > total: 0/10 checks, error: tcp connect timeout
> > 8 table api:9000 empty
> > 11 host 10.0.23.8 0.00% down
> > total: 0/10 checks, error: tcp connect timeout
> > 1 table ap:6443 active (1 hosts)
> > 1 host 10.0.23.6 100.00% up
> > total: 10/10 checksdoas relayctl show hosts
> > Id Type Name Avlblty Status
> > 6 table db:5432 empty
> > 8 host 10.0.23.9 0.00% down
> > total: 0/10 checks, error: tcp connect timeout
> > 9 host 10.0.23.10 0.00% down
> > total: 0/10 checks, error: tcp connect timeout
> > 7 table cache2:11211 empty
> > 10 host 10.0.23.11 0.00% down
> > total: 0/10 checks, error: tcp connect timeout
> > 8 table api:9000 empty
> > 11 host 10.0.23.8 0.00% down
> > total: 0/10 checks, error: tcp connect timeout
> > 1 table ap:6443 active (1 hosts)
> > 1 host 10.0.23.6 100.00% up
> > total: 10/10 checks
> >
> > With diff:
> >
> > $ doas relayctl show summary
> > Id Type Name Avlblty Checks Status
> > 1 rdr db-redirect down
> > 6 table db:5432 empty
> > 8 host 10.0.23.9 0.00% 0/2 down
> > 9 host 10.0.23.10 0.00% 0/2 down
> > 2 rdr cache-redirect down
> > 7 table cache2:11211 empty
> > 10 host 10.0.23.11 0.00% 0/2 down
> > 3 rdr api-redirect down
> > 8 table api:9000 empty
> > 11 host 10.0.23.8 0.00% 0/2 down
> > 1 relay https-gateway-way-to-lon active
> > 1 table ap:6443 active
> > 1 host 10.0.23.6 100.00% 2/2 up
> >
> > $ doas relayctl -v show summary
> > Id Type Name Avlblty Checks Status
> > 1 rdr db-redirect down
> > 6 table db:5432 empty
> > 8 host 10.0.23.9 0.00% 0/3 down (tcp connect timeout)
> > 9 host 10.0.23.10 0.00% 0/3 down (tcp connect timeout)
> > 2 rdr cache-redirect down
> > 7 table cache2:11211 empty
> > 10 host 10.0.23.11 0.00% 0/3 down (tcp connect timeout)
> > 3 rdr api-redirect down
> > 8 table api:9000 empty
> > 11 host 10.0.23.8 0.00% 0/3 down (tcp connect timeout)
> > 1 relay https-gateway-way-to-lon active
> > 1 table ap:6443 active (1 hosts)
> > 1 host 10.0.23.6 100.00% 3/3 up
> >
> > $ doas relayctl show hosts
> > Id Type Name Avlblty Checks Status
> > 8 host 10.0.23.9 0.00% 0/5 down
> > 9 host 10.0.23.10 0.00% 0/5 down
> > 10 host 10.0.23.11 0.00% 0/5 down
> > 11 host 10.0.23.8 0.00% 0/5 down
> > 1 host 10.0.23.6 100.00% 5/5 up
> > 2 host 10.0.23.8 0.00% 0/5 down
> > 3 host 10.0.23.6 0.00% 0/5 down
> > 4 host 10.0.23.7 0.00% 0/5 down
> > 5 host 10.0.23.9 0.00% 0/5 down
> > 6 host 10.0.23.10 0.00% 0/5 down
> > 7 host 10.0.23.11 0.00% 0/5 down
> >
> > $ doas relayctl -v show hosts
> > Id Type Name Avlblty Checks Status
> > 8 host 10.0.23.9 0.00% 0/6 down (tcp connect timeout)
> > 9 host 10.0.23.10 0.00% 0/6 down (tcp connect timeout)
> > 10 host 10.0.23.11 0.00% 0/6 down (tcp connect timeout)
> > 11 host 10.0.23.8 0.00% 0/6 down (tcp connect timeout)
> > 1 host 10.0.23.6 100.00% 6/6 up
> > 2 host 10.0.23.8 0.00% 0/6 down (tcp connect timeout)
> > 3 host 10.0.23.6 0.00% 0/6 down (tls connect failed)
> > 4 host 10.0.23.7 0.00% 0/6 down (tcp connect timeout)
> > 5 host 10.0.23.9 0.00% 0/6 down (tcp connect timeout)
> > 6 host 10.0.23.10 0.00% 0/6 down (tcp connect timeout)
> > 7 host 10.0.23.11 0.00% 0/6 down (tcp connect timeout)
> >
> > $ doas relayctl show relays
> > Id Type Name Avlblty Checks Status
> > 1 relay https-gateway-way-to-lon active
> > 2 relay https-api-gateway active
> > 3 relay wiki-frontend active
> > 4 relay ssh-tunnel active
> > 5 relay cache-service active
> >
> > $ doas relayctl monitor
> > host_status: id: 3 status: down
> > host_status: id: 1 status: up
> > host_status: id: 5 status: down
> > host_status: id: 10 status: down
> > host_status: id: 9 status: down
> >
> > $ doas relayctl -v monitor
> > sync: imsg type 38 len 0 peerid 4294967295 pid 1
> > sync: timestamp: 1785577623, Sat Aug 1 11:47:03 2026
> > host_status: imsg type 37 len 32 peerid 4294967295 pid 1
> > host_status: timestamp: 1785577623, Sat Aug 1 11:47:03 2026
> > host_status: id: 3 status: down
> > host_status: imsg type 37 len 32 peerid 4294967295 pid 1
> > host_status: timestamp: 1785577623, Sat Aug 1 11:47:03 2026
> > host_status: id: 1 status: up
> >
> >
> > commit 900841a571028d4dd0dce801a3abcfdbfa95141c
> > Author: Rafael Sadowski <rafael@sizeofvoid.org>
> > Date: Sat Aug 1 09:52:26 2026 +0200
> >
> > relayctl: rework show output and add -v flag
> >
> > - Added -v flag for more detailed output.
> > - Replaced tab separators with space-padded, truncated columns (%.Ns) for
> > stable alignment.
> > - Added a new "Checks" column for host checks (N/N), replacing the total: N/N
> > checks sub-line.
> > - Shortened redirect to rdr in the Type column to stay under 80 columns.
> > - Without -v: compact status (down); with -v: error inlined (down (tcp connect
> > timeout)).
> > - Table status shows host count (N hosts) only with -v.
> > - retries sub-line only appears with show hosts -v.
> > - show hosts no longer lists tables; use show summary for that.
> >
> > diff --git a/relayctl.8 b/relayctl.8
> > index 96e68a5..fcdf043 100644
> > --- a/relayctl.8
> > +++ b/relayctl.8
> > @@ -23,6 +23,7 @@
> > .Nd control the relay daemon
> > .Sh SYNOPSIS
> > .Nm
> > +.Op Fl v
> > .Op Fl s Ar socket
> > .Ar command
> > .Op Ar argument ...
> > @@ -42,6 +43,8 @@ instead of the default
> > .Pa /var/run/relayd.sock
> > to communicate with
> > .Xr relayd 8 .
> > +.It Fl v
> > +Verbose output.
> > .El
> > .Pp
> > The following commands are available:
> > @@ -78,7 +81,7 @@ the backup table as well.
> > .It Cm reload
> > Reload the configuration file.
> > .It Cm show hosts
> > -Show detailed status of hosts and tables.
> > +Show detailed status of hosts.
> > It will also print the last error for failed host checks;
> > see the
> > .Sx DIAGNOSTICS
> > diff --git a/relayctl.c b/relayctl.c
> > index b76d9fc..a47bf7a 100644
> > --- a/relayctl.c
> > +++ b/relayctl.c
> > @@ -50,6 +50,7 @@ char *print_host_status(int, int);
> > char *print_table_status(int, int);
> > char *print_relay_status(int);
> > void print_statistics(struct ctl_stats [PROC_MAX_INSTANCES+1]);
> > +void print_imsg(struct imsg *, const char *);
> >
> > struct imsgname {
> > int type;
> > @@ -82,13 +83,14 @@ struct imsgname imsgunknown = {
> >
> > struct imsgbuf *ibuf;
> > int error = 0;
> > +int verbose = 0;
> >
> > __dead void
> > usage(void)
> > {
> > extern char *__progname;
> >
> > - fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n",
> > + fprintf(stderr, "usage: %s [-v] [-s socket] command [argument ...]\n",
> > __progname);
> > exit(1);
> > }
> > @@ -101,16 +103,19 @@ main(int argc, char *argv[])
> > struct imsg imsg;
> > int ctl_sock;
> > int done = 0;
> > - int n, verbose = 0;
> > + int n, relayd_log_level = 0;
> > int ch;
> > const char *sockname;
> >
> > sockname = RELAYD_SOCKET;
> > - while ((ch = getopt(argc, argv, "s:")) != -1) {
> > + while ((ch = getopt(argc, argv, "vs:")) != -1) {
> > switch (ch) {
> > case 's':
> > sockname = optarg;
> > break;
> > + case 'v':
> > + verbose++;
> > + break;
> > default:
> > usage();
> > /* NOTREACHED */
> > @@ -163,8 +168,8 @@ main(int argc, char *argv[])
> > case SHOW_RELAYS:
> > case SHOW_ROUTERS:
> > imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0);
> > - printf("%-4s\t%-8s\t%-24s\t%-7s\tStatus\n",
> > - "Id", "Type", "Name", "Avlblty");
> > + printf("%-4s %-6s %-24.24s %-7.7s %-8.8s %s\n",
> > + "Id", "Type", "Name", "Avlblty", "Checks", "Status");
> > break;
> > case SHOW_SESSIONS:
> > imsg_compose(ibuf, IMSG_CTL_SESSION, 0, 0, -1, NULL, 0);
> > @@ -212,11 +217,11 @@ main(int argc, char *argv[])
> > imsg_compose(ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0);
> > break;
> > case LOG_VERBOSE:
> > - verbose = 2;
> > + relayd_log_level = 2;
> > /* FALLTHROUGH */
> > case LOG_BRIEF:
> > imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1,
> > - &verbose, sizeof(verbose));
> > + &relayd_log_level, sizeof(relayd_log_level));
> > printf("logging request sent.\n");
> > done = 1;
> > break;
> > @@ -294,8 +299,7 @@ monitor_host_status(struct imsg *imsg)
> >
> > if (imsg_get_data(imsg, &cs, sizeof(cs)) == -1)
> > errx(1, "imsg_get_data ctl status error");
> > - printf("\tid: %u\n", cs.id);
> > - printf("\tstate: ");
> > + printf("host_status: id: %u status: ", cs.id);
> > switch (cs.up) {
> > case HOST_UP:
> > printf("up\n");
> > @@ -316,25 +320,19 @@ monitor_id(struct imsg *imsg)
> >
> > if (imsg_get_data(imsg, &id, sizeof(id)) == -1)
> > errx(1, "imsg_get_data ctl id error");
> > - printf("\tid: %u\n", id.id);
> > + printf("monitor_id: id: %u\n", id.id);
> > if (strlen(id.name))
> > - printf("\tname: %s\n", id.name);
> > + printf("name: %s\n", id.name);
> > }
> >
> > int
> > monitor(struct imsg *imsg)
> > {
> > - time_t now;
> > int done = 0;
> > struct imsgname *imn;
> >
> > - now = time(NULL);
> > -
> > imn = monitor_lookup(imsg_get_type(imsg));
> > - printf("%s: imsg type %u len %zu peerid %u pid %d\n", imn->name,
> > - imsg_get_type(imsg), imsg_get_len(imsg), imsg_get_id(imsg),
> > - imsg_get_pid(imsg));
> > - printf("\ttimestamp: %lld, %s", (long long)now, ctime(&now));
> > + print_imsg(imsg, imn->name);
> > if (imn->type == -1)
> > done = 1;
> > if (imn->func != NULL)
> > @@ -352,8 +350,10 @@ show_summary_msg(struct imsg *imsg, int type)
> > struct relay rlay;
> > struct router rt;
> > struct netroute nr;
> > - struct ctl_stats stats[PROC_MAX_INSTANCES];
> > + struct ctl_stats stats[PROC_MAX_INSTANCES + 1];
> > char name[HOST_NAME_MAX + 1];
> > + char checks[16];
> > + char status[128];
> >
> > switch (imsg_get_type(imsg)) {
> > case IMSG_CTL_RDR:
> > @@ -362,18 +362,18 @@ show_summary_msg(struct imsg *imsg, int type)
> > if (imsg_get_data(imsg, &rdr, sizeof(rdr)) == -1)
> > errx(1, "imsg_get_data rdr error");
> > rdr.conf.name[sizeof(rdr.conf.name) - 1] = '\0';
> > - printf("%-4u\t%-8s\t%-24s\t%-7s\t%s\n",
> > - rdr.conf.id, "redirect", rdr.conf.name, "",
> > + printf("%-4u %-6s %-24.24s %-7.7s %-8.8s %s\n",
> > + rdr.conf.id, "rdr", rdr.conf.name, "", "",
> > print_rdr_status(rdr.conf.flags));
> > break;
> > case IMSG_CTL_TABLE:
> > - if (!(type == SHOW_SUM || type == SHOW_HOSTS))
> > + if (type != SHOW_SUM)
> > break;
> > if (imsg_get_data(imsg, &table, sizeof(table)) == -1)
> > errx(1, "imsg_get_data table error");
> > table.conf.name[sizeof(table.conf.name) - 1] = '\0';
> > - printf("%-4u\t%-8s\t%-24s\t%-7s\t%s\n",
> > - table.conf.id, "table", table.conf.name, "",
> > + printf("%-4u %-6s %-24.24s %-7.7s %-8.8s %s\n",
> > + table.conf.id, "table", table.conf.name, "", "",
> > print_table_status(table.up, table.conf.flags));
> > break;
> > case IMSG_CTL_HOST:
> > @@ -387,19 +387,24 @@ show_summary_msg(struct imsg *imsg, int type)
> > host.conf.name, host.conf.parentid);
> > else
> > strlcpy(name, host.conf.name, sizeof(name));
> > - printf("%-4u\t%-8s\t%-24s\t%-7s\t%s\n",
> > + if (host.check_cnt)
> > + snprintf(checks, sizeof(checks), "%lu/%lu",
> > + host.up_cnt, host.check_cnt);
> > + else
> > + checks[0] = '\0';
> > + if (host.he && host.up == HOST_DOWN && verbose)
> > + snprintf(status, sizeof(status), "%s (%s)",
> > + print_host_status(host.up, host.flags),
> > + host_error(host.he));
> > + else
> > + strlcpy(status, print_host_status(host.up, host.flags),
> > + sizeof(status));
> > + printf("%-4u %-6s %-24.24s %-7.7s %-8.8s %s\n",
> > host.conf.id, "host", name,
> > print_availability(host.check_cnt, host.up_cnt),
> > - print_host_status(host.up, host.flags));
> > - if (type == SHOW_HOSTS && host.check_cnt) {
> > - printf("\t%8s\ttotal: %lu/%lu checks",
> > - "", host.up_cnt, host.check_cnt);
> > - if (host.retry_cnt)
> > - printf(", %d retries", host.retry_cnt);
> > - if (host.he && host.up == HOST_DOWN)
> > - printf(", error: %s", host_error(host.he));
> > - printf("\n");
> > - }
> > + checks, status);
> > + if (type == SHOW_HOSTS && verbose && host.retry_cnt)
> > + printf("\t%8s\t%d retries\n", "", host.retry_cnt);
> > break;
> > case IMSG_CTL_RELAY:
> > if (!(type == SHOW_SUM || type == SHOW_RELAYS))
> > @@ -407,8 +412,8 @@ show_summary_msg(struct imsg *imsg, int type)
> > if (imsg_get_data(imsg, &rlay, sizeof(rlay)) == -1)
> > errx(1, "imsg_get_data relay error");
> > rlay.rl_conf.name[sizeof(rlay.rl_conf.name) - 1] = '\0';
> > - printf("%-4u\t%-8s\t%-24s\t%-7s\t%s\n",
> > - rlay.rl_conf.id, "relay", rlay.rl_conf.name, "",
> > + printf("%-4u %-6s %-24.24s %-7.7s %-8.8s %s\n",
> > + rlay.rl_conf.id, "relay", rlay.rl_conf.name, "", "",
> > print_relay_status(rlay.rl_conf.flags));
> > break;
> > case IMSG_CTL_RDR_STATS:
> > @@ -433,8 +438,8 @@ show_summary_msg(struct imsg *imsg, int type)
> > errx(1, "imsg_get_data router error");
> > rt.rt_conf.name[sizeof(rt.rt_conf.name) - 1] = '\0';
> > rt.rt_conf.label[sizeof(rt.rt_conf.label) - 1] = '\0';
> > - printf("%-4u\t%-8s\t%-24s\t%-7s\t%s\n",
> > - rt.rt_conf.id, "router", rt.rt_conf.name, "",
> > + printf("%-4u %-6s %-24.24s %-7.7s %-8.8s %s\n",
> > + rt.rt_conf.id, "router", rt.rt_conf.name, "", "",
> > print_relay_status(rt.rt_conf.flags));
> > if (type != SHOW_ROUTERS)
> > break;
> > @@ -483,7 +488,7 @@ show_session_msg(struct imsg *imsg)
> > getmonotime(&tv_now);
> > print_time(&tv_now, &con.se_tv_start, a, sizeof(a));
> > print_time(&tv_now, &con.se_tv_last, b, sizeof(b));
> > - printf("\tage %s, idle %s, relay %u, pid %u",
> > + printf("age %s, idle %s, relay %u, pid %u",
> > a, b, con.se_relayid, con.se_pid);
> > /* XXX grab tagname instead of tag id */
> > if (con.se_tag)
> > @@ -540,8 +545,10 @@ print_table_status(int up, int fl)
> > snprintf(buf, sizeof(buf) - 1, "disabled");
> > } else if (!up) {
> > snprintf(buf, sizeof(buf) - 1, "empty");
> > - } else
> > + } else if (verbose)
> > snprintf(buf, sizeof(buf) - 1, "active (%d hosts)", up);
> > + else
> > + snprintf(buf, sizeof(buf) - 1, "active");
> > return (buf);
> > }
> >
> > @@ -600,3 +607,19 @@ print_statistics(struct ctl_stats stats[PROC_MAX_INSTANCES+1])
> > "", crs.avg, crs.interval,
> > crs.avg_hour, crs.avg_day);
> > }
> > +
> > +void
> > +print_imsg(struct imsg *imsg, const char *name)
> > +{
> > + time_t now;
> > +
> > + if (!verbose)
> > + return;
> > +
> > + now = time(NULL);
> > +
> > + printf("%s: imsg type %u len %zu peerid %u pid %d\n", name,
> > + imsg_get_type(imsg), imsg_get_len(imsg), imsg_get_id(imsg),
> > + imsg_get_pid(imsg));
> > + printf("%s: timestamp: %lld, %s", name, (long long)now, ctime(&now));
> > +}
> >
--
wbr, Kirill
relayctl: rework output and add -v flag