svn commit: r338133 - head/usr.sbin/gstat

Marcelo Araujo araujo at FreeBSD.org
Tue Aug 21 11:22:50 UTC 2018


Author: araujo
Date: Tue Aug 21 11:22:49 2018
New Revision: 338133
URL: https://svnweb.freebsd.org/changeset/base/338133

Log:
  - Add CSV output to gstat via -C flag.
  
  Add a -C option, similar to -B, that allows gstat to produce basic CSV output
  with absolute timestamps (ISO 8601, nearly.) Multiple devices are handled by
  way of a single-pivot CSV table with duplicated timestamps for each object
  output.
  
  Submitted by:	Nick Principe <nap__ixsystems.com>
  Reviewed by:	myself, imp@, asomers (earlier verison), bcr (manpages)
  Sponsored by:	iXsystems Inc.
  Differential Revision:	https://reviews.freebsd.org/D16151

Modified:
  head/usr.sbin/gstat/gstat.8
  head/usr.sbin/gstat/gstat.c

Modified: head/usr.sbin/gstat/gstat.8
==============================================================================
--- head/usr.sbin/gstat/gstat.8	Tue Aug 21 11:17:25 2018	(r338132)
+++ head/usr.sbin/gstat/gstat.8	Tue Aug 21 11:22:49 2018	(r338133)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd November 10, 2016
+.Dd August 21, 2018
 .Dt GSTAT 8
 .Os
 .Sh NAME
@@ -61,6 +61,10 @@ consumers too.
 The default is to show statistics only for
 .Xr geom 4
 producers.
+.It Fl C
+CSV output mode.
+Implies endless batch mode, but output is in the form of comma-separated
+values, with ISO 8601-like timestamps.
 .It Fl d
 Enable display of statistics for delete
 .Pq Dv BIO_DELETE

Modified: head/usr.sbin/gstat/gstat.c
==============================================================================
--- head/usr.sbin/gstat/gstat.c	Tue Aug 21 11:17:25 2018	(r338132)
+++ head/usr.sbin/gstat/gstat.c	Tue Aug 21 11:22:49 2018	(r338133)
@@ -53,9 +53,12 @@
 #include <sysexits.h>
 #include <unistd.h>
 
-static int flag_a, flag_b, flag_B, flag_c, flag_d, flag_o, flag_p, flag_s;
+static int flag_a, flag_b, flag_B, flag_c, flag_C, flag_d, flag_o, flag_p,
+	   flag_s;
 static int flag_I = 1000000;
 
+#define HIGH_PCT_BUSY_THRESH 80
+#define MEDIUM_PCT_BUSY_THRESH 50
 #define PRINTMSG(...) do {						\
 		if ((flag_b && !loop) || (flag_B))			\
 			printf(__VA_ARGS__);				\
@@ -76,7 +79,7 @@ int
 main(int argc, char **argv)
 {
 	int error, i, quit;
-	int curx, cury, maxx, maxy, line_len, loop, max_flen;
+	int curx, cury, maxx, maxy, line_len, loop, max_flen, head_printed;
 	struct devstat *gsp, *gsq;
 	void *sp, *sq;
 	double dt;
@@ -89,6 +92,7 @@ main(int argc, char **argv)
 	short cf, cb;
 	char *p;
 	char f_s[100], pf_s[100], tmp_f_s[100];
+	char ts[100], g_name[4096];
 	const char *line;
 	long double ld[16];
 	uint64_t u64;
@@ -106,7 +110,7 @@ main(int argc, char **argv)
 		flag_b = 1;
 
 	f_s[0] = '\0';
-	while ((i = getopt(argc, argv, "abBdcf:I:ops")) != -1) {
+	while ((i = getopt(argc, argv, "abBdcCf:I:ops")) != -1) {
 		switch (i) {
 		case 'a':
 			flag_a = 1;
@@ -121,6 +125,13 @@ main(int argc, char **argv)
 		case 'c':
 			flag_c = 1;
 			break;
+		case 'C':
+			flag_C = 1;
+			/* csv out implies repeating batch mode */
+			flag_b = 1;
+			flag_B = 1;
+			head_printed = 0;
+			break;
 		case 'd':
 			flag_d = 1;
 			break;
@@ -214,13 +225,21 @@ main(int argc, char **argv)
 		dt = tp.tv_sec - tq.tv_sec;
 		dt += (tp.tv_nsec - tq.tv_nsec) * 1e-9;
 		tq = tp;
+		if (flag_C) { /* set timestamp string */
+			(void)strftime(ts,sizeof(ts),
+					"%F %T",localtime(&tq.tv_sec));
+			(void)snprintf(ts,sizeof(ts),
+					"%s.%.9ld",ts,tq.tv_nsec);
+		}
 	
 		geom_stats_snapshot_reset(sp);
 		geom_stats_snapshot_reset(sq);
 		if (!flag_b)
 			move(0,0);
-		PRINTMSG("dT: %5.3fs  w: %.3fs", dt, (float)flag_I / 1000000);
-		if (f_s[0] != '\0') {
+		if (!flag_C)
+			PRINTMSG("dT: %5.3fs  w: %.3fs", dt,
+					(float)flag_I / 1000000);
+		if (!flag_C && f_s[0] != '\0') {
 			PRINTMSG("  filter: ");
 			if (!flag_b) {
 				getyx(stdscr, cury, curx);
@@ -239,25 +258,52 @@ main(int argc, char **argv)
 			}
 			PRINTMSG("%s", pf_s);
 		}
-		PRINTMSG("\n");
-		PRINTMSG(" L(q)  ops/s   ");
-		if (flag_s) {
-			PRINTMSG(" r/s     kB   kBps   ms/r   ");
-			PRINTMSG(" w/s     kB   kBps   ms/w   ");
+		if (!flag_C) {
+			PRINTMSG("\n");
+			PRINTMSG(" L(q)  ops/s   ");
+			if (flag_s) {
+				PRINTMSG(" r/s     kB   kBps   ms/r   ");
+				PRINTMSG(" w/s     kB   kBps   ms/w   ");
+			}
+			else {
+				PRINTMSG(" r/s   kBps   ms/r   ");
+				PRINTMSG(" w/s   kBps   ms/w   ");
+			}
+			if (flag_d) {
+				if (flag_s) {
+					PRINTMSG(" d/s     kB   kBps");
+					PRINTMSG("   ms/d   ");
+				} else
+					PRINTMSG(" d/s   kBps   ms/d   ");
+			}
+			if (flag_o)
+				PRINTMSG(" o/s   ms/o   ");
+			PRINTMSG("%%busy Name\n");
+		} else if (flag_C && !head_printed) {
+			PRINTMSG("timestamp,name,q-depth,total_ops/s");
+			if (flag_s) {
+				PRINTMSG(",read/s,read_sz-KiB");
+				PRINTMSG(",read-KiB/s,ms/read");
+				PRINTMSG(",write/s,write_sz-KiB");
+				PRINTMSG(",write-KiB/s,ms/write");
+			} else {
+				PRINTMSG(",read/s,read-KiB/s,ms/read");
+				PRINTMSG(",write/s,write-KiB/s,ms/write");
+			}
+			if (flag_d) {
+				if (flag_s) {
+					PRINTMSG(",delete/s,delete-sz-KiB");
+					PRINTMSG(",delete-KiB/s,ms/delete");
+				} else {
+					PRINTMSG(",delete/s,delete-KiB/s");
+					PRINTMSG(",ms/delete");
+				}
+			}
+			if (flag_o)
+				PRINTMSG(",other/s,ms/other");
+			PRINTMSG(",%%busy\n");
+			head_printed = 1;
 		}
-		else {
-			PRINTMSG(" r/s   kBps   ms/r   ");
-			PRINTMSG(" w/s   kBps   ms/w   ");
-		}
-		if (flag_d) {
-			if (flag_s)
-				PRINTMSG(" d/s     kB   kBps   ms/d   ");
-			else
-				PRINTMSG(" d/s   kBps   ms/d   ");
-		}
-		if (flag_o)
-			PRINTMSG(" o/s   ms/o   ");
-		PRINTMSG("%%busy Name\n");
 		for (;;) {
 			gsp = geom_stats_snapshot_next(sp);
 			gsq = geom_stats_snapshot_next(sq);
@@ -278,7 +324,8 @@ main(int argc, char **argv)
 			if (gid->lg_what == ISCONSUMER && !flag_c)
 				continue;
 			if (flag_p && gid->lg_what == ISPROVIDER &&
-			   ((struct gprovider *)(gid->lg_ptr))->lg_geom->lg_rank != 1)
+			   ((struct gprovider *)
+			    (gid->lg_ptr))->lg_geom->lg_rank != 1)
 				continue;
 			/* Do not print past end of window */
 			if (!flag_b) {
@@ -294,7 +341,12 @@ main(int argc, char **argv)
 				  continue;
 			}
 			if (gsp->sequence0 != gsp->sequence1) {
-				PRINTMSG("*\n");
+				/* 
+				 * it is ok to skip entire line silently
+				 * for CSV output
+				 */
+				if (!flag_C)
+					PRINTMSG("*\n");
 				continue;
 			}
 			devstat_compute_statistics(gsp, gsq, dt, 
@@ -329,72 +381,131 @@ main(int argc, char **argv)
 				continue;
 			}
 
-			PRINTMSG(" %4ju", (uintmax_t)u64);
-			PRINTMSG(" %6.0f", (double)ld[0]);
-			PRINTMSG(" %6.0f", (double)ld[1]);
-			if (flag_s)
-				PRINTMSG(" %6.0f", (double)ld[13]);
-			PRINTMSG(" %6.0f", (double)ld[2] * 1024);
-			if (ld[3] > 1e3) 
-				PRINTMSG(" %6.0f", (double)ld[3]);
-			else
-				PRINTMSG(" %6.1f", (double)ld[3]);
-			PRINTMSG(" %6.0f", (double)ld[4]);
-			if (flag_s)
-				PRINTMSG(" %6.0f", (double)ld[14]);
-			PRINTMSG(" %6.0f", (double)ld[5] * 1024);
-			if (ld[6] > 1e3) 
-				PRINTMSG(" %6.0f", (double)ld[6]);
-			else
-				PRINTMSG(" %6.1f", (double)ld[6]);
-
-			if (flag_d) {
-				PRINTMSG(" %6.0f", (double)ld[8]);
-				if (flag_s)
-					PRINTMSG(" %6.0f", (double)ld[15]);
-				PRINTMSG(" %6.0f", (double)ld[9] * 1024);
-				if (ld[10] > 1e3) 
-					PRINTMSG(" %6.0f", (double)ld[10]);
-				else
-					PRINTMSG(" %6.1f", (double)ld[10]);
-			}
-
-			if (flag_o) {
-				PRINTMSG(" %6.0f", (double)ld[11]);
-				if (ld[12] > 1e3) 
-					PRINTMSG(" %6.0f", (double)ld[12]);
-				else
-					PRINTMSG(" %6.1f", (double)ld[12]);
-			}
-
-			if (ld[7] > 80)
-				i = 3;
-			else if (ld[7] > 50)
-				i = 2;
-			else 
-				i = 1;
-			if (!flag_b)
-				attron(COLOR_PAIR(i));
-			PRINTMSG(" %6.1lf", (double)ld[7]);
-			if (!flag_b) {
-				attroff(COLOR_PAIR(i));
-				PRINTMSG("|");
-			} else
-				PRINTMSG(" ");
+			/* store name for geom device */
 			if (gid == NULL) {
-				PRINTMSG(" ??");
+				(void)snprintf(g_name, sizeof(g_name), "??");
 			} else if (gid->lg_what == ISPROVIDER) {
 				pp = gid->lg_ptr;
-				PRINTMSG(" %s", pp->lg_name);
+				(void)snprintf(g_name, sizeof(g_name), "%s",
+						pp->lg_name);
 			} else if (gid->lg_what == ISCONSUMER) {
 				cp = gid->lg_ptr;
-				PRINTMSG(" %s/%s/%s",
-				    cp->lg_geom->lg_class->lg_name,
-				    cp->lg_geom->lg_name,
-				    cp->lg_provider->lg_name);
+				(void)snprintf(g_name, sizeof(g_name),
+					"%s/%s/%s",
+					cp->lg_geom->lg_class->lg_name,
+				   	cp->lg_geom->lg_name,
+				    	cp->lg_provider->lg_name);
 			}
-			if (!flag_b)
-				clrtoeol();
+	
+			if (flag_C) {
+				PRINTMSG("%s", ts); /* timestamp */
+				PRINTMSG(",%s", g_name); /* print name */
+				PRINTMSG(",%ju", (uintmax_t)u64);
+				PRINTMSG(",%.0f", (double)ld[0]);
+				PRINTMSG(",%.0f", (double)ld[1]);
+				if (flag_s)
+					PRINTMSG(",%.0f", (double)ld[13]);
+				PRINTMSG(",%.0f", (double)ld[2] * 1024);
+				if (ld[3] > 1e3) 
+					PRINTMSG(",%.0f", (double)ld[3]);
+				else
+					PRINTMSG(",%.1f", (double)ld[3]);
+				PRINTMSG(",%.0f", (double)ld[4]);
+				if (flag_s)
+					PRINTMSG(",%.0f", (double)ld[14]);
+				PRINTMSG(",%.0f", (double)ld[5] * 1024);
+				if (ld[6] > 1e3) 
+					PRINTMSG(",%.0f", (double)ld[6]);
+				else
+					PRINTMSG(",%.1f", (double)ld[6]);
+
+				if (flag_d) {
+					PRINTMSG(",%.0f", (double)ld[8]);
+					if (flag_s)
+						PRINTMSG(",%.0f",
+								(double)ld[15]);
+					PRINTMSG(",%.0f", (double)ld[9] * 1024);
+					if (ld[10] > 1e3) 
+						PRINTMSG(",%.0f",
+								(double)ld[10]);
+					else
+						PRINTMSG(",%.1f",
+								(double)ld[10]);
+				}
+
+				if (flag_o) {
+					PRINTMSG(",%.0f", (double)ld[11]);
+					if (ld[12] > 1e3) 
+						PRINTMSG(",%.0f",
+								(double)ld[12]);
+					else
+						PRINTMSG(",%.1f", 
+								(double)ld[12]);
+				}
+				PRINTMSG(",%.1lf", (double)ld[7]);
+			} else {
+				PRINTMSG(" %4ju", (uintmax_t)u64);
+				PRINTMSG(" %6.0f", (double)ld[0]);
+				PRINTMSG(" %6.0f", (double)ld[1]);
+				if (flag_s)
+					PRINTMSG(" %6.0f", (double)ld[13]);
+				PRINTMSG(" %6.0f", (double)ld[2] * 1024);
+				if (ld[3] > 1e3) 
+					PRINTMSG(" %6.0f", (double)ld[3]);
+				else
+					PRINTMSG(" %6.1f", (double)ld[3]);
+				PRINTMSG(" %6.0f", (double)ld[4]);
+				if (flag_s)
+					PRINTMSG(" %6.0f", (double)ld[14]);
+				PRINTMSG(" %6.0f", (double)ld[5] * 1024);
+				if (ld[6] > 1e3) 
+					PRINTMSG(" %6.0f", (double)ld[6]);
+				else
+					PRINTMSG(" %6.1f", (double)ld[6]);
+
+				if (flag_d) {
+					PRINTMSG(" %6.0f", (double)ld[8]);
+					if (flag_s)
+						PRINTMSG(" %6.0f", 
+								(double)ld[15]);
+					PRINTMSG(" %6.0f", 
+							(double)ld[9] * 1024);
+					if (ld[10] > 1e3) 
+						PRINTMSG(" %6.0f",
+								(double)ld[10]);
+					else
+						PRINTMSG(" %6.1f",
+								(double)ld[10]);
+				}
+
+				if (flag_o) {
+					PRINTMSG(" %6.0f", (double)ld[11]);
+					if (ld[12] > 1e3) 
+						PRINTMSG(" %6.0f",
+								(double)ld[12]);
+					else
+						PRINTMSG(" %6.1f", 
+								(double)ld[12]);
+				}
+
+				if (ld[7] > HIGH_PCT_BUSY_THRESH)
+					i = 3;
+				else if (ld[7] > MEDIUM_PCT_BUSY_THRESH)
+					i = 2;
+				else 
+					i = 1;
+				if (!flag_b)
+					attron(COLOR_PAIR(i));
+				PRINTMSG(" %6.1lf", (double)ld[7]);
+				if (!flag_b) {
+					attroff(COLOR_PAIR(i));
+					PRINTMSG("|");
+				} else
+					PRINTMSG(" ");
+				PRINTMSG(" %s", g_name);
+				if (!flag_b)
+					clrtoeol();
+			}
 			PRINTMSG("\n");
 			*gsq = *gsp;
 		}
@@ -485,7 +596,7 @@ main(int argc, char **argv)
 static void
 usage(void)
 {
-	fprintf(stderr, "usage: gstat [-abBcdps] [-f filter] [-I interval]\n");
+	fprintf(stderr, "usage: gstat [-abBcCdps] [-f filter] [-I interval]\n");
 	exit(EX_USAGE);
         /* NOTREACHED */
 }


More information about the svn-src-head mailing list