While looking at #2896 it bothered me how much code we spend on
text-processing the CLI output.
Since we now have -j for machine-readable output, it would make
sense to make the non-j output more human-friendly, and avoid some
of all that text-processing at the same time.
I threw together the attached proof-of-concept hack, which adds
a central function to figure out how wide the columns of tabular
output should be, and to reformat it thusly.
The idea is that the CLI code, in this case vcl.list sticks
some ASCII control-chars in the vsb to mark the columns, which then
autosize once all the output is ready, rather than have all the
"lets set this column width to 28 ? 45 ? 51?" guesswork.
In the hack I have also added column headers for nicer output
so that it looks like this:
Status Readiness Ref Name
====== ========= === ====
active auto/warm 1 vcl1
(Ignore the amount of space/padding etc, that's for later)
I kind of like it.
But I am also seriously wondering if we should go even further and
have varnishd *only* produce JSON output, and leave the render-for-humans
aspect to varnishapi or even varnishadm.
Comments welcome...
--
Poul-Henning Kamp | UNIX since Zilog Zeus 3.20
[email protected] | TCP/IP since RFC 956
FreeBSD committer | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.
diff --git a/bin/varnishd/cache/cache_vcl.c b/bin/varnishd/cache/cache_vcl.c
index a524a7981..72c5da737 100644
--- a/bin/varnishd/cache/cache_vcl.c
+++ b/bin/varnishd/cache/cache_vcl.c
@@ -657,6 +657,8 @@ vcl_cli_list(struct cli *cli, const char * const *av, void *priv)
(void)av;
(void)priv;
ASSERT_CLI();
+
+ VCLI_Out(cli, "\x0eStatus\x02Readiness\x02Ref\x02Name\n");
VTAILQ_FOREACH(vcl, &vcl_head, list) {
if (vcl == vcl_active) {
flg = "active";
@@ -664,7 +666,7 @@ vcl_cli_list(struct cli *cli, const char * const *av, void *priv)
flg = "discarded";
} else
flg = "available";
- VCLI_Out(cli, "%-10s %5s/%-8s %6u %s",
+ VCLI_Out(cli, "%s\x01%s/%s\x01%u\x01%s\x01",
flg, vcl->state, vcl->temp, vcl->busy, vcl->loaded_name);
if (vcl->label != NULL) {
VCLI_Out(cli, " -> %s", vcl->label->loaded_name);
diff --git a/bin/varnishd/mgt/mgt_vcl.c b/bin/varnishd/mgt/mgt_vcl.c
index 7d8acb572..32019cbf6 100644
--- a/bin/varnishd/mgt/mgt_vcl.c
+++ b/bin/varnishd/mgt/mgt_vcl.c
@@ -811,13 +811,14 @@ mcf_vcl_list(struct cli *cli, const char * const *av, void *priv)
}
free(p);
} else {
+ VCLI_Out(cli, "\x0eStatus\x02Readiness\x02Ref\x02Name\n");
VTAILQ_FOREACH(vp, &vclhead, list) {
- VCLI_Out(cli, "%-10s %5s",
+ VCLI_Out(cli, "%s\x01%s",
vp == active_vcl ? "active" : "available",
vp->state);
- VCLI_Out(cli, "/%-8s", vp->warm ?
+ VCLI_Out(cli, "/%s\x01", vp->warm ?
VCL_STATE_WARM : VCL_STATE_COLD);
- VCLI_Out(cli, " %6s %s", "-", vp->name);
+ VCLI_Out(cli, "-\x01%s\x01", vp->name);
if (mcf_is_label(vp)) {
vd = VTAILQ_FIRST(&vp->dfrom);
AN(vd);
diff --git a/bin/varnishtest/tests/u00011.vtc b/bin/varnishtest/tests/u00011.vtc
index b53a9ba7b..6e7f8eb11 100644
--- a/bin/varnishtest/tests/u00011.vtc
+++ b/bin/varnishtest/tests/u00011.vtc
@@ -24,7 +24,8 @@ process p1 -expect-text 0 1 "PONG"
process p1 -write "vcl.li\t\r"
-process p1 -expect-text 0 1 "active auto/warm"
+process p1 -expect-text 0 0 "active"
+process p1 -expect-text 0 0 "auto/warm"
process p1 -write "vcl.s\t\th\t vcl1\r"
diff --git a/lib/libvarnish/vcli_serve.c b/lib/libvarnish/vcli_serve.c
index e5cf0c411..3eeeb9431 100644
--- a/lib/libvarnish/vcli_serve.c
+++ b/lib/libvarnish/vcli_serve.c
@@ -247,6 +247,94 @@ cls_dispatch(struct cli *cli, const struct cli_proto *cp,
cp->func(cli, (const char * const *)av, cp->priv);
}
+/*--------------------------------------------------------------------
+ * Reformat CLI output as table
+ */
+
+#define MAXCOL 10
+static char *
+Tabelize(const char *s)
+{
+ int colw[MAXCOL];
+ int ncol = 0;
+ int nln = 0;
+ int cc = 0;
+ int cw = 0;
+ const char *p;
+ char *q, *r;
+ size_t sz = 0;
+
+ assert(*s == '\x0e');
+ memset(colw, 0, sizeof colw);
+ for (p = ++s; *p ; p++) {
+ switch(*p) {
+ case '\x01':
+ case '\x02':
+ if (cw > colw[cc])
+ colw[cc] = cw;
+ cc++;
+ cw = 0;
+ assert(cc < MAXCOL);
+ break;
+ case '\n':
+ if (cc > ncol)
+ ncol = cc;
+ cc = 0;
+ cw = 0;
+ nln++;
+ break;
+ case '\t':
+ WRONG("TAB not allowed in tables");
+ default:
+ cw++;
+ }
+ }
+ for(cc = 0; cc < ncol; cc++)
+ sz += 1 + colw[cc];
+ sz *= nln + 1;
+ sz += 1;
+ q = malloc(sz);
+ AN(q);
+ r = q;
+ cc = 0;
+ cw = 0;
+ nln = 0;
+ for (p = s; *p ; p++) {
+ switch(*p) {
+ case '\x01':
+ case '\x02':
+ while (cw <= colw[cc]) {
+ *r++ = ' ';
+ cw++;
+ }
+ cc++;
+ cw = 0;
+ assert(cc < MAXCOL);
+ break;
+ case '\n':
+ *r++ = '\n';
+ if (++nln == 1) {
+ for (cc = 0; cc < ncol; cc++) {
+ for (cw = 0; cw < colw[cc]; cw++)
+ *r++ = '=';
+ *r++ = ' ';
+ }
+ r[-1] = '\n';
+ }
+ cc = 0;
+ cw = 0;
+ break;
+ default:
+ *r++ = *p;
+ cw++;
+ break;
+ }
+ }
+ *r = '\0';
+ assert(r == q + sz);
+ return (q);
+}
+
/*--------------------------------------------------------------------
* We have collected a full cli line, parse it and execute, if possible.
*/
@@ -329,6 +417,10 @@ cls_exec(struct VCLS_fd *cfd, char * const *av)
s = VSB_data(cli->sb);
len = VSB_len(cli->sb);
+ if (*s == '\x0e') {
+ s = Tabelize(s);
+ len = strlen(s);
+ }
lim = *cs->limit;
if (len > lim) {
if (cli->result == CLIS_OK)
@@ -340,6 +432,9 @@ cls_exec(struct VCLS_fd *cfd, char * const *av)
cli->result == CLIS_CLOSE)
retval = 1;
+ if (s != VSB_data(cli->sb))
+ REPLACE(s, NULL);
+
/*
* In unauthenticated mode we are very intolerant, and close the
* connection at the least provocation.
_______________________________________________
varnish-dev mailing list
[email protected]
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-dev