MINOR: dns: add DNS statistics

add a new command on the stats socket to print a DNS resolvers section
(including per server) statistics: "show stats resolvers <id>"
This commit is contained in:
Baptiste Assmann 2015-05-17 00:33:24 +02:00 committed by Willy Tarreau
parent 1fa666681d
commit 3863f97349
3 changed files with 110 additions and 1 deletions

View 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 A similar empty line appears at the end of the second block (stats) so that
the reader knows the output has not been truncated. 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 show table
Dump general information on all known stick-tables. Their name is returned 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 (the name of the proxy which holds them), their type (currently zero, always

View File

@ -110,6 +110,9 @@ struct appctx {
struct list wake_on_read; struct list wake_on_read;
struct list wake_on_write; struct list wake_on_write;
} hlua; } hlua;
struct {
struct dns_resolvers *ptr;
} resolvers;
} ctx; /* used by stats I/O handlers to dump the stats */ } ctx; /* used by stats I/O handlers to dump the stats */
}; };

View File

@ -39,6 +39,7 @@
#include <types/applet.h> #include <types/applet.h>
#include <types/global.h> #include <types/global.h>
#include <types/dns.h>
#include <proto/backend.h> #include <proto/backend.h>
#include <proto/channel.h> #include <proto/channel.h>
@ -90,6 +91,7 @@ enum {
STAT_CLI_O_MLOOK, /* lookup a map entry */ STAT_CLI_O_MLOOK, /* lookup a map entry */
STAT_CLI_O_POOLS, /* dump memory pools */ STAT_CLI_O_POOLS, /* dump memory pools */
STAT_CLI_O_TLSK, /* list all TLS ticket keys references */ 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 */ /* 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_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_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_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_pats_list(struct stream_interface *si);
static int stats_pat_list(struct stream_interface *si); static int stats_pat_list(struct stream_interface *si);
static int stats_map_lookup(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_errors_to_buffer() // "show errors"
* -> stats_dump_info_to_buffer() // "show info" * -> stats_dump_info_to_buffer() // "show info"
* -> stats_dump_stat_to_buffer() // "show stat" * -> stats_dump_stat_to_buffer() // "show stat"
* -> stats_dump_resolvers_to_buffer() // "show stat resolver <id>"
* -> stats_dump_csv_header() * -> stats_dump_csv_header()
* -> stats_dump_proxy_to_buffer() * -> stats_dump_proxy_to_buffer()
* -> stats_dump_fe_stats() * -> 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; appctx->ctx.stats.flags = 0;
if (strcmp(args[0], "show") == 0) { if (strcmp(args[0], "show") == 0) {
if (strcmp(args[1], "stat") == 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.flags |= STAT_BOUND;
appctx->ctx.stats.iid = atoi(args[2]); appctx->ctx.stats.iid = atoi(args[2]);
appctx->ctx.stats.type = atoi(args[3]); 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)) if (stats_dump_stat_to_buffer(si, NULL))
appctx->st0 = STAT_CLI_PROMPT; appctx->st0 = STAT_CLI_PROMPT;
break; break;
case STAT_CLI_O_RESOLVERS:
if (stats_dump_resolvers_to_buffer(si))
appctx->st0 = STAT_CLI_PROMPT;
break;
case STAT_CLI_O_SESS: case STAT_CLI_O_SESS:
if (stats_dump_sess_to_buffer(si)) if (stats_dump_sess_to_buffer(si))
appctx->st0 = STAT_CLI_PROMPT; 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; 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 /* 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 * read buffer. It returns 0 if the output buffer is full and it needs
* to be called again, otherwise non-zero. * to be called again, otherwise non-zero.