Re: relayctl: rework output and add -v flag

Rafael Sadowski <[email protected]>
Newsgroups gmane.os.openbsd.tech
Message-ID <[email protected]>
Any feeback or better ideas?

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 <[email protected]>
> 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));
> +}
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.