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. --- 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..b4089657 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 "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..97a4eb6e 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 milliseconds 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 }, -- Changed in V2: add a verification function to check date unit argument