]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: dns: add DNS statistics
authorBaptiste Assmann <bedis9@gmail.com>
Sat, 16 May 2015 22:33:24 +0000 (00:33 +0200)
committerWilly Tarreau <w@1wt.eu>
Sat, 13 Jun 2015 20:07:35 +0000 (22:07 +0200)
add a new command on the stats socket to print a DNS resolvers section
(including per server) statistics: "show stats resolvers <id>"

doc/configuration.txt
include/types/applet.h
src/dumpstats.c

index 61f113235807065a8146939257dbc73b0757d1ef..63a28304b62c6b6f3aef8040491ad76e3fb3a0e2 100644 (file)
@@ -15257,6 +15257,23 @@ show stat [<iid> <type> <sid>]
     A similar empty line appears at the end of the second block (stats) so that
     the reader knows the output has not been truncated.
 
+show stat resolvers <resolvers section id>
+  Dump statistics for the given resolvers section.
+  For each name server, the following counters are reported:
+    sent: number of DNS requests sent to this server
+    valid: number of DNS valid responses received from this server
+    update: number of DNS responses used to update the server's IP address
+    cname: number of CNAME responses
+    cname_error: CNAME errors encountered with this server
+    any_err: number of empty response (IE: server does not support ANY type)
+    nx: non existent domain response received from this server
+    timeout: how many time this server did not answer in time
+    refused: number of requests refused by this server
+    other: any other DNS errors
+    invalid: invalid DNS response (from a protocol point of view)
+    too_big: too big response
+    outdated: number of response arrived too late (after an other name server)
+
 show table
   Dump general information on all known stick-tables. Their name is returned
   (the name of the proxy which holds them), their type (currently zero, always
index 5efeea553ba514a2a6037dde6ff41c7f95e1fdc8..ff82ef3c50a6ad698ecf34572b3fd5782488ae7c 100644 (file)
@@ -110,6 +110,9 @@ struct appctx {
                        struct list wake_on_read;
                        struct list wake_on_write;
                } hlua;
+               struct {
+                       struct dns_resolvers *ptr;
+               } resolvers;
        } ctx;                                  /* used by stats I/O handlers to dump the stats */
 };
 
index cd19279558b9ac68bdc84d6676eae6dd25500e01..96180fe710378fdb2626f36420fd1c79dcb3b404 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <types/applet.h>
 #include <types/global.h>
+#include <types/dns.h>
 
 #include <proto/backend.h>
 #include <proto/channel.h>
@@ -90,6 +91,7 @@ enum {
        STAT_CLI_O_MLOOK,    /* lookup a map entry */
        STAT_CLI_O_POOLS,    /* dump memory pools */
        STAT_CLI_O_TLSK,     /* list all TLS ticket keys references */
+       STAT_CLI_O_RESOLVERS,/* dump a resolver's section nameservers counters */
 };
 
 /* Actions available for the stats admin forms */
@@ -133,6 +135,7 @@ static int stats_dump_errors_to_buffer(struct stream_interface *si);
 static int stats_table_request(struct stream_interface *si, int show);
 static int stats_dump_proxy_to_buffer(struct stream_interface *si, struct proxy *px, struct uri_auth *uri);
 static int stats_dump_stat_to_buffer(struct stream_interface *si, struct uri_auth *uri);
+static int stats_dump_resolvers_to_buffer(struct stream_interface *si);
 static int stats_pats_list(struct stream_interface *si);
 static int stats_pat_list(struct stream_interface *si);
 static int stats_map_lookup(struct stream_interface *si);
@@ -147,6 +150,7 @@ static void cli_release_handler(struct appctx *appctx);
  *     -> stats_dump_errors_to_buffer()   // "show errors"
  *     -> stats_dump_info_to_buffer()     // "show info"
  *     -> stats_dump_stat_to_buffer()     // "show stat"
+ *        -> stats_dump_resolvers_to_buffer() // "show stat resolver <id>"
  *        -> stats_dump_csv_header()
  *        -> stats_dump_proxy_to_buffer()
  *           -> stats_dump_fe_stats()
@@ -1145,7 +1149,33 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line)
        appctx->ctx.stats.flags = 0;
        if (strcmp(args[0], "show") == 0) {
                if (strcmp(args[1], "stat") == 0) {
-                       if (*args[2] && *args[3] && *args[4]) {
+                       if (strcmp(args[2], "resolvers") == 0) {
+                               struct dns_resolvers *presolvers;
+
+                               if (!*args[3]) {
+                                       appctx->ctx.cli.msg = "Missing resolver section identifier.\n";
+                                       appctx->st0 = STAT_CLI_PRINT;
+                                       return 1;
+                               }
+
+                               appctx->ctx.resolvers.ptr = NULL;
+                               list_for_each_entry(presolvers, &dns_resolvers, list) {
+                                       if (strcmp(presolvers->id, args[3]) == 0) {
+                                               appctx->ctx.resolvers.ptr = presolvers;
+                                               break;
+                                       }
+                               }
+                               if (appctx->ctx.resolvers.ptr == NULL) {
+                                       appctx->ctx.cli.msg = "Can't find resolvers section.\n";
+                                       appctx->st0 = STAT_CLI_PRINT;
+                                       return 1;
+                               }
+
+                               appctx->st2 = STAT_ST_INIT;
+                               appctx->st0 = STAT_CLI_O_RESOLVERS;
+                               return 1;
+                       }
+                       else if (*args[2] && *args[3] && *args[4]) {
                                appctx->ctx.stats.flags |= STAT_BOUND;
                                appctx->ctx.stats.iid = atoi(args[2]);
                                appctx->ctx.stats.type = atoi(args[3]);
@@ -2450,6 +2480,10 @@ static void cli_io_handler(struct appctx *appctx)
                                if (stats_dump_stat_to_buffer(si, NULL))
                                        appctx->st0 = STAT_CLI_PROMPT;
                                break;
+                       case STAT_CLI_O_RESOLVERS:
+                               if (stats_dump_resolvers_to_buffer(si))
+                                       appctx->st0 = STAT_CLI_PROMPT;
+                               break;
                        case STAT_CLI_O_SESS:
                                if (stats_dump_sess_to_buffer(si))
                                        appctx->st0 = STAT_CLI_PROMPT;
@@ -6178,6 +6212,61 @@ static int dump_text_line(struct chunk *out, const char *buf, int bsize, int len
        return ptr;
 }
 
+/* This function dumps counters from all resolvers section and associated name servers.
+ * It returns 0 if the output buffer is full and it needs
+ * to be called again, otherwise non-zero.
+ */
+static int stats_dump_resolvers_to_buffer(struct stream_interface *si)
+{
+       struct appctx *appctx = __objt_appctx(si->end);
+       struct dns_resolvers *presolvers;
+       struct dns_nameserver *pnameserver;
+
+       chunk_reset(&trash);
+
+       switch (appctx->st2) {
+       case STAT_ST_INIT:
+               appctx->st2 = STAT_ST_LIST; /* let's start producing data */
+               /* fall through */
+
+       case STAT_ST_LIST:
+               presolvers = appctx->ctx.resolvers.ptr;
+               chunk_appendf(&trash, "Resolvers section %s\n", presolvers->id);
+               list_for_each_entry(pnameserver, &presolvers->nameserver_list, list) {
+                       chunk_appendf(&trash, " nameserver %s:\n", pnameserver->id);
+                       chunk_appendf(&trash, "  sent: %ld\n", pnameserver->counters.sent);
+                       chunk_appendf(&trash, "  valid: %ld\n", pnameserver->counters.valid);
+                       chunk_appendf(&trash, "  update: %ld\n", pnameserver->counters.update);
+                       chunk_appendf(&trash, "  cname: %ld\n", pnameserver->counters.cname);
+                       chunk_appendf(&trash, "  cname_error: %ld\n", pnameserver->counters.cname_error);
+                       chunk_appendf(&trash, "  any_err: %ld\n", pnameserver->counters.any_err);
+                       chunk_appendf(&trash, "  nx: %ld\n", pnameserver->counters.nx);
+                       chunk_appendf(&trash, "  timeout: %ld\n", pnameserver->counters.timeout);
+                       chunk_appendf(&trash, "  refused: %ld\n", pnameserver->counters.refused);
+                       chunk_appendf(&trash, "  other: %ld\n", pnameserver->counters.other);
+                       chunk_appendf(&trash, "  invalid: %ld\n", pnameserver->counters.invalid);
+                       chunk_appendf(&trash, "  too_big: %ld\n", pnameserver->counters.too_big);
+                       chunk_appendf(&trash, "  outdated: %ld\n", pnameserver->counters.outdated);
+               }
+
+               /* display response */
+               if (bi_putchk(si_ic(si), &trash) == -1) {
+                       /* let's try again later from this session. We add ourselves into
+                        * this session's users so that it can remove us upon termination.
+                        */
+                       si->flags |= SI_FL_WAIT_ROOM;
+                       return 0;
+               }
+
+               appctx->st2 = STAT_ST_FIN;
+               /* fall through */
+
+       default:
+               appctx->st2 = STAT_ST_FIN;
+               return 1;
+       }
+}
+
 /* This function dumps all captured errors onto the stream interface's
  * read buffer. It returns 0 if the output buffer is full and it needs
  * to be called again, otherwise non-zero.