Elukey has submitted this change and it was merged.

Change subject: Extend the %{format}t timestamp formatter with the 'end:' prefix
......................................................................


Extend the %{format}t timestamp formatter with the 'end:' prefix

The current code stores the time-format string configured for %{time-format}t
in tag->var; then it leverages TAG_F_NOVARMATCH to avoid any match
between each Varnish tag. This does not allow to match the various SLT_Timestamp
types (Start, Resp, etc..) with tag->var. To correct this, I implemented the 
following
convention inspired by the Apache log format specifications:

http://httpd.apache.org/docs/current/mod/mod_log_config.html#formats

If the timestamp format starts with the 'end:' prefix then the SLT_Timestamp 
'Resp'
will be chosen for each request, otherwise the default will be 'Start'.
The 'end' prefix will be removed from the output.

TAG_F_NOVARMATCH is also removed completely in favor of a more clean
TAG_F_TIMESTAMP flag.

Bug: T136314
Change-Id: Ib20b0cc6fa8ecc2fd6f1fe899d0c5d630681c373
---
M varnishkafka.c
M varnishkafka.conf.example
M varnishkafka.h
3 files changed, 124 insertions(+), 62 deletions(-)

Approvals:
  Elukey: Verified; Looks good to me, approved
  Ottomata: Looks good to me, but someone else must approve
  BBlack: Looks good to me, but someone else must approve



diff --git a/varnishkafka.c b/varnishkafka.c
index b928bb3..1ab6980 100644
--- a/varnishkafka.c
+++ b/varnishkafka.c
@@ -318,7 +318,8 @@
 
 
        /* Allocate initial space for escaped string.
-        * The maximum expansion size per character is 5 (octal coding). */
+        * The maximum expansion size per character is 5 (octal coding).
+        */
        const size_t in_len = *len;
        char dst[in_len * 5];
        char *d = dst;
@@ -554,18 +555,28 @@
        const int timelen   = 64;
        size_t tlen;
 
-       /* Use config-supplied time formatting */
-       if (tag->var)
-               timefmt = tag->var;
-
-       if (tag->tag == SLT_BereqHeader) {
-               if (unlikely(!strptime(strndupa(ptr, len),
-                                      "%a, %d %b %Y %T", &tm)))
-                       return 0;
-       } else {
-               time_t t = strtoul(ptr, NULL, 10);
-               localtime_r(&t, &tm);
+       /*
+        * The special format for tag->var "end:strftime" is used
+        * to force Varnishkafka to use the SLT_Timestamp 'Resp' instead
+        * of 'Start' for timestamp formatters. The prefix is removed
+        * from 'timefmt' accordingly.
+        */
+       if (tag->var){
+               const char *fmt_tmp = tag->var;
+               // Remove APACHE_LOG_END_PREFIX from the format string
+               if (tag->flags & TAG_F_TIMESTAMP_END) {
+                       fmt_tmp += strlen(APACHE_LOG_END_PREFIX);
+               }
+               /* If the rest of the format string without the
+                * 'end:' prefix is not empty, use it
+                * in place of the default.
+                */
+               if (*fmt_tmp)
+                       timefmt = fmt_tmp;
        }
+
+       time_t t = strtoul(ptr, NULL, 10);
+       localtime_r(&t, &tm);
 
        char dst[timelen];
 
@@ -741,7 +752,26 @@
         */
        struct {
                /* A formatter may be backed by multiple tags.
-                * The first matching tag observed in the log will be used. */
+                * The first matching tag observed in the log will be used.
+                *
+                * Example:
+                * A formatter declared as following in 'map':
+                * ['x'] = { {
+                *              { VSL_CLIENTMARKER, SLT_Timestamp,
+                *                .var = "Process",
+                *                .fmtvar = "Varnish:time_firstbyte", .col = 2 
},
+                *              { VSL_CLIENTMARKER, SLT_Begin,
+                *                .fmtvar = "Varnish:xvid", .col = 2 }
+                *      } },
+                *
+                * In this case, the struct below is replicated two
+                * times to match the 'x' formatter to multiple
+                * Varnish tags (establishing also a priority).
+                * Therefore, supposing that 'x' corresponds to 'map[42]',
+                * the following variables will be accessible:
+                * - map[42].f[0].var    ==> "Process"
+                * - map[42].f[1].fmtvar ==> "Varnish:xvid"
+                */
                struct {
                        /* VSL_CLIENTMARKER or VSL_BACKENDMARKER, or both */
                        int spec;
@@ -786,7 +816,6 @@
                 * (for perf reason the field passed is pointer to
                 * the start of the substring in the original payload
                 * plus its length, keep it in mind when writing a parser).
-                *
                 */
                ['b'] = { {
                                /* Size of response in bytes, with HTTP 
headers. */
@@ -845,20 +874,10 @@
                                  .tag_flags = TAG_F_LAST }
                        } },
                ['t'] = { {
-                               /* Time the request was received.
-                                * TAG_F_NOVARMATCH forces varnishkafka to avoid
-                                * any sort of var comparison so the .var field 
is
-                                * not usable for this option. This flag is 
needed
-                                * since 'var' in %{<strftime-format>}t gets
-                                * the '<strftime-format>' value, that is not
-                                * usable for tag match operations.
-                                * The only option available is:
-                                * - Start timestamp (TAG_F_NOVARMATCH needs to 
be set)
-                                */
                                { VSL_CLIENTMARKER, SLT_Timestamp,
                                  .col = 2,
                                  .parser = parse_t,
-                                 .tag_flags = TAG_F_NOVARMATCH }
+                                 .tag_flags = TAG_F_TIMESTAMP }
                        } },
                ['U'] = { {
                                /* The URL path requested, not including any 
query string. */
@@ -881,7 +900,6 @@
                                  .parser = parse_vcl_handling },
                                { VSL_CLIENTMARKER, SLT_VCL_Log,
                                  .fmtvar = "VCL_Log:*" },
-
                        } },
                ['n'] = { {
                                { VSL_CLIENTMARKER, VSL_TAG__ONCE,
@@ -1077,6 +1095,23 @@
                for (i = 0 ; map[(int)*s].f[i].spec ; i++) {
                        if (map[(int)*s].f[i].tag == 0)
                                continue;
+
+                       /* The %{format}t formatter handles SLT_Timestamp tags.
+                        * Its format allows the use of a prefix like "end:"
+                        * to specify what SLT_Timestamp tag to pick:
+                        * - "end:" corresponds to Varnish "Resp" timestamp.
+                        * - Anything else will default to Varnish "Start" 
timestamp.
+                        * This check is useful to find string prefixes in all
+                        * the %{}t timestamp formatters and store the result 
among its tags
+                        * to avoid repeating the same operation at run time 
for each
+                        * request (wasting resources).
+                        */
+                       if ((map[(int)*s].f[i].tag_flags & TAG_F_TIMESTAMP) && 
var) {
+                               if (strncmp(var, APACHE_LOG_END_PREFIX,
+                                               strlen(APACHE_LOG_END_PREFIX)) 
== 0) {
+                                       map[(int)*s].f[i].tag_flags |= 
TAG_F_TIMESTAMP_END;
+                               }
+                       }
 
                        /* mapping has fmtvar specified, make sure it
                         * matches the format's variable. */
@@ -1481,33 +1516,14 @@
                if (!(tag->spec & spec))
                        continue;
 
-               /*
-                * TAG_F_NOVARMATCH is a special flag used for format tags like
-                * %{<strftime-format>}t because the related tag->var value
-                * is not usable.
-                * The only use case at the moment is represented by the 
SLT_Timestamp
-                * tag that occurs multiple times during the request processing.
-                * The format is always the same, for example:
-                * Start: 1464628135.916033 0.000885 0.000084
-                * TAG_F_NOVARMATCH avoids the match between the tag 't' var
-                * specified in format_parse and the content of ptr since 'var'
-                * in %{<strftime-format>}t gets the '<strftime-format>' string 
value
-                * (not usable for comparison with the content of the ptr 
payload).
-                * This means that at the moment the only possible match for 
't' is:
-                * - Start timestamp (TAG_F_NOVARMATCH needs to be set).
-                * This feature is not really flexible and it would need to be 
improved
-                * in the future to let the users to specify the desired 
Timestamp in
-                * their config files, rather than forcing it in the code.
-                */
-               if ((tag->var) && !(tag->flags & TAG_F_NOVARMATCH)) {
+               if ((tag->var) && !(tag->flags & TAG_F_TIMESTAMP)){
                        const char *t;
 
                        /* Get the occurence of ":" in ("Varname: value") */
                        if (!(t = strnchr(ptr, len, ':')))
                                continue;
 
-                       /*
-                        * Variable match ("Varname: value") checks:
+                       /* Variable match ("Varname: value") checks:
                         * 1) the len of the substring before the ':' (Varname) 
needs
                         *    to match the len of the tag requested.
                         * 2) strncasecmp between ptr (up to tag->varlen chars) 
and
@@ -1531,6 +1547,38 @@
                                ptr2 = NULL;
                        }
 
+               } else if (tag->flags & TAG_F_TIMESTAMP) {
+                       /* The TAG_F_TIMESTAMP is related to the %{format}t
+                        * output formatter available in the config.
+                        * This formatter is special because tag->var gets 
populared
+                        * with a string like '%FT%T', that represents a 
strftime
+                        * compatible formatter, meanwhile there are multiple
+                        * Varnish timestamp to choose (like Start, Resp, 
etc..) that
+                        * can't be easily be matched comparing the Varnish tag 
read
+                        * and tag->var. To add some flexibility, these are the
+                        * allowed formats:
+                        * 1) %{end:strftime_formatter}t
+                        * 2) %{strftime_formatter}t
+                        * The "end:" prefix will force Varnishkafka to pick the
+                        * SLT_timestamp "Resp" timestamp, meanwhile the 
default is to
+                        * use the "Start" one.
+                        * Help to read the if conditions: strncmp returns 0 if 
the two
+                        * strings are equal (up to some amount of chars) so 
the not
+                        * operator is needed.
+                        */
+                       if (!(tag->flags & TAG_F_TIMESTAMP_END)
+                               && !strncmp(ptr, SLT_TIMESTAMP_START,
+                                               strlen(SLT_TIMESTAMP_START))) {
+                               ptr2 = ptr;
+                               len2 = len;
+                       } else if ((tag->flags & TAG_F_TIMESTAMP_END)
+                                       && !strncmp(ptr, SLT_TIMESTAMP_RESP,
+                                                       
strlen(SLT_TIMESTAMP_RESP))) {
+                               ptr2 = ptr;
+                               len2 = len;
+                       } else {
+                               continue;
+                       }
                } else {
                        ptr2 = ptr;
                        len2 = len;
diff --git a/varnishkafka.conf.example b/varnishkafka.conf.example
index d854bab..d47dea5 100644
--- a/varnishkafka.conf.example
+++ b/varnishkafka.conf.example
@@ -67,6 +67,12 @@
 #  Additional formatter specials:                                     #
 #    %{<strftime-format>}t - format timestamp according to supplied   #
 #                            strftime(3) compatible format string.    #
+#                            If the format starts with 'end:'         #
+#                            the SLT_Timestamp used is 'Resp'         #
+#                            (end of the request processing),         #
+#                            otherwise SLT_Timestamp 'Start'          #
+#                            will be used.                            #
+#                                                                     #
 #    %{Varnish:xid}x       - transaction id of client request.        #
 #                            Same value as X-Varnish header           #
 #                                                                     #
diff --git a/varnishkafka.h b/varnishkafka.h
index a838e73..e07d576 100644
--- a/varnishkafka.h
+++ b/varnishkafka.h
@@ -5,24 +5,24 @@
  * Copyright (c) 2013 Magnus Edenhill <[email protected]>
  *
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met: 
- * 
+ * modification, are permitted provided that the following conditions are met:
+ *
  * 1. Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer. 
+ *    this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright notice,
  *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution. 
- * 
+ *    and/or other materials provided with the distribution.
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
@@ -89,11 +89,19 @@
                        const char *ptr, size_t len);
        int    col;
        int    flags;
-#define TAG_F_NOVARMATCH  0x1  /* Dont attempt to match tag->var to input */
-#define TAG_F_LAST        0x2  /* If multiple, log last one not first one */
+#define TAG_F_TIMESTAMP 1           /* var is a SLT_Timestamp formatter */
+#define TAG_F_TIMESTAMP_END 1<<2    /* var contains the end prefix */
+#define TAG_F_LAST 1<<3             /* If multiple, log last one not first one 
*/
 };
 
 /**
+ * String constants to be used to parse the %{format}t formatter.
+ */
+#define APACHE_LOG_END_PREFIX "end:"
+#define SLT_TIMESTAMP_START "Start"
+#define SLT_TIMESTAMP_RESP "Resp"
+
+/**
  * Formatting from format
  */
 struct fmt {

-- 
To view, visit https://gerrit.wikimedia.org/r/292172
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ib20b0cc6fa8ecc2fd6f1fe899d0c5d630681c373
Gerrit-PatchSet: 14
Gerrit-Project: operations/software/varnish/varnishkafka
Gerrit-Branch: master
Gerrit-Owner: Elukey <[email protected]>
Gerrit-Reviewer: BBlack <[email protected]>
Gerrit-Reviewer: Elukey <[email protected]>
Gerrit-Reviewer: Ema <[email protected]>
Gerrit-Reviewer: Ottomata <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to