From: Kulemin Alexander Date: Thu, 9 Jul 2020 16:40:57 +0000 (+0300) Subject: report: json: reworked with libjansson X-Git-Tag: v0.94~6^2 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F355%2Fhead;p=thirdparty%2Fmtr.git report: json: reworked with libjansson --- diff --git a/Makefile.am b/Makefile.am index 7fed5ce..7719be1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -92,8 +92,8 @@ ASAN_CFLAGS += -fsanitize=address endif mtr_INCLUDES = $(GLIB_CFLAGS) -I$(top_builddir) -I$(top_srcdir) -mtr_CFLAGS = $(GTK_CFLAGS) $(NCURSES_CFLAGS) $(ASAN_CFLAGS) -mtr_LDADD = $(GTK_LIBS) $(NCURSES_LIBS) $(RESOLV_LIBS) +mtr_CFLAGS = $(GTK_CFLAGS) $(NCURSES_CFLAGS) $(ASAN_CFLAGS) $(JANSSON_CFLAGS) +mtr_LDADD = $(GTK_LIBS) $(NCURSES_LIBS) $(RESOLV_LIBS) $(JANSSON_LIBS) mtr_packet_SOURCES = \ diff --git a/configure.ac b/configure.ac index 2ec0a79..88b508c 100644 --- a/configure.ac +++ b/configure.ac @@ -104,6 +104,15 @@ AS_IF([test "x$with_gtk" = "xyes"], ]) AM_CONDITIONAL([WITH_GTK], [test "x$with_gtk" = xyes]) +AC_ARG_WITH([jansson], + [AS_HELP_STRING([--without-jansson], [Build without JSON output])], + [], [with_jansson=yes]) +AS_IF([test "x$with_jansson" = "xyes"], + [PKG_CHECK_MODULES([JANSSON], [jansson], + [AC_DEFINE([HAVE_JANSSON], [1], [Define if jansson library available])], + [with_jansson=no]) +]) + # Find ncurses AC_ARG_WITH([ncurses], [AS_HELP_STRING([--without-ncurses], [Build without the ncurses interface])], @@ -259,6 +268,7 @@ echo "ipv6 :$USES_IPV6" echo "ipinfo :$with_ipinfo" echo "ncurses :$with_ncurses" echo "gtk :$with_gtk" +echo "jansson :$with_jansson" echo "cap :$have_cap" echo "libs :$LIBS" echo "cflags :$CFLAGS" diff --git a/man/mtr.8.in b/man/mtr.8.in index e8c5404..9d13535 100644 --- a/man/mtr.8.in +++ b/man/mtr.8.in @@ -267,6 +267,9 @@ Use this option to tell .B mtr to use the JSON output format. This format is better suited for automated processing of the measurement results. +Jansson library must have been available on the system when +.B mtr +was built for this to work. .TP .B \-p\fR, \fB\-\-split Use this option to set diff --git a/ui/display.c b/ui/display.c index e533f97..7127be5 100644 --- a/ui/display.c +++ b/ui/display.c @@ -81,9 +81,11 @@ void display_open( case DisplayTXT: txt_open(); break; +#ifdef HAVE_JANSSON case DisplayJSON: json_open(); break; +#endif case DisplayXML: xml_open(); break; @@ -127,9 +129,11 @@ void display_close( case DisplayTXT: txt_close(ctl); break; +#ifdef HAVE_JANSSON case DisplayJSON: json_close(ctl); break; +#endif case DisplayXML: xml_close(ctl); break; diff --git a/ui/display.h b/ui/display.h index 5b37b56..3eaa291 100644 --- a/ui/display.h +++ b/ui/display.h @@ -41,7 +41,9 @@ enum { DisplayXML, DisplayCSV, DisplayTXT, - DisplayJSON +#ifdef HAVE_JANSSON + DisplayJSON, +#endif }; enum { diff --git a/ui/mtr.c b/ui/mtr.c index bfc89c3..b33a136 100644 --- a/ui/mtr.c +++ b/ui/mtr.c @@ -349,7 +349,9 @@ static void parse_arg( #endif {"raw", 0, NULL, 'l'}, {"csv", 0, NULL, 'C'}, +#ifdef HAVE_JANSSON {"json", 0, NULL, 'j'}, +#endif {"displaymode", 1, NULL, OPT_DISPLAYMODE}, {"split", 0, NULL, 'p'}, /* BL */ /* maybe above should change to -d 'x' */ @@ -445,9 +447,11 @@ static void parse_arg( case 'C': ctl->DisplayMode = DisplayCSV; break; +#ifdef HAVE_JANSSON case 'j': ctl->DisplayMode = DisplayJSON; break; +#endif case 'x': ctl->DisplayMode = DisplayXML; break; @@ -644,7 +648,9 @@ static void parse_arg( if (ctl->DisplayMode == DisplayReport || ctl->DisplayMode == DisplayTXT || +#ifdef HAVE_JANSSON ctl->DisplayMode == DisplayJSON || +#endif ctl->DisplayMode == DisplayXML || ctl->DisplayMode == DisplayRaw || ctl->DisplayMode == DisplayCSV) ctl->Interactive = 0; diff --git a/ui/report.c b/ui/report.c index 97a3fa4..1f5bd28 100644 --- a/ui/report.c +++ b/ui/report.c @@ -26,6 +26,14 @@ #include #include #include +#ifdef HAVE_JANSSON +#include +#endif +#ifdef HAVE_ERROR_H +#include +#else +#include "portability/error.h" +#endif #include "mtr.h" #include "report.h" @@ -269,111 +277,111 @@ void txt_close( report_close(ctl); } - +#ifdef HAVE_JANSSON void json_open( void) { } - -void json_close( - struct mtr_ctl *ctl) +void json_close(struct mtr_ctl *ctl) { - int i, j, at, first, max; + int i, j, at, max; + int ret; + char buf[128]; + json_t *jreport, *jmtr, *jhubs, *jh; ip_t *addr; char name[MAX_FORMAT_STR]; - printf("{\n"); - printf(" \"report\": {\n"); - printf(" \"mtr\": {\n"); - printf(" \"src\": \"%s\",\n", ctl->LocalHostname); - printf(" \"dst\": \"%s\",\n", ctl->Hostname); - printf(" \"tos\": \"0x%X\",\n", ctl->tos); + jmtr = json_pack("{ss ss si si}", + "src", ctl->LocalHostname, + "dst", ctl->Hostname, + "tos", ctl->tos, + "tests", ctl->MaxPing); + if (!jmtr) + goto on_error; + if (ctl->cpacketsize >= 0) { - printf(" \"psize\": \"%d\",\n", ctl->cpacketsize); + snprintf(buf, sizeof(buf), "%d", ctl->cpacketsize); } else { - printf(" \"psize\": \"rand(%d-%d)\",\n", MINPACKET, - -ctl->cpacketsize); + snprintf(buf, sizeof(buf), "rand(%d-%d)", MINPACKET, -ctl->cpacketsize); } + ret = json_object_set_new(jmtr, "psize", json_string(buf)); + if (ret == -1) + goto on_error; + if (ctl->bitpattern >= 0) { - printf(" \"bitpattern\": \"0x%02X\",\n", - (unsigned char) (ctl->bitpattern)); + snprintf(buf, sizeof(buf), "0x%02X", (unsigned char)(ctl->bitpattern)); } else { - printf(" \"bitpattern\": \"rand(0x00-FF)\",\n"); + snprintf(buf, sizeof(buf), "rand(0x00-FF)"); } - printf(" \"tests\": \"%d\"\n", ctl->MaxPing); - printf(" },\n"); - printf(" \"hubs\": ["); + ret = json_object_set_new(jmtr, "bitpattern", json_string(buf)); + if (ret == -1) + goto on_error; + + jhubs = json_array(); + if (!jhubs) + goto on_error; max = net_max(ctl); - at = first = net_min(ctl); + at = net_min(ctl); for (; at < max; at++) { addr = net_addr(at); snprint_addr(ctl, name, sizeof(name), addr); - if (at == first) { - printf("{\n"); - } else { - printf(" {\n"); - } - printf(" \"count\": \"%d\",\n", at + 1); - printf(" \"host\": \"%s\",\n", name); + jh = json_pack("{si ss}", "count", at + 1, "host", name); + if (!jh) + goto on_error; + #ifdef HAVE_IPINFO if(!ctl->ipinfo_no) { - char* fmtinfo = fmt_ipinfo(ctl, addr); - if (fmtinfo != NULL) fmtinfo = trim(fmtinfo, '\0'); - printf(" \"ASN\": \"%s\",\n", fmtinfo); + char* fmtinfo = fmt_ipinfo(ctl, addr); + if (fmtinfo != NULL) + fmtinfo = trim(fmtinfo, '\0'); + + ret = json_object_set_new(jh, "ASN", json_string(fmtinfo)); + if (ret == -1) + goto on_error; } #endif - for (i = 0; i < MAXFLD; i++) { - const char *format; + for (i = 0; i < MAXFLD; i++) { j = ctl->fld_index[ctl->fld_active[i]]; - /* Commas */ - if (i + 1 == MAXFLD) { - printf("\n"); - } else if (j > 0 && i != 0) { - printf(",\n"); - } - if (j <= 0) - continue; /* Field nr 0, " " shouldn't be printed in this method. */ + continue; /* Field nr 0, " " shouldn't be printed in this method. */ - /* Format value */ - format = data_fields[j].format; - if (strchr(format, 'f')) { - format = "%.2f"; - } else { - format = "%d"; - } - - /* Format json line */ - snprintf(name, sizeof(name), "%s%s", " \"%s\": ", format); - - /* Output json line */ if (strchr(data_fields[j].format, 'f')) { - /* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */ - printf(name, - data_fields[j].title, - data_fields[j].net_xxx(at) / 1000.0); + ret = json_object_set_new( + jh, data_fields[j].title, + json_real(data_fields[j].net_xxx(at) / 1000.0)); } else { - printf(name, - data_fields[j].title, data_fields[j].net_xxx(at)); + ret = json_object_set_new( + jh, data_fields[j].title, + json_integer(data_fields[j].net_xxx(at))); } + if (ret == -1) + goto on_error; } - if (at + 1 == max) { - printf(" }"); - } else { - printf(" },\n"); - } + + ret = json_array_append_new(jhubs, jh); + if (ret == -1) + goto on_error; } - printf("]\n"); - printf(" }\n"); - printf("}\n"); -} + jreport = json_pack("{s{so so}}", "report", "mtr", jmtr, "hubs", jhubs); + + ret = json_dumpf(jreport, stdout, JSON_INDENT(4) | JSON_REAL_PRECISION(5)); + if (ret == -1) + goto on_error; + + printf("\n"); // bash promt should be on new line + json_decref(jreport); + return; +on_error: + error(EXIT_FAILURE, 0, "json_close failed"); +} +#endif void xml_open(