[ntpsec commit] Add JSON mode output to ntpdig, and document it.

Eric S. Raymond esr at ntpsec.org
Wed Oct 14 18:59:49 UTC 2015


Module:    ntpsec
Branch:    master
Commit:    10051fd8ae545e87e75cd0a11955690121742c99
Changeset: http://git.ntpsec.org/ntpsec/commit/?id=10051fd8ae545e87e75cd0a11955690121742c99

Author:    Eric S. Raymond <esr at thyrsus.com>
Date:      Wed Oct 14 14:59:12 2015 -0400

Add JSON mode output to ntpdig, and document it.

---

 devel-docs/TODO               |  3 +++
 docs/includes/ntpdig-body.txt | 32 +++++++++++++++++++++++++-------
 ntpdig/kod_management.c       |  2 +-
 ntpdig/main.c                 | 39 +++++++++++++++++++++++++++------------
 ntpdig/utilities.c            |  7 +++++--
 ntpdig/utilities.h            |  2 +-
 6 files changed, 62 insertions(+), 23 deletions(-)

diff --git a/devel-docs/TODO b/devel-docs/TODO
index e5e9115..cc6bb65 100644
--- a/devel-docs/TODO
+++ b/devel-docs/TODO
@@ -52,6 +52,9 @@ None right now. (Sep-22 2015)
 
 * systime.c needs patching to put ntpdsim's hook back in place.
 
+* ntpfrob -c behaves mysteriously.  Someone with domain knowledge (probably Hal)
+  should review the code.
+
 * Fixup copyright notices.
   See Mark's message of Oct-13th.
   Subject: FLOSS license policy and copyright marking policy
diff --git a/docs/includes/ntpdig-body.txt b/docs/includes/ntpdig-body.txt
index 23e5a45..8d470ec 100644
--- a/docs/includes/ntpdig-body.txt
+++ b/docs/includes/ntpdig-body.txt
@@ -6,7 +6,7 @@
 
 {ntpdig}
     [--help | -?] [-4 | -6] [-a keynum] [-b bcaddress] [-B bctimeout]
-    [-c] [-d] [-D debug-level] [-g delay] [-K kodfile] [-k keyfile]
+    [-c] [-d] [-D debug-level] [-g delay] [-j] [-K kodfile] [-k keyfile]
     [-l logfile] [-M steplimit] [-o ntpver] [-r] [-S] [-s]
     [-u uctimeout] [--wait] [--version] [address...]`
 
@@ -22,15 +22,15 @@ The default is to write the estimated correct local date and time (i.e.
 not UTC) to the standard output in a format like:
 
 -----------------------------------------------------
-1996-10-15 20:17:25.123 (+0800) +4.567 +/- 0.089 secs
+2015-10-14 13:46:04.534916 (+0500) -0.000007 +/- 0.084075 localhost 127.0.0.1 s2 no-leap
 -----------------------------------------------------
 
-where the `(+0800)` means that to get to UTC from the reported local
-time one must add 8 hours and 0 minutes, the `4.567` indicates the
-local clock is 4.567 seconds behind the correct time (so 4.567 seconds
-must be added to the local clock to get it to be correct). Note that
+where the `(+0500)` means that to get to UTC from the reported local
+time one must add 5 hours and 0 minutes, the `-0.000007` indicates the
+local clock is 0.000007 seconds ahead of correct time (so 0.000007 seconds
+must be subtracted from the local clock to get it to be correct). Note that
 the number of decimals printed for this value will change based on the
-reported precision of the server.`+/- 0.089` is the reported
+reported precision of the server.`+/- 0.084075` is the reported
 _synchronization_ _distance_ (in seconds), which represents the
 maximum error due to all causes. If the server does not report valid
 data needed to calculate the synchronization distance, this will be
@@ -41,6 +41,21 @@ displayed. Otherwise, only the _IP_ is displayed. Finally, the
 _stratum_ of the host is reported and the leap indicator is decoded
 and displayed.
 
+With the -j (JSON) option, the output format becomes a self-describing
+JSON record:
+
+---------------------------------------------------------------------------------
+{"time":"2015-10-14T13:46:04.534916+0500",
+         "offset":-0.000007,"precision":"0.084075",
+	 "host":"localhost",ip:"127.0.0.1",
+	 "stratum":2,"leap":"noleap","adjusted":false}
+---------------------------------------------------------------------------------
+
+In the JSON format, time is in ISO8601 format; precision is the synch
+distance, with an unknown synch distance is reported as 0.  Host and
+IP are always emitted even if duplicate. The "adjusted" boolean
+reports whether ntpdig adusted the time.
+
 == OPTIONS ==
 
 //`-?, --help`::
@@ -112,6 +127,9 @@ milliseconds. A larger _delay_ reduces the query load on the time
 sources, iat the cost of ncreasing the time to receive a valid
 response if the first source attempted is slow or unreachable.
 
+`-j`::
+  Output to stdout in JSON, suppressing syslog messages.
+
 `-K` file-name, `--kod`=_file-name_::
   KoD history filename. The default _file-name_ for this option is:
   `/var/db/ntp-kod`.
diff --git a/ntpdig/kod_management.c b/ntpdig/kod_management.c
index 19536fd..d75c978 100644
--- a/ntpdig/kod_management.c
+++ b/ntpdig/kod_management.c
@@ -151,7 +151,7 @@ write_kod_db(void)
 	}
 
 	if (NULL == db_s) {
-		msyslog(LOG_WARNING, "Can't open KOD db file %s for writing: %m",
+		msyslog(LOG_WARNING, "Can't open KoD db file %s for writing: %m",
 			kod_db_file);
 
 		return false;
diff --git a/ntpdig/main.c b/ntpdig/main.c
index bc77f83..78440e0 100644
--- a/ntpdig/main.c
+++ b/ntpdig/main.c
@@ -121,7 +121,7 @@ int  gettimeofday_cached(struct event_base *b, struct timeval *tv);
 
 #define EXIT_SOFTWARE	70
 
-#define ALL_OPTIONS "46a:b:c:dD:g:K:k:l:M:o:rSst:VwW"
+#define ALL_OPTIONS "46a:b:c:dD:g:jK:k:l:M:o:rSst:VwW"
 static const struct option longoptions[] = {
     { "ipv4",		    0, 0, '4' },
     { "ipv6",		    0, 0, '6' },
@@ -132,6 +132,7 @@ static const struct option longoptions[] = {
     { "set-debug-level",    1, 0, 'D' },
     { "gap",                1, 0, 'g' },
     { "kod",                1, 0, 'K' },
+    { "json",               1, 0, 'j' },
     { "keyfile",            1, 0, 'k' },
     { "logfile",            1, 0, 'l' },
     { "steplimit",          1, 0, 'M' },
@@ -151,6 +152,7 @@ static char *opt_authkey = NULL;
 static char *opt_broadcast = NULL;
 static char *opt_concurrent = NULL;
 static int opt_gap;
+static bool opt_json;
 static char *opt_kodfile = "/var/db/ntp-kod";
 static char *opt_keyfile = NULL;
 static char *opt_logfile = NULL;
@@ -222,6 +224,10 @@ ntpdig_main (
 			exit(1);
 		}
 		break;
+	    case 'j':
+		opt_json = true;
+		syslogit = false;
+		break;
 	    case 'K':
 		opt_kodfile = ntp_optarg;
 		break;
@@ -284,7 +290,7 @@ ntpdig_main (
 	if (opt_logfile)
 		open_logfile(opt_logfile);
 
-	msyslog(LOG_INFO, "ntpdig %s", ntpdigVersion);
+	//msyslog(LOG_INFO, "ntpdig %s", ntpdigVersion);
 
 	if (0 == argc && !opt_broadcast && !opt_concurrent) {
 		printf("%s: Must supply at least one of -b hostname, -c hostname, or hostname.\n",
@@ -1007,7 +1013,7 @@ sock_cb(
 
 	/* If the packet is good, set the time and we're all done */
 	rc = handle_pkt(rpktl, &r_pkt, &spkt->addr, spkt->dctx->name);
-	if (0 != rc)
+	if (EXIT_SUCCESS != rc)
 		TRACE(1, ("sock_cb: handle_pkt() returned %d\n", rc));
 	check_exit_conditions();
 }
@@ -1311,7 +1317,7 @@ handle_pkt(
 		if (digits > 6)
 			digits = 6;
 
-		ts_str = tv_to_str(&tv_dst);
+		ts_str = tv_to_str(&tv_dst, opt_json);
 		stratum = rpkt->stratum;
 		if (0 == stratum)
 				stratum = 16;
@@ -1345,13 +1351,22 @@ handle_pkt(
 			break;
 		}
 
-		msyslog(LOG_INFO, "%s %+.*f%s %s s%d %s%s", ts_str,
-			digits, offset, disptxt,
-			hostnameaddr(hostname, host), stratum,
-			leaptxt,
-			(time_adjusted)
-			    ? " [excess]"
-			    : "");
+		if (opt_json) {
+		    printf("{\"time\"\"%s\",\"offset\":%f,\"precision\":%f,",
+		    	ts_str, offset, synch_distance);
+		    printf("\"host\":\"%s\",\"ip\":\"%s\",",
+			   hostname, stoa(host));
+		    printf("\"stratum\":%d,\"leap\":\"%s\",\"adjusted\":%s}\n",
+			   stratum,
+		    	   leaptxt,
+		    	   time_adjusted ? "true" : "false");
+		}
+		else
+		    msyslog(LOG_INFO, "%s %+.*f%s %s s%d %s%s", ts_str,
+			    digits, offset, disptxt,
+			    hostnameaddr(hostname, host), stratum,
+			    leaptxt,
+			    time_adjusted ? " [excess]" : "");
 		free(ts_str);
 
 		if (p_NTPDIG_PRETEND_TIME)
@@ -1363,7 +1378,7 @@ handle_pkt(
 		return EXIT_SUCCESS;
 	}
 
-	return 1;
+	return EXIT_FAILURE;
 }
 
 
diff --git a/ntpdig/utilities.c b/ntpdig/utilities.c
index 0f763fc..193b6f4 100644
--- a/ntpdig/utilities.c
+++ b/ntpdig/utilities.c
@@ -134,7 +134,8 @@ ss_to_str(
  */
 char *
 tv_to_str(
-	const struct timeval *tv
+	const struct timeval *tv,
+	const bool json
 	)
 {
 	const size_t bufsize = 48;
@@ -142,6 +143,8 @@ tv_to_str(
 	time_t gmt_time, local_time;
 	struct tm tmbuf, tmbuf2, *p_tm_local;
 	int hh, mm, lto;
+	const char *oldstyle = "%d-%.2d-%.2d %.2d:%.2d:%.2d.%.6d (%+03d%02d)";
+	const char *jsonstyle = "%d-%.2d-%.2dT%.2d:%.2d:%.2d.%.6d%+03d%02d";
 
 	/*
 	 * convert to struct tm in UTC, then intentionally feed
@@ -160,7 +163,7 @@ tv_to_str(
 
 	buf = emalloc(bufsize);
 	snprintf(buf, bufsize,
-		 "%d-%.2d-%.2d %.2d:%.2d:%.2d.%.6d (%+03d%02d)",
+		 json ? jsonstyle : oldstyle,
 		 p_tm_local->tm_year + 1900,
 		 p_tm_local->tm_mon + 1,
 		 p_tm_local->tm_mday,
diff --git a/ntpdig/utilities.h b/ntpdig/utilities.h
index bba6ffe..772f370 100644
--- a/ntpdig/utilities.h
+++ b/ntpdig/utilities.h
@@ -21,7 +21,7 @@ void l_fp_output_dec(l_fp *ts, FILE *output);
 
 char *addrinfo_to_str(const struct addrinfo *addr);
 char *ss_to_str(sockaddr_u *saddr);
-char *tv_to_str(const struct timeval *tv);
+char *tv_to_str(const struct timeval *tv, const bool json);
 const char * hostnameaddr(const char *, const sockaddr_u *);
 
 #endif	/* GUARD_UTILITIES_H */



More information about the vc mailing list