[PATCH v3 3/3] syslogd: Add a configurable option to log timestamps in ISO 8601 format

Grant Erickson <[email protected]>
Newsgroups gmane.linux.busybox
Message-ID <67440dc463e277a6d65ed1155e6cedfbcf15a1dc.1768850836.git.gerickson@nuovations.com>
This adds a configurable option 'FEATURE_SYSLOGD_ISO8601FMT' enabling
a command line option ('-I', with semantics similar to 'date') that
directs syslogd to log timestamps in ISO 8601 format.

Precision in seconds (the default), milliseconds, and microseconds are
supported. Without the 'FEATURE_SYSLOGD_UTC' configuration and its
'-u' option, outputs are of the form:

  YYYY-MM-DDThh:mm:ss±hhmm (seconds)
  YYYY-MM-DDThh:mm:ss.sss±hhmm (milliseconds)
  YYYY-MM-DDThh:mm:ss.uuuuuu±hhmm (microseconds)

with the 'FEATURE_SYSLOGD_UTC' configuration and its '-u' option,
outputs are of the form:

  YYYY-MM-DDThh:mm:ssZ (seconds)
  YYYY-MM-DDThh:mm:ss.sssZ (milliseconds)
  YYYY-MM-DDThh:mm:ss.uuuuuuZ (microseconds)
---
 sysklogd/syslogd.c | 155 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 117 insertions(+), 38 deletions(-)

diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index d9d7ac266b01..368e5f7a68de 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -44,6 +44,15 @@
 //config:	syslogd to log timestamps in Coordinated Universal Time
 //config:	(UTC) rather than in local time.
 //config:
+//config:config FEATURE_SYSLOGD_ISO8601FMT
+//config:	bool "Log timestamps in ISO 8601 format"
+//config:	default n
+//config:	depends on SYSLOGD
+//config:	help
+//config:	This enables a command line option ('-I') that directs
+//config:	syslogd to log timestamps in ISO 8601 format with second,
+//config:	millisecond, or microsecond resolution.
+//config:
 //config:config FEATURE_REMOTE_LOG
 //config:	bool "Remote Log support"
 //config:	default y
@@ -159,6 +168,10 @@
 //usage:	IF_FEATURE_SYSLOGD_UTC(
 //usage:     "\n	-u		Log timestamps in Coordinated Universal Time (UTC)"
 //usage:	)
+//usage:	IF_FEATURE_SYSLOGD_ISO8601FMT(
+//usage:     "\n	-I[SPEC]	Log timestamps in ISO 8601 format"
+//usage:     "\n			SPEC=seconds (default), ms, or us"
+//usage:	)
 //usage:     "\n	-t		Strip client-generated timestamps"
 //usage:	IF_FEATURE_SYSLOGD_DUP(
 //usage:     "\n	-D		Drop duplicates"
@@ -272,6 +285,9 @@ IF_FEATURE_SYSLOGD_CFG( \
 IF_FEATURE_KMSG_SYSLOG( \
 	int kmsgfd; \
 	int primask; \
+) \
+IF_FEATURE_SYSLOGD_ISO8601FMT( \
+	int iso8601fmt; \
 )
 
 struct init_globals {
@@ -298,7 +314,7 @@ struct globals {
 	/* ...then sprintf into printbuf, adding timestamp (15 or 19 chars),
 	 * host (64), fac.prio (20) to the message */
 	/* (growth by: 15 + 64 + 20 + delims = ~110) */
-	char printbuf[MAX_READ*2 + 128];
+	char printbuf[MAX_READ*2 + 144];
 };
 
 static const struct init_globals init_data = {
@@ -337,15 +353,16 @@ enum {
 	OPTBIT_loglevel, // -l
 	OPTBIT_small, // -S
 	OPTBIT_timestamp, // -t
-	IF_FEATURE_ROTATE_LOGFILE(OPTBIT_filesize   ,)	// -s
-	IF_FEATURE_ROTATE_LOGFILE(OPTBIT_rotatecnt  ,)	// -b
-	IF_FEATURE_REMOTE_LOG(    OPTBIT_remotelog  ,)	// -R
-	IF_FEATURE_REMOTE_LOG(    OPTBIT_locallog   ,)	// -L
-	IF_FEATURE_IPC_SYSLOG(    OPTBIT_circularlog,)	// -C
-	IF_FEATURE_SYSLOGD_DUP(   OPTBIT_dup        ,)	// -D
-	IF_FEATURE_SYSLOGD_CFG(   OPTBIT_cfg        ,)	// -f
-	IF_FEATURE_KMSG_SYSLOG(   OPTBIT_kmsg       ,)	// -K
-	IF_FEATURE_SYSLOGD_UTC(   OPTBIT_utc        ,)	// -u
+	IF_FEATURE_ROTATE_LOGFILE(    OPTBIT_filesize   ,)	// -s
+	IF_FEATURE_ROTATE_LOGFILE(    OPTBIT_rotatecnt  ,)	// -b
+	IF_FEATURE_REMOTE_LOG(        OPTBIT_remotelog  ,)	// -R
+	IF_FEATURE_REMOTE_LOG(        OPTBIT_locallog   ,)	// -L
+	IF_FEATURE_IPC_SYSLOG(        OPTBIT_circularlog,)	// -C
+	IF_FEATURE_SYSLOGD_DUP(       OPTBIT_dup        ,)	// -D
+	IF_FEATURE_SYSLOGD_CFG(       OPTBIT_cfg        ,)	// -f
+	IF_FEATURE_KMSG_SYSLOG(       OPTBIT_kmsg       ,)	// -K
+	IF_FEATURE_SYSLOGD_UTC(       OPTBIT_utc        ,)	// -u
+	IF_FEATURE_SYSLOGD_ISO8601FMT(OPTBIT_iso8601fmt ,)	// -I
 
 	OPT_mark        = 1 << OPTBIT_mark    ,
 	OPT_nofork      = 1 << OPTBIT_nofork  ,
@@ -353,38 +370,41 @@ enum {
 	OPT_loglevel    = 1 << OPTBIT_loglevel,
 	OPT_small       = 1 << OPTBIT_small   ,
 	OPT_timestamp   = 1 << OPTBIT_timestamp,
-	OPT_filesize    = IF_FEATURE_ROTATE_LOGFILE((1 << OPTBIT_filesize   )) + 0,
-	OPT_rotatecnt   = IF_FEATURE_ROTATE_LOGFILE((1 << OPTBIT_rotatecnt  )) + 0,
-	OPT_remotelog   = IF_FEATURE_REMOTE_LOG(    (1 << OPTBIT_remotelog  )) + 0,
-	OPT_locallog    = IF_FEATURE_REMOTE_LOG(    (1 << OPTBIT_locallog   )) + 0,
-	OPT_circularlog = IF_FEATURE_IPC_SYSLOG(    (1 << OPTBIT_circularlog)) + 0,
-	OPT_dup         = IF_FEATURE_SYSLOGD_DUP(   (1 << OPTBIT_dup        )) + 0,
-	OPT_cfg         = IF_FEATURE_SYSLOGD_CFG(   (1 << OPTBIT_cfg        )) + 0,
-	OPT_kmsg        = IF_FEATURE_KMSG_SYSLOG(   (1 << OPTBIT_kmsg       )) + 0,
+	OPT_filesize    = IF_FEATURE_ROTATE_LOGFILE(    (1 << OPTBIT_filesize   )) + 0,
+	OPT_rotatecnt   = IF_FEATURE_ROTATE_LOGFILE(    (1 << OPTBIT_rotatecnt  )) + 0,
+	OPT_remotelog   = IF_FEATURE_REMOTE_LOG(        (1 << OPTBIT_remotelog  )) + 0,
+	OPT_locallog    = IF_FEATURE_REMOTE_LOG(        (1 << OPTBIT_locallog   )) + 0,
+	OPT_circularlog = IF_FEATURE_IPC_SYSLOG(        (1 << OPTBIT_circularlog)) + 0,
+	OPT_dup         = IF_FEATURE_SYSLOGD_DUP(       (1 << OPTBIT_dup        )) + 0,
+	OPT_cfg         = IF_FEATURE_SYSLOGD_CFG(       (1 << OPTBIT_cfg        )) + 0,
+	OPT_kmsg        = IF_FEATURE_KMSG_SYSLOG(       (1 << OPTBIT_kmsg       )) + 0,
 	OPT_utc         = IF_FEATURE_SYSLOGD_UTC(   (1 << OPTBIT_utc        )) + 0,
+	OPT_iso8601fmt  = IF_FEATURE_SYSLOGD_ISO8601FMT((1 << OPTBIT_iso8601fmt )) + 0,
 };
 #define OPTION_STR "m:nO:l:St" \
-	IF_FEATURE_ROTATE_LOGFILE("s:" ) \
-	IF_FEATURE_ROTATE_LOGFILE("b:" ) \
-	IF_FEATURE_REMOTE_LOG(    "R:*") \
-	IF_FEATURE_REMOTE_LOG(    "L"  ) \
-	IF_FEATURE_IPC_SYSLOG(    "C::") \
-	IF_FEATURE_SYSLOGD_DUP(   "D"  ) \
-	IF_FEATURE_SYSLOGD_CFG(   "f:" ) \
-	IF_FEATURE_KMSG_SYSLOG(   "K"  ) \
-	IF_FEATURE_SYSLOGD_UTC(   "u"  )
+	IF_FEATURE_ROTATE_LOGFILE(    "s:" ) \
+	IF_FEATURE_ROTATE_LOGFILE(    "b:" ) \
+	IF_FEATURE_REMOTE_LOG(        "R:*") \
+	IF_FEATURE_REMOTE_LOG(        "L"  ) \
+	IF_FEATURE_IPC_SYSLOG(        "C::") \
+	IF_FEATURE_SYSLOGD_DUP(       "D"  ) \
+	IF_FEATURE_SYSLOGD_CFG(       "f:" ) \
+	IF_FEATURE_KMSG_SYSLOG(       "K"  ) \
+	IF_FEATURE_SYSLOGD_UTC(       "u"  ) \
+	IF_FEATURE_SYSLOGD_ISO8601FMT("I::")
 #define OPTION_DECL *opt_m, *opt_l \
-	IF_FEATURE_ROTATE_LOGFILE(,*opt_s) \
-	IF_FEATURE_ROTATE_LOGFILE(,*opt_b) \
-	IF_FEATURE_IPC_SYSLOG(    ,*opt_C = NULL) \
-	IF_FEATURE_SYSLOGD_CFG(   ,*opt_f = NULL)
+	IF_FEATURE_ROTATE_LOGFILE(    ,*opt_s) \
+	IF_FEATURE_ROTATE_LOGFILE(    ,*opt_b) \
+	IF_FEATURE_IPC_SYSLOG(        ,*opt_C = NULL) \
+	IF_FEATURE_SYSLOGD_CFG(       ,*opt_f = NULL) \
+	IF_FEATURE_SYSLOGD_ISO8601FMT(,*opt_I = NULL)
 #define OPTION_PARAM &opt_m, &(G.logFile.path), &opt_l \
-	IF_FEATURE_ROTATE_LOGFILE(,&opt_s) \
-	IF_FEATURE_ROTATE_LOGFILE(,&opt_b) \
-	IF_FEATURE_REMOTE_LOG(    ,&remoteAddrList) \
-	IF_FEATURE_IPC_SYSLOG(    ,&opt_C) \
-	IF_FEATURE_SYSLOGD_CFG(   ,&opt_f)
-
+	IF_FEATURE_ROTATE_LOGFILE(    ,&opt_s) \
+	IF_FEATURE_ROTATE_LOGFILE(    ,&opt_b) \
+	IF_FEATURE_REMOTE_LOG(        ,&remoteAddrList) \
+	IF_FEATURE_IPC_SYSLOG(        ,&opt_C) \
+	IF_FEATURE_SYSLOGD_CFG(       ,&opt_f) \
+	IF_FEATURE_SYSLOGD_ISO8601FMT(,&opt_I)
 
 #if ENABLE_FEATURE_SYSLOGD_CFG
 static const CODE* find_by_name(char *name, const CODE* c_set)
@@ -873,6 +893,21 @@ static struct tm * generate_time(struct timeval *tvp, struct tm *tmp)
 	return tm;
 }
 
+#if ENABLE_FEATURE_SYSLOGD_ISO8601FMT
+static void append_zone_string(char *timestamp, size_t max, const struct tm *tmp)
+{
+	if (timestamp && tmp) {
+#if ENABLE_FEATURE_SYSLOGD_UTC
+		if (option_mask32 & OPT_utc)
+	        snprintf(timestamp, max, "%c", 'Z');
+	    else
+	        strftime(timestamp, max, "%z", tmp);
+#else
+		strftime(timestamp, max, "%z", tmp);
+#endif
+	}
+}
+#endif
 
 /* len parameter is used only for "is there a timestamp?" check.
  * NB: some callers cheat and supply len==0 when they know
@@ -887,11 +922,15 @@ static void timestamp_and_log(int pri, char *msg, int len)
 		msg[15] == ' ');
 	const char *format="%h %e %T";
 	char *timestamp = NULL;
-	char timestampbuf[20];
+	char timestampbuf[32];
 	/* MMM DD hh:mm:ss default */
 	/* 0123456789012345                 - 16 */
 	/* MMM DD hh:mm:ss.mmm ENABLE_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS */
 	/* 01234567890123456789             - 20 */
+	/* YYYY-MM-DDThh:mm:ss.uuuuuuZ OPT_utc & OPT_iso8601fmt */
+	/* 0123456789012345678901234567     - 28 */
+	/* YYYY-MM-DDThh:mm:ss.uuuuuu+hhmm OPT_iso8601fmt */
+	/* 01234567890123456789012345678901 - 32 */
 	struct timeval tvnow;
 #if ENABLE_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS || ENABLE_FEATURE_SYSLOGD_UTC
 	struct tm parsed;
@@ -941,6 +980,33 @@ static void timestamp_and_log(int pri, char *msg, int len)
 		tmp = generate_time(&tvnow, &tmnow);
 	}
 
+#if ENABLE_FEATURE_SYSLOGD_ISO8601FMT
+	if (tmp && !timestamp && G.iso8601fmt >= 0) {
+	    format = "%FT%T";
+		/* -I[SPEC]: 0:seconds 1:ms 2:us */
+		n = strftime(timestampbuf + n, sizeof(timestampbuf) - n, format, tmp);
+
+	    if (G.iso8601fmt == 1 || G.iso8601fmt == 2) {
+	        const char *iso8601fracfmt;
+	        unsigned long divisor;
+
+	        if (G.iso8601fmt == 1) {
+	            iso8601fracfmt = ".%03lu";
+	            divisor = 1000u;
+	        } else {
+	            iso8601fracfmt = ".%06lu";
+	            divisor = 1u;
+	        }
+
+			n += snprintf(timestampbuf + n, sizeof(timestampbuf) - n, iso8601fracfmt, tvnow.tv_usec / divisor);
+		}
+
+		append_zone_string(timestampbuf + n, sizeof(timestampbuf) - n, tmp);
+
+		timestamp = timestampbuf;
+	}
+#endif /* ENABLE_FEATURE_SYSLOGD_ISO8601FMT */
+
 #if ENABLE_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS
 	if (tmp && !timestamp) {
 		n = strftime(timestampbuf + n, sizeof(timestampbuf) - n, format, tmp);
@@ -1138,6 +1204,19 @@ static int NOINLINE syslogd_init(char **argv)
 #if ENABLE_FEATURE_IPC_SYSLOG
 	if (opt_C) // -Cn
 		G.shm_size = xatoul_range(opt_C, 4, INT_MAX/1024) * 1024;
+#endif
+#if ENABLE_FEATURE_SYSLOGD_ISO8601FMT
+	G.iso8601fmt = -1;
+	if (opts & OPT_iso8601fmt) {
+		G.iso8601fmt = 0; /* default is seconds */
+		if (opt_I) {
+			static const char iso8601fmts[] ALIGN1 =
+				"seconds\0""ms\0""us\0";
+			G.iso8601fmt = index_in_substrings(iso8601fmts, opt_I);
+			if (G.iso8601fmt < 0)
+				bb_show_usage();
+		}
+	}
 #endif
 	/* If they have not specified remote logging, then log locally */
 	if (ENABLE_FEATURE_REMOTE_LOG && !(opts & OPT_remotelog)) // -R
-- 
2.45.0

_______________________________________________
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.