summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2013-11-30 13:45:41 -0800
committerKaz Kylheku <kaz@kylheku.com>2013-11-30 13:45:41 -0800
commit95a207ac94980b02ef3ea5d58e697089955ff9b5 (patch)
tree6cae416db70ad7e9467a65227506786a00994085
parent9859818eccb27a330537258d9149c7c5f32292f6 (diff)
downloadrsyslog-95a207ac94980b02ef3ea5d58e697089955ff9b5.tar.gz
rsyslog-95a207ac94980b02ef3ea5d58e697089955ff9b5.tar.bz2
rsyslog-95a207ac94980b02ef3ea5d58e697089955ff9b5.zip
New feature: date-strftime().HEADv3-stable-kaz
-rw-r--r--runtime/datetime.c36
-rw-r--r--runtime/msg.c50
-rw-r--r--runtime/msg.h6
-rw-r--r--runtime/syslogd-types.h1
-rw-r--r--template.c48
-rw-r--r--template.h3
6 files changed, 130 insertions, 14 deletions
diff --git a/runtime/datetime.c b/runtime/datetime.c
index bed33127..b795fc5d 100644
--- a/runtime/datetime.c
+++ b/runtime/datetime.c
@@ -83,6 +83,9 @@ static void getCurrTime(struct syslogTime *t)
# else
gettimeofday(&tp, NULL);
# endif
+
+ t->epoch = tp.tv_sec;
+
tm = localtime_r((time_t*) &(tp.tv_sec), &tmBuf);
t->year = tm->tm_year + 1900;
@@ -157,6 +160,35 @@ static int srSLMGParseInt32(char** ppsz)
}
+static void
+ComputeEpoch(struct syslogTime *pTime)
+{
+ struct tm utc;
+ long offset = pTime->OffsetHour * 3600 + pTime->OffsetMinute * 60;
+ time_t epoch;
+
+ utc.tm_year = pTime->year - 1900;
+ utc.tm_mon = pTime->month - 1;
+ utc.tm_mday = pTime->day;
+ utc.tm_hour = pTime->hour;
+ utc.tm_min = pTime->minute;
+ utc.tm_sec = pTime->second;
+ utc.tm_isdst = 0;
+
+ epoch = timegm(&utc);
+
+ switch (pTime->OffsetMode) {
+ case '-':
+ epoch += offset;
+ break;
+ case '+':
+ epoch -= offset;
+ break;
+ }
+
+ pTime->epoch = epoch;
+}
+
/**
* Parse a TIMESTAMP-3339.
* updates the parse pointer position. The pTime parameter
@@ -280,6 +312,8 @@ ParseTIMESTAMP3339(struct syslogTime *pTime, char** ppszTS)
pTime->OffsetHour = OffsetHour;
pTime->OffsetMinute = OffsetMinute;
+ ComputeEpoch(pTime);
+
finalize_it:
RETiRet;
}
@@ -501,6 +535,8 @@ ParseTIMESTAMP3164(struct syslogTime *pTime, char** ppszTS)
pTime->secfracPrecision = 0;
pTime->secfrac = 0;
+ ComputeEpoch(pTime);
+
finalize_it:
RETiRet;
}
diff --git a/runtime/msg.c b/runtime/msg.c
index 22303adb..8e19d98f 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -735,7 +735,7 @@ int getPRIi(msg_t *pM)
}
-char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt)
+char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt, const char *sfmt)
{
if(pM == NULL)
return "";
@@ -807,11 +807,31 @@ char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt)
}
MsgUnlock(pM);
return(pM->pszTIMESTAMP_SecFrac);
+ case tplFmtStrftime:
+ MsgLock(pM);
+ if(pM->pszTIMESTAMP_Strftime == NULL) {
+ char *str, *rstr;
+ size_t actual;
+ struct tm local;
+ if((str = malloc(256)) == NULL) {
+ MsgUnlock(pM);
+ return ""; /* TODO: check this: can it cause a free() of constant memory?) */
+ }
+ localtime_r(&pM->tTIMESTAMP.epoch, &local);
+ actual = strftime(str, 256, sfmt, &local);
+ rstr = realloc(str, actual + 1);
+ if (rstr)
+ str = rstr;
+ pM->pszTIMESTAMP_Strftime = str;
+
+ }
+ MsgUnlock(pM);
+ return(pM->pszTIMESTAMP_Strftime);
}
return "INVALID eFmt OPTION!";
}
-char *getTimeGenerated(msg_t *pM, enum tplFormatTypes eFmt)
+char *getTimeGenerated(msg_t *pM, enum tplFormatTypes eFmt, const char *sfmt)
{
if(pM == NULL)
return "";
@@ -883,6 +903,26 @@ char *getTimeGenerated(msg_t *pM, enum tplFormatTypes eFmt)
}
MsgUnlock(pM);
return(pM->pszRcvdAt_SecFrac);
+ case tplFmtStrftime:
+ MsgLock(pM);
+ if(pM->pszRcvdAt_Strftime == NULL) {
+ char *str, *rstr;
+ size_t actual;
+ struct tm local;
+ if((str = malloc(256)) == NULL) {
+ MsgUnlock(pM);
+ return ""; /* TODO: check this: can it cause a free() of constant memory?) */
+ }
+ localtime_r(&pM->tRcvdAt.epoch, &local);
+ actual = strftime(str, 256, sfmt, &local);
+ rstr = realloc(str, actual + 1);
+ if (rstr)
+ str = rstr;
+ pM->pszRcvdAt_Strftime = str;
+
+ }
+ MsgUnlock(pM);
+ return(pM->pszRcvdAt_Strftime);
}
return "INVALID eFmt OPTION!";
}
@@ -1768,10 +1808,12 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
} else if(!strcmp((char*) pName, "syslogseverity-text") || !strcmp((char*) pName, "syslogpriority-text")) {
pRes = getSeverityStr(pMsg);
} else if(!strcmp((char*) pName, "timegenerated")) {
- pRes = getTimeGenerated(pMsg, pTpe->data.field.eDateFormat);
+ pRes = getTimeGenerated(pMsg, pTpe->data.field.eDateFormat,
+ pTpe->data.field.strftime_fmt);
} else if(!strcmp((char*) pName, "timereported")
|| !strcmp((char*) pName, "timestamp")) {
- pRes = getTimeReported(pMsg, pTpe->data.field.eDateFormat);
+ pRes = getTimeReported(pMsg, pTpe->data.field.eDateFormat,
+ pTpe->data.field.strftime_fmt);
} else if(!strcmp((char*) pName, "programname")) {
pRes = getProgramName(pMsg);
} else if(!strcmp((char*) pName, "protocol-version")) {
diff --git a/runtime/msg.h b/runtime/msg.h
index 1bad9c66..9d4753a8 100644
--- a/runtime/msg.h
+++ b/runtime/msg.h
@@ -104,6 +104,7 @@ short bDoLock; /* use the mutex? */
char *pszRcvdAt3164; /* time as RFC3164 formatted string (always 15 charcters) */
char *pszRcvdAt3339; /* time as RFC3164 formatted string (32 charcters at most) */
char *pszRcvdAt_SecFrac;/* time just as fractional seconds (6 charcters) */
+ char *pszRcvdAt_Strftime;/* time as user-defined arbitrary format */
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 */
@@ -112,6 +113,7 @@ short bDoLock; /* use the mutex? */
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) */
+ char *pszTIMESTAMP_Strftime;/* TIMESTAMP arbitrary format */
int msgFlags; /* flags associated with this message */
};
@@ -132,8 +134,8 @@ char *getUxTradMsg(msg_t *pM);
char *getMSG(msg_t *pM);
char *getPRI(msg_t *pM);
int getPRIi(msg_t *pM);
-char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt);
-char *getTimeGenerated(msg_t *pM, enum tplFormatTypes eFmt);
+char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt, const char *sfmt);
+char *getTimeGenerated(msg_t *pM, enum tplFormatTypes eFmt, const char *sfmt);
char *getSeverity(msg_t *pM);
char *getSeverityStr(msg_t *pM);
char *getFacility(msg_t *pM);
diff --git a/runtime/syslogd-types.h b/runtime/syslogd-types.h
index be0dfdd8..b871d378 100644
--- a/runtime/syslogd-types.h
+++ b/runtime/syslogd-types.h
@@ -95,6 +95,7 @@ struct syslogTime {
/* full UTC offset minutes = OffsetHours*60 + OffsetMinute. Then use
* OffsetMode to know the direction.
*/
+ time_t epoch; /* The original epoch */
};
typedef struct syslogTime syslogTime_t;
diff --git a/template.c b/template.c
index 6fb7ba2b..6736df80 100644
--- a/template.c
+++ b/template.c
@@ -407,6 +407,7 @@ static void doOptions(unsigned char **pp, struct templateEntry *pTpe)
register unsigned char *p;
unsigned char Buf[64];
size_t i;
+ size_t parenlevel = 0;
assert(pp != NULL);
assert(*pp != NULL);
@@ -414,14 +415,29 @@ static void doOptions(unsigned char **pp, struct templateEntry *pTpe)
p = *pp;
- while(*p && *p != '%') {
+ while(*p && (parenlevel > 0 || *p != '%')) {
/* outer loop - until end of options */
i = 0;
while((i < sizeof(Buf) / sizeof(char)) &&
- *p && *p != '%' && *p != ',') {
+ *p && (parenlevel > 0 || *p != '%') && *p != ',')
+ {
+ char ch = *p++;
/* inner loop - until end of ONE option */
- Buf[i++] = tolower((int)*p);
- ++p;
+
+ switch (ch) {
+ case '(':
+ parenlevel++;
+ break;
+ case ')':
+ parenlevel--;
+ break;
+ default:
+ if (parenlevel == 0)
+ ch = tolower(ch);
+ break;
+ }
+
+ Buf[i++] = ch;
}
Buf[i] = '\0'; /* terminate */
/* check if we need to skip oversize option */
@@ -442,6 +458,11 @@ static void doOptions(unsigned char **pp, struct templateEntry *pTpe)
pTpe->data.field.eDateFormat = tplFmtRFC3339Date;
} else if(!strcmp((char*)Buf, "date-subseconds")) {
pTpe->data.field.eDateFormat = tplFmtSecFrac;
+ } else if(!strncmp((char*)Buf, "date-strftime(", 14)) {
+ char *sft = strdup((char *) Buf + 14); pTpe->data.field.eDateFormat = tplFmtSecFrac;
+ sft[strcspn(sft, ")")] = 0;
+ pTpe->data.field.eDateFormat = tplFmtStrftime;
+ pTpe->data.field.strftime_fmt = sft;
} else if(!strcmp((char*)Buf, "lowercase")) {
pTpe->data.field.eCaseConv = tplCaseConvLower;
} else if(!strcmp((char*)Buf, "uppercase")) {
@@ -480,6 +501,7 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl)
struct templateEntry *pTpe;
int iNum; /* to compute numbers */
rsRetVal iRetLocal;
+ int parenlevel = 0;
#ifdef FEATURE_REGEXP
/* APR: variables for regex */
@@ -504,9 +526,21 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl)
}
pTpe->eEntryType = FIELD;
- while(*p && *p != '%' && *p != ':') {
- rsCStrAppendChar(pStrB, tolower(*p));
- ++p; /* do NOT do this in tolower()! */
+ while(*p && (parenlevel > 0 || (*p != '%' && *p != ':'))) {
+ char ch = *p++;
+ switch (ch) {
+ case '(':
+ parenlevel++;
+ break;
+ case ')':
+ parenlevel--;
+ break;
+ default:
+ if (parenlevel == 0)
+ ch = tolower(ch);
+ break;
+ }
+ rsCStrAppendChar(pStrB, ch);
}
/* got the name*/
diff --git a/template.h b/template.h
index 04137b09..07496fe8 100644
--- a/template.h
+++ b/template.h
@@ -48,7 +48,7 @@ struct template {
enum EntryTypes { UNDEFINED = 0, CONSTANT = 1, FIELD = 2 };
enum tplFormatTypes { tplFmtDefault = 0, tplFmtMySQLDate = 1,
tplFmtRFC3164Date = 2, tplFmtRFC3339Date = 3, tplFmtPgSQLDate = 4,
- tplFmtSecFrac = 5};
+ tplFmtSecFrac = 5, tplFmtStrftime = 6};
enum tplFormatCaseConvTypes { tplCaseConvNo = 0, tplCaseConvUpper = 1, tplCaseConvLower = 2 };
#include "msg.h"
@@ -88,6 +88,7 @@ struct templateEntry {
int field_expand; /* use multiple instances of the field delimiter as a single one? */
enum tplFormatTypes eDateFormat;
+ char *strftime_fmt; /* for the tplFormatStrftime eDateFormat */
enum tplFormatCaseConvTypes eCaseConv;
struct { /* bit fields! */
unsigned bDropCC: 1; /* drop control characters? */