It can be sometimes interesting to have a timestamp with a
resolution of less than a second.
It is currently painful to obtain this, because concatenation
of date and date_us lead to a shorter timestamp during first
100ms of a second, which is not parseable and needs ugly ACLs
in configuration to prepend 0s when needed.
To improve this, add an optional <unit> parameter to date sample.
This allows to have milliseconds or microseconds appended to
timestamp with the correct length.
---
 Changed in V3:
 - fix a comment typo (s/milli/micro/)
 - Talk about "seconds" unit in doc
 doc/configuration.txt |  8 ++++++-
 src/sample.c          | 52 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 77f95572..390b7b79 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -14050,7 +14050,7 @@ cpu_ns_tot : integer
   high cpu_calls count, for example when processing many HTTP chunks, and for
   this reason it is often preferred to log cpu_ns_avg instead.
 
-date([<offset>]) : integer
+date([<offset>, <unit>]) : integer
   Returns the current date as the epoch (number of seconds since 01/01/1970).
   If an offset value is specified, then it is a number of seconds that is added
   to the current date before returning the value. This is particularly useful
@@ -14062,6 +14062,12 @@ date([<offset>]) : integer
      # set an expires header to now+1 hour in every response
      http-response set-header Expires %[date(3600),http_date]
 
+  <unit> is facultative, and can be set to "s" for seconds, "ms" for
+  milliseconds or "us" for microseconds. Default unit is seconds.
+  If <unit> is set, microseconds or milliseconds of current date sample are
+  appended to timestamp. This is useful when a time resolution of less than
+  a second is needed.
+
 date_us : integer
   Return the microseconds part of the date (the "second" part is returned by
   date sample). This sample is coherent with the date sample as it is comes
diff --git a/src/sample.c b/src/sample.c
index 98b5d573..7052815f 100644
--- a/src/sample.c
+++ b/src/sample.c
@@ -2940,8 +2940,45 @@ smp_fetch_env(const struct arg *args, struct sample 
*smp, const char *kw, void *
        return 1;
 }
 
+/* Validates the data unit argument passed to "date" fetch. Argument 1 support 
an
+ * optional string representing the unit of the result: "s" for seconds, "ms" 
for
+ * milliseconds and "us" for microseconds.
+ * Returns 0 on error and non-zero if OK.
+ */
+static int smp_check_date_unit(struct arg *args, char **err)
+{
+        if (args[1].type == ARGT_STR) {
+                if (strcmp(args[1].data.str.area, "s") == 0) {
+                        free(args[1].data.str.area);
+                        args[1].type = ARGT_SINT;
+                        args[1].data.sint = TIME_UNIT_S;
+                }
+                else if (strcmp(args[1].data.str.area, "ms") == 0) {
+                        free(args[1].data.str.area);
+                        args[1].type = ARGT_SINT;
+                        args[1].data.sint = TIME_UNIT_MS;
+                }
+                else if (strcmp(args[1].data.str.area, "us") == 0) {
+                        free(args[1].data.str.area);
+                        args[1].type = ARGT_SINT;
+                        args[1].data.sint = TIME_UNIT_US;
+                }
+                else {
+                        memprintf(err, "expects 's', 'ms' or 'us', got '%s'",
+                                  args[1].data.str.area);
+                        return 0;
+                }
+        }
+        else if (args[1].type != ARGT_STOP) {
+                memprintf(err, "Unexpected arg type");
+                return 0;
+        }
+
+        return 1;
+}
+
 /* retrieve the current local date in epoch time, and applies an optional 
offset
- * of args[0] seconds.
+ * of args[0] seconds. Add milli/microseconds if asked to in args[1].
  */
 static int
 smp_fetch_date(const struct arg *args, struct sample *smp, const char *kw, 
void *private)
@@ -2952,6 +2989,17 @@ smp_fetch_date(const struct arg *args, struct sample 
*smp, const char *kw, void
        if (args && args[0].type == ARGT_SINT)
                smp->data.u.sint += args[0].data.sint;
 
+       /* add milliseconds to timestamp if needed */
+       if (args[1].type == ARGT_SINT && args[1].data.sint == TIME_UNIT_MS) {
+               smp->data.u.sint *= 1000;
+               smp->data.u.sint += (date.tv_usec + 500) / 1000;
+       }
+       /* add microseconds to timestamp if needed */
+       else if (args[1].type == ARGT_SINT && args[1].data.sint == 
TIME_UNIT_US) {
+               smp->data.u.sint *= 1000000;
+               smp->data.u.sint += date.tv_usec;
+       }
+
        smp->data.type = SMP_T_SINT;
        smp->flags |= SMP_F_VOL_TEST | SMP_F_MAY_CHANGE;
        return 1;
@@ -3259,7 +3307,7 @@ static struct sample_fetch_kw_list smp_kws = {ILH, {
        { "always_false", smp_fetch_false, 0,            NULL, SMP_T_BOOL, 
SMP_USE_INTRN },
        { "always_true",  smp_fetch_true,  0,            NULL, SMP_T_BOOL, 
SMP_USE_INTRN },
        { "env",          smp_fetch_env,   ARG1(1,STR),  NULL, SMP_T_STR,  
SMP_USE_INTRN },
-       { "date",         smp_fetch_date,  ARG1(0,SINT), NULL, SMP_T_SINT, 
SMP_USE_INTRN },
+       { "date",         smp_fetch_date,  ARG2(0,SINT,STR), 
smp_check_date_unit, SMP_T_SINT, SMP_USE_INTRN },
        { "date_us",      smp_fetch_date_us,  0,         NULL, SMP_T_SINT, 
SMP_USE_INTRN },
        { "hostname",     smp_fetch_hostname, 0,         NULL, SMP_T_STR,  
SMP_USE_INTRN },
        { "nbproc",       smp_fetch_nbproc,0,            NULL, SMP_T_SINT, 
SMP_USE_INTRN },
-- 
2.20.1


Reply via email to