[PATCH v3 3/3] syslogd: Add a configurable option to log timestamps in ISO 8601 format
Grant Erickson
gerickson at nuovations.com
Fri Apr 4 16:58:11 UTC 2025
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)
Signed-off-by: Grant Erickson <gerickson at nuovations.com>
---
sysklogd/syslogd.c | 157 ++++++++++++++++++++++++++++++++++-----------
1 file changed, 118 insertions(+), 39 deletions(-)
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index 0894693c4580..e9404eaf003f 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_utc = IF_FEATURE_SYSLOGD_UTC( (1 << OPTBIT_utc )) + 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
More information about the busybox
mailing list