]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: stats: define the concept of domain for statistics
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 5 Oct 2020 09:49:37 +0000 (11:49 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 5 Oct 2020 10:02:14 +0000 (12:02 +0200)
The domain option will be used to have statistics attached to other
objects than proxies/listeners/servers. At the moment, only the PROXY
domain is available.

Add an argument 'domain' on the 'show stats' cli command to specify the
domain. Only 'domain proxy' is available now. If not specified, proxy
will be considered the default domain.

For HTML output, only proxy statistics will be displayed.

doc/management.txt
include/haproxy/applet-t.h
include/haproxy/stats-t.h
src/stats.c

index adbad95d346d4bf46c80a27cad9b88038da4e9b8..9a749e48a3daccbf69fb9a339e4641fbe6e91a12 100644 (file)
@@ -944,6 +944,8 @@ mechanism is the HTTP statistics page. This page also exposes an alternative
 CSV output format for monitoring tools. The same format is provided on the
 Unix socket.
 
+Statistics are regroup in categories labelled as domains, corresponding to the
+multiple components of HAProxy. Only the proxy domain is available.
 
 9.1. CSV format
 ---------------
@@ -2423,12 +2425,13 @@ show sess <id>
   The special id "all" dumps the states of all sessions, which must be avoided
   as much as possible as it is highly CPU intensive and can take a lot of time.
 
-show stat [{<iid>|<proxy>} <type> <sid>] [typed|json] [desc]
-  Dump statistics using the CSV format; using the extended typed output
-  format described in the section above if "typed" is passed after the
-  other arguments; or in JSON if "json" is passed after the other arguments
-  . By passing <id>, <type> and <sid>, it is possible to dump only selected
-  items :
+show stat [domain <domain>] [{<iid>|<proxy>} <type> <sid>] [typed|json] [desc]
+  Dump statistics. The domain is used to select which statistics to print; only
+  proxy is available for now. By default, the CSV format is used; you can
+  activate the extended typed output format described in the section above if
+  "typed" is passed after the other arguments; or in JSON if "json" is passed
+  after the other arguments. By passing <id>, <type> and <sid>, it is possible
+  to dump only selected items :
     - <iid> is a proxy ID, -1 to dump everything. Alternatively, a proxy name
       <proxy> may be specified. In this case, this proxy's ID will be used as
       the ID selector.
index 7c97f191764c5819b8915b9801f33c6877522974..eca55c92af534c72d697e2dd13571f1623809d98 100644 (file)
@@ -120,6 +120,7 @@ struct appctx {
                struct {
                        void *obj1;             /* context pointer used in stats dump */
                        void *obj2;             /* context pointer used in stats dump */
+                       uint32_t domain;        /* set the stats to used, for now only proxy stats are supported */
                        int scope_str;          /* limit scope to a frontend/backend substring */
                        int scope_len;          /* length of the string above in the buffer */
                        int px_st;              /* STAT_PX_ST* */
index 139b5468b157abaf6ad66310a794f179190ced7a..be4c6865c0eff0541efcc3a2e2238ac615677343 100644 (file)
@@ -50,6 +50,8 @@
 #define STATS_TYPE_SV  2
 #define STATS_TYPE_SO  3
 
+#define STATS_DOMAIN  (0)               /* used for bitshifting, type of statistics, for now only proxy is available */
+
 /* HTTP stats : applet.st0 */
 enum {
        STAT_HTTP_INIT = 0,  /* Initial state */
@@ -450,5 +452,12 @@ struct field {
        } u;
 };
 
+/* stats_domain is used in a flag as a 1 byte field */
+enum stats_domain {
+       STATS_DOMAIN_PROXY = 0,
+       STATS_DOMAIN_COUNT,
+
+       STATS_DOMAIN_MASK  = 0xff
+};
 
 #endif /* _HAPROXY_STATS_T_H */
index 66b8a49475733773ab62bd9545b24e20f3980aed..16e0c10fdffd597a8ec744b1b7528b4afff1e086 100644 (file)
@@ -257,6 +257,11 @@ static THREAD_LOCAL struct field info[INF_TOTAL_FIELDS];
 /* one line of stats */
 static THREAD_LOCAL struct field stats[ST_F_TOTAL_FIELDS];
 
+static inline uint8_t stats_get_domain(uint32_t domain)
+{
+       return domain >> STATS_DOMAIN & STATS_DOMAIN_MASK;
+}
+
 static void stats_dump_json_schema(struct buffer *out);
 
 int stats_putchk(struct channel *chn, struct htx *htx, struct buffer *chk)
@@ -531,7 +536,8 @@ static int stats_dump_fields_csv(struct buffer *out,
 static int stats_dump_fields_typed(struct buffer *out,
                                    const struct field *stats,
                                    size_t stats_count,
-                                   unsigned int flags)
+                                   unsigned int flags,
+                                   enum stats_domain domain)
 {
        int field;
 
@@ -539,14 +545,23 @@ static int stats_dump_fields_typed(struct buffer *out,
                if (!stats[field].type)
                        continue;
 
-               chunk_appendf(out, "%c.%u.%u.%d.%s.%u:",
-                             stats[ST_F_TYPE].u.u32 == STATS_TYPE_FE ? 'F' :
-                             stats[ST_F_TYPE].u.u32 == STATS_TYPE_BE ? 'B' :
-                             stats[ST_F_TYPE].u.u32 == STATS_TYPE_SO ? 'L' :
-                             stats[ST_F_TYPE].u.u32 == STATS_TYPE_SV ? 'S' :
-                             '?',
-                             stats[ST_F_IID].u.u32, stats[ST_F_SID].u.u32,
-                             field, stat_fields[field].name, stats[ST_F_PID].u.u32);
+               switch (domain) {
+               case STATS_DOMAIN_PROXY:
+                       chunk_appendf(out, "%c.%u.%u.%d.%s.%u:",
+                                     stats[ST_F_TYPE].u.u32 == STATS_TYPE_FE ? 'F' :
+                                     stats[ST_F_TYPE].u.u32 == STATS_TYPE_BE ? 'B' :
+                                     stats[ST_F_TYPE].u.u32 == STATS_TYPE_SO ? 'L' :
+                                     stats[ST_F_TYPE].u.u32 == STATS_TYPE_SV ? 'S' :
+                                     '?',
+                                     stats[ST_F_IID].u.u32, stats[ST_F_SID].u.u32,
+                                     field,
+                                     stat_fields[field].name,
+                                     stats[ST_F_PID].u.u32);
+                       break;
+
+               default:
+                       break;
+               }
 
                if (!stats_emit_field_tags(out, &stats[field], ':'))
                        return 0;
@@ -640,7 +655,8 @@ static void stats_print_proxy_field_json(struct buffer *out,
 /* Dump all fields from <stats> into <out> using a typed "field:desc:type:value" format */
 static int stats_dump_fields_json(struct buffer *out,
                                   const struct field *stats, size_t stats_count,
-                                  unsigned int flags)
+                                  unsigned int flags,
+                                  enum stats_domain domain)
 {
        int field;
        int started = 0;
@@ -661,12 +677,14 @@ static int stats_dump_fields_json(struct buffer *out,
                started = 1;
 
                old_len = out->data;
-               stats_print_proxy_field_json(out, &stats[field],
-                                            stat_fields[field].name, field,
-                                            stats[ST_F_TYPE].u.u32,
-                                            stats[ST_F_IID].u.u32,
-                                            stats[ST_F_SID].u.u32,
-                                            stats[ST_F_PID].u.u32);
+               if (domain == STATS_DOMAIN_PROXY) {
+                       stats_print_proxy_field_json(out, &stats[field],
+                                                    stat_fields[field].name, field,
+                                                    stats[ST_F_TYPE].u.u32,
+                                                    stats[ST_F_IID].u.u32,
+                                                    stats[ST_F_SID].u.u32,
+                                                    stats[ST_F_PID].u.u32);
+               }
 
                if (old_len == out->data)
                        goto err;
@@ -1408,9 +1426,9 @@ int stats_dump_one_line(const struct field *stats, size_t stats_count,
        if (appctx->ctx.stats.flags & STAT_FMT_HTML)
                ret = stats_dump_fields_html(&trash, stats, appctx->ctx.stats.flags);
        else if (appctx->ctx.stats.flags & STAT_FMT_TYPED)
-               ret = stats_dump_fields_typed(&trash, stats, stats_count, appctx->ctx.stats.flags);
+               ret = stats_dump_fields_typed(&trash, stats, stats_count, appctx->ctx.stats.flags, appctx->ctx.stats.domain);
        else if (appctx->ctx.stats.flags & STAT_FMT_JSON)
-               ret = stats_dump_fields_json(&trash, stats, stats_count, appctx->ctx.stats.flags);
+               ret = stats_dump_fields_json(&trash, stats, stats_count, appctx->ctx.stats.flags, appctx->ctx.stats.domain);
        else
                ret = stats_dump_fields_csv(&trash, stats, stats_count, appctx->ctx.stats.flags);
 
@@ -3339,6 +3357,9 @@ static void http_stats_io_handler(struct appctx *appctx)
        struct channel *res = si_ic(si);
        struct htx *req_htx, *res_htx;
 
+       /* only proxy stats are available via http */
+       appctx->ctx.stats.domain = STATS_DOMAIN_PROXY;
+
        res_htx = htx_from_buf(&res->buf);
 
        if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
@@ -3932,7 +3953,19 @@ static int cli_parse_show_stat(char **args, char *payload, struct appctx *appctx
        if ((strm_li(si_strm(appctx->owner))->bind_conf->level & ACCESS_LVL_MASK) >= ACCESS_LVL_OPER)
                appctx->ctx.stats.flags |= STAT_SHLGNDS;
 
-       if (*args[arg] && *args[arg+1] && *args[arg+2]) {
+       /* proxy is the default domain */
+       appctx->ctx.stats.domain = STATS_DOMAIN_PROXY;
+       if (!strcmp(args[arg], "domain")) {
+               ++args;
+
+               if (!strcmp(args[arg], "proxy"))
+                       ++args;
+               else
+                       return cli_err(appctx, "Invalid statistics domain.\n");
+       }
+
+       if (appctx->ctx.stats.domain == STATS_DOMAIN_PROXY
+           && *args[arg] && *args[arg+1] && *args[arg+2]) {
                struct proxy *px;
 
                px = proxy_find_by_name(args[arg], 0, 0);