MINOR: dns/stats: integrate dns counters in stats

Use the new stats module API to integrate the dns counters in the
standard stats. This is done in order to avoid code duplication, keep
the code related to cli out of dns and use the full possibility of the
stats function, allowing to print dns stats in csv or json format.
This commit is contained in:
Amaury Denoyelle 2020-10-05 11:49:46 +02:00 committed by Christopher Faulet
parent 0b70a8a314
commit fbd0bc98fe
7 changed files with 374 additions and 59 deletions

View File

@ -945,7 +945,9 @@ 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.
multiple components of HAProxy. There are two domains avaiable: proxy and dns.
If not specified, the proxy domain is selected. Note that only the proxy
statistics are printed on the HTTP page.
9.1. CSV format
---------------

View File

@ -27,6 +27,7 @@
#include <haproxy/connection-t.h>
#include <haproxy/dgram-t.h>
#include <haproxy/obj_type-t.h>
#include <haproxy/stats-t.h>
#include <haproxy/task-t.h>
#include <haproxy/thread.h>
@ -210,26 +211,31 @@ struct dns_nameserver {
struct dgram_conn *dgram; /* transport layer */
struct sockaddr_storage addr; /* IP address */
struct { /* numbers relted to this name server: */
long long sent; /* - queries sent */
long long snd_error; /* - sending errors */
long long valid; /* - valid response */
long long update; /* - valid response used to update server's IP */
long long cname; /* - CNAME response requiring new resolution */
long long cname_error; /* - error when resolving CNAMEs */
long long any_err; /* - void response (usually because ANY qtype) */
long long nx; /* - NX response */
long long timeout; /* - queries which reached timeout */
long long refused; /* - queries refused */
long long other; /* - other type of response */
long long invalid; /* - malformed DNS response */
long long too_big; /* - too big response */
long long outdated; /* - outdated response (server slower than the other ones) */
long long truncated; /* - truncated response */
} counters;
EXTRA_COUNTERS(extra_counters);
struct dns_counters *counters;
struct list list; /* nameserver chained list */
};
struct dns_counters {
char *id;
long long sent; /* - queries sent */
long long snd_error; /* - sending errors */
long long valid; /* - valid response */
long long update; /* - valid response used to update server's IP */
long long cname; /* - CNAME response requiring new resolution */
long long cname_error; /* - error when resolving CNAMEs */
long long any_err; /* - void response (usually because ANY qtype) */
long long nx; /* - NX response */
long long timeout; /* - queries which reached timeout */
long long refused; /* - queries refused */
long long other; /* - other type of response */
long long invalid; /* - malformed DNS response */
long long too_big; /* - too big response */
long long outdated; /* - outdated response (server slower than the other ones) */
long long truncated; /* - truncated response */;
};
struct dns_options {
int family_prio; /* which IP family should the resolver use when both are returned */
struct {

View File

@ -48,5 +48,10 @@ void dns_trigger_resolution(struct dns_requester *requester);
enum act_parse_ret dns_parse_do_resolve(const char **args, int *orig_arg, struct proxy *px, struct act_rule *rule, char **err);
int check_action_do_resolve(struct act_rule *rule, struct proxy *px, char **err);
int stats_dump_dns(struct stream_interface *si,
struct field *stats, size_t stats_count,
struct list *stat_modules);
void dns_stats_clear_counters(int clrall, struct list *stat_modules);
int dns_allocate_counters(struct list *stat_modules);
#endif // _HAPROXY_DNS_H

View File

@ -51,7 +51,7 @@
#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 */
#define STATS_DOMAIN (0) /* used for bitshifting, type of statistics: proxy or dns */
#define STATS_PX_CAP (8) /* used for bitshifting, differentiate obj1 type for proxy statistics */
/* HTTP stats : applet.st0 */
@ -459,6 +459,7 @@ enum counters_type {
COUNTERS_BE,
COUNTERS_SV,
COUNTERS_LI,
COUNTERS_DNS,
COUNTERS_OFF_END
};
@ -490,6 +491,7 @@ struct extra_counters {
/* stats_domain is used in a flag as a 1 byte field */
enum stats_domain {
STATS_DOMAIN_PROXY = 0,
STATS_DOMAIN_DNS,
STATS_DOMAIN_COUNT,
STATS_DOMAIN_MASK = 0xff

282
src/dns.c
View File

@ -36,7 +36,7 @@
#include <haproxy/proxy.h>
#include <haproxy/sample.h>
#include <haproxy/server.h>
#include <haproxy/stats-t.h>
#include <haproxy/stats.h>
#include <haproxy/stream_interface.h>
#include <haproxy/task.h>
#include <haproxy/tcp_rules.h>
@ -57,6 +57,78 @@ DECLARE_POOL(dns_requester_pool, "dns_requester", sizeof(struct dns_requester)
static unsigned int resolution_uuid = 1;
unsigned int dns_failed_resolutions = 0;
enum {
DNS_STAT_ID,
DNS_STAT_SND_ERROR,
DNS_STAT_VALID,
DNS_STAT_UPDATE,
DNS_STAT_CNAME,
DNS_STAT_CNAME_ERROR,
DNS_STAT_ANY_ERR,
DNS_STAT_NX,
DNS_STAT_TIMEOUT,
DNS_STAT_REFUSED,
DNS_STAT_OTHER,
DNS_STAT_INVALID,
DNS_STAT_TOO_BIG,
DNS_STAT_TRUNCATED,
DNS_STAT_OUTDATED,
DNS_STAT_END,
};
static struct name_desc dns_stats[] = {
[DNS_STAT_ID] = { .name = "id", .desc = "ID" },
[DNS_STAT_SND_ERROR] = { .name = "send_error", .desc = "Send error" },
[DNS_STAT_VALID] = { .name = "valid", .desc = "Valid" },
[DNS_STAT_UPDATE] = { .name = "update", .desc = "Update" },
[DNS_STAT_CNAME] = { .name = "cname", .desc = "CNAME" },
[DNS_STAT_CNAME_ERROR] = { .name = "cname_error", .desc = "CNAME error" },
[DNS_STAT_ANY_ERR] = { .name = "any_err", .desc = "Any errors" },
[DNS_STAT_NX] = { .name = "nx", .desc = "NX" },
[DNS_STAT_TIMEOUT] = { .name = "timeout", .desc = "Timeout" },
[DNS_STAT_REFUSED] = { .name = "refused", .desc = "Refused" },
[DNS_STAT_OTHER] = { .name = "other", .desc = "Other" },
[DNS_STAT_INVALID] = { .name = "invalid", .desc = "Invalid" },
[DNS_STAT_TOO_BIG] = { .name = "too_big", .desc = "Too big" },
[DNS_STAT_TRUNCATED] = { .name = "truncated", .desc = "Truncated" },
[DNS_STAT_OUTDATED] = { .name = "outdated", .desc = "Outdated" },
};
static struct dns_counters dns_counters;
static void dns_fill_stats(void *d, struct field *stats)
{
struct dns_counters *counters = d;
stats[DNS_STAT_ID] = mkf_str(FO_CONFIG, counters->id);
stats[DNS_STAT_SND_ERROR] = mkf_u64(FN_GAUGE, counters->snd_error);
stats[DNS_STAT_VALID] = mkf_u64(FN_GAUGE, counters->valid);
stats[DNS_STAT_UPDATE] = mkf_u64(FN_GAUGE, counters->update);
stats[DNS_STAT_CNAME] = mkf_u64(FN_GAUGE, counters->cname);
stats[DNS_STAT_CNAME_ERROR] = mkf_u64(FN_GAUGE, counters->cname_error);
stats[DNS_STAT_ANY_ERR] = mkf_u64(FN_GAUGE, counters->any_err);
stats[DNS_STAT_NX] = mkf_u64(FN_GAUGE, counters->nx);
stats[DNS_STAT_TIMEOUT] = mkf_u64(FN_GAUGE, counters->timeout);
stats[DNS_STAT_REFUSED] = mkf_u64(FN_GAUGE, counters->refused);
stats[DNS_STAT_OTHER] = mkf_u64(FN_GAUGE, counters->other);
stats[DNS_STAT_INVALID] = mkf_u64(FN_GAUGE, counters->invalid);
stats[DNS_STAT_TOO_BIG] = mkf_u64(FN_GAUGE, counters->too_big);
stats[DNS_STAT_TRUNCATED] = mkf_u64(FN_GAUGE, counters->truncated);
stats[DNS_STAT_OUTDATED] = mkf_u64(FN_GAUGE, counters->outdated);
}
static struct stats_module dns_stats_module = {
.name = "dns",
.domain_flags = STATS_DOMAIN_DNS << STATS_DOMAIN,
.fill_stats = dns_fill_stats,
.stats = dns_stats,
.stats_count = DNS_STAT_END,
.counters = &dns_counters,
.counters_size = sizeof(dns_counters),
.clearable = 0,
};
INITCALL1(STG_REGISTER, stats_register_module, &dns_stats_module);
/* Returns a pointer to the resolvers matching the id <id>. NULL is returned if
* no match is found.
*/
@ -307,7 +379,7 @@ static int dns_send_query(struct dns_resolution *resolution)
ret = send(fd, trash.area, len, 0);
if (ret == len) {
ns->counters.sent++;
ns->counters->sent++;
resolution->nb_queries++;
continue;
}
@ -319,7 +391,7 @@ static int dns_send_query(struct dns_resolution *resolution)
}
snd_error:
ns->counters.snd_error++;
ns->counters->snd_error++;
resolution->nb_queries++;
}
@ -1834,7 +1906,7 @@ static void dns_resolve_recv(struct dgram_conn *dgram)
/* message too big */
if (buflen > resolvers->accepted_payload_size) {
ns->counters.too_big++;
ns->counters->too_big++;
continue;
}
@ -1843,7 +1915,7 @@ static void dns_resolve_recv(struct dgram_conn *dgram)
/* read the query id from the packet (16 bits) */
if (buf + 2 > bufend) {
ns->counters.invalid++;
ns->counters->invalid++;
continue;
}
query_id = dns_response_get_query_id(buf);
@ -1852,7 +1924,7 @@ static void dns_resolve_recv(struct dgram_conn *dgram)
eb = eb32_lookup(&resolvers->query_ids, query_id);
if (eb == NULL) {
/* unknown query id means an outdated response and can be safely ignored */
ns->counters.outdated++;
ns->counters->outdated++;
continue;
}
@ -1872,39 +1944,39 @@ static void dns_resolve_recv(struct dgram_conn *dgram)
case DNS_RESP_QUERY_COUNT_ERROR:
case DNS_RESP_WRONG_NAME:
res->status = RSLV_STATUS_INVALID;
ns->counters.invalid++;
ns->counters->invalid++;
break;
case DNS_RESP_NX_DOMAIN:
res->status = RSLV_STATUS_NX;
ns->counters.nx++;
ns->counters->nx++;
break;
case DNS_RESP_REFUSED:
res->status = RSLV_STATUS_REFUSED;
ns->counters.refused++;
ns->counters->refused++;
break;
case DNS_RESP_ANCOUNT_ZERO:
res->status = RSLV_STATUS_OTHER;
ns->counters.any_err++;
ns->counters->any_err++;
break;
case DNS_RESP_CNAME_ERROR:
res->status = RSLV_STATUS_OTHER;
ns->counters.cname_error++;
ns->counters->cname_error++;
break;
case DNS_RESP_TRUNCATED:
res->status = RSLV_STATUS_OTHER;
ns->counters.truncated++;
ns->counters->truncated++;
break;
case DNS_RESP_NO_EXPECTED_RECORD:
case DNS_RESP_ERROR:
case DNS_RESP_INTERNAL:
res->status = RSLV_STATUS_OTHER;
ns->counters.other++;
ns->counters->other++;
break;
}
@ -1943,14 +2015,14 @@ static void dns_resolve_recv(struct dgram_conn *dgram)
query = LIST_NEXT(&res->response.query_list, struct dns_query_item *, list);
if (query && dns_hostname_cmp(query->name, res->hostname_dn, res->hostname_dn_len) != 0) {
dns_resp = DNS_RESP_WRONG_NAME;
ns->counters.other++;
ns->counters->other++;
goto report_res_error;
}
/* So the resolution succeeded */
res->status = RSLV_STATUS_VALID;
res->last_valid = now_ms;
ns->counters.valid++;
ns->counters->valid++;
goto report_res_success;
report_res_error:
@ -2032,12 +2104,13 @@ static void dns_resolve_send(struct dgram_conn *dgram)
goto snd_error;
}
ns->counters.sent++;
ns->counters->sent++;
res->nb_queries++;
continue;
snd_error:
ns->counters.snd_error++;
ns->counters->snd_error++;
res->nb_queries++;
}
HA_SPIN_UNLOCK(DNS_LOCK, &resolvers->lock);
@ -2144,6 +2217,7 @@ static void dns_deinit(void)
fd_delete(ns->dgram->t.sock.fd);
free(ns->dgram);
LIST_DEL(&ns->list);
EXTRA_COUNTERS_FREE(ns->extra_counters);
free(ns);
}
@ -2229,6 +2303,12 @@ static int dns_finalize_config(void)
dgram->data = &resolve_dgram_cb;
dgram->t.sock.fd = -1;
ns->dgram = dgram;
/* Store the ns counters pointer */
if (ns->extra_counters) {
ns->counters = EXTRA_COUNTERS_GET(ns->extra_counters, &dns_stats_module);
ns->counters->id = ns->id;
}
}
/* Create the task associated to the resolvers section */
@ -2290,6 +2370,144 @@ static int dns_finalize_config(void)
}
static int stats_dump_dns_to_buffer(struct stream_interface *si,
struct dns_nameserver *ns,
struct field *stats, size_t stats_count,
struct list *stat_modules)
{
struct appctx *appctx = __objt_appctx(si->end);
struct channel *rep = si_ic(si);
struct stats_module *mod;
size_t idx = 0;
memset(stats, 0, sizeof(struct field) * stats_count);
list_for_each_entry(mod, stat_modules, list) {
struct counters_node *counters = EXTRA_COUNTERS_GET(ns->extra_counters, mod);
mod->fill_stats(counters, stats + idx);
idx += mod->stats_count;
}
if (!stats_dump_one_line(stats, idx, appctx))
return 0;
if (!stats_putchk(rep, NULL, &trash))
goto full;
return 1;
full:
si_rx_room_rdy(si);
return 0;
}
/* Uses <appctx.ctx.stats.obj1> as a pointer to the current resolver and <obj2>
* as a pointer to the current nameserver.
*/
int stats_dump_dns(struct stream_interface *si,
struct field *stats, size_t stats_count,
struct list *stat_modules)
{
struct appctx *appctx = __objt_appctx(si->end);
struct channel *rep = si_ic(si);
struct dns_resolvers *resolver = appctx->ctx.stats.obj1;
struct dns_nameserver *ns = appctx->ctx.stats.obj2;
if (!resolver)
resolver = LIST_NEXT(&dns_resolvers, struct dns_resolvers *, list);
/* dump resolvers */
list_for_each_entry_from(resolver, &dns_resolvers, list) {
appctx->ctx.stats.obj1 = resolver;
ns = appctx->ctx.stats.obj2 ?
appctx->ctx.stats.obj2 :
LIST_NEXT(&resolver->nameservers, struct dns_nameserver *, list);
list_for_each_entry_from(ns, &resolver->nameservers, list) {
appctx->ctx.stats.obj2 = ns;
if (buffer_almost_full(&rep->buf))
goto full;
if (!stats_dump_dns_to_buffer(si, ns,
stats, stats_count,
stat_modules)) {
return 0;
}
}
appctx->ctx.stats.obj2 = NULL;
}
return 1;
full:
si_rx_room_blk(si);
return 0;
}
void dns_stats_clear_counters(int clrall, struct list *stat_modules)
{
struct dns_resolvers *resolvers;
struct dns_nameserver *ns;
struct stats_module *mod;
void *counters;
list_for_each_entry(mod, stat_modules, list) {
if (!mod->clearable && !clrall)
continue;
list_for_each_entry(resolvers, &dns_resolvers, list) {
list_for_each_entry(ns, &resolvers->nameservers, list) {
counters = EXTRA_COUNTERS_GET(ns->extra_counters, mod);
memcpy(counters, mod->counters, mod->counters_size);
}
}
}
}
int dns_allocate_counters(struct list *stat_modules)
{
struct stats_module *mod;
struct dns_resolvers *resolvers;
struct dns_nameserver *ns;
list_for_each_entry(resolvers, &dns_resolvers, list) {
list_for_each_entry(ns, &resolvers->nameservers, list) {
EXTRA_COUNTERS_REGISTER(&ns->extra_counters, COUNTERS_DNS,
alloc_failed);
list_for_each_entry(mod, stat_modules, list) {
EXTRA_COUNTERS_ADD(mod,
ns->extra_counters,
mod->counters,
mod->counters_size);
}
EXTRA_COUNTERS_ALLOC(ns->extra_counters, alloc_failed);
list_for_each_entry(mod, stat_modules, list) {
memcpy(ns->extra_counters->data + mod->counters_off[ns->extra_counters->type],
mod->counters, mod->counters_size);
/* Store the ns counters pointer */
if (!strcmp(mod->name, "dns")) {
ns->counters = (struct dns_counters *)ns->extra_counters->data + mod->counters_off[COUNTERS_DNS];
ns->counters->id = ns->id;
}
}
}
}
return 1;
alloc_failed:
return 0;
}
/* if an arg is found, it sets the resolvers section pointer into cli.p0 */
static int cli_parse_stat_resolvers(char **args, char *payload, struct appctx *appctx, void *private)
{
@ -2338,21 +2556,21 @@ static int cli_io_handler_dump_resolvers_to_buffer(struct appctx *appctx)
chunk_appendf(&trash, "Resolvers section %s\n", resolvers->id);
list_for_each_entry(ns, &resolvers->nameservers, list) {
chunk_appendf(&trash, " nameserver %s:\n", ns->id);
chunk_appendf(&trash, " sent: %lld\n", ns->counters.sent);
chunk_appendf(&trash, " snd_error: %lld\n", ns->counters.snd_error);
chunk_appendf(&trash, " valid: %lld\n", ns->counters.valid);
chunk_appendf(&trash, " update: %lld\n", ns->counters.update);
chunk_appendf(&trash, " cname: %lld\n", ns->counters.cname);
chunk_appendf(&trash, " cname_error: %lld\n", ns->counters.cname_error);
chunk_appendf(&trash, " any_err: %lld\n", ns->counters.any_err);
chunk_appendf(&trash, " nx: %lld\n", ns->counters.nx);
chunk_appendf(&trash, " timeout: %lld\n", ns->counters.timeout);
chunk_appendf(&trash, " refused: %lld\n", ns->counters.refused);
chunk_appendf(&trash, " other: %lld\n", ns->counters.other);
chunk_appendf(&trash, " invalid: %lld\n", ns->counters.invalid);
chunk_appendf(&trash, " too_big: %lld\n", ns->counters.too_big);
chunk_appendf(&trash, " truncated: %lld\n", ns->counters.truncated);
chunk_appendf(&trash, " outdated: %lld\n", ns->counters.outdated);
chunk_appendf(&trash, " sent: %lld\n", ns->counters->sent);
chunk_appendf(&trash, " snd_error: %lld\n", ns->counters->snd_error);
chunk_appendf(&trash, " valid: %lld\n", ns->counters->valid);
chunk_appendf(&trash, " update: %lld\n", ns->counters->update);
chunk_appendf(&trash, " cname: %lld\n", ns->counters->cname);
chunk_appendf(&trash, " cname_error: %lld\n", ns->counters->cname_error);
chunk_appendf(&trash, " any_err: %lld\n", ns->counters->any_err);
chunk_appendf(&trash, " nx: %lld\n", ns->counters->nx);
chunk_appendf(&trash, " timeout: %lld\n", ns->counters->timeout);
chunk_appendf(&trash, " refused: %lld\n", ns->counters->refused);
chunk_appendf(&trash, " other: %lld\n", ns->counters->other);
chunk_appendf(&trash, " invalid: %lld\n", ns->counters->invalid);
chunk_appendf(&trash, " too_big: %lld\n", ns->counters->too_big);
chunk_appendf(&trash, " truncated: %lld\n", ns->counters->truncated);
chunk_appendf(&trash, " outdated: %lld\n", ns->counters->outdated);
}
chunk_appendf(&trash, "\n");
}

View File

@ -3868,7 +3868,7 @@ int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *na
save_ip:
if (nameserver) {
nameserver->counters.update++;
nameserver->counters->update++;
/* save the first ip we found */
chunk_printf(chk, "%s/%s", nameserver->resolvers->id, nameserver->id);
}
@ -3882,7 +3882,7 @@ int snr_resolution_cb(struct dns_requester *requester, struct dns_nameserver *na
invalid:
if (nameserver) {
nameserver->counters.invalid++;
nameserver->counters->invalid++;
goto update_status;
}
snr_update_srv_status(s, has_no_ip);

View File

@ -265,6 +265,7 @@ static struct field *stat_l[STATS_DOMAIN_COUNT];
/* list of all registered stats module */
static struct list stats_module_list[STATS_DOMAIN_COUNT] = {
LIST_HEAD_INIT(stats_module_list[STATS_DOMAIN_PROXY]),
LIST_HEAD_INIT(stats_module_list[STATS_DOMAIN_DNS]),
};
static inline uint8_t stats_get_domain(uint32_t domain)
@ -604,6 +605,11 @@ static int stats_dump_fields_typed(struct buffer *out,
stats[ST_F_PID].u.u32);
break;
case STATS_DOMAIN_DNS:
chunk_appendf(out, "D.%d.%s:", field,
stat_f[domain][field].name);
break;
default:
break;
}
@ -701,6 +707,18 @@ static void stats_print_proxy_field_json(struct buffer *out,
obj_type, iid, sid, pos, name, pid);
}
static void stats_print_dns_field_json(struct buffer *out,
const struct field *stat,
const char *name,
int pos)
{
chunk_appendf(out,
"{"
"\"field\":{\"pos\":%d,\"name\":\"%s\"},",
pos, name);
}
/* 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,
@ -734,6 +752,10 @@ static int stats_dump_fields_json(struct buffer *out,
stats[ST_F_IID].u.u32,
stats[ST_F_SID].u.u32,
stats[ST_F_PID].u.u32);
} else if (domain == STATS_DOMAIN_DNS) {
stats_print_dns_field_json(out, &stats[field],
stat_f[domain][field].name,
field);
}
if (old_len == out->data)
@ -3052,6 +3074,7 @@ static int stats_dump_stat_to_buffer(struct stream_interface *si, struct htx *ht
{
struct appctx *appctx = __objt_appctx(si->end);
struct channel *rep = si_ic(si);
enum stats_domain domain = appctx->ctx.stats.domain;
chunk_reset(&trash);
@ -3087,15 +3110,30 @@ static int stats_dump_stat_to_buffer(struct stream_interface *si, struct htx *ht
goto full;
}
appctx->ctx.stats.obj1 = proxies_list;
if (domain == STATS_DOMAIN_PROXY)
appctx->ctx.stats.obj1 = proxies_list;
appctx->ctx.stats.px_st = STAT_PX_ST_INIT;
appctx->st2 = STAT_ST_LIST;
/* fall through */
case STAT_ST_LIST:
/* dump proxies */
if (!stats_dump_proxies(si, htx, uri))
return 0;
switch (domain) {
case STATS_DOMAIN_DNS:
if (!stats_dump_dns(si, stat_l[domain],
stat_count[domain],
&stats_module_list[domain])) {
return 0;
}
break;
case STATS_DOMAIN_PROXY:
default:
/* dump proxies */
if (!stats_dump_proxies(si, htx, uri))
return 0;
break;
}
appctx->st2 = STAT_ST_END;
/* fall through */
@ -4194,6 +4232,8 @@ static int cli_parse_clear_counters(char **args, char *payload, struct appctx *a
}
}
dns_stats_clear_counters(clrall, &stats_module_list[STATS_DOMAIN_DNS]);
memset(activity, 0, sizeof(activity));
return 1;
}
@ -4236,10 +4276,14 @@ static int cli_parse_show_stat(char **args, char *payload, struct appctx *appctx
if (!strcmp(args[arg], "domain")) {
++args;
if (!strcmp(args[arg], "proxy"))
if (!strcmp(args[arg], "proxy")) {
++args;
else
} else if (!strcmp(args[arg], "dns")) {
appctx->ctx.stats.domain = STATS_DOMAIN_DNS;
++args;
} else {
return cli_err(appctx, "Invalid statistics domain.\n");
}
}
if (appctx->ctx.stats.domain == STATS_DOMAIN_PROXY
@ -4417,6 +4461,44 @@ static int allocate_stats_px_postcheck(void)
REGISTER_CONFIG_POSTPARSER("allocate-stats-px", allocate_stats_px_postcheck);
static int allocate_stats_dns_postcheck(void)
{
struct stats_module *mod;
size_t i = 0;
int err_code = 0;
stat_f[STATS_DOMAIN_DNS] = malloc(stat_count[STATS_DOMAIN_DNS] * sizeof(struct name_desc));
if (!stat_f[STATS_DOMAIN_DNS]) {
ha_alert("stats: cannot allocate all fields for dns statistics\n");
err_code |= ERR_ALERT | ERR_FATAL;
return err_code;
}
list_for_each_entry(mod, &stats_module_list[STATS_DOMAIN_DNS], list) {
memcpy(stat_f[STATS_DOMAIN_DNS] + i,
mod->stats,
mod->stats_count * sizeof(struct name_desc));
i += mod->stats_count;
}
if (!dns_allocate_counters(&stats_module_list[STATS_DOMAIN_DNS])) {
ha_alert("stats: cannot allocate all counters for dns statistics\n");
err_code |= ERR_ALERT | ERR_FATAL;
return err_code;
}
stat_l[STATS_DOMAIN_DNS] = malloc(stat_count[STATS_DOMAIN_DNS] * sizeof(struct field));
if (!stat_l[STATS_DOMAIN_DNS]) {
ha_alert("stats: cannot allocate a line for dns statistics\n");
err_code |= ERR_ALERT | ERR_FATAL;
return err_code;
}
return err_code;
}
REGISTER_CONFIG_POSTPARSER("allocate-stats-dns", allocate_stats_dns_postcheck);
/* register cli keywords */
static struct cli_kw_list cli_kws = {{ },{
{ { "clear", "counters", NULL }, "clear counters : clear max statistics counters (add 'all' for all counters)", cli_parse_clear_counters, NULL, NULL },