]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: time: add timeofday_as_iso_us() to return instant time as ISO
authorWilly Tarreau <w@1wt.eu>
Thu, 26 Sep 2019 06:00:23 +0000 (08:00 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 26 Sep 2019 06:13:38 +0000 (08:13 +0200)
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.

include/common/time.h
src/time.c

index 2633b1c5eea070de270649c0e3df2eca2ebfce10..d6bbecb8e1c06f151e7f0ae7c0273303576e7fbe 100644 (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
index e830f851adbfd2770c6040174ae1a035ad951524..1a18c7641ee1f398654f3f52c14dcb1dbc6f2199 100644 (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