vmstat: Support for timestamps with '-t' & fix for '-wd'

From now the vmstat can append a timestamp to each line in the
VMSTAT and DISKSTAT mode. You can achieve that with the '-t'
switch.
The '-w' switch now works in the DISKSTAT mode too.
This commit is contained in:
Jaromir Capik 2014-02-04 19:10:42 +01:00
parent 8e7ef322e2
commit 4fcd56bf58
2 changed files with 167 additions and 33 deletions

View File

@ -74,6 +74,9 @@ or 1048576
bytes. Note this does not change the swap (si/so) or block (bi/bo) bytes. Note this does not change the swap (si/so) or block (bi/bo)
fields. fields.
.TP .TP
\fB\-t\fR, \fB\-\-timestamp\fR
Append timestamp to each line
.TP
\fB\-w\fR, \fB\-\-wide\fR \fB\-w\fR, \fB\-\-wide\fR
Wide output mode (useful for systems with higher amount of memory, Wide output mode (useful for systems with higher amount of memory,
where the default output mode suffers from unwanted column breakage). where the default output mode suffers from unwanted column breakage).

197
vmstat.c
View File

@ -43,6 +43,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <termios.h> #include <termios.h>
#include <unistd.h> #include <unistd.h>
#include <time.h>
#include "c.h" #include "c.h"
#include "fileutils.h" #include "fileutils.h"
@ -75,6 +76,9 @@ static int a_option;
/* "-w" means "wide output" */ /* "-w" means "wide output" */
static int w_option; static int w_option;
/* "-t" means "show timestamp" */
static int t_option;
static unsigned sleep_time = 1; static unsigned sleep_time = 1;
static int infinite_updates = 0; static int infinite_updates = 0;
static unsigned long num_updates; static unsigned long num_updates;
@ -100,6 +104,7 @@ static void __attribute__ ((__noreturn__))
fputs(_(" -p, --partition <dev> partition specific statistics\n"), out); fputs(_(" -p, --partition <dev> partition specific statistics\n"), out);
fputs(_(" -S, --unit <char> define display unit\n"), out); fputs(_(" -S, --unit <char> define display unit\n"), out);
fputs(_(" -w, --wide wide output\n"), out); fputs(_(" -w, --wide wide output\n"), out);
fputs(_(" -t, --timestamp show timestamp\n"), out);
fputs(USAGE_SEPARATOR, out); fputs(USAGE_SEPARATOR, out);
fputs(USAGE_HELP, out); fputs(USAGE_HELP, out);
fputs(USAGE_VERSION, out); fputs(USAGE_VERSION, out);
@ -180,21 +185,33 @@ static int format_1000(unsigned long long val64, char *restrict dst)
static void new_header(void) static void new_header(void)
{ {
struct tm *tm_ptr;
time_t the_time;
char timebuf[32];
/* Translation Hint: Translating folloging header & fields /* Translation Hint: Translating folloging header & fields
* that follow (marked with max x chars) might not work, * that follow (marked with max x chars) might not work,
* unless manual page is translated as well. */ * unless manual page is translated as well. */
const char *header =
const char header[] = _("procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----");
"procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----\n"; const char *wide_header =
const char wide_header[] = _("procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu--------");
"procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu--------\n"; const char *timestamp_header = _(" -----timestamp-----");
const char format[] = const char format[] =
"%2s %2s %6s %6s %6s %6s %4s %4s %5s %5s %4s %4s %2s %2s %2s %2s %2s\n"; "%2s %2s %6s %6s %6s %6s %4s %4s %5s %5s %4s %4s %2s %2s %2s %2s %2s";
const char wide_format[] = const char wide_format[] =
"%2s %2s %12s %12s %12s %12s %4s %4s %5s %5s %4s %4s %3s %3s %3s %3s %3s\n"; "%2s %2s %12s %12s %12s %12s %4s %4s %5s %5s %4s %4s %3s %3s %3s %3s %3s";
printf(w_option ? wide_header : header);
if (t_option) {
printf(timestamp_header);
}
printf("\n");
printf(w_option ? _(wide_header) : _(header));
printf( printf(
w_option ? wide_format : format, w_option ? wide_format : format,
/* Translation Hint: max 2 chars */ /* Translation Hint: max 2 chars */
@ -235,6 +252,19 @@ static void new_header(void)
_("wa"), _("wa"),
/* Translation Hint: max 2 chars */ /* Translation Hint: max 2 chars */
_("st")); _("st"));
if (t_option) {
(void) time( &the_time );
tm_ptr = localtime( &the_time );
if (strftime(timebuf, sizeof(timebuf), "%Z", tm_ptr)) {
timebuf[strlen(timestamp_header) - 1] = '\0';
} else {
timebuf[0] = '\0';
}
printf(" %*s", (int)(strlen(timestamp_header) - 1), timebuf);
}
printf("\n");
} }
static unsigned long unitConvert(unsigned long size) static unsigned long unitConvert(unsigned long size)
@ -247,9 +277,9 @@ static unsigned long unitConvert(unsigned long size)
static void new_format(void) static void new_format(void)
{ {
const char format[] = const char format[] =
"%2u %2u %6lu %6lu %6lu %6lu %4u %4u %5u %5u %4u %4u %2u %2u %2u %2u %2u\n"; "%2u %2u %6lu %6lu %6lu %6lu %4u %4u %5u %5u %4u %4u %2u %2u %2u %2u %2u";
const char wide_format[] = const char wide_format[] =
"%2u %2u %12lu %12lu %12lu %12lu %4u %4u %5u %5u %4u %4u %3u %3u %3u %3u %3u\n"; "%2u %2u %12lu %12lu %12lu %12lu %4u %4u %5u %5u %4u %4u %3u %3u %3u %3u %3u";
unsigned int tog = 0; /* toggle switch for cleaner code */ unsigned int tog = 0; /* toggle switch for cleaner code */
unsigned int i; unsigned int i;
@ -263,6 +293,9 @@ static void new_format(void)
unsigned int sleep_half; unsigned int sleep_half;
unsigned long kb_per_page = sysconf(_SC_PAGESIZE) / 1024ul; unsigned long kb_per_page = sysconf(_SC_PAGESIZE) / 1024ul;
int debt = 0; /* handle idle ticks running backwards */ int debt = 0; /* handle idle ticks running backwards */
struct tm *tm_ptr;
time_t the_time;
char timebuf[32];
sleep_half = (sleep_time / 2); sleep_half = (sleep_time / 2);
new_header(); new_header();
@ -272,6 +305,12 @@ static void new_format(void)
cpu_zzz, pgpgin, pgpgout, pswpin, pswpout, intr, ctxt, &running, cpu_zzz, pgpgin, pgpgout, pswpin, pswpout, intr, ctxt, &running,
&blocked, &dummy_1, &dummy_2); &blocked, &dummy_1, &dummy_2);
if (t_option) {
(void) time( &the_time );
tm_ptr = localtime( &the_time );
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_ptr);
}
duse = *cpu_use + *cpu_nic; duse = *cpu_use + *cpu_nic;
dsys = *cpu_sys + *cpu_xxx + *cpu_yyy; dsys = *cpu_sys + *cpu_xxx + *cpu_yyy;
didl = *cpu_idl; didl = *cpu_idl;
@ -298,6 +337,12 @@ static void new_format(void)
(unsigned)( (100*dstl + divo2) / Div ) (unsigned)( (100*dstl + divo2) / Div )
); );
if (t_option) {
printf(" %s", timebuf);
}
printf("\n");
/* main loop */ /* main loop */
for (i = 1; infinite_updates || i < num_updates; i++) { for (i = 1; infinite_updates || i < num_updates; i++) {
sleep(sleep_time); sleep(sleep_time);
@ -313,6 +358,12 @@ static void new_format(void)
pgpgout + tog, pswpin + tog, pswpout + tog, intr + tog, pgpgout + tog, pswpin + tog, pswpout + tog, intr + tog,
ctxt + tog, &running, &blocked, &dummy_1, &dummy_2); ctxt + tog, &running, &blocked, &dummy_1, &dummy_2);
if (t_option) {
(void) time( &the_time );
tm_ptr = localtime( &the_time );
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_ptr);
}
duse = duse =
cpu_use[tog] - cpu_use[!tog] + cpu_nic[tog] - cpu_nic[!tog]; cpu_use[tog] - cpu_use[!tog] + cpu_nic[tog] - cpu_nic[!tog];
dsys = dsys =
@ -364,6 +415,12 @@ static void new_format(void)
/* st */ /* st */
(unsigned)( (100*dstl+divo2)/Div ) (unsigned)( (100*dstl+divo2)/Div )
); );
if (t_option) {
printf(" %s", timebuf);
}
printf("\n");
} }
} }
@ -453,11 +510,33 @@ static int diskpartition_format(const char *partition_name)
static void diskheader(void) static void diskheader(void)
{ {
struct tm *tm_ptr;
time_t the_time;
char timebuf[32];
/* Translation Hint: Translating folloging header & fields /* Translation Hint: Translating folloging header & fields
* that follow (marked with max x chars) might not work, * that follow (marked with max x chars) might not work,
* unless manual page is translated as well. */ * unless manual page is translated as well. */
printf(_("disk- ------------reads------------ ------------writes----------- -----IO------\n")); const char *header =
printf("%5s %6s %6s %7s %7s %6s %6s %7s %7s %6s %6s\n", _("disk- ------------reads------------ ------------writes----------- -----IO------");
const char *wide_header =
_("disk- -------------------reads------------------- -------------------writes------------------ ------IO-------");
const char *timestamp_header = _(" -----timestamp-----");
const char format[] =
"%5s %6s %6s %7s %7s %6s %6s %7s %7s %6s %6s";
const char wide_format[] =
"%5s %9s %9s %11s %11s %9s %9s %11s %11s %7s %7s";
printf(w_option ? wide_header : header);
if (t_option) {
printf(timestamp_header);
}
printf("\n");
printf(w_option ? wide_format : format,
" ", " ",
/* Translation Hint: max 6 chars */ /* Translation Hint: max 6 chars */
_("total"), _("total"),
@ -479,25 +558,53 @@ static void diskheader(void)
_("cur"), _("cur"),
/* Translation Hint: max 6 chars */ /* Translation Hint: max 6 chars */
_("sec")); _("sec"));
if (t_option) {
(void) time( &the_time );
tm_ptr = localtime( &the_time );
if (strftime(timebuf, sizeof(timebuf), "%Z", tm_ptr)) {
timebuf[strlen(timestamp_header) - 1] = '\0';
} else {
timebuf[0] = '\0';
}
printf(" %*s", (int)(strlen(timestamp_header) - 1), timebuf);
}
printf("\n");
} }
static void diskformat(void) static void diskformat(void)
{ {
const char format[] =
"%-5s %6u %6u %7llu %7u %6u %6u %7llu %7u %6u %6u";
const char wide_format[] =
"%-5s %9u %9u %11llu %11u %9u %9u %11llu %11u %7u %7u";
FILE *fDiskstat; FILE *fDiskstat;
struct disk_stat *disks; struct disk_stat *disks;
struct partition_stat *partitions; struct partition_stat *partitions;
unsigned long ndisks, i, j, k; unsigned long ndisks, i, j, k;
const char format[] = "%-5s %6u %6u %7llu %7u %6u %6u %7llu %7u %6u %6u\n"; struct tm *tm_ptr;
time_t the_time;
char timebuf[32];
if ((fDiskstat = fopen("/proc/diskstats", "rb"))) { if ((fDiskstat = fopen("/proc/diskstats", "rb"))) {
fclose(fDiskstat); fclose(fDiskstat);
ndisks = getdiskstat(&disks, &partitions); ndisks = getdiskstat(&disks, &partitions);
if (t_option) {
(void) time( &the_time );
tm_ptr = localtime( &the_time );
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_ptr);
}
if (!moreheaders) if (!moreheaders)
diskheader(); diskheader();
for (k = 0; k < ndisks; k++) { for (k = 0; k < ndisks; k++) {
if (moreheaders && ((k % height) == 0)) if (moreheaders && ((k % height) == 0))
diskheader(); diskheader();
printf(format, printf(w_option ? wide_format : format,
disks[k].disk_name, disks[k].disk_name,
disks[k].reads, disks[k].reads,
disks[k].merged_reads, disks[k].merged_reads,
@ -510,31 +617,51 @@ static void diskformat(void)
disks[k].inprogress_IO ? disks[k].inprogress_IO / 1000 : 0, disks[k].inprogress_IO ? disks[k].inprogress_IO / 1000 : 0,
disks[k].milli_spent_IO ? disks[k]. disks[k].milli_spent_IO ? disks[k].
milli_spent_IO / 1000 : 0); milli_spent_IO / 1000 : 0);
if (t_option) {
printf(" %s", timebuf);
}
printf("\n");
fflush(stdout); fflush(stdout);
} }
free(disks); free(disks);
free(partitions); free(partitions);
for (j = 1; infinite_updates || j < num_updates; j++) { for (j = 1; infinite_updates || j < num_updates; j++) {
sleep(sleep_time); sleep(sleep_time);
ndisks = getdiskstat(&disks, &partitions); ndisks = getdiskstat(&disks, &partitions);
for (i = 0; i < ndisks; i++, k++) {
if (moreheaders && ((k % height) == 0)) if (t_option) {
diskheader(); (void) time( &the_time );
printf(format, tm_ptr = localtime( &the_time );
disks[i].disk_name, strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_ptr);
disks[i].reads, }
disks[i].merged_reads,
disks[i].reads_sectors, for (i = 0; i < ndisks; i++, k++) {
disks[i].milli_reading, if (moreheaders && ((k % height) == 0))
disks[i].writes, diskheader();
disks[i].merged_writes, printf(w_option ? wide_format : format,
disks[i].written_sectors, disks[i].disk_name,
disks[i].milli_writing, disks[i].reads,
disks[i].inprogress_IO ? disks[i].inprogress_IO / 1000 : 0, disks[i].merged_reads,
disks[i].milli_spent_IO ? disks[i]. disks[i].reads_sectors,
milli_spent_IO / 1000 : 0); disks[i].milli_reading,
fflush(stdout); disks[i].writes,
} disks[i].merged_writes,
disks[i].written_sectors,
disks[i].milli_writing,
disks[i].inprogress_IO ? disks[i].inprogress_IO / 1000 : 0,
disks[i].milli_spent_IO ? disks[i].
milli_spent_IO / 1000 : 0);
if (t_option) {
printf(" %s", timebuf);
}
printf("\n");
fflush(stdout);
}
free(disks); free(disks);
free(partitions); free(partitions);
} }
@ -740,6 +867,7 @@ int main(int argc, char *argv[])
{"partition", required_argument, NULL, 'p'}, {"partition", required_argument, NULL, 'p'},
{"unit", required_argument, NULL, 'S'}, {"unit", required_argument, NULL, 'S'},
{"wide", no_argument, NULL, 'w'}, {"wide", no_argument, NULL, 'w'},
{"timestamp", no_argument, NULL, 't'},
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'}, {"version", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
@ -754,7 +882,7 @@ int main(int argc, char *argv[])
atexit(close_stdout); atexit(close_stdout);
while ((c = while ((c =
getopt_long(argc, argv, "afmnsdDp:S:whV", longopts, getopt_long(argc, argv, "afmnsdDp:S:wthV", longopts,
NULL)) != EOF) NULL)) != EOF)
switch (c) { switch (c) {
case 'V': case 'V':
@ -820,6 +948,9 @@ int main(int argc, char *argv[])
case 'w': case 'w':
w_option = 1; w_option = 1;
break; break;
case 't':
t_option = 1;
break;
default: default:
/* no other aguments defined yet. */ /* no other aguments defined yet. */
usage(stderr); usage(stderr);