diff --git a/systemd/zpcimon.service.in b/systemd/zpcimon.service.in index cf1ea122..9be0caa4 100644 --- a/systemd/zpcimon.service.in +++ b/systemd/zpcimon.service.in @@ -13,7 +13,7 @@ Description=Monitor health of directly attached PCI NIC optical modules [Service] Type=exec -ExecStart=@usrsbin_path@/zpcimon --send-report --monitor --interval 86400 +ExecStart=@usrsbin_path@/zpcimon --send-report --monitor --format jsonl --interval 86400 KillMode=control-group [Install] diff --git a/zpcimon/zpcimon.8 b/zpcimon/zpcimon.8 index 3c274b45..9b16fa91 100644 --- a/zpcimon/zpcimon.8 +++ b/zpcimon/zpcimon.8 @@ -84,6 +84,14 @@ on". .PP .PP . +.SS Output Format Options +.OD format "" +Set the output format out of json, json-seq, jsonl, pairs, and csv. Note that +only json-seq and jsonl sequence formats are supported for monitoring mode as +they handle a continuous stream of updates well. While they are not supported +in query mode. +.PP +. .SS General Options .OD help "h" "" Print usage information, then exit. diff --git a/zpcimon/zpcimon.c b/zpcimon/zpcimon.c index 7df87e81..98a2871a 100644 --- a/zpcimon/zpcimon.c +++ b/zpcimon/zpcimon.c @@ -40,6 +40,8 @@ struct options { bool report; bool module_info; bool quiet; + enum util_fmt_t format; + bool explicit_format; uint32_t interval_seconds; }; @@ -63,6 +65,7 @@ static const struct util_prg prg = { static void parse_cmdline(int argc, char *argv[], struct options *opts) { + enum util_fmt_t fmt; uint32_t seconds; int cmd, ret; @@ -85,6 +88,12 @@ static void parse_cmdline(int argc, char *argv[], struct options *opts) case OPT_DUMP: opts->module_info = true; break; + case OPT_FORMAT: + if (!util_fmt_name_to_type(optarg, &fmt)) + errx(EXIT_FAILURE, "Unknown format %s", optarg); + opts->format = fmt; + opts->explicit_format = true; + break; case 'i': ret = sscanf(optarg, "%u", &seconds); if (ret != 1) { @@ -224,7 +233,7 @@ static void dump_all_adapter_data(struct opticsmon_ctx *ctx) static int oneshot_mode(struct opticsmon_ctx *ctx) { - util_fmt_init(stdout, FMT_JSON, FMT_DEFAULT, API_LEVEL); + util_fmt_init(stdout, ctx->opts.format, FMT_DEFAULT, API_LEVEL); if (!ctx->opts.quiet) util_fmt_obj_start(FMT_LIST, "adapters"); dump_all_adapter_data(ctx); @@ -375,7 +384,7 @@ static int monitor_mode(struct opticsmon_ctx *ctx) goto close_timerfd; } - util_fmt_init(stdout, FMT_JSONSEQ, FMT_DEFAULT, API_LEVEL); + util_fmt_init(stdout, ctx->opts.format, FMT_DEFAULT, API_LEVEL); ret = link_mon_nl_waitfd_create(&ctx->lctx, on_link_change, ctx); if (ret) { fprintf(stderr, "Failed to create link monitoring socket\n"); @@ -393,12 +402,42 @@ close_timerfd: return ret; } +static bool is_supported_fmt(enum util_fmt_t fmt, bool monitor) +{ + switch (fmt) { + case FMT_JSON: + case FMT_PAIRS: + return monitor ? false : true; + case FMT_JSONL: + case FMT_JSONSEQ: + return monitor ? true : false; + default: + return false; + } +} + +static int set_format(struct options *opts) +{ + if (!opts->explicit_format) + opts->format = (opts->monitor) ? FMT_JSONSEQ : FMT_JSON; + + if (!is_supported_fmt(opts->format, opts->monitor)) { + warnx("Format %s is not supported in %s mode", + util_fmt_type_to_name(opts->format), (opts->monitor) ? "monitor" : "query"); + return -EINVAL; + } + return 0; +} + int main(int argc, char **argv) { struct opticsmon_ctx ctx = { .opts = { .interval_seconds = 86400 } }; int ret; parse_cmdline(argc, argv, &ctx.opts); + ret = set_format(&ctx.opts); + if (ret) + return ret; ret = ethtool_nl_connect(&ctx.ethtool_ctx); if (ret) return ret; diff --git a/zpcimon/zpcimon_cli.h b/zpcimon/zpcimon_cli.h index c69f349a..f5a0dc3e 100644 --- a/zpcimon/zpcimon_cli.h +++ b/zpcimon/zpcimon_cli.h @@ -7,9 +7,11 @@ #ifndef OPTICSMON_CLI_H #define OPTICSMON_CLI_H +#include "lib/util_fmt.h" #include "lib/util_opt.h" #define OPT_DUMP 128 +#define OPT_FORMAT 129 static struct util_opt opt_vec[] = { UTIL_OPT_SECTION("OPERATION OPTIONS"), @@ -41,6 +43,13 @@ static struct util_opt opt_vec[] = { "in the absence of link state changes. A value larger than " "24 hours (86400 seconds) is clamped down to 24 hours.", }, + UTIL_OPT_SECTION("OUTPUT FORMAT OPTIONS"), + { + .option = { "format", required_argument, NULL, OPT_FORMAT }, + .argument = "FORMAT", + .flags = UTIL_OPT_FLAG_NOSHORT, + .desc = "Output format (" FMT_TYPE_NAMES ")", + }, UTIL_OPT_SECTION("GENERAL OPTIONS"), UTIL_OPT_HELP, UTIL_OPT_VERSION,