diff options
-rw-r--r-- | runtime/datetime.c | 36 | ||||
-rw-r--r-- | runtime/msg.c | 50 | ||||
-rw-r--r-- | runtime/msg.h | 6 | ||||
-rw-r--r-- | runtime/syslogd-types.h | 1 | ||||
-rw-r--r-- | template.c | 48 | ||||
-rw-r--r-- | template.h | 3 |
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; @@ -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*/ @@ -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? */ |