]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] stats: add the ability to dump table entries matching criteria
authorWilly Tarreau <w@1wt.eu>
Sun, 18 Jul 2010 09:46:20 +0000 (11:46 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 10 Aug 2010 16:04:14 +0000 (18:04 +0200)
It is now possible to dump some select table entries based on criteria
which apply to the stored data. This is enabled by appending the following
options to the end of the "show table" statement :

  data.<data_type> {eq|ne|lt|gt|le|ge} <value>

For intance :

  show table http_proxy data.conn_rate gt 5
  show table http_proxy data.gpc0 ne 0

The compare applies to the integer value as it would be displayed, and
operates on signed long long integers.

include/types/session.h
src/dumpstats.c

index f2f15c45634bc64e681e8cb2d9502594903250c1..4a1dc6e841bc2c19b97c8f888e8599c5a2c633fe 100644 (file)
@@ -234,6 +234,9 @@ struct session {
                        void *target;           /* table we want to dump, or NULL for all */
                        struct proxy *proxy;    /* table being currently dumped (first if NULL) */
                        struct stksess *entry;  /* last entry we were trying to dump (or first if NULL) */
+                       long long value;        /* value to compare against */
+                       signed char data_type;  /* type of data to compare, or -1 if none */
+                       signed char data_op;    /* operator (STD_OP_*) when data_type set */
                } table;
                struct {
                        const char *msg;        /* pointer to a persistent message to be returned in PRINT state */
index 836d20d916091fd96e04177d7c27ff383ca17815..a8c832ef86c0e7d282676094e3b367cf4a748651 100644 (file)
@@ -391,6 +391,42 @@ int stats_sock_parse_request(struct stream_interface *si, char *line)
                        }
                        else
                                s->data_ctx.table.target = NULL;
+
+                       s->data_ctx.table.data_type = -1;
+                       if (s->data_ctx.table.target && strncmp(args[3], "data.", 5) == 0) {
+                               /* condition on stored data value */
+                               s->data_ctx.table.data_type = stktable_get_data_type(args[3] + 5);
+                               if (s->data_ctx.table.data_type < 0) {
+                                       s->data_ctx.cli.msg = "Unknown data type\n";
+                                       si->st0 = STAT_CLI_PRINT;
+                                       return 1;
+                               }
+
+                               if (!((struct proxy *)s->data_ctx.table.target)->table.data_ofs[s->data_ctx.table.data_type]) {
+                                       s->data_ctx.cli.msg = "Data type not stored in this table\n";
+                                       si->st0 = STAT_CLI_PRINT;
+                                       return 1;
+                               }
+
+                               s->data_ctx.table.data_op = get_std_op(args[4]);
+                               if (s->data_ctx.table.data_op < 0) {
+                                       s->data_ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
+                                       si->st0 = STAT_CLI_PRINT;
+                                       return 1;
+                               }
+
+                               if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &s->data_ctx.table.value) != 0) {
+                                       s->data_ctx.cli.msg = "Require a valid integer value to compare against\n";
+                                       si->st0 = STAT_CLI_PRINT;
+                                       return 1;
+                               }
+                       }
+                       else if (*args[3]) {
+                               s->data_ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value>\n";
+                               si->st0 = STAT_CLI_PRINT;
+                               return 1;
+                       }
+
                        s->data_ctx.table.proxy = NULL;
                        s->data_ctx.table.entry = NULL;
                        si->st0 = STAT_CLI_O_TAB; // stats_dump_table_to_buffer
@@ -2943,6 +2979,49 @@ int stats_dump_table_to_buffer(struct session *s, struct buffer *rep)
                        break;
 
                case DATA_ST_LIST:
+                       if (s->data_ctx.table.data_type >= 0) {
+                               /* we're filtering on some data contents */
+                               void *ptr;
+                               long long data;
+
+                               dt = s->data_ctx.table.data_type;
+                               ptr = stktable_data_ptr(&s->data_ctx.table.proxy->table,
+                                                       s->data_ctx.table.entry,
+                                                       dt);
+
+                               data = 0;
+                               switch (stktable_data_types[dt].std_type) {
+                               case STD_T_SINT:
+                                       data = stktable_data_cast(ptr, std_t_sint);
+                                       break;
+                               case STD_T_UINT:
+                                       data = stktable_data_cast(ptr, std_t_uint);
+                                       break;
+                               case STD_T_ULL:
+                                       data = stktable_data_cast(ptr, std_t_ull);
+                                       break;
+                               case STD_T_FRQP:
+                                       data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
+                                                                   s->data_ctx.table.proxy->table.data_arg[dt].u);
+                                       break;
+                               }
+
+                               /* skip the entry if the data does not match the test and the value */
+                               if ((data < s->data_ctx.table.value &&
+                                    (s->data_ctx.table.data_op == STD_OP_EQ ||
+                                     s->data_ctx.table.data_op == STD_OP_GT ||
+                                     s->data_ctx.table.data_op == STD_OP_GE)) ||
+                                   (data == s->data_ctx.table.value &&
+                                    (s->data_ctx.table.data_op == STD_OP_NE ||
+                                     s->data_ctx.table.data_op == STD_OP_GT ||
+                                     s->data_ctx.table.data_op == STD_OP_LT)) ||
+                                   (data > s->data_ctx.table.value &&
+                                    (s->data_ctx.table.data_op == STD_OP_EQ ||
+                                     s->data_ctx.table.data_op == STD_OP_LT ||
+                                     s->data_ctx.table.data_op == STD_OP_LE)))
+                                       goto skip_entry;
+                       }
+
                        chunk_printf(&msg, "%p:", s->data_ctx.table.entry);
 
                        if (s->data_ctx.table.proxy->table.type == STKTABLE_TYPE_IP) {
@@ -2996,6 +3075,7 @@ int stats_dump_table_to_buffer(struct session *s, struct buffer *rep)
                        if (buffer_feed_chunk(rep, &msg) >= 0)
                                return 0;
 
+               skip_entry:
                        s->data_ctx.table.entry->ref_cnt--;
 
                        eb = ebmb_next(&s->data_ctx.table.entry->key);