]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: stats: parse values from stats-file
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 24 Apr 2024 09:15:18 +0000 (11:15 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 26 Apr 2024 09:34:02 +0000 (11:34 +0200)
This patch implement parsing of counter values line from stats-file. It
reuses domain context previously set by the last header line. Each
value is separated by ',' character, relative to the list of column
names describe by the header line.

This is implemented via static function parse_stat_line(). It first
extract a GUID and retrieve the object instance. Then each numerical
value is parsed and object counters updated. For the moment, only U64
counters metrics is supported. parse_stat_line() is called on each line
until a new header line is found.

src/stats-file.c

index 1e94e293e8bd422db9cd011568552a3caa52b5a1..2706dbff14c774fa4ed8033f2868e69f3de99f69 100644 (file)
@@ -12,7 +12,8 @@
 #include <haproxy/chunk.h>
 #include <haproxy/errors.h>
 #include <haproxy/global.h>
-#include <haproxy/guid-t.h>
+#include <haproxy/guid.h>
+#include <haproxy/intops.h>
 #include <haproxy/list.h>
 #include <haproxy/listener-t.h>
 #include <haproxy/obj_type.h>
@@ -188,6 +189,116 @@ static int parse_header_line(struct ist header, struct eb_root *st_tree,
        return 1;
 }
 
+/* Parse a non header stats-file line <line>. Specify current parsing <domain>
+ * and <cols> stats column matrix derived from the last header line.
+ *
+ * Returns 0 on success else non-zero.
+ */
+static int parse_stat_line(struct ist line,
+                           enum stfile_domain domain,
+                           const struct stat_col *cols[])
+{
+       struct guid_node *node;
+       struct listener *li;
+       struct server *srv;
+       struct proxy *px;
+       struct ist token;
+       char *base_off;
+       char *guid;
+       int i, off;
+
+       token = istsplit(&line, ',');
+       guid = ist0(token);
+       if (!guid_is_valid_fmt(guid, NULL))
+               goto err;
+
+       node = guid_lookup(guid);
+       if (!node) {
+               /* Silently ignored unknown GUID. */
+               return 0;
+       }
+
+       switch (obj_type(node->obj_type)) {
+       case OBJ_TYPE_PROXY:
+               px = objt_proxy(node->obj_type);
+
+               if (domain == STFILE_DOMAIN_PX_FE) {
+                       if (!(px->cap & PR_CAP_FE))
+                               goto err;
+                       base_off = (char *)&px->fe_counters;
+                       off = 0;
+               }
+               else if (domain == STFILE_DOMAIN_PX_BE) {
+                       if (!(px->cap & PR_CAP_BE))
+                               goto err;
+                       base_off = (char *)&px->be_counters;
+                       off = 1;
+               }
+               else {
+                       goto err;
+               }
+
+               break;
+
+       case OBJ_TYPE_LISTENER:
+               if (domain != STFILE_DOMAIN_PX_FE)
+                       goto err;
+
+               li = objt_listener(node->obj_type);
+               /* Listeners counters are not allocated if 'option socket-stats' unset. */
+               if (!li->counters)
+                       return 0;
+
+               base_off = (char *)li->counters;
+               off = 0;
+               break;
+
+       case OBJ_TYPE_SERVER:
+               if (domain != STFILE_DOMAIN_PX_BE)
+                       goto err;
+
+               srv = objt_server(node->obj_type);
+               base_off = (char *)&srv->counters;
+               off = 1;
+               break;
+
+       default:
+               goto err;
+       }
+
+       i = 0;
+       while (istlen(line) && i < STAT_FILE_MAX_COL_COUNT) {
+               const struct stat_col *col = cols[i++];
+               enum field_format ff;
+
+               token = istsplit(&line, ',');
+               if (!istlen(token))
+                       continue;
+
+               if (!col)
+                       continue;
+
+               ff = stcol_format(col);
+               if (ff == FF_U64) {
+                       uint64_t *offset, value;
+                       const char *ptr;
+
+                       ptr = istptr(token);
+                       value = read_uint64(&ptr, istend(token));
+                       /* Do not load value if non numeric characters present. */
+                       if (ptr == istend(token)) {
+                               offset = (uint64_t *)(base_off + col->metric.offset[off]);
+                               *offset = value;
+                       }
+               }
+       }
+
+       return 0;
+
+ err:
+       return 1;
+}
+
 /* Parse a stats-file and preload haproxy internal counters. */
 void apply_stats_file(void)
 {
@@ -241,7 +352,11 @@ void apply_stats_file(void)
 
                        valid_format = 1;
                }
-               else if (domain == STFILE_DOMAIN_UNSET) {
+               else if (domain != STFILE_DOMAIN_UNSET) {
+                       if (parse_stat_line(istline, domain, cols))
+                               ha_warning("config: Ignored stats-file line %d.\n", linenum);
+               }
+               else {
                        /* Stop parsing if first line is not a valid header.
                         * Allows to immediately stop reading garbage file.
                         */