From 1a234323a3912fda3c1d90743d903beb737df862 Mon Sep 17 00:00:00 2001 From: Roger Light Date: Tue, 12 Mar 2019 23:28:54 +0000 Subject: [PATCH] Add support for custom log timestamps. Closes #1121. --- man/mosquitto.conf.5.xml | 15 ++++++++ mosquitto.conf | 7 ++++ src/conf.c | 7 ++++ src/logging.c | 63 +++++++++++++++++++++++++++++++-- src/mosquitto_broker_internal.h | 1 + 5 files changed, 90 insertions(+), 3 deletions(-) diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index b4e9ca56..df1a3638 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -407,6 +407,21 @@ Reloaded on reload signal. + + format + + Set the format of the log timestamp. If left unset, + this is the number of seconds since the Unix epoch. + This option is a free text string which will be passed + to the strftime function as the format specifier. To + get an ISO 8601 datetime, for example: + +log_timestamp_format %Y-%m-%dT%H:%M:%S + + Reloaded on reload signal. + + + types diff --git a/mosquitto.conf b/mosquitto.conf index c625a46f..3bab72c7 100644 --- a/mosquitto.conf +++ b/mosquitto.conf @@ -610,6 +610,13 @@ # If set to true, add a timestamp value to each log message. #log_timestamp true +# Set the format of the log timestamp. If left unset, this is the number of +# seconds since the Unix epoch. +# This is a free text string which will be passed to the strftime function. To +# get an ISO 8601 datetime, for example: +# log_timestamp_format %Y-%m-%dT%H:%M:%S +#log_timestamp_format + # ================================================================= # Security # ================================================================= diff --git a/src/conf.c b/src/conf.c index 4d65a08b..5251e1f3 100644 --- a/src/conf.c +++ b/src/conf.c @@ -213,6 +213,8 @@ static void config__init_reload(struct mosquitto_db *db, struct mosquitto__confi } #endif config->log_timestamp = true; + mosquitto__free(config->log_timestamp_format); + config->log_timestamp_format = NULL; config->max_keepalive = 65535; config->max_packet_size = 0; config->max_inflight_messages = 20; @@ -571,6 +573,9 @@ void config__copy(struct mosquitto__config *src, struct mosquitto__config *dest) dest->log_type = src->log_type; dest->log_timestamp = src->log_timestamp; + mosquitto__free(dest->log_timestamp_format); + dest->log_timestamp_format = src->log_timestamp_format; + mosquitto__free(dest->log_file); dest->log_file = src->log_file; @@ -1460,6 +1465,8 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct #endif }else if(!strcmp(token, "log_timestamp")){ if(conf__parse_bool(&token, token, &config->log_timestamp, saveptr)) return MOSQ_ERR_INVAL; + }else if(!strcmp(token, "log_timestamp_format")){ + if(conf__parse_string(&token, token, &config->log_timestamp_format, saveptr)) return MOSQ_ERR_INVAL; }else if(!strcmp(token, "log_type")){ token = strtok_r(NULL, " ", &saveptr); if(token){ diff --git a/src/logging.c b/src/logging.c index 0a09d6d4..3803d76d 100644 --- a/src/logging.c +++ b/src/logging.c @@ -56,6 +56,43 @@ static int log_priorities = MOSQ_LOG_ERR | MOSQ_LOG_WARNING | MOSQ_LOG_NOTICE | static DltContext dltContext; #endif +static int get_time(struct tm **ti) +{ +#ifdef WIN32 + SYSTEMTIME st; +#elif defined(__APPLE__) + struct timeval tv; +#else + struct timespec ts; +#endif + time_t s; + +#ifdef WIN32 + s = time(NULL); + + GetLocalTime(&st); + *ns = st.wMilliseconds*1000000L; +#elif defined(__APPLE__) + gettimeofday(&tv, NULL); + s = tv.tv_sec; +#else + if(clock_gettime(CLOCK_REALTIME, &ts) != 0){ + fprintf(stderr, "Error obtaining system time.\n"); + return 1; + } + s = ts.tv_sec; +#endif + + *ti = localtime(&s); + if(!(*ti)){ + fprintf(stderr, "Error obtaining system time.\n"); + return 1; + } + + return 0; +} + + int log__init(struct mosquitto__config *config) { int rc = 0; @@ -149,6 +186,7 @@ int log__vprintf(int priority, const char *fmt, va_list va) int syslog_priority; time_t now = time(NULL); static time_t last_flush = 0; + char time_buf[50]; if((log_priorities & priority) && log_destinations != MQTT3_LOG_NONE){ switch(priority){ @@ -233,9 +271,20 @@ int log__vprintf(int priority, const char *fmt, va_list va) vsnprintf(s, len, fmt, va); s[len-1] = '\0'; /* Ensure string is null terminated. */ + if(int_db.config && int_db.config->log_timestamp && int_db.config->log_timestamp_format){ + struct tm *ti = NULL; + get_time(&ti); + if(strftime(time_buf, 50, int_db.config->log_timestamp_format, ti) == 0){ + snprintf(time_buf, 50, "Time error"); + } + } if(log_destinations & MQTT3_LOG_STDOUT){ if(int_db.config && int_db.config->log_timestamp){ - fprintf(stdout, "%d: %s\n", (int)now, s); + if(int_db.config->log_timestamp_format){ + fprintf(stdout, "%s: %s\n", time_buf, s); + }else{ + fprintf(stdout, "%d: %s\n", (int)now, s); + } }else{ fprintf(stdout, "%s\n", s); } @@ -243,7 +292,11 @@ int log__vprintf(int priority, const char *fmt, va_list va) } if(log_destinations & MQTT3_LOG_STDERR){ if(int_db.config && int_db.config->log_timestamp){ - fprintf(stderr, "%d: %s\n", (int)now, s); + if(int_db.config->log_timestamp_format){ + fprintf(stderr, "%s: %s\n", time_buf, s); + }else{ + fprintf(stderr, "%d: %s\n", (int)now, s); + } }else{ fprintf(stderr, "%s\n", s); } @@ -251,7 +304,11 @@ int log__vprintf(int priority, const char *fmt, va_list va) } if(log_destinations & MQTT3_LOG_FILE && int_db.config->log_fptr){ if(int_db.config && int_db.config->log_timestamp){ - fprintf(int_db.config->log_fptr, "%d: %s\n", (int)now, s); + if(int_db.config->log_timestamp_format){ + fprintf(int_db.config->log_fptr, "%s: %s\n", time_buf, s); + }else{ + fprintf(int_db.config->log_fptr, "%d: %s\n", (int)now, s); + } }else{ fprintf(int_db.config->log_fptr, "%s\n", s); } diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 5055fe66..7e7fea98 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -255,6 +255,7 @@ struct mosquitto__config { int log_facility; int log_type; bool log_timestamp; + char *log_timestamp_format; char *log_file; FILE *log_fptr; uint16_t max_inflight_messages;