mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-25 07:41:36 +02:00
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:
parent
1fa666681d
commit
3863f97349
@ -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
|
||||||
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user