diff options
author | Stephen Hemminger <stephen@networkplumber.org> | 2013-09-24 11:55:13 -0700 |
---|---|---|
committer | Stephen Hemminger <stephen@networkplumber.org> | 2013-09-24 11:55:13 -0700 |
commit | ec3e625c410feaad1b3da4c8e4b8e91069a862ba (patch) | |
tree | c325dc57a47ab83c25713eabe0620445de92762e /misc/ifstat.c | |
parent | 404582c8ebc99920bdfe8ba0fdef8ee4ee4d9783 (diff) |
ifstat: add json output format
Diffstat (limited to 'misc/ifstat.c')
-rw-r--r-- | misc/ifstat.c | 131 |
1 files changed, 112 insertions, 19 deletions
diff --git a/misc/ifstat.c b/misc/ifstat.c index 6d0ad8cc..a47c0461 100644 --- a/misc/ifstat.c +++ b/misc/ifstat.c @@ -38,6 +38,7 @@ int dump_zeros = 0; int reset_history = 0; int ignore_history = 0; int no_output = 0; +int json_output = 0; int no_update = 0; int scan_interval = 0; int time_constant = 0; @@ -61,6 +62,32 @@ struct ifstat_ent __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 *hist_db; @@ -212,8 +239,13 @@ static void load_raw_table(FILE *fp) static void dump_raw_db(FILE *fp, int to_hist) { struct ifstat_ent *n, *h; + const char *eol = "\n"; + 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) { int i; @@ -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++) - fprintf(fp, "%llu %u ", vals[i], (unsigned)rates[i]); - fprintf(fp, "\n"); + + if (json_output) { + fprintf(fp, "%s \"%s\":{", + 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; static const unsigned long long mega = 1000000; static const unsigned long long kilo = 1000; -static void format_rate(FILE *fp, unsigned long long *vals, - double *rates, int i) +static void format_rate(FILE *fp, const unsigned long long *vals, + const double *rates, int i) { char temp[64]; + if (vals[i] > giga) fprintf(fp, "%7lluM ", vals[i]/mega); else if (vals[i] > mega) @@ -265,7 +310,7 @@ static void format_rate(FILE *fp, unsigned long long *vals, 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]; if (vals[i] > giga) @@ -328,10 +373,27 @@ static void print_head(FILE *fp) } } -static void print_one_if(FILE *fp, struct ifstat_ent *n, - unsigned long long *vals) +static void print_one_json(FILE *fp, const struct ifstat_ent *n, + 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; + fprintf(fp, "%-15s ", n->name); for (i=0; i<4; i++) format_rate(fp, vals, n->rate, i); @@ -375,27 +437,42 @@ static void print_one_if(FILE *fp, struct ifstat_ent *n, } } - static void dump_kern_db(FILE *fp) { 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) { if (!match(n->name)) 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) { 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) { int i; @@ -414,8 +491,16 @@ static void dump_incr_db(FILE *fp) } if (!match(n->name)) 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) " -a, --ignore ignore history\n" " -d, --scan=SECS sample every statistics every SECS\n" " -e, --errors show errors\n" +" -j, --json format output in JSON\n" " -n, --nooutput do history only\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" " -V, --version output version information\n" " -z, --zeros show entries with zero activity\n"); @@ -575,6 +661,7 @@ static const struct option longopts[] = { { "scan", 1, 0, 'd'}, { "errors", 0, 0, 'e' }, { "nooutput", 0, 0, 'n' }, + { "json", 0, 0, 'j' }, { "reset", 0, 0, 'r' }, { "noupdate", 0, 0, 's' }, { "interval", 1, 0, 't' }, @@ -591,7 +678,7 @@ int main(int argc, char *argv[]) int ch; int fd; - while ((ch = getopt_long(argc, argv, "hvVzrnasd:t:eK", + while ((ch = getopt_long(argc, argv, "hjvVzrnasd:t:e", longopts, NULL)) != EOF) { switch(ch) { case 'z': @@ -612,6 +699,9 @@ int main(int argc, char *argv[]) case 'e': show_errors = 1; break; + case 'j': + json_output = 1; + break; case 'd': scan_interval = atoi(optarg) * 1000; if (scan_interval <= 0) { @@ -759,11 +849,14 @@ int main(int argc, char *argv[]) else dump_incr_db(stdout); } + if (!no_update) { ftruncate(fileno(hist_fp), 0); rewind(hist_fp); + + json_output = 0; dump_raw_db(hist_fp, 1); - fflush(hist_fp); + fclose(hist_fp); } exit(0); } |