]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: stats: prepare stats-file support for values other than FN_COUNTER
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 29 Apr 2024 15:06:27 +0000 (17:06 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 2 May 2024 08:55:25 +0000 (10:55 +0200)
Currently, only FN_COUNTER are dumped and preloaded via a stats-file.
Thus in several places we relied on the assumption that only FN_COUNTER
are valid in stats-file context.

New stats types will soon be implemented as they are also eligilible to
statistics reloading on process startup. Thus, prepare stats-file
functions to remove any FN_COUNTER restriction.

As one of this change, generate_stat_tree() now uses stcol_is_generic()
for stats name tree indexing before stats-file parsing.

Also related to stats-file parsing, individual counter preloading step
as been extracted from line parsing in a dedicated new function
load_ctr(). This will allow to extend it to support multiple mechanism
of counter preloading depending on the stats type.

include/haproxy/stats.h
src/stats-file.c
src/stats.c

index 90141a331d4ca745e0b00480f5e49da9c9bae0b6..516529970adc7285ee9a481a799e5785454138a0 100644 (file)
@@ -74,6 +74,12 @@ int stats_emit_field_tags(struct buffer *out, const struct field *f,
                          char delim);
 
 
+/* Returns true if <col> is fully defined, false if only used as name-desc. */
+static inline int stcol_is_generic(const struct stat_col *col)
+{
+       return !!(col->cap);
+}
+
 static inline enum field_format stcol_format(const struct stat_col *col)
 {
        return col->type & FF_MASK;
index a41df828f4f6528e1af1ac072e65e8dfbc449587..828c0a1bf2b2c05fd72ee807409c2357bd5e1623 100644 (file)
@@ -85,16 +85,20 @@ void stats_dump_file_header(int type, struct buffer *out)
                chunk_strcat(out, "#fe guid,");
                for (i = 0; i < ST_I_PX_MAX; ++i) {
                        col = &stat_cols_px[i];
-                       if (stcol_nature(col) == FN_COUNTER && (col->cap & (STATS_PX_CAP_FE|STATS_PX_CAP_LI)))
+                       if (stcol_is_generic(col) &&
+                           col->cap & (STATS_PX_CAP_FE|STATS_PX_CAP_LI)) {
                                chunk_appendf(out, "%s,", col->name);
+                       }
                }
        }
        else {
                chunk_appendf(out, "#be guid,");
                for (i = 0; i < ST_I_PX_MAX; ++i) {
                        col = &stat_cols_px[i];
-                       if (stcol_nature(col) == FN_COUNTER && (col->cap & (STATS_PX_CAP_BE|STATS_PX_CAP_SRV)))
+                       if (stcol_is_generic(col) &&
+                           col->cap & (STATS_PX_CAP_BE|STATS_PX_CAP_SRV)) {
                                chunk_appendf(out, "%s,", col->name);
+                       }
                }
        }
 
@@ -189,6 +193,44 @@ static int parse_header_line(struct ist header, struct eb_root *st_tree,
        return 1;
 }
 
+/* Preload an individual counter instance stored at <counter> with <token>
+ * value> for the <col> stat column.
+ *
+ * Returns 0 on success else non-zero if counter was not updated.
+ */
+static int load_ctr(const struct stat_col *col, const struct ist token,
+                    void* counter)
+{
+       const enum field_nature fn = stcol_nature(col);
+       const enum field_format ff = stcol_format(col);
+       const char *ptr = istptr(token);
+       struct field value;
+
+       switch (ff) {
+       case FF_U64:
+               value.u.u64 = read_uint64(&ptr, istend(token));
+               break;
+
+       default:
+               /* Unsupported field nature. */
+               return 1;
+       }
+
+       /* Do not load value if non numeric characters present. */
+       if (ptr != istend(token))
+               return 1;
+
+       if (fn == FN_COUNTER && ff == FF_U64) {
+               *(uint64_t *)counter = value.u.u64;
+       }
+       else {
+               /* Unsupported field format/nature combination. */
+               return 1;
+       }
+
+       return 0;
+}
+
 /* Parse a non header stats-file line <line>. Specify current parsing <domain>
  * and <cols> stats column matrix derived from the last header line.
  *
@@ -269,7 +311,6 @@ static int parse_stat_line(struct ist line,
        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))
@@ -278,19 +319,7 @@ static int parse_stat_line(struct ist line,
                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;
-                       }
-               }
+               load_ctr(col, token, base_off + col->metric.offset[off]);
        }
 
        return 0;
index 3f3ee0fe3c5b557064e6fb2bd83d5df77ffec8a2..5ada0503eeafcc5ae9eae977bb5838b242d354e5 100644 (file)
     .cap = (cap_f),                                                           \
   }
 
-/* Returns true if <col> is fully defined, false if only used as name-desc. */
-static int stcol_is_generic(const struct stat_col *col)
-{
-       return !!(col->cap);
-}
-
 /* Convert stat_col <col> to old-style <name> as name_desc. */
 static void stcol2ndesc(struct name_desc *name, const struct stat_col *col)
 {
@@ -338,7 +332,7 @@ struct list stats_module_list[STATS_DOMAIN_COUNT] = {
 
 THREAD_LOCAL void *trash_counters;
 
-/* Insert into <st_tree> all stat columns from <cols> indexed by their name. */
+/* Insert <cols> generic stat columns into <st_tree> indexed by their name. */
 int generate_stat_tree(struct eb_root *st_tree, const struct stat_col cols[])
 {
        const struct stat_col *col;
@@ -348,7 +342,8 @@ int generate_stat_tree(struct eb_root *st_tree, const struct stat_col cols[])
 
        for (i = 0; i < ST_I_PX_MAX; ++i) {
                col = &cols[i];
-               if (stcol_nature(col) == FN_COUNTER) {
+
+               if (stcol_is_generic(col)) {
                        len = strlen(col->name);
                        node = malloc(sizeof(struct stcol_node) + len + 1);
                        if (!node)
@@ -739,6 +734,7 @@ static struct field me_generate_field(const struct stat_col *col,
                                       const void *counters, uint8_t cap,
                                       int stat_file)
 {
+       enum field_nature fn;
        struct field value;
        void *counter = NULL;
        int wrong_side = 0;
@@ -794,12 +790,19 @@ static struct field me_generate_field(const struct stat_col *col,
                        return (struct field){ .type = FF_EMPTY };
        }
 
-       switch (stcol_format(col)) {
-       case FF_U64:
-               value = mkf_u64(stcol_nature(col), *(uint64_t *)counter);
-               break;
-       default:
-               /* only FF_U64 counters currently use generic metric calculation */
+       fn = stcol_nature(col);
+       if (fn == FN_COUNTER) {
+               switch (stcol_format(col)) {
+               case FF_U64:
+                       value = mkf_u64(FN_COUNTER, *(uint64_t *)counter);
+                       break;
+               default:
+                       /* only FF_U64 counters currently use generic metric calculation */
+                       ABORT_NOW();
+               }
+       }
+       else {
+               /* No generic column available for other field nature. */
                ABORT_NOW();
        }