Commit ec3e625c authored by Stephen Hemminger's avatar Stephen Hemminger

ifstat: add json output format

parent 404582c8
...@@ -38,6 +38,7 @@ int dump_zeros = 0; ...@@ -38,6 +38,7 @@ int dump_zeros = 0;
int reset_history = 0; int reset_history = 0;
int ignore_history = 0; int ignore_history = 0;
int no_output = 0; int no_output = 0;
int json_output = 0;
int no_update = 0; int no_update = 0;
int scan_interval = 0; int scan_interval = 0;
int time_constant = 0; int time_constant = 0;
...@@ -61,6 +62,32 @@ struct ifstat_ent ...@@ -61,6 +62,32 @@ struct ifstat_ent
__u32 ival[MAXS]; __u32 ival[MAXS];
}; };
static const char *stats[MAXS] = {
"rx_packets",
"tx_packets",
"rx_bytes",
"tx_bytes",
"rx_errors",
"tx_errors",
"rx_dropped",
"tx_dropped",
"multicast",
"collisions",
"rx_length_errors",
"rx_over_errors",
"rx_crc_errors",
"rx_frame_errors",
"rx_fifo_errors",
"rx_missed_errors",
"tx_aborted_errors",
"tx_carrier_errors",
"tx_fifo_errors",
"tx_heartbeat_errors",
"tx_window_errors",
"rx_compressed",
"tx_compressed"
};
struct ifstat_ent *kern_db; struct ifstat_ent *kern_db;
struct ifstat_ent *hist_db; struct ifstat_ent *hist_db;
...@@ -212,8 +239,13 @@ static void load_raw_table(FILE *fp) ...@@ -212,8 +239,13 @@ static void load_raw_table(FILE *fp)
static void dump_raw_db(FILE *fp, int to_hist) static void dump_raw_db(FILE *fp, int to_hist)
{ {
struct ifstat_ent *n, *h; struct ifstat_ent *n, *h;
const char *eol = "\n";
h = hist_db; h = hist_db;
fprintf(fp, "#%s\n", info_source); if (json_output)
fprintf(fp, "{ \"%s\":{", info_source);
else
fprintf(fp, "#%s\n", info_source);
for (n=kern_db; n; n=n->next) { for (n=kern_db; n; n=n->next) {
int i; int i;
...@@ -232,10 +264,22 @@ static void dump_raw_db(FILE *fp, int to_hist) ...@@ -232,10 +264,22 @@ static void dump_raw_db(FILE *fp, int to_hist)
} }
} }
} }
fprintf(fp, "%d %s ", n->ifindex, n->name);
for (i=0; i<MAXS; i++) if (json_output) {
fprintf(fp, "%llu %u ", vals[i], (unsigned)rates[i]); fprintf(fp, "%s \"%s\":{",
fprintf(fp, "\n"); eol, n->name);
eol = ",\n";
for (i=0; i<MAXS && stats[i]; i++)
fprintf(fp, " \"%s\":%llu",
stats[i], vals[i]);
fprintf(fp, "}");
} else {
fprintf(fp, "%d %s ", n->ifindex, n->name);
for (i=0; i<MAXS; i++)
fprintf(fp, "%llu %u ", vals[i],
(unsigned)rates[i]);
fprintf(fp, "\n");
}
} }
} }
...@@ -244,10 +288,11 @@ static const unsigned long long giga = 1000000000ull; ...@@ -244,10 +288,11 @@ static const unsigned long long giga = 1000000000ull;
static const unsigned long long mega = 1000000; static const unsigned long long mega = 1000000;
static const unsigned long long kilo = 1000; static const unsigned long long kilo = 1000;
static void format_rate(FILE *fp, unsigned long long *vals, static void format_rate(FILE *fp, const unsigned long long *vals,
double *rates, int i) const double *rates, int i)
{ {
char temp[64]; char temp[64];
if (vals[i] > giga) if (vals[i] > giga)
fprintf(fp, "%7lluM ", vals[i]/mega); fprintf(fp, "%7lluM ", vals[i]/mega);
else if (vals[i] > mega) else if (vals[i] > mega)
...@@ -265,7 +310,7 @@ static void format_rate(FILE *fp, unsigned long long *vals, ...@@ -265,7 +310,7 @@ static void format_rate(FILE *fp, unsigned long long *vals,
fprintf(fp, "%-6u ", (unsigned)rates[i]); fprintf(fp, "%-6u ", (unsigned)rates[i]);
} }
static void format_pair(FILE *fp, unsigned long long *vals, int i, int k) static void format_pair(FILE *fp, const unsigned long long *vals, int i, int k)
{ {
char temp[64]; char temp[64];
if (vals[i] > giga) if (vals[i] > giga)
...@@ -328,10 +373,27 @@ static void print_head(FILE *fp) ...@@ -328,10 +373,27 @@ static void print_head(FILE *fp)
} }
} }
static void print_one_if(FILE *fp, struct ifstat_ent *n, static void print_one_json(FILE *fp, const struct ifstat_ent *n,
unsigned long long *vals) const unsigned long long *vals)
{
int i, m;
const char *sep = " ";
m = show_errors ? 20 : 10;
fprintf(fp, " \"%s\":{", n->name);
for (i=0; i < m && stats[i]; i++) {
fprintf(fp, "%s\"%s\":%llu",
sep, stats[i], vals[i]);
sep = ", ";
}
fprintf(fp, " }");
}
static void print_one_if(FILE *fp, const struct ifstat_ent *n,
const unsigned long long *vals)
{ {
int i; int i;
fprintf(fp, "%-15s ", n->name); fprintf(fp, "%-15s ", n->name);
for (i=0; i<4; i++) for (i=0; i<4; i++)
format_rate(fp, vals, n->rate, i); format_rate(fp, vals, n->rate, i);
...@@ -375,27 +437,42 @@ static void print_one_if(FILE *fp, struct ifstat_ent *n, ...@@ -375,27 +437,42 @@ static void print_one_if(FILE *fp, struct ifstat_ent *n,
} }
} }
static void dump_kern_db(FILE *fp) static void dump_kern_db(FILE *fp)
{ {
struct ifstat_ent *n; struct ifstat_ent *n;
const char *eol = "\n";
print_head(fp); if (json_output)
fprintf(fp, "{ \"%s\": {", info_source);
else
print_head(fp);
for (n=kern_db; n; n=n->next) { for (n=kern_db; n; n=n->next) {
if (!match(n->name)) if (!match(n->name))
continue; continue;
print_one_if(fp, n, n->val);
if (json_output) {
fprintf(fp, "%s", eol);
eol = ",\n";
print_one_json(fp, n, n->val);
} else
print_one_if(fp, n, n->val);
} }
if (json_output)
fprintf(fp, "\n} }\n");
} }
static void dump_incr_db(FILE *fp) static void dump_incr_db(FILE *fp)
{ {
struct ifstat_ent *n, *h; struct ifstat_ent *n, *h;
h = hist_db; const char *eol = "\n";
print_head(fp); h = hist_db;
if (json_output)
fprintf(fp, "{ \"%s\":{", info_source);
else
print_head(fp);
for (n=kern_db; n; n=n->next) { for (n=kern_db; n; n=n->next) {
int i; int i;
...@@ -414,8 +491,16 @@ static void dump_incr_db(FILE *fp) ...@@ -414,8 +491,16 @@ static void dump_incr_db(FILE *fp)
} }
if (!match(n->name)) if (!match(n->name))
continue; continue;
print_one_if(fp, n, vals);
if (json_output) {
fprintf(fp, "%s", eol);
eol = ",\n";
print_one_json(fp, n, n->val);
} else
print_one_if(fp, n, vals);
} }
if (json_output)
fprintf(fp, "\n} }\n");
} }
...@@ -559,9 +644,10 @@ static void usage(void) ...@@ -559,9 +644,10 @@ static void usage(void)
" -a, --ignore ignore history\n" " -a, --ignore ignore history\n"
" -d, --scan=SECS sample every statistics every SECS\n" " -d, --scan=SECS sample every statistics every SECS\n"
" -e, --errors show errors\n" " -e, --errors show errors\n"
" -j, --json format output in JSON\n"
" -n, --nooutput do history only\n" " -n, --nooutput do history only\n"
" -r, --reset reset history\n" " -r, --reset reset history\n"
" -s, --noupdate don;t update history\n" " -s, --noupdate don\'t update history\n"
" -t, --interval=SECS report average over the last SECS\n" " -t, --interval=SECS report average over the last SECS\n"
" -V, --version output version information\n" " -V, --version output version information\n"
" -z, --zeros show entries with zero activity\n"); " -z, --zeros show entries with zero activity\n");
...@@ -575,6 +661,7 @@ static const struct option longopts[] = { ...@@ -575,6 +661,7 @@ static const struct option longopts[] = {
{ "scan", 1, 0, 'd'}, { "scan", 1, 0, 'd'},
{ "errors", 0, 0, 'e' }, { "errors", 0, 0, 'e' },
{ "nooutput", 0, 0, 'n' }, { "nooutput", 0, 0, 'n' },
{ "json", 0, 0, 'j' },
{ "reset", 0, 0, 'r' }, { "reset", 0, 0, 'r' },
{ "noupdate", 0, 0, 's' }, { "noupdate", 0, 0, 's' },
{ "interval", 1, 0, 't' }, { "interval", 1, 0, 't' },
...@@ -591,7 +678,7 @@ int main(int argc, char *argv[]) ...@@ -591,7 +678,7 @@ int main(int argc, char *argv[])
int ch; int ch;
int fd; int fd;
while ((ch = getopt_long(argc, argv, "hvVzrnasd:t:eK", while ((ch = getopt_long(argc, argv, "hjvVzrnasd:t:e",
longopts, NULL)) != EOF) { longopts, NULL)) != EOF) {
switch(ch) { switch(ch) {
case 'z': case 'z':
...@@ -612,6 +699,9 @@ int main(int argc, char *argv[]) ...@@ -612,6 +699,9 @@ int main(int argc, char *argv[])
case 'e': case 'e':
show_errors = 1; show_errors = 1;
break; break;
case 'j':
json_output = 1;
break;
case 'd': case 'd':
scan_interval = atoi(optarg) * 1000; scan_interval = atoi(optarg) * 1000;
if (scan_interval <= 0) { if (scan_interval <= 0) {
...@@ -759,11 +849,14 @@ int main(int argc, char *argv[]) ...@@ -759,11 +849,14 @@ int main(int argc, char *argv[])
else else
dump_incr_db(stdout); dump_incr_db(stdout);
} }
if (!no_update) { if (!no_update) {
ftruncate(fileno(hist_fp), 0); ftruncate(fileno(hist_fp), 0);
rewind(hist_fp); rewind(hist_fp);
json_output = 0;
dump_raw_db(hist_fp, 1); dump_raw_db(hist_fp, 1);
fflush(hist_fp); fclose(hist_fp);
} }
exit(0); exit(0);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment