From d5f78989d8fd2a3c11fd1e6ed1cd4d688b1e6728 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 20 Jun 2011 12:17:51 +0200 Subject: added support for obtaining timestamp from system for imuxsock This permits to read the time a message was submitted to the system log socket. Most importantly, this is provided in microsecond resolution. So we are able to obtain high precision timestampis even for messages that were - as is usual - not formatted with them. This also simplifies things in regard to local time calculation in chroot environments. Many thanks to Lennart Poettering for suggesting this feature, providing some guidance on implementing it and coordinating getting the necessary support into the Linux kernel. --- runtime/datetime.c | 77 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 34 deletions(-) (limited to 'runtime/datetime.c') diff --git a/runtime/datetime.c b/runtime/datetime.c index f81180ea..89452f1c 100644 --- a/runtime/datetime.c +++ b/runtime/datetime.c @@ -55,6 +55,47 @@ static const int tenPowers[6] = { 1, 10, 100, 1000, 10000, 100000 }; /* ------------------------------ methods ------------------------------ */ +/** + * Convert struct timeval to syslog_time + */ +void +timeval2syslogTime(struct timeval *tp, struct syslogTime *t) +{ + struct tm *tm; + struct tm tmBuf; + long lBias; + + tm = localtime_r((time_t*) &(tp->tv_sec), &tmBuf); + + t->year = tm->tm_year + 1900; + t->month = tm->tm_mon + 1; + t->day = tm->tm_mday; + t->hour = tm->tm_hour; + t->minute = tm->tm_min; + t->second = tm->tm_sec; + t->secfrac = tp->tv_usec; + t->secfracPrecision = 6; + +# if __sun + /* Solaris uses a different method of exporting the time zone. + * It is UTC - localtime, which is the opposite sign of mins east of GMT. + */ + lBias = -(daylight ? altzone : timezone); +# elif defined(__hpux) + lBias = tz.tz_dsttime ? - tz.tz_minuteswest : 0; +# else + lBias = tm->tm_gmtoff; +# endif + if(lBias < 0) { + t->OffsetMode = '-'; + lBias *= -1; + } else + t->OffsetMode = '+'; + t->OffsetHour = lBias / 3600; + t->OffsetMinute = (lBias % 3600) / 60; + t->timeType = TIME_TYPE_RFC5424; /* we have a high precision timestamp */ +} + /** * Get the current date/time in the best resolution the operating * system has to offer (well, actually at most down to the milli- @@ -74,9 +115,6 @@ static const int tenPowers[6] = { 1, 10, 100, 1000, 10000, 100000 }; static void getCurrTime(struct syslogTime *t, time_t *ttSeconds) { struct timeval tp; - struct tm *tm; - struct tm tmBuf; - long lBias; # if defined(__hpux) struct timezone tz; # endif @@ -93,37 +131,7 @@ static void getCurrTime(struct syslogTime *t, time_t *ttSeconds) if(ttSeconds != NULL) *ttSeconds = tp.tv_sec; - tm = localtime_r((time_t*) &(tp.tv_sec), &tmBuf); - - t->year = tm->tm_year + 1900; - t->month = tm->tm_mon + 1; - t->day = tm->tm_mday; - t->hour = tm->tm_hour; - t->minute = tm->tm_min; - t->second = tm->tm_sec; - t->secfrac = tp.tv_usec; - t->secfracPrecision = 6; - -# if __sun - /* Solaris uses a different method of exporting the time zone. - * It is UTC - localtime, which is the opposite sign of mins east of GMT. - */ - lBias = -(daylight ? altzone : timezone); -# elif defined(__hpux) - lBias = tz.tz_dsttime ? - tz.tz_minuteswest : 0; -# else - lBias = tm->tm_gmtoff; -# endif - if(lBias < 0) - { - t->OffsetMode = '-'; - lBias *= -1; - } - else - t->OffsetMode = '+'; - t->OffsetHour = lBias / 3600; - t->OffsetMinute = (lBias % 3600) / 60; - t->timeType = TIME_TYPE_RFC5424; /* we have a high precision timestamp */ + timeval2syslogTime(&tp, t); } @@ -861,6 +869,7 @@ CODESTARTobjQueryInterface(datetime) */ pIf->getCurrTime = getCurrTime; pIf->GetTime = getTime; + pIf->timeval2syslogTime = timeval2syslogTime; pIf->ParseTIMESTAMP3339 = ParseTIMESTAMP3339; pIf->ParseTIMESTAMP3164 = ParseTIMESTAMP3164; pIf->formatTimestampToMySQL = formatTimestampToMySQL; -- cgit From 31900e004bbfd6da025e64844e2a07247dc87e94 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 15:36:05 +0200 Subject: more cleanup... --- runtime/datetime.c | 1 - 1 file changed, 1 deletion(-) (limited to 'runtime/datetime.c') diff --git a/runtime/datetime.c b/runtime/datetime.c index 89452f1c..753d2068 100644 --- a/runtime/datetime.c +++ b/runtime/datetime.c @@ -40,7 +40,6 @@ #include "obj.h" #include "modules.h" #include "datetime.h" -#include "sysvar.h" #include "srUtils.h" #include "stringbuf.h" #include "errmsg.h" -- cgit From b88ba949f8d657034f808034321fabbd65bf8078 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 29 Mar 2012 18:04:12 +0200 Subject: added "date-unixtimestamp" property replacer option to format as a unix timestamp --- runtime/datetime.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) (limited to 'runtime/datetime.c') diff --git a/runtime/datetime.c b/runtime/datetime.c index d30c6e0b..830c67e3 100644 --- a/runtime/datetime.c +++ b/runtime/datetime.c @@ -850,6 +850,117 @@ int formatTimestamp3164(struct syslogTime *ts, char* pBuf, int bBuggyDay) } +/** + * format a timestamp as a UNIX timestamp; subsecond resolution is + * discarded. + * Note that this code can use some refactoring. I decided to use it + * because mktime() requires an upfront TZ update as it works on local + * time. In any case, it is worth reconsidering to move to mktime() or + * some other method. + * Important: pBuf must point to a buffer of at least 11 bytes. + * rgerhards, 2012-03-29 + */ +int formatTimestampUnix(struct syslogTime *ts, char *pBuf) +{ + long MonthInDays, NumberOfYears, NumberOfDays, i; + int utcOffset; + time_t TimeInUnixFormat; + + /* Counting how many Days have passed since the 01.01 of the + * selected Year (Month level), according to the selected Month*/ + + switch(ts->month) + { + case 1: + MonthInDays = 0; //until 01 of January + break; + case 2: + MonthInDays = 31; //until 01 of February - leap year handling down below! + break; + case 3: + MonthInDays = 59; //until 01 of March + break; + case 4: + MonthInDays = 90; //until 01 of April + break; + case 5: + MonthInDays = 120; //until 01 of Mai + break; + case 6: + MonthInDays = 151; //until 01 of June + break; + case 7: + MonthInDays = 181; //until 01 of July + break; + case 8: + MonthInDays = 212; //until 01 of August + break; + case 9: + MonthInDays = 243; //until 01 of September + break; + case 10: + MonthInDays = 273; //until 01 of Oktober + break; + case 11: + MonthInDays = 304; //until 01 of November + break; + case 12: + MonthInDays = 334; //until 01 of December + break; + } + + + /* 1) Counting how many Years have passed since 1970 + 2) Counting how many Days have passed since the 01.01 of the selected Year + (Day level) according to the Selected Month and Day. Last day doesn't count, + it should be until last day + 3) Calculating this period (NumberOfDays) in seconds*/ + + NumberOfYears = ts->year - 1970; + NumberOfDays = MonthInDays + ts->day - 1; + TimeInUnixFormat = NumberOfYears * 31536000 + NumberOfDays * 86400; + + /* Now we need to adjust the number of years for leap + * year processing. If we are in Jan or Feb, this year + * will never be considered - because we haven't arrived + * at then end of Feb right now. [Feb, 29th in a leap year + * is handled correctly, because the day (29) is correctly + * added to the date serial] + */ + if(ts->month < 3) + NumberOfYears--; + + /*...AND ADDING ONE DAY FOR EACH YEAR WITH 366 DAYS + * note that we do not handle 2000 any special, as it was a + * leap year. The current code works OK until 2100, when it will + * break. As we do not process future dates, we accept that fate... + * the whole thing could be refactored by a table-based approach. + */ + for(i = 1;i <= NumberOfYears; i++) + { + /* If i = 2 we have 1972, which was a Year with 366 Days + and if (i + 2) Mod (4) = 0 we have a Year after 1972 + which is also a Year with 366 Days (repeated every 4 Years) */ + if ((i == 2) || (((i + 2) % 4) == 0)) + { /*Year with 366 Days!!!*/ + TimeInUnixFormat += 86400; + } + } + + /*Add Hours, minutes and seconds */ + TimeInUnixFormat += ts->hour*60*60; + TimeInUnixFormat += ts->minute*60; + TimeInUnixFormat += ts->second; + /* do UTC offset */ + utcOffset = ts->OffsetHour*3600 + ts->OffsetMinute*60; + if(ts->OffsetMode == '+') + utcOffset *= -1; /* if timestamp is ahead, we need to "go back" to UTC */ + TimeInUnixFormat += utcOffset; + snprintf(pBuf, 11, "%u", (unsigned) TimeInUnixFormat); + return 11; +} + + /* queryInterface function * rgerhards, 2008-03-05 */ @@ -874,6 +985,7 @@ CODESTARTobjQueryInterface(datetime) pIf->formatTimestampSecFrac = formatTimestampSecFrac; pIf->formatTimestamp3339 = formatTimestamp3339; pIf->formatTimestamp3164 = formatTimestamp3164; + pIf->formatTimestampUnix = formatTimestampUnix; finalize_it: ENDobjQueryInterface(datetime) -- cgit From 2fbac28d3c1335e1283596b4f574fd55d8117fd6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 30 Mar 2012 09:55:45 +0200 Subject: ommongodb: now writes a real timestamp into mongo --- runtime/datetime.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'runtime/datetime.c') diff --git a/runtime/datetime.c b/runtime/datetime.c index 830c67e3..10ab3c64 100644 --- a/runtime/datetime.c +++ b/runtime/datetime.c @@ -851,16 +851,9 @@ int formatTimestamp3164(struct syslogTime *ts, char* pBuf, int bBuggyDay) /** - * format a timestamp as a UNIX timestamp; subsecond resolution is - * discarded. - * Note that this code can use some refactoring. I decided to use it - * because mktime() requires an upfront TZ update as it works on local - * time. In any case, it is worth reconsidering to move to mktime() or - * some other method. - * Important: pBuf must point to a buffer of at least 11 bytes. - * rgerhards, 2012-03-29 + * convert syslog timestamp to time_t */ -int formatTimestampUnix(struct syslogTime *ts, char *pBuf) +time_t syslogTime2time_t(struct syslogTime *ts) { long MonthInDays, NumberOfYears, NumberOfDays, i; int utcOffset; @@ -956,7 +949,23 @@ int formatTimestampUnix(struct syslogTime *ts, char *pBuf) if(ts->OffsetMode == '+') utcOffset *= -1; /* if timestamp is ahead, we need to "go back" to UTC */ TimeInUnixFormat += utcOffset; - snprintf(pBuf, 11, "%u", (unsigned) TimeInUnixFormat); + return TimeInUnixFormat; +} + + +/** + * format a timestamp as a UNIX timestamp; subsecond resolution is + * discarded. + * Note that this code can use some refactoring. I decided to use it + * because mktime() requires an upfront TZ update as it works on local + * time. In any case, it is worth reconsidering to move to mktime() or + * some other method. + * Important: pBuf must point to a buffer of at least 11 bytes. + * rgerhards, 2012-03-29 + */ +int formatTimestampUnix(struct syslogTime *ts, char *pBuf) +{ + snprintf(pBuf, 11, "%u", (unsigned) syslogTime2time_t(ts)); return 11; } @@ -986,6 +995,7 @@ CODESTARTobjQueryInterface(datetime) pIf->formatTimestamp3339 = formatTimestamp3339; pIf->formatTimestamp3164 = formatTimestamp3164; pIf->formatTimestampUnix = formatTimestampUnix; + pIf->syslogTime2time_t = syslogTime2time_t; finalize_it: ENDobjQueryInterface(datetime) -- cgit