MINOR: time: add timeofday_as_iso_us() to return instant time as ISO

We often need ISO time + microseconds in traces and ring buffers, thus
function does this by calling gettimeofday() and keeping a cached value
of the part representing the tv_sec value, and only rewrites the microsecond
part. The cache is per-thread so it's lockless and safe to use as-is.
Some tests already show that it's easy to see 3-4 events in a single
microsecond, thus it's likely that the nanosecond version will have to
be implemented as well. But certain comments on the net suggest that
some parsers are having trouble beyond microsecond, thus for now let's
stick to the microsecond only.
This commit is contained in:
Willy Tarreau 2019-09-26 08:00:23 +02:00
parent 710d987cd6
commit 93acfa2263
2 changed files with 32 additions and 0 deletions

View File

@ -103,6 +103,8 @@ REGPRM1 static inline struct timeval *tv_now(struct timeval *tv)
*/
REGPRM2 void tv_update_date(int max_wait, int interrupted);
char *timeofday_as_iso_us(int pad);
/*
* sets a struct timeval to its highest value so that it can never happen
* note that only tv_usec is necessary to detect it since a tv_usec > 999999

View File

@ -32,6 +32,9 @@ THREAD_LOCAL struct timeval after_poll; /* system date after leaving poll()
static THREAD_LOCAL struct timeval tv_offset; /* per-thread time ofsset relative to global time */
static volatile unsigned long long global_now; /* common date between all threads (32:32) */
static THREAD_LOCAL unsigned int iso_time_sec; /* last iso time value for this thread */
static THREAD_LOCAL char iso_time_str[28]; /* ISO time representation of gettimeofday() */
/*
* adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
*/
@ -262,6 +265,33 @@ REGPRM2 void tv_update_date(int max_wait, int interrupted)
return;
}
/* returns the current date as returned by gettimeofday() in ISO+microsecond
* format. It uses a thread-local static variable that the reader can consume
* for as long as it wants until next call. Thus, do not call it from a signal
* handler. If <pad> is non-0, a trailing space will be added. It will always
* return exactly 26 or 27 characters (depending on padding) and will always be
* zero-terminated, thus it will always fit into a 28 bytes buffer.
*/
char *timeofday_as_iso_us(int pad)
{
struct timeval new_date;
struct tm tm;
gettimeofday(&new_date, NULL);
if (new_date.tv_sec != iso_time_sec || !new_date.tv_sec) {
get_localtime(new_date.tv_sec, &tm);
if (unlikely(strftime(iso_time_str, sizeof(iso_time_str), "%Y-%m-%dT%H:%M:%S.000000", &tm) != 26))
strcpy(iso_time_str, "YYYY-mm-ddTHH:MM:SS.000000"); // make the failure visible but respect format.
iso_time_sec = new_date.tv_sec;
}
utoa_pad(new_date.tv_usec, iso_time_str + 20, 7);
if (pad) {
iso_time_str[26] = ' ';
iso_time_str[27] = 0;
}
return iso_time_str;
}
/*
* Local variables:
* c-indent-level: 8