diff --git a/include/haproxy/stats.h b/include/haproxy/stats.h index 90141a331..516529970 100644 --- a/include/haproxy/stats.h +++ b/include/haproxy/stats.h @@ -74,6 +74,12 @@ int stats_emit_field_tags(struct buffer *out, const struct field *f, char delim); +/* Returns true if 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; diff --git a/src/stats-file.c b/src/stats-file.c index a41df828f..828c0a1bf 100644 --- a/src/stats-file.c +++ b/src/stats-file.c @@ -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 with + * value> for the 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 . Specify current parsing * and 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; diff --git a/src/stats.c b/src/stats.c index 3f3ee0fe3..5ada0503e 100644 --- a/src/stats.c +++ b/src/stats.c @@ -92,12 +92,6 @@ .cap = (cap_f), \ } -/* Returns true if 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 to old-style 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 all stat columns from indexed by their name. */ +/* Insert generic stat columns into 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(); }