- 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
This commit is contained in:
parent
3b27d79c2a
commit
0b9079bf95
@ -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
|
||||
|
@ -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_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();
|
||||
}
|
||||
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 */
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user