*/
/* Maximum number of fields that can be displayed */
-#define MAX_FIELDS 64
+#define MAX_FIELDS 128
/* Maximum number of header lines */
-#define HDR_LINES 10
+#define HDR_LINES 10
/* default field width if none specified */
#define FIELD_WIDTH_DEFAULT 8
#include <string.h>
#include <getopt.h>
+#include <json_writer.h>
#include "lnstat.h"
static struct option opts[] = {
{ "version", 0, NULL, 'V' },
{ "count", 1, NULL, 'c' },
- { "dump", 1, NULL, 'd' },
+ { "dump", 0, NULL, 'd' },
+ { "json", 0, NULL, 'j' },
{ "file", 1, NULL, 'f' },
{ "help", 0, NULL, 'h' },
{ "interval", 1, NULL, 'i' },
- { "key", 1, NULL, 'k' },
+ { "keys", 1, NULL, 'k' },
{ "subject", 1, NULL, 's' },
{ "width", 1, NULL, 'w' },
+ { "oneline", 0, NULL, 0 },
};
static int usage(char *name, int exit_code)
{
fprintf(stderr, "%s Version %s\n", name, LNSTAT_VERSION);
- fprintf(stderr, "Copyright (C) 2004 by Harald Welte "
- "<laforge@gnumonks.org>\n");
- fprintf(stderr, "This program is free software licensed under GNU GPLv2"
- "\nwith ABSOLUTELY NO WARRANTY.\n\n");
+ fprintf(stderr, "Copyright (C) 2004 by Harald Welte <laforge@gnumonks.org>\n");
+ fprintf(stderr, "This program is free software licensed under GNU GPLv2\nwith ABSOLUTELY NO WARRANTY.\n\n");
fprintf(stderr, "Parameters:\n");
fprintf(stderr, "\t-V --version\t\tPrint Version of Program\n");
fprintf(stderr, "\t-c --count <count>\t"
"Print <count> number of intervals\n");
- fprintf(stderr, "\t-d --dumpt\t\t"
+ fprintf(stderr, "\t-d --dump\t\t"
"Dump list of available files/keys\n");
+ fprintf(stderr, "\t-j --json\t\t"
+ "Display in JSON format\n");
fprintf(stderr, "\t-f --file <file>\tStatistics file to use\n");
fprintf(stderr, "\t-h --help\t\tThis help message\n");
fprintf(stderr, "\t-i --interval <intv>\t"
"Set interval to 'intv' seconds\n");
fprintf(stderr, "\t-k --keys k,k,k,...\tDisplay only keys specified\n");
- fprintf(stderr, "\t-s --subject [0-2]\t?\n");
+ fprintf(stderr, "\t-s --subject [0-2]\tControl header printing:\n");
+ fprintf(stderr, "\t\t\t\t0 = never\n");
+ fprintf(stderr, "\t\t\t\t1 = once\n");
+ fprintf(stderr, "\t\t\t\t2 = every 20 lines (default))\n");
fprintf(stderr, "\t-w --width n,n,n,...\tWidth for each field\n");
fprintf(stderr, "\n");
int i;
for (i = 0; i < fp->num; i++) {
- struct lnstat_field *lf = fp->params[i].lf;
- char formatbuf[255];
+ const struct lnstat_field *lf = fp->params[i].lf;
- snprintf(formatbuf, sizeof(formatbuf)-1, "%%%ulu|",
- fp->params[i].print.width);
- fprintf(of, formatbuf, lf->result);
+ fprintf(of, "%*lu|", fp->params[i].print.width, lf->result);
}
fputc('\n', of);
}
+static void print_json(FILE *of, const struct lnstat_file *lnstat_files,
+ const struct field_params *fp)
+{
+ json_writer_t *jw = jsonw_new(of);
+ int i;
+
+ jsonw_start_object(jw);
+ for (i = 0; i < fp->num; i++) {
+ const struct lnstat_field *lf = fp->params[i].lf;
+
+ jsonw_uint_field(jw, lf->name, lf->result);
+ }
+ jsonw_end_object(jw);
+ jsonw_destroy(&jw);
+}
+
/* find lnstat_field according to user specification */
static int map_field_params(struct lnstat_file *lnstat_files,
struct field_params *fps, int interval)
fps->params[j].lf->file->interval.tv_sec =
interval;
if (!fps->params[j].print.width)
- fps->params[j].print.width =
+ fps->params[j].print.width =
FIELD_WIDTH_DEFAULT;
- j++;
+
+ if (++j >= MAX_FIELDS - 1) {
+ fprintf(stderr,
+ "WARN: MAX_FIELDS (%d) reached, truncating number of keys\n",
+ MAX_FIELDS);
+ goto full;
+ }
}
}
+full:
fps->num = j;
return 1;
}
struct field_params *fps,
int linewidth)
{
- int h,i;
+ int h, i;
static struct table_hdr th;
int ofs = 0;
- for (i = 0; i < HDR_LINES; i++) {
- th.hdr[i] = malloc(HDR_LINE_LENGTH);
- memset(th.hdr[i], 0, sizeof(th.hdr[i]));
- }
+ for (i = 0; i < HDR_LINES; i++)
+ th.hdr[i] = calloc(1, HDR_LINE_LENGTH);
for (i = 0; i < fps->num; i++) {
char *cname, *fname = fps->params[i].lf->name;
- char fmt[12];
unsigned int width = fps->params[i].print.width;
- snprintf(fmt, sizeof(fmt)-1, "%%%u.%us|", width, width);
-
- snprintf(th.hdr[0]+ofs, width+2, fmt,
+ snprintf(th.hdr[0]+ofs, width+2, "%*.*s|", width, width,
fps->params[i].lf->file->basename);
cname = fname;
for (h = 1; h < HDR_LINES; h++) {
if (cname - fname >= strlen(fname))
- snprintf(th.hdr[h]+ofs, width+2, fmt, "");
+ snprintf(th.hdr[h]+ofs, width+2,
+ "%*.*s|", width, width, "");
else {
th.num_lines = h+1;
- snprintf(th.hdr[h]+ofs, width+2, fmt, cname);
+ snprintf(th.hdr[h]+ofs, width+2,
+ "%*.*s|", width, width, cname);
}
cname += width;
}
}
return 0;
}
-
+
int main(int argc, char **argv)
{
struct lnstat_file *lnstat_files;
const char *basename;
- int c;
+ int i, c;
int interval = DEFAULT_INTERVAL;
int hdr = 2;
enum {
MODE_DUMP,
+ MODE_JSON,
MODE_NORMAL,
} mode = MODE_NORMAL;
-
unsigned long count = 0;
+ struct table_hdr *header;
static struct field_params fp;
int num_req_files = 0;
char *req_files[LNSTAT_MAX_FILES];
-
+
/* backwards compatibility mode for old tools */
basename = strrchr(argv[0], '/');
- if (basename)
+ if (basename)
basename += 1; /* name after slash */
else
basename = argv[0]; /* no slash */
num_req_files = 1;
}
- while ((c = getopt_long(argc, argv,"Vc:df:h?i:k:s:w:",
+ while ((c = getopt_long(argc, argv, "Vc:djpf:h?i:k:s:w:",
opts, NULL)) != -1) {
- int i, len = 0;
+ int len = 0;
char *tmp, *tok;
switch (c) {
- case 'c':
- count = strtoul(optarg, NULL, 0);
- break;
- case 'd':
- mode = MODE_DUMP;
- break;
- case 'f':
- req_files[num_req_files++] = strdup(optarg);
+ case 'c':
+ count = strtoul(optarg, NULL, 0);
+ break;
+ case 'd':
+ mode = MODE_DUMP;
+ break;
+ case 'j':
+ mode = MODE_JSON;
+ break;
+ case 'f':
+ req_files[num_req_files++] = strdup(optarg);
+ break;
+ case '?':
+ case 'h':
+ usage(argv[0], 0);
+ break;
+ case 'i':
+ sscanf(optarg, "%u", &interval);
+ break;
+ case 'k':
+ tmp = strdup(optarg);
+ if (!tmp)
break;
- case '?':
- case 'h':
- usage(argv[0], 0);
- break;
- case 'i':
- sscanf(optarg, "%u", &interval);
- break;
- case 'k':
- tmp = strdup(optarg);
- if (!tmp)
+ for (tok = strtok(tmp, ",");
+ tok;
+ tok = strtok(NULL, ",")) {
+ if (fp.num >= MAX_FIELDS) {
+ fprintf(stderr,
+ "WARN: too many keys requested: (%d max)\n",
+ MAX_FIELDS);
break;
- for (tok = strtok(tmp, ",");
- tok;
- tok = strtok(NULL, ",")) {
- if (fp.num >= MAX_FIELDS)
- break;
- fp.params[fp.num++].name = tok;
}
+ fp.params[fp.num++].name = tok;
+ }
+ break;
+ case 's':
+ sscanf(optarg, "%u", &hdr);
+ break;
+ case 'w':
+ tmp = strdup(optarg);
+ if (!tmp)
break;
- case 's':
- sscanf(optarg, "%u", &hdr);
- break;
- case 'w':
- tmp = strdup(optarg);
- if (!tmp)
- break;
- i = 0;
- for (tok = strtok(tmp, ",");
- tok;
- tok = strtok(NULL, ",")) {
- len = strtoul(tok, NULL, 0);
- if (len > FIELD_WIDTH_MAX)
- len = FIELD_WIDTH_MAX;
+ i = 0;
+ for (tok = strtok(tmp, ",");
+ tok;
+ tok = strtok(NULL, ",")) {
+ len = strtoul(tok, NULL, 0);
+ if (len > FIELD_WIDTH_MAX)
+ len = FIELD_WIDTH_MAX;
+ fp.params[i].print.width = len;
+ i++;
+ }
+ if (i == 1) {
+ for (i = 0; i < MAX_FIELDS; i++)
fp.params[i].print.width = len;
- i++;
- }
- if (i == 1) {
- for (i = 0; i < MAX_FIELDS; i++)
- fp.params[i].print.width = len;
- }
- break;
- default:
- usage(argv[0], 1);
- break;
+ }
+ break;
+ default:
+ usage(argv[0], 1);
+ break;
}
}
(const char **) req_files);
switch (mode) {
- int i;
- struct table_hdr *header;
case MODE_DUMP:
- lnstat_dump(stderr, lnstat_files);
+ lnstat_dump(stdout, lnstat_files);
break;
- case MODE_NORMAL:
+ case MODE_NORMAL:
+ case MODE_JSON:
if (!map_field_params(lnstat_files, &fp, interval))
exit(1);
-
+
header = build_hdr_string(lnstat_files, &fp, 80);
if (!header)
exit(1);
- if (interval < 1 )
- interval=1;
+ if (interval < 1)
+ interval = 1;
- for (i = 0; i < count; i++) {
- if ((hdr > 1 && (! (i % 20))) || (hdr == 1 && i == 0))
- print_hdr(stdout, header);
+ for (i = 0; i < count || !count; i++) {
lnstat_update(lnstat_files);
- print_line(stdout, lnstat_files, &fp);
- sleep(interval);
+ if (mode == MODE_JSON)
+ print_json(stdout, lnstat_files, &fp);
+ else {
+ if ((hdr > 1 && !(i % 20)) ||
+ (hdr == 1 && i == 0))
+ print_hdr(stdout, header);
+ print_line(stdout, lnstat_files, &fp);
+ }
+ fflush(stdout);
+ if (i < count - 1 || !count)
+ sleep(interval);
}
+ break;
}
return 1;
}
-