Greetings,
I have a need to have rsyslog log TAI timestamps. For reference:
http://cr.yp.to/libtai/tai64.html
I have created a patch that appears to basically work.
Here's the rsyslog.conf to enable what I'm after:
$template tai,"%timegenerated:1:25:date-tai% <%syslogfacility%>%timegenerated% %msg%\n"
*.info;mail.none;authpriv.none;cron.none -/var/log/messages;tai
As a test, I perform some log activity with my tai template in action along with rfc3339, and compare the two templates. Note the use of *tai64nlocal* from D. Bernstein's daemontools package to validate the output. [url]http://cr.yp.to/daemontools/tai64nlocal.html[/url]
$template taiplus,"%timegenerated:1:25:date-tai% %timegenerated:1:25:date-rfc3339%%msg%\n"
*.info;mail.none;authpriv.none;cron.none -/var/log/messages;taiplus
[root@host ~] while true; do date | logger && tail -1 /var/log/messages | tai64nlocal ; sleep 1; done
2009-08-29 15:03:55.805317000 2009-08-29T15:03:55.80531 Sat Aug 29 15:03:55 CDT 2009
2009-08-29 15:03:56.819275000 2009-08-29T15:03:56.81927 Sat Aug 29 15:03:56 CDT 2009
2009-08-29 15:03:57.834073000 2009-08-29T15:03:57.83407 Sat Aug 29 15:03:57 CDT 2009
So, it appears that my TAI timestamp matches the RFC3339 timestamp.
Here's the patch. Feedback and/or review would be great. The tai.h and taia.h header files are in libtai, which I've compiled and installed in /usr/include/libtai/. [url]http://cr.yp.to/libtai.html[/url].
diff -ruN rsyslog-4.2.0.orig/runtime/datetime.c rsyslog-4.2.0/runtime/datetime.c
--- rsyslog-4.2.0.orig/runtime/datetime.c 2009-06-22 12:11:10.000000000 -0500
+++ rsyslog-4.2.0/runtime/datetime.c 2009-08-29 18:54:18.000000000 -0500
@@ -45,6 +45,12 @@
#include "stringbuf.h"
#include "errmsg.h"
+#include
+#include
+
+#define tai_unix(t,u) ((void) ((t)->x = 4611686018427387914ULL + (uint64) (u)))
+#define TIMESTAMP 25
+
/* static data */
DEFobjStaticHelpers
DEFobjCurrIf(errmsg)
@@ -670,6 +676,79 @@
}
/**
+ * Format a syslogTimestamp to TAI timestamp string.
+ */
+int formatTimestampTAI(struct syslogTime *ts, char* pBuf, size_t iLenBuf)
+{
+ int iRet = 0;
+ int i;
+ long offset;
+
+ struct taia taiatime;
+ struct tai taitime;
+ struct tm logtm = {0};
+ struct timeval logtimeval = {0};
+ time_t logtimet = 0;
+
+ char taiapack[TAIA_PACK];
+ char s[TIMESTAMP];
+
+ static char hex[16] = "0123456789abcdef";
+
+ assert(ts != NULL);
+ assert(pBuf != NULL);
+
+ if(iLenBuf < 25)
+ return(0); // we NEED at least 25 bytes
+
+ logtm.tm_year = ts->year - 1900;
+ logtm.tm_mon = ts->month - 1;
+ logtm.tm_mday = ts->day;
+ logtm.tm_hour = ts->hour;
+ logtm.tm_min = ts->minute;
+ logtm.tm_sec = ts->second;
+ logtm.tm_wday = 0;
+ logtm.tm_yday = 0;
+ logtm.tm_isdst = -1;
+ // adjust for 24 hour clock
+ if (logtm.tm_hour == 24)
+ {
+ logtm.tm_hour = 0;
+ }
+
+ offset = (int)ts->OffsetHour;
+ if (ts->OffsetMode == '+') offset *= -1;
+ logtm.tm_hour += offset;
+
+ offset = ts->OffsetMinute;
+ if (ts->OffsetMode == '+') offset *= -1;
+ logtm.tm_min += offset;
+
+ logtimet = mktime(&logtm);
+
+ logtimeval.tv_sec = logtimet;
+ tai_unix(&taiatime.sec,logtimeval.tv_sec);
+ taiatime.nano = 0;
+ taiatime.atto = 0;
+
+ if(ts->secfracPrecision > 0)
+ {
+ taiatime.nano = 1000*ts->secfrac;
+ }
+
+ // taiapack is string
+ taia_pack(taiapack,&taiatime);
+
+ s[0] = '@';
+ for (i = 0;i < 12;++i) {
+ s[i * 2 + 1] = hex[(taiapack[i] >> 4) & 15];
+ s[i * 2 + 2] = hex[taiapack[i] & 15];
+ }
+ iRet = snprintf(pBuf, iLenBuf, "%25.25s", s);
+ return(iRet);
+}
+
+/**
* Format a syslogTimestamp to a RFC3164 timestamp sring.
* The caller must provide the timestamp as well as a character
* buffer that will receive the resulting string. The function
@@ -738,6 +817,7 @@
pIf->formatTimestampSecFrac = formatTimestampSecFrac;
pIf->formatTimestamp3339 = formatTimestamp3339;
pIf->formatTimestamp3164 = formatTimestamp3164;
+ pIf->formatTimestampTAI = formatTimestampTAI;
finalize_it:
ENDobjQueryInterface(datetime)
diff -ruN rsyslog-4.2.0.orig/runtime/datetime.h rsyslog-4.2.0/runtime/datetime.h
--- rsyslog-4.2.0.orig/runtime/datetime.h 2009-06-22 12:11:10.000000000 -0500
+++ rsyslog-4.2.0/runtime/datetime.h 2009-08-29 18:39:23.000000000 -0500
@@ -43,6 +43,7 @@
int (*formatTimestamp3339)(struct syslogTime *ts, char* pBuf, size_t iLenBuf);
int (*formatTimestamp3164)(struct syslogTime *ts, char* pBuf, size_t iLenBuf);
int (*formatTimestampSecFrac)(struct syslogTime *ts, char* pBuf, size_t iLenBuf);
+ int (*formatTimestampTAI)(struct syslogTime *ts, char* pBuf, size_t iLenBuf);
ENDinterface(datetime)
#define datetimeCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */
/* interface changes:
diff -ruN rsyslog-4.2.0.orig/runtime/Makefile.in rsyslog-4.2.0/runtime/Makefile.in
--- rsyslog-4.2.0.orig/runtime/Makefile.in 2009-06-22 12:25:05.000000000 -0500
+++ rsyslog-4.2.0/runtime/Makefile.in 2009-08-29 18:39:23.000000000 -0500
@@ -222,7 +222,7 @@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-LDFLAGS = @LDFLAGS@
+LDFLAGS = @LDFLAGS@ -ltai
LIBDBI_CFLAGS = @LIBDBI_CFLAGS@
LIBDBI_LIBS = @LIBDBI_LIBS@
LIBLOGGING_CFLAGS = @LIBLOGGING_CFLAGS@
diff -ruN rsyslog-4.2.0.orig/runtime/msg.c rsyslog-4.2.0/runtime/msg.c
--- rsyslog-4.2.0.orig/runtime/msg.c 2009-06-22 12:11:10.000000000 -0500
+++ rsyslog-4.2.0/runtime/msg.c 2009-08-29 18:39:23.000000000 -0500
@@ -369,6 +369,8 @@
free(pThis->pszRcvdAt3164);
if(pThis->pszRcvdAt3339 != NULL)
free(pThis->pszRcvdAt3339);
+ if(pThis->pszRcvdAtTAI != NULL)
+ free(pThis->pszRcvdAtTAI);
if(pThis->pszRcvdAt_SecFrac != NULL)
free(pThis->pszRcvdAt_SecFrac);
if(pThis->pszRcvdAt_MySQL != NULL)
@@ -379,6 +381,8 @@
free(pThis->pszTIMESTAMP3164);
if(pThis->pszTIMESTAMP3339 != NULL)
free(pThis->pszTIMESTAMP3339);
+ if(pThis->pszTIMESTAMPTAI != NULL)
+ free(pThis->pszTIMESTAMPTAI);
if(pThis->pszTIMESTAMP_SecFrac != NULL)
free(pThis->pszTIMESTAMP_SecFrac);
if(pThis->pszTIMESTAMP_MySQL != NULL)
@@ -844,6 +848,16 @@
}
MsgUnlock(pM);
return(pM->pszTIMESTAMP3339);
+ case tplFmtTAIDate:
+ MsgLock(pM);
+ if(pM->pszTIMESTAMPTAI == NULL) {
+ if((pM->pszTIMESTAMPTAI= malloc(26)) == NULL) {
+ MsgUnlock(pM);
+ return ""; /* TODO: check this: can it cause a free() of constant memory?) */
+ }
+ datetime.formatTimestampTAI(&pM->tTIMESTAMP, pM->pszTIMESTAMPTAI, 26);
+ }
+ MsgUnlock(pM);
case tplFmtSecFrac:
MsgLock(pM);
if(pM->pszTIMESTAMP_SecFrac == NULL) {
@@ -922,6 +936,17 @@
}
MsgUnlock(pM);
return(pM->pszRcvdAt3339);
+ case tplFmtTAIDate:
+ MsgLock(pM);
+ if(pM->pszRcvdAtTAI == NULL) {
+ if((pM->pszRcvdAtTAI = malloc(26)) == NULL) {
+ MsgUnlock(pM);
+ return "";
+ }
+ datetime.formatTimestampTAI(&pM->tRcvdAt, pM->pszRcvdAtTAI, 26);
+ }
+ MsgUnlock(pM);
+ return(pM->pszRcvdAtTAI);
case tplFmtSecFrac:
MsgLock(pM);
if(pM->pszRcvdAt_SecFrac == NULL) {
diff -ruN rsyslog-4.2.0.orig/runtime/msg.h rsyslog-4.2.0/runtime/msg.h
--- rsyslog-4.2.0.orig/runtime/msg.h 2009-06-22 12:11:10.000000000 -0500
+++ rsyslog-4.2.0/runtime/msg.h 2009-08-29 18:39:23.000000000 -0500
@@ -110,12 +110,14 @@
struct syslogTime tRcvdAt;/* time the message entered this program */
char *pszRcvdAt3164; /* time as RFC3164 formatted string (always 15 charcters) */
char *pszRcvdAt3339; /* time as RFC3164 formatted string (32 charcters at most) */
+ char *pszRcvdAtTAI; /* time as TAI formatted string (25 charcters at most) */
char *pszRcvdAt_SecFrac;/* time just as fractional seconds (6 charcters) */
char *pszRcvdAt_MySQL; /* rcvdAt as MySQL formatted string (always 14 charcters) */
char *pszRcvdAt_PgSQL; /* rcvdAt as PgSQL formatted string (always 21 characters) */
struct syslogTime tTIMESTAMP;/* (parsed) value of the timestamp */
char *pszTIMESTAMP3164; /* TIMESTAMP as RFC3164 formatted string (always 15 charcters) */
char *pszTIMESTAMP3339; /* TIMESTAMP as RFC3339 formatted string (32 charcters at most) */
+ char *pszTIMESTAMPTAI; /* TIMESTAMP as TAI formatted string (25 charcters at most) */
char *pszTIMESTAMP_MySQL;/* TIMESTAMP as MySQL formatted string (always 14 charcters) */
char *pszTIMESTAMP_PgSQL;/* TIMESTAMP as PgSQL formatted string (always 21 characters) */
char *pszTIMESTAMP_SecFrac;/* TIMESTAMP fractional seconds (always 6 characters) */
diff -ruN rsyslog-4.2.0.orig/template.c rsyslog-4.2.0/template.c
--- rsyslog-4.2.0.orig/template.c 2009-06-22 12:11:10.000000000 -0500
+++ rsyslog-4.2.0/template.c 2009-08-29 18:39:23.000000000 -0500
@@ -496,6 +496,8 @@
pTpe->data.field.eDateFormat = tplFmtRFC3164Date;
} else if(!strcmp((char*)Buf, "date-rfc3339")) {
pTpe->data.field.eDateFormat = tplFmtRFC3339Date;
+ } else if(!strcmp((char*)Buf, "date-tai")) {
+ pTpe->data.field.eDateFormat = tplFmtTAIDate;
} else if(!strcmp((char*)Buf, "date-subseconds")) {
pTpe->data.field.eDateFormat = tplFmtSecFrac;
} else if(!strcmp((char*)Buf, "lowercase")) {
@@ -1132,6 +1134,9 @@
case tplFmtRFC3339Date:
dbgprintf("[Format as RFC3339-Date] ");
break;
+ case tplFmtTAIDate:
+ dbgprintf("[Format as TAI-Date] ");
+ break;
default:
dbgprintf("[INVALID eDateFormat %d] ", pTpe->data.field.eDateFormat);
}
diff -ruN rsyslog-4.2.0.orig/template.h rsyslog-4.2.0/template.h
--- rsyslog-4.2.0.orig/template.h 2009-06-22 12:11:10.000000000 -0500
+++ rsyslog-4.2.0/template.h 2009-08-29 18:39:23.000000000 -0500
@@ -48,7 +48,7 @@
enum EntryTypes { UNDEFINED = 0, CONSTANT = 1, FIELD = 2 };
enum tplFormatTypes { tplFmtDefault = 0, tplFmtMySQLDate = 1,
tplFmtRFC3164Date = 2, tplFmtRFC3339Date = 3, tplFmtPgSQLDate = 4,
- tplFmtSecFrac = 5};
+ tplFmtSecFrac = 5, tplFmtTAIDate = 6};
enum tplFormatCaseConvTypes { tplCaseConvNo = 0, tplCaseConvUpper = 1, tplCaseConvLower = 2 };
#include "msg.h"