From 37a1c614ab2e5521161428a29f1178154aeda69d Mon Sep 17 00:00:00 2001 From: Jannik Peters Date: Fri, 31 Jan 2025 14:39:37 +0100 Subject: [PATCH 1/9] Add metrics configure option and make target --- Makefile.in | 5 ++++- configure.ac | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 5d2c2124..7c6c3a06 100644 --- a/Makefile.in +++ b/Makefile.in @@ -31,6 +31,8 @@ chrootdir= @chrootdir@ user = @user@ DNSTAP_SRC=@DNSTAP_SRC@ DNSTAP_OBJ=@DNSTAP_OBJ@ +METRICS_SRC=@METRICS_SRC@ +METRICS_OBJ=@METRICS_OBJ@ # override $U variable which is used by autotools for deansification (for # K&R C compilers), but causes problems if $U is defined in the env). @@ -88,7 +90,7 @@ TARGETS=nsd nsd-checkconf nsd-checkzone nsd-control nsd.conf.sample nsd-control- MANUALS=nsd.8 nsd-checkconf.8 nsd-checkzone.8 nsd-control.8 nsd.conf.5 COMMON_OBJ=answer.o axfr.o ixfr.o ixfrcreate.o buffer.o configlexer.o configparser.o dname.o dns.o edns.o iterated_hash.o lookup3.o namedb.o nsec3.o options.o packet.o query.o rbtree.o radtree.o rdata.o region-allocator.o rrl.o siphash.o tsig.o tsig-openssl.o udb.o util.o bitset.o popen3.o proxy_protocol.o -XFRD_OBJ=xfrd-catalog-zones.o xfrd-disk.o xfrd-notify.o xfrd-tcp.o xfrd.o remote.o $(DNSTAP_OBJ) +XFRD_OBJ=xfrd-catalog-zones.o xfrd-disk.o xfrd-notify.o xfrd-tcp.o xfrd.o remote.o $(METRICS_OBJ) $(DNSTAP_OBJ) NSD_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) difffile.o ipc.o mini_event.o netio.o nsd.o server.o dbaccess.o dbcreate.o zonec.o verify.o ALL_OBJ=$(NSD_OBJ) nsd-checkconf.o nsd-checkzone.o nsd-control.o nsd-mem.o xfr-inspect.o NSD_CHECKCONF_OBJ=$(COMMON_OBJ) nsd-checkconf.o @@ -408,6 +410,7 @@ configparser.o: configparser.c config.h configparser.h options.o: $(srcdir)/options.c config.h configparser.h dns.o: $(srcdir)/dns.c config.h zonec.o: $(srcdir)/zonec.c config.h +metrics.o: $(srcdir)/metrics.c config.h # dnstap dnstap.o: $(srcdir)/dnstap/dnstap.c config.h dnstap/dnstap_config.h \ diff --git a/configure.ac b/configure.ac index b1a812d0..23796451 100644 --- a/configure.ac +++ b/configure.ac @@ -1157,6 +1157,19 @@ case "$enable_packed" in ;; esac +AC_ARG_ENABLE(metrics, AS_HELP_STRING([--enable-metrics],[Enable prometheus metrics support.])) +case "$enable_metrics" in + yes) + AC_DEFINE_UNQUOTED([USE_METRICS], [], [Define this to expose NSD statistics via a prometheus metrics HTTP endpoint.]) + AC_DEFINE_UNQUOTED([NSD_METRICS_PORT], [9100], [Define to the default metrics HTTP endpoint port.]) + AC_SEARCH_LIBS(evhttp_free, [event], , AC_MSG_ERROR(Cannot find libevent, but is needed for prometheus metrics support.)) + AC_SUBST([METRICS_SRC], ["metrics.c"]) + AC_SUBST([METRICS_OBJ], ["metrics.o"]) + ;; + no|*) + ;; +esac + # check for dnstap if requested dt_DNSTAP([${localstatedir}/run/nsd-dnstap.sock], [ From 88ee960244f8b2dd7f13e103f4edecc54925f37b Mon Sep 17 00:00:00 2001 From: Jannik Peters Date: Fri, 31 Jan 2025 15:04:00 +0100 Subject: [PATCH 2/9] Add metrics configuration options --- configlexer.lex | 4 ++++ configparser.y | 38 ++++++++++++++++++++++++++++++++++++++ options.c | 10 ++++++++++ options.h | 11 +++++++++++ 4 files changed, 63 insertions(+) diff --git a/configlexer.lex b/configlexer.lex index e3dbc9cc..ce3e6a16 100644 --- a/configlexer.lex +++ b/configlexer.lex @@ -258,6 +258,10 @@ server-key-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_KEY_FILE; server-cert-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_CERT_FILE;} control-key-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_KEY_FILE;} control-cert-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CONTROL_CERT_FILE;} +metrics-enable{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_METRICS_ENABLE;} +metrics-interface{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_METRICS_INTERFACE;} +metrics-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_METRICS_PORT;} +metrics-path{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_METRICS_PATH;} AXFR { LEXOUT(("v(%s) ", yytext)); return VAR_AXFR;} UDP { LEXOUT(("v(%s) ", yytext)); return VAR_UDP;} rrl-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RRL_SIZE;} diff --git a/configparser.y b/configparser.y index 9204bb7f..2cd67b9f 100644 --- a/configparser.y +++ b/configparser.y @@ -139,6 +139,10 @@ struct component { %token VAR_DROP_UPDATES %token VAR_XFRD_TCP_MAX %token VAR_XFRD_TCP_PIPELINE +%token VAR_METRICS_ENABLE +%token VAR_METRICS_INTERFACE +%token VAR_METRICS_PORT +%token VAR_METRICS_PATH /* dnstap */ %token VAR_DNSTAP @@ -588,6 +592,40 @@ server_option: } } } + | VAR_METRICS_ENABLE boolean + { +#ifdef USE_METRICS + cfg_parser->opt->metrics_enable = $2; +#endif /* USE_METRICS */ + } + | VAR_METRICS_INTERFACE ip_address + { +#ifdef USE_METRICS + struct ip_address_option *ip = cfg_parser->opt->metrics_interface; + if(ip == NULL) { + cfg_parser->opt->metrics_interface = $2; + } else { + while(ip->next != NULL) { ip = ip->next; } + ip->next = $2; + } +#endif /* USE_METRICS */ + } + | VAR_METRICS_PORT number + { +#ifdef USE_METRICS + if($2 == 0) { + yyerror("metrics port number expected"); + } else { + cfg_parser->opt->metrics_port = (int)$2; + } +#endif /* USE_METRICS */ + } + | VAR_METRICS_PATH STRING + { +#ifdef USE_METRICS + cfg_parser->opt->metrics_path = region_strdup(cfg_parser->opt->region, $2); +#endif /* USE_METRICS */ + } ; socket_options: diff --git a/options.c b/options.c index ee8011f8..20dd76f6 100644 --- a/options.c +++ b/options.c @@ -162,6 +162,12 @@ nsd_options_create(region_type* region) opt->server_cert_file = CONFIGDIR"/nsd_server.pem"; opt->control_key_file = CONFIGDIR"/nsd_control.key"; opt->control_cert_file = CONFIGDIR"/nsd_control.pem"; +#ifdef USE_METRICS + opt->metrics_enable = 0; + opt->metrics_interface = NULL; + opt->metrics_port = NSD_METRICS_PORT; + opt->metrics_path = "/metrics"; +#endif /* USE_METRICS */ opt->verify_enable = 0; opt->verify_ip_addresses = NULL; @@ -3082,6 +3088,10 @@ resolve_interface_names(struct nsd_options* options) addrs, options->region); resolve_interface_names_for_ref(&options->control_interface, addrs, options->region); +#ifdef USE_METRICS + resolve_interface_names_for_ref(&options->metrics_interface, + addrs, options->region); +#endif /* USE_METRICS */ freeifaddrs(addrs); #else diff --git a/options.h b/options.h index 2567a62d..f92f9211 100644 --- a/options.h +++ b/options.h @@ -163,6 +163,17 @@ struct nsd_options { /** certificate file for nsd-control */ char* control_cert_file; +#ifdef USE_METRICS + /** metrics section. enable toggle. */ + int metrics_enable; + /** the interfaces the metrics endpoint should listen on */ + struct ip_address_option* metrics_interface; + /** port number for the metrics endpoint */ + int metrics_port; + /** HTTP path for the metrics endpoint */ + char* metrics_path; +#endif /* USE_METRICS */ + #ifdef RATELIMIT /** number of buckets in rrl hashtable */ size_t rrl_size; From 3e6017da8173ab4c008e98e56d61ec672d901d1b Mon Sep 17 00:00:00 2001 From: Jannik Peters Date: Mon, 10 Feb 2025 17:04:39 +0100 Subject: [PATCH 3/9] Implement prometheus metrics endpoint --- metrics.c | 848 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ metrics.h | 57 ++++ 2 files changed, 905 insertions(+) create mode 100644 metrics.c create mode 100644 metrics.h diff --git a/metrics.c b/metrics.c new file mode 100644 index 00000000..6da5f4d4 --- /dev/null +++ b/metrics.c @@ -0,0 +1,848 @@ +/* + * metrics.c -- prometheus metrics endpoint + * + * Copyright (c) 2001-2025, NLnet Labs. All rights reserved. + * + * See LICENSE for the license. + * + */ + +#include "config.h" + +#ifdef USE_METRICS + +#include +#include +#include +#include +#include +#ifndef USE_MINI_EVENT +# include +#else +# warning "Using metrics with mini_event is untested, and libevent is needed anyway for http" +# include "mini_event.h" +#endif +#include "event2/http.h" +#include "nsd.h" +#include "xfrd.h" +#include "options.h" +#include "ipc.h" +/* remote.h: re-using create_local_accept_sock as it happens to not be static + * and is not remote control specific (w.r.t. log messages and ssl). + */ +#include "remote.h" +#include "metrics.h" + +/** if you want zero to be inhibited in stats output. + * it omits zeroes for types that have no acronym and unused-rcodes */ +const int metrics_inhibit_zero = 1; + +/** + * list of events for accepting connections + */ +struct metrics_acceptlist { + struct metrics_acceptlist* next; + int accept_fd; + char* ident; + struct daemon_metrics* metrics; +}; + +/** + * The metrics daemon state. + */ +struct daemon_metrics { + /** the master process for this metrics daemon */ + struct xfrd_state* xfrd; + /** commpoints for accepting HTTP connections */ + struct metrics_acceptlist* accept_list; + /** last time stats was reported */ + struct timeval stats_time, boot_time; + /** libevent http server */ + struct evhttp *http_server; +}; + +static void +metrics_http_callback(struct evhttp_request *req, void *p); + +#ifdef BIND8_STATS +static void +process_stats(struct evbuffer* buf, xfrd_state_type* xfrd, int peek); + +static void +do_stats(struct evbuffer *buf, xfrd_state_type *xfrd, int peek); +#endif /*BIND8_STATS*/ + +struct daemon_metrics* +daemon_metrics_create(struct nsd_options* cfg) +{ + struct daemon_metrics* metrics = (struct daemon_metrics*)xalloc_zero( + sizeof(*metrics)); + assert(cfg->metrics_enable); + + /* and try to open the ports */ + if(!daemon_metrics_open_ports(metrics, cfg)) { + log_msg(LOG_ERR, "could not open metrics port"); + daemon_metrics_delete(metrics); + return NULL; + } + + if(gettimeofday(&metrics->boot_time, NULL) == -1) + log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno)); + metrics->stats_time = metrics->boot_time; + + return metrics; +} + +void daemon_metrics_close(struct daemon_metrics* metrics) +{ + struct metrics_acceptlist *h, *nh; + if(!metrics) return; + + /* close listen sockets */ + h = metrics->accept_list; + while(h) { + nh = h->next; + close(h->accept_fd); + free(h->ident); + free(h); + h = nh; + } + metrics->accept_list = NULL; + + if (metrics->http_server) { + evhttp_free(metrics->http_server); + } +} + +void daemon_metrics_delete(struct daemon_metrics* metrics) +{ + if(!metrics) return; + daemon_metrics_close(metrics); + free(metrics); +} + +static int +create_tcp_accept_sock(struct addrinfo* addr, int* noproto) +{ +#if defined(SO_REUSEADDR) || (defined(INET6) && (defined(IPV6_V6ONLY) || defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU))) + int on = 1; +#endif + int s; + *noproto = 0; + if ((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { +#if defined(INET6) + if (addr->ai_family == AF_INET6 && + errno == EAFNOSUPPORT) { + *noproto = 1; + log_msg(LOG_WARNING, "fallback to TCP4, no IPv6: not supported"); + return -1; + } +#endif /* INET6 */ + log_msg(LOG_ERR, "can't create a socket: %s", strerror(errno)); + return -1; + } +#ifdef SO_REUSEADDR + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { + log_msg(LOG_ERR, "setsockopt(..., SO_REUSEADDR, ...) failed: %s", strerror(errno)); + } +#endif /* SO_REUSEADDR */ +#if defined(INET6) && defined(IPV6_V6ONLY) + if (addr->ai_family == AF_INET6 && + setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) + { + log_msg(LOG_ERR, "setsockopt(..., IPV6_V6ONLY, ...) failed: %s", strerror(errno)); + close(s); + return -1; + } +#endif + /* set it nonblocking */ + /* (StevensUNP p463), if tcp listening socket is blocking, then + it may block in accept, even if select() says readable. */ + if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { + log_msg(LOG_ERR, "cannot fcntl tcp: %s", strerror(errno)); + } + /* Bind it... */ + if (bind(s, (struct sockaddr *)addr->ai_addr, addr->ai_addrlen) != 0) { + log_msg(LOG_ERR, "can't bind tcp socket: %s", strerror(errno)); + close(s); + return -1; + } + /* Listen to it... */ + if (listen(s, TCP_BACKLOG_METRICS) == -1) { + log_msg(LOG_ERR, "can't listen: %s", strerror(errno)); + close(s); + return -1; + } + return s; +} + +/** + * Add and open a new metrics port + * @param metrics: metrics with result list. + * @param ip: ip str + * @param nr: port nr + * @param noproto_is_err: if lack of protocol support is an error. + * @return false on failure. + */ +static int +metrics_add_open(struct daemon_metrics* metrics, struct nsd_options* cfg, const char* ip, + int nr, int noproto_is_err) +{ + struct addrinfo hints; + struct addrinfo* res; + struct metrics_acceptlist* hl; + int noproto = 0; + int fd, r; + char port[15]; + snprintf(port, sizeof(port), "%d", nr); + port[sizeof(port)-1]=0; + memset(&hints, 0, sizeof(hints)); + assert(ip); + + if(ip[0] == '/') { + /* This looks like a local socket */ + fd = create_local_accept_sock(ip, &noproto); + /* + * Change socket ownership and permissions so users other + * than root can access it provided they are in the same + * group as the user we run as. + */ + if(fd != -1) { +#ifdef HAVE_CHOWN + if(chmod(ip, (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) { + VERBOSITY(3, (LOG_INFO, "cannot chmod metrics socket %s: %s", ip, strerror(errno))); + } + if (cfg->username && cfg->username[0] && + nsd.uid != (uid_t)-1) { + if(chown(ip, nsd.uid, nsd.gid) == -1) + VERBOSITY(2, (LOG_INFO, "cannot chown %u.%u %s: %s", + (unsigned)nsd.uid, (unsigned)nsd.gid, + ip, strerror(errno))); + } +#else + (void)cfg; +#endif + } + } else { + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + /* if we had no interface ip name, "default" is what we + * would do getaddrinfo for. */ + if((r = getaddrinfo(ip, port, &hints, &res)) != 0 || !res) { + log_msg(LOG_ERR, "metrics interface %s:%s getaddrinfo: %s %s", + ip, port, gai_strerror(r), +#ifdef EAI_SYSTEM + r==EAI_SYSTEM?(char*)strerror(errno):"" +#else + "" +#endif + ); + return 0; + } + + /* open fd */ + fd = create_tcp_accept_sock(res, &noproto); + freeaddrinfo(res); + } + + if(fd == -1 && noproto) { + if(!noproto_is_err) + return 1; /* return success, but do nothing */ + log_msg(LOG_ERR, "cannot open metrics interface %s %d : " + "protocol not supported", ip, nr); + return 0; + } + if(fd == -1) { + log_msg(LOG_ERR, "cannot open metrics interface %s %d", ip, nr); + return 0; + } + + /* alloc */ + hl = (struct metrics_acceptlist*)xalloc_zero(sizeof(*hl)); + hl->metrics = metrics; + hl->ident = strdup(ip); + if(!hl->ident) { + log_msg(LOG_ERR, "malloc failure"); + close(fd); + free(hl); + return 0; + } + hl->next = metrics->accept_list; + metrics->accept_list = hl; + + hl->accept_fd = fd; + return 1; +} + +int +daemon_metrics_open_ports(struct daemon_metrics* metrics, struct nsd_options* cfg) +{ + assert(cfg->metrics_enable && cfg->metrics_port); + if(cfg->metrics_interface) { + ip_address_option_type* p; + for(p = cfg->metrics_interface; p; p = p->next) { + if(!metrics_add_open(metrics, cfg, p->address, cfg->metrics_port, 1)) { + return 0; + } + } + } else { + /* defaults */ + if(cfg->do_ip6 && !metrics_add_open(metrics, cfg, "::1", cfg->metrics_port, 0)) { + return 0; + } + if(cfg->do_ip4 && + !metrics_add_open(metrics, cfg, "127.0.0.1", cfg->metrics_port, 1)) { + return 0; + } + } + return 1; +} + +void +daemon_metrics_attach(struct daemon_metrics* metrics, struct xfrd_state* xfrd) +{ + int fd; + struct metrics_acceptlist* p; + if(!metrics) return; + metrics->xfrd = xfrd; + + metrics->http_server = evhttp_new(xfrd->event_base); + for(p = metrics->accept_list; p; p = p->next) { + fd = p->accept_fd; + if (evhttp_accept_socket(metrics->http_server, fd)) { + log_msg(LOG_ERR, "metrics: cannot set http server to accept socket"); + } + + /* only handle requests to metrics_path, anything else returns 404 */ + evhttp_set_cb(metrics->http_server, + metrics->xfrd->nsd->options->metrics_path, + metrics_http_callback, p); + /* evhttp_set_gencb(metrics->http_server, metrics_http_callback_generic, p); */ + } +} + +/* Callback for handling the active http request to the specific URI */ +static void +metrics_http_callback(struct evhttp_request *req, void *p) +{ + struct daemon_metrics *metrics = ((struct metrics_acceptlist *)p)->metrics; + + /* currently only GET requests are supported/allowed */ + enum evhttp_cmd_type cmd = evhttp_request_get_command(req); + if (cmd != EVHTTP_REQ_GET /* && cmd != EVHTTP_REQ_HEAD */) { + evhttp_send_error(req, HTTP_BADMETHOD, 0); + return; + } + + struct evbuffer *reply = evbuffer_new(); + + if (!reply) { + evhttp_send_error(req, HTTP_INTERNAL, 0); + log_msg(LOG_ERR, "failed to allocate reply buffer\n"); + return; + } + + evhttp_add_header(evhttp_request_get_output_headers(req), + "Content-Type", "text/plain; version=0.0.4"); +#ifdef BIND8_STATS + process_stats(reply, metrics->xfrd, 1); + evhttp_send_reply(req, HTTP_OK, NULL, reply); + VERBOSITY(3, (LOG_INFO, "metrics operation completed, response sent")); +#else + evhttp_send_reply(req, HTTP_NOCONTENT, "No Content - Statistics disabled", reply); + /* TODO: should this be verbosity 3 too? */ + log_msg(LOG_NOTICE, "no stats enabled at compile time\n"); +#endif /* BIND8_STATS */ + + evbuffer_free(reply); +} + +#ifdef BIND8_STATS +/** subtract timers and the values do not overflow or become negative */ +static void +timeval_subtract(struct timeval* d, const struct timeval* end, + const struct timeval* start) +{ +#ifndef S_SPLINT_S + time_t end_usec = end->tv_usec; + d->tv_sec = end->tv_sec - start->tv_sec; + if(end_usec < start->tv_usec) { + end_usec += 1000000; + d->tv_sec--; + } + d->tv_usec = end_usec - start->tv_usec; +#endif +} +static const char* +opcode2str(int o) +{ + switch(o) { + case OPCODE_QUERY: return "QUERY"; + case OPCODE_IQUERY: return "IQUERY"; + case OPCODE_STATUS: return "STATUS"; + case OPCODE_NOTIFY: return "NOTIFY"; + case OPCODE_UPDATE: return "UPDATE"; + default: return "OTHER"; + } +} + +/** print long number*/ +static int +print_longnum(struct evbuffer *buf, char* desc, uint64_t x) +{ + if(x > (uint64_t)1024*1024*1024) { + /*more than a Gb*/ + size_t front = (size_t)(x / (uint64_t)1000000); + size_t back = (size_t)(x % (uint64_t)1000000); + return evbuffer_add_printf(buf, "%s%lu%6.6lu\n", desc, + (unsigned long)front, (unsigned long)back); + } else { + return evbuffer_add_printf(buf, "%s%lu\n", desc, (unsigned long)x); + } +} + +/*print one block of statistics. n is name and d is delimiter*/ +static void +print_stat_block(struct evbuffer *buf, struct nsdst* st) +{ + const char* rcstr[] = {"NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", + "NOTIMP", "REFUSED", "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH", + "NOTZONE", "RCODE11", "RCODE12", "RCODE13", "RCODE14", "RCODE15", + "BADVERS" + }; + size_t i; + for(i=0; i<= 255; i++) { + if(metrics_inhibit_zero && st->qtype[i] == 0 && + strncmp(rrtype_to_string(i), "TYPE", 4) == 0) + continue; + evbuffer_add_printf(buf, "nsd_queries_total{type=\"%s\"} %lu\n", + rrtype_to_string(i), (unsigned long)st->qtype[i]); + } + + /*opcode*/ + for(i=0; i<6; i++) { + if(metrics_inhibit_zero && st->opcode[i] == 0 && i != OPCODE_QUERY) + continue; + evbuffer_add_printf(buf, "nsd_queries_total{opcode=\"%s\"} %lu\n", + opcode2str(i), (unsigned long)st->opcode[i]); + } + + /*qclass*/ + for(i=0; i<4; i++) { + if(metrics_inhibit_zero && st->qclass[i] == 0 && i != CLASS_IN) + continue; + evbuffer_add_printf(buf, "nsd_queries_total{class=\"%s\"} %lu\n", + rrclass_to_string(i), (unsigned long)st->qclass[i]); + } + + /*rcode*/ + for(i=0; i<17; i++) { + if(metrics_inhibit_zero && st->rcode[i] == 0 && + i > RCODE_YXDOMAIN) /*NSD does not use larger*/ + continue; + evbuffer_add_printf(buf, "nsd_queries_total{rcode=\"%s\"} %lu\n", + rcstr[i], (unsigned long)st->rcode[i]); + } + + /*edns*/ + /* TODO: maybe use label? */ + evbuffer_add_printf(buf, "nsd_queries_edns_total %lu\n", (unsigned long)st->edns); + + /*ednserr*/ + /* TODO: maybe use label? */ + evbuffer_add_printf(buf, "nsd_queries_ednserr_total %lu\n", + (unsigned long)st->ednserr); + + /*qudp*/ + /* TODO: maybe use label? */ + evbuffer_add_printf(buf, "nsd_queries_udp_total %lu\n", (unsigned long)st->qudp); + /*qudp6*/ + /* TODO: maybe use label? */ + evbuffer_add_printf(buf, "nsd_queries_udp6_total %lu\n", (unsigned long)st->qudp6); + /*ctcp*/ + evbuffer_add_printf(buf, "nsd_connections_total{transport=\"tcp\"} %lu\n", (unsigned long)st->ctcp); + /*ctcp6*/ + evbuffer_add_printf(buf, "nsd_connections_total{transport=\"tcp6\"} %lu\n", (unsigned long)st->ctcp6); + /*ctls*/ + evbuffer_add_printf(buf, "nsd_connections_total{transport=\"tls\"} %lu\n", (unsigned long)st->ctls); + /*ctls6*/ + evbuffer_add_printf(buf, "nsd_connections_total{transport=\"tls6\"} %lu\n", (unsigned long)st->ctls6); + + /*nona*/ + evbuffer_add_printf(buf, "nsd_answers_without_aa_total %lu\n", + (unsigned long)st->nona); + + /*rxerr*/ + evbuffer_add_printf(buf, "nsd_queries_rxerr_total %lu\n", (unsigned long)st->rxerr); + + /*txerr*/ + evbuffer_add_printf(buf, "nsd_queries_txerr_total %lu\n", (unsigned long)st->txerr); + + /*number of requested-axfr, number of times axfr served to clients*/ + evbuffer_add_printf(buf, "nsd_answered_axfr_requests_total %lu\n", (unsigned long)st->raxfr); + + /*number of requested-ixfr, number of times ixfr served to clients*/ + evbuffer_add_printf(buf, "nsd_answered_ixfr_requests_total %lu\n", (unsigned long)st->rixfr); + + /*truncated*/ + evbuffer_add_printf(buf, "nsd_answers_truncated_total %lu\n", + (unsigned long)st->truncated); + + /*dropped*/ + evbuffer_add_printf(buf, "nsd_queries_dropped_total %lu\n", + (unsigned long)st->dropped); +} + +/*print one block of statistics. n is name and d is delimiter*/ +static void +print_stat_block_with_zone(struct evbuffer *buf, char* n, struct nsdst* st) +{ + const char* rcstr[] = {"NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", + "NOTIMP", "REFUSED", "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH", + "NOTZONE", "RCODE11", "RCODE12", "RCODE13", "RCODE14", "RCODE15", + "BADVERS" + }; + size_t i; + for(i=0; i<= 255; i++) { + if(metrics_inhibit_zero && st->qtype[i] == 0 && + strncmp(rrtype_to_string(i), "TYPE", 4) == 0) + continue; + evbuffer_add_printf(buf, "nsd_queries_total{zone=\"%s\", type=\"%s\"} %lu\n", + n, rrtype_to_string(i), (unsigned long)st->qtype[i]); + } + + /*opcode*/ + for(i=0; i<6; i++) { + if(metrics_inhibit_zero && st->opcode[i] == 0 && i != OPCODE_QUERY) + continue; + evbuffer_add_printf(buf, + "nsd_queries_total{zone=\"%s\", opcode=\"%s\"} %lu\n", + n, opcode2str(i), (unsigned long)st->opcode[i]); + } + + /*qclass*/ + for(i=0; i<4; i++) { + if(metrics_inhibit_zero && st->qclass[i] == 0 && i != CLASS_IN) + continue; + evbuffer_add_printf(buf, + "nsd_queries_total{zone=\"%s\", class=\"%s\"} %lu\n", + n, rrclass_to_string(i), (unsigned long)st->qclass[i]); + } + + /*rcode*/ + for(i=0; i<17; i++) { + if(metrics_inhibit_zero && st->rcode[i] == 0 && + i > RCODE_YXDOMAIN) /*NSD does not use larger*/ + continue; + evbuffer_add_printf(buf, + "nsd_queries_total{zone=\"%s\", rcode=\"%s\"} %lu\n", + n, rcstr[i], (unsigned long)st->rcode[i]); + } + + /*edns*/ + evbuffer_add_printf(buf, "nsd_queries_edns_total{zone=\"%s\"} %lu\n", + n, (unsigned long)st->edns); + + /*ednserr*/ + evbuffer_add_printf(buf, "nsd_queries_ednserr_total{zone=\"%s\"} %lu\n", + n, (unsigned long)st->ednserr); + + /*qudp*/ + evbuffer_add_printf(buf, "nsd_queries_udp_total{zone=\"%s\"} %lu\n", n, (unsigned long)st->qudp); + /*qudp6*/ + evbuffer_add_printf(buf, "nsd_queries_udp6_total{zone=\"%s\"} %lu\n", n, (unsigned long)st->qudp6); + /*ctcp*/ + evbuffer_add_printf(buf, + "nsd_connections_total{zone=\"%s\", transport=\"tcp\"} %lu\n", + n, (unsigned long)st->ctcp); + /*ctcp6*/ + evbuffer_add_printf(buf, + "nsd_connections_total{zone=\"%s\", transport=\"tcp6\"} %lu\n", + n, (unsigned long)st->ctcp6); + /*ctls*/ + evbuffer_add_printf(buf, + "nsd_connections_total{zone=\"%s\", transport=\"tls\"} %lu\n", + n, (unsigned long)st->ctls); + /*ctls6*/ + evbuffer_add_printf(buf, + "nsd_connections_total{zone=\"%s\", transport=\"tls6\"} %lu\n", + n, (unsigned long)st->ctls6); + + /*nona*/ + evbuffer_add_printf(buf, + "nsd_answer_without_aa_total{zone=\"%s\"} %lu\n", + n, (unsigned long)st->nona); + + /*rxerr*/ + evbuffer_add_printf(buf, + "nsd_queries_rxerr_total{zone=\"%s\"} %lu\n", + n, (unsigned long)st->rxerr); + + /*txerr*/ + evbuffer_add_printf(buf, + "nsd_queries_txerr_total{zone=\"%s\"} %lu\n", + n, (unsigned long)st->txerr); + + /*number of requested-axfr, + number of times axfr served to clients*/ + evbuffer_add_printf(buf, + "nsd_answered_axfr_requests_total{zone=\"%s\"} %lu\n", + n, (unsigned long)st->raxfr); + + /*number of requested-ixfr, + number of times ixfr served to clients*/ + evbuffer_add_printf(buf, + "nsd_answered_ixfr_requests_total{zone=\"%s\"} %lu\n", + n, (unsigned long)st->rixfr); + + /*truncated*/ + evbuffer_add_printf(buf, + "nsd_answers_truncated_total{zone=\"%s\"} %lu\n", + n, (unsigned long)st->truncated); + + /*dropped*/ + evbuffer_add_printf(buf, + "nsd_queries_dropped_total{zone=\"%s\"} %lu\n", + n, (unsigned long)st->dropped); +} + +#ifdef USE_ZONE_STATS +static void +resize_zonestat(xfrd_state_type* xfrd, size_t num) +{ + struct nsdst** a = xalloc_array_zero(num, sizeof(struct nsdst*)); + if(xfrd->zonestat_clear_num != 0) + memcpy(a, xfrd->zonestat_clear, xfrd->zonestat_clear_num + * sizeof(struct nsdst*)); + free(xfrd->zonestat_clear); + xfrd->zonestat_clear = a; + xfrd->zonestat_clear_num = num; +} + +static void +zonestat_print(struct evbuffer *buf, xfrd_state_type* xfrd, int clear, + struct nsdst** zonestats) +{ + struct zonestatname* n; + struct nsdst stat0, stat1; + RBTREE_FOR(n, struct zonestatname*, xfrd->nsd->options->zonestatnames){ + char* name = (char*)n->node.key; + if(n->id >= xfrd->zonestat_safe) + continue; /*newly allocated and reload has not yet + done and replied with new size*/ + if(name == NULL || name[0]==0) + continue; /*empty name, do not output*/ + /*the statistics are stored in two blocks, during reload + * the newly forked processes get the other block to use, + * these blocks are mmapped and are currently in use to + * add statistics to*/ + memcpy(&stat0, &zonestats[0][n->id], sizeof(stat0)); + memcpy(&stat1, &zonestats[1][n->id], sizeof(stat1)); + stats_add(&stat0, &stat1); + + /*save a copy of current (cumulative) stats in stat1*/ + memcpy(&stat1, &stat0, sizeof(stat1)); + /*subtract last total of stats that was 'cleared'*/ + if(n->id < xfrd->zonestat_clear_num && + xfrd->zonestat_clear[n->id]) + stats_subtract(&stat0, xfrd->zonestat_clear[n->id]); + if(clear) { + /*extend storage array if needed*/ + if(n->id >= xfrd->zonestat_clear_num) { + if(n->id+1 < xfrd->nsd->options->zonestatnames->count) + resize_zonestat(xfrd, xfrd->nsd->options->zonestatnames->count); + else + resize_zonestat(xfrd, n->id+1); + } + if(!xfrd->zonestat_clear[n->id]) + xfrd->zonestat_clear[n->id] = xalloc( + sizeof(struct nsdst)); + /*store last total of stats*/ + memcpy(xfrd->zonestat_clear[n->id], &stat1, + sizeof(struct nsdst)); + } + + /*stat0 contains the details that we want to print*/ + evbuffer_add_printf(buf, "nsd_queries_total{zone=\"%s\"} %lu\n", name, + (unsigned long)(stat0.qudp + stat0.qudp6 + stat0.ctcp + + stat0.ctcp6 + stat0.ctls + stat0.ctls6)); + print_stat_block_with_zone(buf, name, &stat0); + } +} +#endif /*USE_ZONE_STATS*/ + +static void +print_stats(struct evbuffer *buf, xfrd_state_type* xfrd, struct timeval* now, int clear, + struct nsdst* st, struct nsdst** zonestats) +{ + size_t i; + stc_type total = 0; + struct timeval elapsed, uptime; + + /*per CPU and total*/ + for(i=0; insd->child_count; i++) { + evbuffer_add_printf(buf, "nsd_queries_total{server=\"%d\"} %lu\n", + (int)i, (unsigned long)xfrd->nsd->children[i].query_count); + total += xfrd->nsd->children[i].query_count; + } + evbuffer_add_printf(buf, "nsd_queries_total %lu\n", (unsigned long)total); + + /*time elapsed and uptime (in seconds)*/ + timeval_subtract(&uptime, now, &xfrd->nsd->metrics->boot_time); + timeval_subtract(&elapsed, now, &xfrd->nsd->metrics->stats_time); + evbuffer_add_printf(buf, "nsd_time_up_seconds %lu.%6.6lu\n", + (unsigned long)uptime.tv_sec, (unsigned long)uptime.tv_usec); + evbuffer_add_printf(buf, "nsd_time_elapsed_seconds %lu.%6.6lu\n", + (unsigned long)elapsed.tv_sec, (unsigned long)elapsed.tv_usec); + + /*mem info, database on disksize*/ + print_longnum(buf, "nsd_size_db_on_disk_bytes ", st->db_disk); + print_longnum(buf, "nsd_size_db_in_mem_bytes ", st->db_mem); + print_longnum(buf, "nsd_size_xfrd_in_mem_bytes ", region_get_mem(xfrd->region)); + print_longnum(buf, "nsd_size_config_on_disk_bytes ", + xfrd->nsd->options->zonelist_off); + print_longnum(buf, "nsd_size_config_in_mem_bytes ", region_get_mem( + xfrd->nsd->options->region)); + print_stat_block(buf, st); + + /*zone statistics*/ + evbuffer_add_printf(buf, "nsd_zones_primary_total %lu\n", + (unsigned long)(xfrd->notify_zones->count - xfrd->zones->count)); + evbuffer_add_printf(buf, "nsd_zones_secondary_total %lu\n", + (unsigned long)xfrd->zones->count); +#ifdef USE_ZONE_STATS + zonestat_print(buf, xfrd, clear, zonestats); /*per-zone statistics*/ +#else + (void)clear; (void)zonestats; +#endif +} + +/*allocate stats temp arrays, for taking a coherent snapshot of the + * statistics values at that time.*/ +static void +process_stats_alloc(xfrd_state_type* xfrd, struct nsdst** stats, + struct nsdst** zonestats) +{ + *stats = xmallocarray(xfrd->nsd->child_count*2, sizeof(struct nsdst)); +#ifdef USE_ZONE_STATS + zonestats[0] = xmallocarray(xfrd->zonestat_safe, sizeof(struct nsdst)); + zonestats[1] = xmallocarray(xfrd->zonestat_safe, sizeof(struct nsdst)); +#else + (void)zonestats; +#endif +} + +/*grab a copy of the statistics, at this particular time.*/ +static void +process_stats_grab(xfrd_state_type* xfrd, struct timeval* stattime, + struct nsdst* stats, struct nsdst** zonestats) +{ + if(gettimeofday(stattime, NULL) == -1) + log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno)); + memcpy(stats, xfrd->nsd->stat_map, + xfrd->nsd->child_count*2*sizeof(struct nsdst)); +#ifdef USE_ZONE_STATS + memcpy(zonestats[0], xfrd->nsd->zonestat[0], + xfrd->zonestat_safe*sizeof(struct nsdst)); + memcpy(zonestats[1], xfrd->nsd->zonestat[1], + xfrd->zonestat_safe*sizeof(struct nsdst)); +#else + (void)zonestats; +#endif +} + +/*add the old and new processes stat values into the first part of the + * array of stats*/ +static void +process_stats_add_old_new(xfrd_state_type* xfrd, struct nsdst* stats) +{ + size_t i; + uint64_t dbd = stats[0].db_disk; + uint64_t dbm = stats[0].db_mem; + /*The old and new server processes have separate stat blocks, + * and these are added up together. This results in the statistics + * values per server-child. The reload task briefly forks both + * old and new server processes.*/ + for(i=0; insd->child_count; i++) { + stats_add(&stats[i], &stats[xfrd->nsd->child_count+i]); + } + stats[0].db_disk = dbd; + stats[0].db_mem = dbm; +} + +/*manage clearing of stats, a cumulative count of cleared statistics*/ +static void +process_stats_manage_clear(xfrd_state_type* xfrd, struct nsdst* stats, + int peek) +{ + struct nsdst st; + size_t i; + if(peek) { + /*Subtract the earlier resetted values from the numbers, + * but do not reset the values that are retrieved now.*/ + if(!xfrd->stat_clear) + return; /*nothing to subtract*/ + for(i=0; insd->child_count; i++) { + /*subtract cumulative count that has been reset*/ + stats_subtract(&stats[i], &xfrd->stat_clear[i]); + } + return; + } + if(!xfrd->stat_clear) + xfrd->stat_clear = region_alloc_zero(xfrd->region, + sizeof(struct nsdst)*xfrd->nsd->child_count); + for(i=0; insd->child_count; i++) { + /*store cumulative count copy*/ + memcpy(&st, &stats[i], sizeof(st)); + /*subtract cumulative count that has been reset*/ + stats_subtract(&stats[i], &xfrd->stat_clear[i]); + /*store cumulative count in the cleared value array*/ + memcpy(&xfrd->stat_clear[i], &st, sizeof(st)); + } +} + +/*add up the statistics to get the total over the server children.*/ +static void +process_stats_add_total(xfrd_state_type* xfrd, struct nsdst* total, + struct nsdst* stats) +{ + size_t i; + /*copy over the first one, with also the nonadded values.*/ + memcpy(total, &stats[0], sizeof(*total)); + xfrd->nsd->children[0].query_count = stats[0].qudp + stats[0].qudp6 + + stats[0].ctcp + stats[0].ctcp6 + stats[0].ctls + + stats[0].ctls6; + for(i=1; insd->child_count; i++) { + stats_add(total, &stats[i]); + xfrd->nsd->children[i].query_count = stats[i].qudp + + stats[i].qudp6 + stats[i].ctcp + stats[i].ctcp6 + + stats[i].ctls + stats[i].ctls6; + } +} + +/** process the statistics and write them into the buffer */ +static void +process_stats(struct evbuffer *buf, xfrd_state_type* xfrd, int peek) +{ + struct timeval stattime; + struct nsdst* stats, *zonestats[2], total; + + process_stats_alloc(xfrd, &stats, zonestats); + process_stats_grab(xfrd, &stattime, stats, zonestats); + process_stats_add_old_new(xfrd, stats); + process_stats_manage_clear(xfrd, stats, peek); + process_stats_add_total(xfrd, &total, stats); + print_stats(buf, xfrd, &stattime, !peek, &total, zonestats); + /* if(!peek) { */ + /* xfrd->nsd->metrics->stats_time = stattime; */ + /* } */ + + free(stats); +#ifdef USE_ZONE_STATS + free(zonestats[0]); + free(zonestats[1]); +#endif +} +#endif /*BIND8_STATS*/ + +#endif /* USE_METRICS */ diff --git a/metrics.h b/metrics.h new file mode 100644 index 00000000..712c307e --- /dev/null +++ b/metrics.h @@ -0,0 +1,57 @@ +/* + * metrics.h -- prometheus metrics endpoint + * + * Copyright (c) 2001-2025, NLnet Labs. All rights reserved. + * + * See LICENSE for the license. + * + */ + +#ifndef DAEMON_METRICS_H +#define DAEMON_METRICS_H + +struct xfrd_state; +struct nsd_options; +struct daemon_metrics; + +/* the metrics daemon needs little backlog */ +#define TCP_BACKLOG_METRICS 16 /* listen() tcp backlog */ + +/** + * Create new metrics endpoint for the daemon. + * @param cfg: config. + * @return new state, or NULL on failure. + */ +struct daemon_metrics* daemon_metrics_create(struct nsd_options* cfg); + +/** + * Delete metrics daemon and close HTTP listeners. + * @param m: daemon to delete. + */ +void daemon_metrics_delete(struct daemon_metrics* m); + +/** + * Close metrics HTTP listener ports. + * Does not delete the object itself. + * @param m: state to close. + */ +void daemon_metrics_close(struct daemon_metrics* m); + +/** + * Open and create HTTP listeners for metrics daemon. + * @param m: metrics state that contains list of accept sockets. + * @param cfg: config options. + * @return false on failure. + */ +int daemon_metrics_open_ports(struct daemon_metrics* m, + struct nsd_options* cfg); + +/** + * Setup HTTP listener. + * @param m: state + * @param xfrd: the process that hosts the daemon. + * m's HTTP listener is attached to its event base. + */ +void daemon_metrics_attach(struct daemon_metrics* m, struct xfrd_state* xfrd); + +#endif /* DAEMON_METRICS_H */ From ff6615ac3e6c79d0fe039497d1413b3d74bbb497 Mon Sep 17 00:00:00 2001 From: Jannik Peters Date: Mon, 10 Feb 2025 17:04:26 +0100 Subject: [PATCH 4/9] Enable use of metrics endpoint --- nsd.c | 10 ++++++++++ nsd.h | 6 ++++++ server.c | 6 ++++++ xfrd.c | 7 +++++++ 4 files changed, 29 insertions(+) diff --git a/nsd.c b/nsd.c index 575a0cf7..f0bdb0ae 100644 --- a/nsd.c +++ b/nsd.c @@ -54,6 +54,9 @@ #include "remote.h" #include "xfrd-disk.h" #include "ipc.h" +#ifdef USE_METRICS +#include "metrics.h" +#endif /* USE_METRICS */ #ifdef USE_DNSTAP #include "dnstap/dnstap_collector.h" #endif @@ -1517,6 +1520,13 @@ main(int argc, char *argv[]) if(!(nsd.rc = daemon_remote_create(nsd.options))) error("could not perform remote control setup"); } +#ifdef USE_METRICS + if(nsd.options->metrics_enable) { + /* read ssl keys while superuser and outside chroot */ + if(!(nsd.metrics = daemon_metrics_create(nsd.options))) + error("could not perform metrics server setup"); + } +#endif /* USE_METRICS */ #if defined(HAVE_SSL) if(nsd.options->tls_service_key && nsd.options->tls_service_key[0] && nsd.options->tls_service_pem && nsd.options->tls_service_pem[0]) { diff --git a/nsd.h b/nsd.h index f48db3dc..bd5a8246 100644 --- a/nsd.h +++ b/nsd.h @@ -30,6 +30,9 @@ struct netio_handler; struct nsd_options; struct udb_base; struct daemon_remote; +#ifdef USE_METRICS +struct daemon_metrics; +#endif /* USE_METRICS */ #ifdef USE_DNSTAP struct dt_collector; #endif @@ -255,6 +258,9 @@ struct nsd region_type* server_region; struct netio_handler* xfrd_listener; struct daemon_remote* rc; +#ifdef USE_METRICS + struct daemon_metrics* metrics; +#endif /* USE_METRICS */ /* Configuration */ const char *pidfile; diff --git a/server.c b/server.c index 9100cbad..7958bbf3 100644 --- a/server.c +++ b/server.c @@ -87,6 +87,9 @@ #endif #include "verify.h" #include "util/proxy_protocol.h" +#ifdef USE_METRICS +#include "metrics.h" +#endif /* USE_METRICS */ #define RELOAD_SYNC_TIMEOUT 25 /* seconds */ @@ -1600,6 +1603,9 @@ server_shutdown(struct nsd *nsd) tsig_finalize(); daemon_remote_delete(nsd->rc); /* ssl-delete secret keys */ +#ifdef USE_METRICS + daemon_metrics_delete(nsd->metrics); +#endif /* USE_METRICS */ #ifdef HAVE_SSL if (nsd->tls_ctx) SSL_CTX_free(nsd->tls_ctx); diff --git a/xfrd.c b/xfrd.c index 1022f74d..e139ff78 100644 --- a/xfrd.c +++ b/xfrd.c @@ -35,6 +35,9 @@ #ifdef USE_DNSTAP #include "dnstap/dnstap_collector.h" #endif +#ifdef USE_METRICS +#include "metrics.h" +#endif /* USE_METRICS */ #ifdef HAVE_SYSTEMD #include @@ -212,6 +215,10 @@ xfrd_init(int socket, struct nsd* nsd, int shortsoa, int reload_active, daemon_remote_attach(xfrd->nsd->rc, xfrd); +#ifdef USE_METRICS + daemon_metrics_attach(xfrd->nsd->metrics, xfrd); +#endif /* USE_METRICS */ + xfrd->tcp_set = xfrd_tcp_set_create(xfrd->region, nsd->options->tls_cert_bundle, nsd->options->xfrd_tcp_max, nsd->options->xfrd_tcp_pipeline); xfrd->tcp_set->tcp_timeout = nsd->tcp_timeout; #if !defined(HAVE_ARC4RANDOM) && !defined(HAVE_GETRANDOM) From 457e5ca4cd6988750038f68b52efa16f5e898c0a Mon Sep 17 00:00:00 2001 From: Jannik Peters Date: Tue, 11 Feb 2025 13:28:43 +0100 Subject: [PATCH 5/9] Update metrics config documentation --- nsd.conf.5.in | 24 ++++++++++++++++++++++++ nsd.conf.sample.in | 17 +++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/nsd.conf.5.in b/nsd.conf.5.in index 6c13847e..69ab60a3 100644 --- a/nsd.conf.5.in +++ b/nsd.conf.5.in @@ -603,6 +603,30 @@ The port number for proxy protocol service. If the statement is given multiple times, additional port numbers can be used for proxy protocol service. The interface definitions that use this port number expect PROXYv2 proxy protocol traffic, for UDP, TCP and for TLS service. +.TP +.B metrics\-enable:\fR +Enable the prometheus metrics HTTP endpoint. It exposes the same statistics as +the \fInsd\-control\fR(8) stats_noreset command, but with metric names +following the prometheus specification. + +Beware, that when using \fInsd\-control\fR(8) stats (instead of stats_noreset), +the statistics will be reset for the HTTP metrics endpoint as well. +.TP +.B metrics\-interface:\fR +NSD will bind to the listed addresses or interfaces to serve the prometheus +metrics. Can be given multiple times to bind multiple ip\-addresses. Use +0.0.0.0 and ::0 to bind to the wildcard interface. + +If an interface name is used instead of ip4 or ip6, the list of IP addresses +associated with that interface is picked up and used at server start. + +Default is 127.0.0.1 and ::1. +.TP +.B metrics\-port:\fR +The port number for the HTTP service. Default is 9100. +.TP +.B metrics\-path:\fR +The HTTP path to expose the metrics at. Default is /metrics. .SS "Remote Control" The .B remote\-control: diff --git a/nsd.conf.sample.in b/nsd.conf.sample.in index 705539eb..a33417c6 100644 --- a/nsd.conf.sample.in +++ b/nsd.conf.sample.in @@ -283,6 +283,23 @@ server: # expect PROXYv2. For UDP and TCP/TLS interfaces. # proxy-protocol-port: portno for each of the port numbers. + # Enable the prometheus metrics HTTP endpoint. Default is no. + # metrics-enable: no + + # Interfaces to expose the HTTP endpoint on, default is on localhost. + # Interfaces can be specified by IP address or interface name. + # With an interface name, all IP addresses associated with that + # interface are used. Default is 127.0.0.1 and ::1. + # metrics-interface: 127.0.0.1 + # metrics-interface: ::1 + # metrics-interface: lo + + # Port number for the HTTP metrics endpoint. Default is 9100. + # metrics-port: 9100 + + # HTTP path for the metrics endpoint. Default is /metrics. + # metrics-path: "/metrics" + verify: # Enable zone verification. Default is no. # enable: no From 73c4ac4b7c6adc90acafd664babceb5d3d87b4d0 Mon Sep 17 00:00:00 2001 From: Jannik Peters Date: Mon, 17 Feb 2025 13:31:00 +0100 Subject: [PATCH 6/9] Rename metrics and add help texts Metrics should not contain duplicate data, summing all metrics of a given name (regardless of labels) needs to be meaningful. Therefore the counter metrics based on different DNS aspects have been split into separate metric names. --- metrics.c | 357 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 236 insertions(+), 121 deletions(-) diff --git a/metrics.c b/metrics.c index 6da5f4d4..8d97bf89 100644 --- a/metrics.c +++ b/metrics.c @@ -401,96 +401,144 @@ print_longnum(struct evbuffer *buf, char* desc, uint64_t x) } } -/*print one block of statistics. n is name and d is delimiter*/ static void -print_stat_block(struct evbuffer *buf, struct nsdst* st) +print_metric_help_and_type(struct evbuffer *buf, char *name, + char *help, char *type) +{ + evbuffer_add_printf(buf, "# HELP %s %s\n# TYPE %s %s\n", + name, help, name, type); +} + +static void +print_metric_help_and_type_zonestats(struct evbuffer *buf, char *name, + char *help, char *type, char *zonestat_name) +{ + evbuffer_add_printf(buf, "# HELP nsd_zonestats_%s_%s %s\n# TYPE %s %s\n", + zonestat_name, name, help, name, type); +} + +static void +print_stat_block(struct evbuffer *buf, struct nsdst* st, + struct nsdst** zonestats) { + size_t i; + const char* rcstr[] = {"NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED", "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH", "NOTZONE", "RCODE11", "RCODE12", "RCODE13", "RCODE14", "RCODE15", "BADVERS" }; - size_t i; + + /* nsd_queries_by_type_total */ + print_metric_help_and_type(buf, "nsd_queries_by_type_total", + "Total number of queries recieved by type.", + "counter"); for(i=0; i<= 255; i++) { if(metrics_inhibit_zero && st->qtype[i] == 0 && strncmp(rrtype_to_string(i), "TYPE", 4) == 0) continue; - evbuffer_add_printf(buf, "nsd_queries_total{type=\"%s\"} %lu\n", + evbuffer_add_printf(buf, "nsd_queries_by_type_total{type=\"%s\"} %lu\n", rrtype_to_string(i), (unsigned long)st->qtype[i]); } - /*opcode*/ - for(i=0; i<6; i++) { - if(metrics_inhibit_zero && st->opcode[i] == 0 && i != OPCODE_QUERY) - continue; - evbuffer_add_printf(buf, "nsd_queries_total{opcode=\"%s\"} %lu\n", - opcode2str(i), (unsigned long)st->opcode[i]); - } - - /*qclass*/ + /* nsd_queries_by_class_total */ + print_metric_help_and_type(buf, "nsd_queries_by_class_total", + "Total number of queries recieved by class.", + "counter"); for(i=0; i<4; i++) { if(metrics_inhibit_zero && st->qclass[i] == 0 && i != CLASS_IN) continue; - evbuffer_add_printf(buf, "nsd_queries_total{class=\"%s\"} %lu\n", + evbuffer_add_printf(buf, "nsd_queries_by_class_total{class=\"%s\"} %lu\n", rrclass_to_string(i), (unsigned long)st->qclass[i]); } - /*rcode*/ + /* nsd_queries_by_opcode_total */ + print_metric_help_and_type(buf, "nsd_queries_by_opcode_total", + "Total number of queries recieved by opcode.", + "counter"); + for(i=0; i<6; i++) { + if(metrics_inhibit_zero && st->opcode[i] == 0 && i != OPCODE_QUERY) + continue; + evbuffer_add_printf(buf, "nsd_queries_by_opcode_total{opcode=\"%s\"} %lu\n", + opcode2str(i), (unsigned long)st->opcode[i]); + } + + /* nsd_queries_by_rcode_total */ + print_metric_help_and_type(buf, "nsd_queries_by_rcode_total", + "Total number of queries recieved by rcode.", + "counter"); for(i=0; i<17; i++) { if(metrics_inhibit_zero && st->rcode[i] == 0 && i > RCODE_YXDOMAIN) /*NSD does not use larger*/ continue; - evbuffer_add_printf(buf, "nsd_queries_total{rcode=\"%s\"} %lu\n", + evbuffer_add_printf(buf, "nsd_queries_by_rcode_total{rcode=\"%s\"} %lu\n", rcstr[i], (unsigned long)st->rcode[i]); } - /*edns*/ - /* TODO: maybe use label? */ - evbuffer_add_printf(buf, "nsd_queries_edns_total %lu\n", (unsigned long)st->edns); - - /*ednserr*/ - /* TODO: maybe use label? */ - evbuffer_add_printf(buf, "nsd_queries_ednserr_total %lu\n", - (unsigned long)st->ednserr); - - /*qudp*/ - /* TODO: maybe use label? */ - evbuffer_add_printf(buf, "nsd_queries_udp_total %lu\n", (unsigned long)st->qudp); - /*qudp6*/ - /* TODO: maybe use label? */ - evbuffer_add_printf(buf, "nsd_queries_udp6_total %lu\n", (unsigned long)st->qudp6); - /*ctcp*/ + /* nsd_queries_by_transport_total */ + print_metric_help_and_type(buf, "nsd_queries_by_transport_total", + "Total number of queries recieved by transport.", + "counter"); + evbuffer_add_printf(buf, "nsd_queries_by_transport_total{transport=\"udp\"} %lu\n", (unsigned long)st->qudp); + evbuffer_add_printf(buf, "nsd_queries_by_transport_total{transport=\"udp6\"} %lu\n", (unsigned long)st->qudp6); + + /* nsd_queries_with_edns_total */ + print_metric_help_and_type(buf, "nsd_queries_with_edns_total", + "Total number of queries recieved with EDNS OPT.", + "counter"); + evbuffer_add_printf(buf, "nsd_queries_with_edns_total %lu\n", (unsigned long)st->edns); + + /* nsd_queries_with_edns_failed_total */ + print_metric_help_and_type(buf, "nsd_queries_with_edns_failed_total", + "Total number of queries recieved with EDNS OPT where EDNS parsing failed.", + "counter"); + evbuffer_add_printf(buf, "nsd_queries_with_edns_failed_total %lu\n", (unsigned long)st->ednserr); + + /* nsd_connections_total */ + print_metric_help_and_type(buf, "nsd_connections_total", + "Total number of connections.", + "counter"); evbuffer_add_printf(buf, "nsd_connections_total{transport=\"tcp\"} %lu\n", (unsigned long)st->ctcp); - /*ctcp6*/ evbuffer_add_printf(buf, "nsd_connections_total{transport=\"tcp6\"} %lu\n", (unsigned long)st->ctcp6); - /*ctls*/ evbuffer_add_printf(buf, "nsd_connections_total{transport=\"tls\"} %lu\n", (unsigned long)st->ctls); - /*ctls6*/ evbuffer_add_printf(buf, "nsd_connections_total{transport=\"tls6\"} %lu\n", (unsigned long)st->ctls6); - /*nona*/ - evbuffer_add_printf(buf, "nsd_answers_without_aa_total %lu\n", - (unsigned long)st->nona); - - /*rxerr*/ - evbuffer_add_printf(buf, "nsd_queries_rxerr_total %lu\n", (unsigned long)st->rxerr); - - /*txerr*/ - evbuffer_add_printf(buf, "nsd_queries_txerr_total %lu\n", (unsigned long)st->txerr); - - /*number of requested-axfr, number of times axfr served to clients*/ - evbuffer_add_printf(buf, "nsd_answered_axfr_requests_total %lu\n", (unsigned long)st->raxfr); - - /*number of requested-ixfr, number of times ixfr served to clients*/ - evbuffer_add_printf(buf, "nsd_answered_ixfr_requests_total %lu\n", (unsigned long)st->rixfr); - - /*truncated*/ - evbuffer_add_printf(buf, "nsd_answers_truncated_total %lu\n", - (unsigned long)st->truncated); - - /*dropped*/ - evbuffer_add_printf(buf, "nsd_queries_dropped_total %lu\n", - (unsigned long)st->dropped); + /* nsd_xfr_requests_served_total */ + print_metric_help_and_type(buf, "nsd_xfr_requests_served_total", + "Total number of answered zone transfers.", + "counter"); + evbuffer_add_printf(buf, "nsd_xfr_requests_served_total{xfrtype=\"AXFR\"} %lu\n", (unsigned long)st->raxfr); + evbuffer_add_printf(buf, "nsd_xfr_requests_served_total{xfrtype=\"IXFR\"} %lu\n", (unsigned long)st->rixfr); + + /* nsd_queries_dropped_total */ + print_metric_help_and_type(buf, "nsd_queries_dropped_total", + "Total number of dropped queries.", + "counter"); + evbuffer_add_printf(buf, "nsd_queries_dropped_total %lu\n", (unsigned long)st->dropped); + + /* nsd_queries_rx_failed_total */ + print_metric_help_and_type(buf, "nsd_queries_rx_failed_total", + "Total number of queries where receive failed.", + "counter"); + evbuffer_add_printf(buf, "nsd_queries_rx_failed_total %lu\n", (unsigned long)st->rxerr); + + /* nsd_answers_tx_failed_total */ + print_metric_help_and_type(buf, "nsd_answers_tx_failed_total", + "Total number of answers where transmit failed.", + "counter"); + evbuffer_add_printf(buf, "nsd_answers_tx_failed_total %lu\n", (unsigned long)st->txerr); + + /* nsd_answers_without_aa_total */ + print_metric_help_and_type(buf, "nsd_answers_without_aa_total", + "Total number of NOERROR answers without AA flag set.", + "counter"); + evbuffer_add_printf(buf, "nsd_answers_without_aa_total %lu\n", (unsigned long)st->nona); + + /* nsd_answers_truncated_total */ + print_metric_help_and_type(buf, "nsd_answers_truncated_total", + "Total number of truncated answers.", + "counter"); + evbuffer_add_printf(buf, "nsd_answers_truncated_total %lu\n", (unsigned long)st->truncated); } /*print one block of statistics. n is name and d is delimiter*/ @@ -503,107 +551,141 @@ print_stat_block_with_zone(struct evbuffer *buf, char* n, struct nsdst* st) "BADVERS" }; size_t i; + + /* nsd_zonestats_%s_queries_by_type_total */ + print_metric_help_and_type_zonestats(buf, "queries_by_type_total", + "Total number of queries recieved by type.", + "counter", n); for(i=0; i<= 255; i++) { if(metrics_inhibit_zero && st->qtype[i] == 0 && strncmp(rrtype_to_string(i), "TYPE", 4) == 0) continue; - evbuffer_add_printf(buf, "nsd_queries_total{zone=\"%s\", type=\"%s\"} %lu\n", + evbuffer_add_printf(buf, "nsd_zonestats_%s_queries_by_type_total{type=\"%s\"} %lu\n", n, rrtype_to_string(i), (unsigned long)st->qtype[i]); } - /*opcode*/ - for(i=0; i<6; i++) { - if(metrics_inhibit_zero && st->opcode[i] == 0 && i != OPCODE_QUERY) + /* nsd_zonestats_%s_queries_by_class_total */ + print_metric_help_and_type_zonestats(buf, "queries_by_class_total", + "Total number of queries recieved by class.", + "counter", n); + for(i=0; i<4; i++) { + if(metrics_inhibit_zero && st->qclass[i] == 0 && i != CLASS_IN) continue; evbuffer_add_printf(buf, - "nsd_queries_total{zone=\"%s\", opcode=\"%s\"} %lu\n", - n, opcode2str(i), (unsigned long)st->opcode[i]); + "nsd_zonestats_%s_queries_by_class_total{class=\"%s\"} %lu\n", + n, rrclass_to_string(i), (unsigned long)st->qclass[i]); } - /*qclass*/ - for(i=0; i<4; i++) { - if(metrics_inhibit_zero && st->qclass[i] == 0 && i != CLASS_IN) + /* nsd_zonestats_%s_queries_by_opcode_total */ + print_metric_help_and_type_zonestats(buf, "queries_by_opcode_total", + "Total number of queries recieved by opcode.", + "counter", n); + for(i=0; i<6; i++) { + if(metrics_inhibit_zero && st->opcode[i] == 0 && i != OPCODE_QUERY) continue; evbuffer_add_printf(buf, - "nsd_queries_total{zone=\"%s\", class=\"%s\"} %lu\n", - n, rrclass_to_string(i), (unsigned long)st->qclass[i]); + "nsd_zonestats_%s_queries_by_opcode_total{opcode=\"%s\"} %lu\n", + n, opcode2str(i), (unsigned long)st->opcode[i]); } - /*rcode*/ + /* nsd_zonestats_%s_queries_by_rcode_total */ + print_metric_help_and_type_zonestats(buf, "queries_by_rcode_total", + "Total number of queries recieved by rcode.", + "counter", n); for(i=0; i<17; i++) { if(metrics_inhibit_zero && st->rcode[i] == 0 && i > RCODE_YXDOMAIN) /*NSD does not use larger*/ continue; evbuffer_add_printf(buf, - "nsd_queries_total{zone=\"%s\", rcode=\"%s\"} %lu\n", + "nsd_zonestats_%s_queries_by_rcode_total{rcode=\"%s\"} %lu\n", n, rcstr[i], (unsigned long)st->rcode[i]); } - /*edns*/ - evbuffer_add_printf(buf, "nsd_queries_edns_total{zone=\"%s\"} %lu\n", + /* nsd_zonestats_%s_queries_by_transport_total */ + print_metric_help_and_type_zonestats(buf, "queries_by_transport_total", + "Total number of queries recieved by transport.", "counter", n); + evbuffer_add_printf(buf, + "nsd_zonestats_%s_queries_by_transport_total{" + "transport=\"udp\"} %lu\n", + n, (unsigned long)st->qudp); + evbuffer_add_printf(buf, + "nsd_zonestats_%s_queries_by_transport_total{" + "transport=\"udp6\"} %lu\n", + n, (unsigned long)st->qudp6); + + /* nsd_zonestats_%s_queries_with_edns_total */ + print_metric_help_and_type_zonestats(buf, "queries_with_edns_total", + "Total number of queries recieved with EDNS OPT.", "counter", n); + evbuffer_add_printf(buf, "nsd_zonestats_%s_queries_with_edns_total %lu\n", n, (unsigned long)st->edns); - /*ednserr*/ - evbuffer_add_printf(buf, "nsd_queries_ednserr_total{zone=\"%s\"} %lu\n", + /* nsd_zonestats_%s_queries_with_edns_failed_total */ + print_metric_help_and_type_zonestats(buf, "queries_with_edns_failed_total", + "Total number of queries recieved with EDNS OPT where EDNS parsing failed.", + "counter", n); + evbuffer_add_printf(buf, "nsd_zonestats_%s_queries_with_edns_failed_total %lu\n", n, (unsigned long)st->ednserr); - /*qudp*/ - evbuffer_add_printf(buf, "nsd_queries_udp_total{zone=\"%s\"} %lu\n", n, (unsigned long)st->qudp); - /*qudp6*/ - evbuffer_add_printf(buf, "nsd_queries_udp6_total{zone=\"%s\"} %lu\n", n, (unsigned long)st->qudp6); - /*ctcp*/ + /* nsd_zonestats_%s_connections_total */ + print_metric_help_and_type_zonestats(buf, "connections_total", + "Total number of connections.", "counter", n); evbuffer_add_printf(buf, - "nsd_connections_total{zone=\"%s\", transport=\"tcp\"} %lu\n", + "nsd_zonestats_%s_connections_total{transport=\"tcp\"} %lu\n", n, (unsigned long)st->ctcp); - /*ctcp6*/ evbuffer_add_printf(buf, - "nsd_connections_total{zone=\"%s\", transport=\"tcp6\"} %lu\n", + "nsd_zonestats_%s_connections_total{transport=\"tcp6\"} %lu\n", n, (unsigned long)st->ctcp6); - /*ctls*/ evbuffer_add_printf(buf, - "nsd_connections_total{zone=\"%s\", transport=\"tls\"} %lu\n", + "nsd_zonestats_%s_connections_total{transport=\"tls\"} %lu\n", n, (unsigned long)st->ctls); - /*ctls6*/ evbuffer_add_printf(buf, - "nsd_connections_total{zone=\"%s\", transport=\"tls6\"} %lu\n", + "nsd_zonestats_%s_connections_total{transport=\"tls6\"} %lu\n", n, (unsigned long)st->ctls6); - /*nona*/ + /* nsd_zonestats_%s_xfr_requests_served_total */ + print_metric_help_and_type_zonestats(buf, "xfr_requests_served_total", + "Total number of answered zone transfers.", "counter", n); evbuffer_add_printf(buf, - "nsd_answer_without_aa_total{zone=\"%s\"} %lu\n", - n, (unsigned long)st->nona); - - /*rxerr*/ + "nsd_zonestats_%s_xfr_requests_served_total{xfrtype=\"AXFR\"} %lu\n", + n, (unsigned long)st->raxfr); evbuffer_add_printf(buf, - "nsd_queries_rxerr_total{zone=\"%s\"} %lu\n", - n, (unsigned long)st->rxerr); + "nsd_zonestats_%s_xfr_requests_served_total{xfrtype=\"IXFR\"} %lu\n", + n, (unsigned long)st->rixfr); - /*txerr*/ + /* nsd_zonestats_%s_zonestats_%s_queries_dropped_total */ + print_metric_help_and_type_zonestats(buf, "queries_dropped_total", + "Total number of dropped queries.", "counter", n); evbuffer_add_printf(buf, - "nsd_queries_txerr_total{zone=\"%s\"} %lu\n", - n, (unsigned long)st->txerr); + "nsd_zonestats_%s_queries_dropped_total %lu\n", + n, (unsigned long)st->dropped); - /*number of requested-axfr, - number of times axfr served to clients*/ + /* nsd_zonestats_%s_queries_rx_failed_total */ + print_metric_help_and_type_zonestats(buf, "queries_rx_failed_total", + "Total number of queries where receive failed.", "counter", n); evbuffer_add_printf(buf, - "nsd_answered_axfr_requests_total{zone=\"%s\"} %lu\n", - n, (unsigned long)st->raxfr); + "nsd_zonestats_%s_queries_rx_failed_total %lu\n", + n, (unsigned long)st->rxerr); - /*number of requested-ixfr, - number of times ixfr served to clients*/ + /* nsd_zonestats_%s_answers_tx_failed_total */ + print_metric_help_and_type_zonestats(buf, "answers_tx_failed_total", + "Total number of answers where transmit failed.", "counter", n); evbuffer_add_printf(buf, - "nsd_answered_ixfr_requests_total{zone=\"%s\"} %lu\n", - n, (unsigned long)st->rixfr); + "nsd_zonestats_%s_answers_tx_failed_total %lu\n", + n, (unsigned long)st->txerr); - /*truncated*/ + /* nsd_zonestats_%s_answers_without_aa_total */ + print_metric_help_and_type_zonestats(buf, "answers_without_aa_total", + "Total number of NOERROR answers without AA flag set.", "counter", n); evbuffer_add_printf(buf, - "nsd_answers_truncated_total{zone=\"%s\"} %lu\n", - n, (unsigned long)st->truncated); + "nsd_zonestats_%s_answers_without_aa_total %lu\n", + n, (unsigned long)st->nona); - /*dropped*/ + /* nsd_zonestats_%s_answers_truncated_total */ + print_metric_help_and_type_zonestats(buf, "answers_truncated_total", + "Total number of truncated answers.", "counter", n); evbuffer_add_printf(buf, - "nsd_queries_dropped_total{zone=\"%s\"} %lu\n", - n, (unsigned long)st->dropped); + "nsd_zonestats_%s_answers_truncated_total %lu\n", + n, (unsigned long)st->truncated); } #ifdef USE_ZONE_STATS @@ -663,7 +745,10 @@ zonestat_print(struct evbuffer *buf, xfrd_state_type* xfrd, int clear, } /*stat0 contains the details that we want to print*/ - evbuffer_add_printf(buf, "nsd_queries_total{zone=\"%s\"} %lu\n", name, + print_metric_help_and_type_zonestats(buf, "queries_total", + "Total number of queries recieved.", + "counter", name); + evbuffer_add_printf(buf, "nsd_zonestats_%s_queries_total %lu\n", name, (unsigned long)(stat0.qudp + stat0.qudp6 + stat0.ctcp + stat0.ctcp6 + stat0.ctls + stat0.ctls6)); print_stat_block_with_zone(buf, name, &stat0); @@ -676,40 +761,70 @@ print_stats(struct evbuffer *buf, xfrd_state_type* xfrd, struct timeval* now, in struct nsdst* st, struct nsdst** zonestats) { size_t i; - stc_type total = 0; struct timeval elapsed, uptime; + /* nsd_queries_total */ + print_metric_help_and_type(buf, "nsd_queries_total", + "Total number of queries recieved.", "counter"); /*per CPU and total*/ for(i=0; insd->child_count; i++) { evbuffer_add_printf(buf, "nsd_queries_total{server=\"%d\"} %lu\n", (int)i, (unsigned long)xfrd->nsd->children[i].query_count); - total += xfrd->nsd->children[i].query_count; } - evbuffer_add_printf(buf, "nsd_queries_total %lu\n", (unsigned long)total); + + print_stat_block(buf, st, zonestats); /*time elapsed and uptime (in seconds)*/ timeval_subtract(&uptime, now, &xfrd->nsd->metrics->boot_time); timeval_subtract(&elapsed, now, &xfrd->nsd->metrics->stats_time); - evbuffer_add_printf(buf, "nsd_time_up_seconds %lu.%6.6lu\n", + print_metric_help_and_type(buf, "nsd_time_up_seconds_total", + "Uptime since server boot in seconds.", "counter"); + evbuffer_add_printf(buf, "nsd_time_up_seconds_total %lu.%6.6lu\n", (unsigned long)uptime.tv_sec, (unsigned long)uptime.tv_usec); + /* TODO: re-add when elapsed time resetting on nsd-control stats is implemented + print_metric_help_and_type(buf, "nsd_time_elapsed_seconds", + "Time since last statistics printout in seconds.", + "untyped"); evbuffer_add_printf(buf, "nsd_time_elapsed_seconds %lu.%6.6lu\n", (unsigned long)elapsed.tv_sec, (unsigned long)elapsed.tv_usec); + */ /*mem info, database on disksize*/ + print_metric_help_and_type(buf, "nsd_size_db_on_disk_bytes", + "Size of DNS database on disk.", "gauge"); print_longnum(buf, "nsd_size_db_on_disk_bytes ", st->db_disk); + + print_metric_help_and_type(buf, "nsd_size_db_in_mem_bytes", + "Size of DNS database in memory.", "gauge"); print_longnum(buf, "nsd_size_db_in_mem_bytes ", st->db_mem); + + print_metric_help_and_type(buf, "nsd_size_xfrd_in_mem_bytes", + "Size of zone transfers and notifies in xfrd process, excluding TSIG data.", + "gauge"); print_longnum(buf, "nsd_size_xfrd_in_mem_bytes ", region_get_mem(xfrd->region)); + + print_metric_help_and_type(buf, "nsd_size_config_on_disk_bytes", + "Size of zonelist file on disk, excluding nsd.conf.", + "gauge"); print_longnum(buf, "nsd_size_config_on_disk_bytes ", - xfrd->nsd->options->zonelist_off); + xfrd->nsd->options->zonelist_off); + + print_metric_help_and_type(buf, "nsd_size_config_in_mem_bytes", + "Size of config data in memory.", "gauge"); print_longnum(buf, "nsd_size_config_in_mem_bytes ", region_get_mem( xfrd->nsd->options->region)); - print_stat_block(buf, st); - /*zone statistics*/ - evbuffer_add_printf(buf, "nsd_zones_primary_total %lu\n", + /* number of zones serverd */ + print_metric_help_and_type(buf, "nsd_zones_primary", + "Number of primary zones served.", "gauge"); + evbuffer_add_printf(buf, "nsd_zones_primary %lu\n", (unsigned long)(xfrd->notify_zones->count - xfrd->zones->count)); - evbuffer_add_printf(buf, "nsd_zones_secondary_total %lu\n", + + print_metric_help_and_type(buf, "nsd_zones_secondary", + "Number of secondary zones served.", "gauge"); + evbuffer_add_printf(buf, "nsd_zones_secondary %lu\n", (unsigned long)xfrd->zones->count); + #ifdef USE_ZONE_STATS zonestat_print(buf, xfrd, clear, zonestats); /*per-zone statistics*/ #else From 1ec6f148d3f77637a7104cf3f3e1551523e6db4d Mon Sep 17 00:00:00 2001 From: Jannik Peters Date: Mon, 17 Feb 2025 14:00:02 +0100 Subject: [PATCH 7/9] Deduplicate stats code by using a prefix string --- metrics.c | 277 +++++++++++++----------------------------------------- 1 file changed, 66 insertions(+), 211 deletions(-) diff --git a/metrics.c b/metrics.c index 8d97bf89..a2b79539 100644 --- a/metrics.c +++ b/metrics.c @@ -402,27 +402,26 @@ print_longnum(struct evbuffer *buf, char* desc, uint64_t x) } static void -print_metric_help_and_type(struct evbuffer *buf, char *name, +print_metric_help_and_type(struct evbuffer *buf, char *prefix, char *name, char *help, char *type) { - evbuffer_add_printf(buf, "# HELP %s %s\n# TYPE %s %s\n", - name, help, name, type); -} - -static void -print_metric_help_and_type_zonestats(struct evbuffer *buf, char *name, - char *help, char *type, char *zonestat_name) -{ - evbuffer_add_printf(buf, "# HELP nsd_zonestats_%s_%s %s\n# TYPE %s %s\n", - zonestat_name, name, help, name, type); + evbuffer_add_printf(buf, "# HELP %s%s %s\n# TYPE %s%s %s\n", + prefix, name, help, prefix, name, type); } static void print_stat_block(struct evbuffer *buf, struct nsdst* st, - struct nsdst** zonestats) + char *name) { size_t i; + char prefix[512] = {0}; + if (name) { + snprintf(prefix, sizeof(prefix), "nsd_zonestats_%s_", name); + } else { + sprintf(prefix, "nsd_"); + } + const char* rcstr[] = {"NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED", "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH", "NOTZONE", "RCODE11", "RCODE12", "RCODE13", "RCODE14", "RCODE15", @@ -430,262 +429,115 @@ print_stat_block(struct evbuffer *buf, struct nsdst* st, }; /* nsd_queries_by_type_total */ - print_metric_help_and_type(buf, "nsd_queries_by_type_total", + print_metric_help_and_type(buf, prefix, "queries_by_type_total", "Total number of queries recieved by type.", "counter"); for(i=0; i<= 255; i++) { if(metrics_inhibit_zero && st->qtype[i] == 0 && strncmp(rrtype_to_string(i), "TYPE", 4) == 0) continue; - evbuffer_add_printf(buf, "nsd_queries_by_type_total{type=\"%s\"} %lu\n", - rrtype_to_string(i), (unsigned long)st->qtype[i]); + evbuffer_add_printf(buf, "%squeries_by_type_total{type=\"%s\"} %lu\n", + prefix, rrtype_to_string(i), (unsigned long)st->qtype[i]); } /* nsd_queries_by_class_total */ - print_metric_help_and_type(buf, "nsd_queries_by_class_total", + print_metric_help_and_type(buf, prefix, "queries_by_class_total", "Total number of queries recieved by class.", "counter"); for(i=0; i<4; i++) { if(metrics_inhibit_zero && st->qclass[i] == 0 && i != CLASS_IN) continue; - evbuffer_add_printf(buf, "nsd_queries_by_class_total{class=\"%s\"} %lu\n", - rrclass_to_string(i), (unsigned long)st->qclass[i]); + evbuffer_add_printf(buf, "%squeries_by_class_total{class=\"%s\"} %lu\n", + prefix, rrclass_to_string(i), (unsigned long)st->qclass[i]); } /* nsd_queries_by_opcode_total */ - print_metric_help_and_type(buf, "nsd_queries_by_opcode_total", + print_metric_help_and_type(buf, prefix, "queries_by_opcode_total", "Total number of queries recieved by opcode.", "counter"); for(i=0; i<6; i++) { if(metrics_inhibit_zero && st->opcode[i] == 0 && i != OPCODE_QUERY) continue; - evbuffer_add_printf(buf, "nsd_queries_by_opcode_total{opcode=\"%s\"} %lu\n", - opcode2str(i), (unsigned long)st->opcode[i]); + evbuffer_add_printf(buf, "%squeries_by_opcode_total{opcode=\"%s\"} %lu\n", + prefix, opcode2str(i), (unsigned long)st->opcode[i]); } /* nsd_queries_by_rcode_total */ - print_metric_help_and_type(buf, "nsd_queries_by_rcode_total", + print_metric_help_and_type(buf, prefix, "queries_by_rcode_total", "Total number of queries recieved by rcode.", "counter"); for(i=0; i<17; i++) { if(metrics_inhibit_zero && st->rcode[i] == 0 && i > RCODE_YXDOMAIN) /*NSD does not use larger*/ continue; - evbuffer_add_printf(buf, "nsd_queries_by_rcode_total{rcode=\"%s\"} %lu\n", - rcstr[i], (unsigned long)st->rcode[i]); + evbuffer_add_printf(buf, "%squeries_by_rcode_total{rcode=\"%s\"} %lu\n", + prefix, rcstr[i], (unsigned long)st->rcode[i]); } /* nsd_queries_by_transport_total */ - print_metric_help_and_type(buf, "nsd_queries_by_transport_total", + print_metric_help_and_type(buf, prefix, "queries_by_transport_total", "Total number of queries recieved by transport.", "counter"); - evbuffer_add_printf(buf, "nsd_queries_by_transport_total{transport=\"udp\"} %lu\n", (unsigned long)st->qudp); - evbuffer_add_printf(buf, "nsd_queries_by_transport_total{transport=\"udp6\"} %lu\n", (unsigned long)st->qudp6); + evbuffer_add_printf(buf, "%squeries_by_transport_total{transport=\"udp\"} %lu\n", prefix, (unsigned long)st->qudp); + evbuffer_add_printf(buf, "%squeries_by_transport_total{transport=\"udp6\"} %lu\n", prefix, (unsigned long)st->qudp6); /* nsd_queries_with_edns_total */ - print_metric_help_and_type(buf, "nsd_queries_with_edns_total", + print_metric_help_and_type(buf, prefix, "queries_with_edns_total", "Total number of queries recieved with EDNS OPT.", "counter"); - evbuffer_add_printf(buf, "nsd_queries_with_edns_total %lu\n", (unsigned long)st->edns); + evbuffer_add_printf(buf, "%squeries_with_edns_total %lu\n", prefix, (unsigned long)st->edns); /* nsd_queries_with_edns_failed_total */ - print_metric_help_and_type(buf, "nsd_queries_with_edns_failed_total", + print_metric_help_and_type(buf, prefix, "queries_with_edns_failed_total", "Total number of queries recieved with EDNS OPT where EDNS parsing failed.", "counter"); - evbuffer_add_printf(buf, "nsd_queries_with_edns_failed_total %lu\n", (unsigned long)st->ednserr); + evbuffer_add_printf(buf, "%squeries_with_edns_failed_total %lu\n", prefix, (unsigned long)st->ednserr); /* nsd_connections_total */ - print_metric_help_and_type(buf, "nsd_connections_total", + print_metric_help_and_type(buf, prefix, "connections_total", "Total number of connections.", "counter"); - evbuffer_add_printf(buf, "nsd_connections_total{transport=\"tcp\"} %lu\n", (unsigned long)st->ctcp); - evbuffer_add_printf(buf, "nsd_connections_total{transport=\"tcp6\"} %lu\n", (unsigned long)st->ctcp6); - evbuffer_add_printf(buf, "nsd_connections_total{transport=\"tls\"} %lu\n", (unsigned long)st->ctls); - evbuffer_add_printf(buf, "nsd_connections_total{transport=\"tls6\"} %lu\n", (unsigned long)st->ctls6); + evbuffer_add_printf(buf, "%sconnections_total{transport=\"tcp\"} %lu\n", prefix, (unsigned long)st->ctcp); + evbuffer_add_printf(buf, "%sconnections_total{transport=\"tcp6\"} %lu\n", prefix, (unsigned long)st->ctcp6); + evbuffer_add_printf(buf, "%sconnections_total{transport=\"tls\"} %lu\n", prefix, (unsigned long)st->ctls); + evbuffer_add_printf(buf, "%sconnections_total{transport=\"tls6\"} %lu\n", prefix, (unsigned long)st->ctls6); /* nsd_xfr_requests_served_total */ - print_metric_help_and_type(buf, "nsd_xfr_requests_served_total", + print_metric_help_and_type(buf, prefix, "xfr_requests_served_total", "Total number of answered zone transfers.", "counter"); - evbuffer_add_printf(buf, "nsd_xfr_requests_served_total{xfrtype=\"AXFR\"} %lu\n", (unsigned long)st->raxfr); - evbuffer_add_printf(buf, "nsd_xfr_requests_served_total{xfrtype=\"IXFR\"} %lu\n", (unsigned long)st->rixfr); + evbuffer_add_printf(buf, "%sxfr_requests_served_total{xfrtype=\"AXFR\"} %lu\n", prefix, (unsigned long)st->raxfr); + evbuffer_add_printf(buf, "%sxfr_requests_served_total{xfrtype=\"IXFR\"} %lu\n", prefix, (unsigned long)st->rixfr); /* nsd_queries_dropped_total */ - print_metric_help_and_type(buf, "nsd_queries_dropped_total", + print_metric_help_and_type(buf, prefix, "queries_dropped_total", "Total number of dropped queries.", "counter"); - evbuffer_add_printf(buf, "nsd_queries_dropped_total %lu\n", (unsigned long)st->dropped); + evbuffer_add_printf(buf, "%squeries_dropped_total %lu\n", prefix, (unsigned long)st->dropped); /* nsd_queries_rx_failed_total */ - print_metric_help_and_type(buf, "nsd_queries_rx_failed_total", + print_metric_help_and_type(buf, prefix, "queries_rx_failed_total", "Total number of queries where receive failed.", "counter"); - evbuffer_add_printf(buf, "nsd_queries_rx_failed_total %lu\n", (unsigned long)st->rxerr); + evbuffer_add_printf(buf, "%squeries_rx_failed_total %lu\n", prefix, (unsigned long)st->rxerr); /* nsd_answers_tx_failed_total */ - print_metric_help_and_type(buf, "nsd_answers_tx_failed_total", + print_metric_help_and_type(buf, prefix, "answers_tx_failed_total", "Total number of answers where transmit failed.", "counter"); - evbuffer_add_printf(buf, "nsd_answers_tx_failed_total %lu\n", (unsigned long)st->txerr); + evbuffer_add_printf(buf, "%sanswers_tx_failed_total %lu\n", prefix, (unsigned long)st->txerr); /* nsd_answers_without_aa_total */ - print_metric_help_and_type(buf, "nsd_answers_without_aa_total", + print_metric_help_and_type(buf, prefix, "answers_without_aa_total", "Total number of NOERROR answers without AA flag set.", "counter"); - evbuffer_add_printf(buf, "nsd_answers_without_aa_total %lu\n", (unsigned long)st->nona); + evbuffer_add_printf(buf, "%sanswers_without_aa_total %lu\n", prefix, (unsigned long)st->nona); /* nsd_answers_truncated_total */ - print_metric_help_and_type(buf, "nsd_answers_truncated_total", + print_metric_help_and_type(buf, prefix, "answers_truncated_total", "Total number of truncated answers.", "counter"); - evbuffer_add_printf(buf, "nsd_answers_truncated_total %lu\n", (unsigned long)st->truncated); -} - -/*print one block of statistics. n is name and d is delimiter*/ -static void -print_stat_block_with_zone(struct evbuffer *buf, char* n, struct nsdst* st) -{ - const char* rcstr[] = {"NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", - "NOTIMP", "REFUSED", "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH", - "NOTZONE", "RCODE11", "RCODE12", "RCODE13", "RCODE14", "RCODE15", - "BADVERS" - }; - size_t i; - - /* nsd_zonestats_%s_queries_by_type_total */ - print_metric_help_and_type_zonestats(buf, "queries_by_type_total", - "Total number of queries recieved by type.", - "counter", n); - for(i=0; i<= 255; i++) { - if(metrics_inhibit_zero && st->qtype[i] == 0 && - strncmp(rrtype_to_string(i), "TYPE", 4) == 0) - continue; - evbuffer_add_printf(buf, "nsd_zonestats_%s_queries_by_type_total{type=\"%s\"} %lu\n", - n, rrtype_to_string(i), (unsigned long)st->qtype[i]); - } - - /* nsd_zonestats_%s_queries_by_class_total */ - print_metric_help_and_type_zonestats(buf, "queries_by_class_total", - "Total number of queries recieved by class.", - "counter", n); - for(i=0; i<4; i++) { - if(metrics_inhibit_zero && st->qclass[i] == 0 && i != CLASS_IN) - continue; - evbuffer_add_printf(buf, - "nsd_zonestats_%s_queries_by_class_total{class=\"%s\"} %lu\n", - n, rrclass_to_string(i), (unsigned long)st->qclass[i]); - } - - /* nsd_zonestats_%s_queries_by_opcode_total */ - print_metric_help_and_type_zonestats(buf, "queries_by_opcode_total", - "Total number of queries recieved by opcode.", - "counter", n); - for(i=0; i<6; i++) { - if(metrics_inhibit_zero && st->opcode[i] == 0 && i != OPCODE_QUERY) - continue; - evbuffer_add_printf(buf, - "nsd_zonestats_%s_queries_by_opcode_total{opcode=\"%s\"} %lu\n", - n, opcode2str(i), (unsigned long)st->opcode[i]); - } - - /* nsd_zonestats_%s_queries_by_rcode_total */ - print_metric_help_and_type_zonestats(buf, "queries_by_rcode_total", - "Total number of queries recieved by rcode.", - "counter", n); - for(i=0; i<17; i++) { - if(metrics_inhibit_zero && st->rcode[i] == 0 && - i > RCODE_YXDOMAIN) /*NSD does not use larger*/ - continue; - evbuffer_add_printf(buf, - "nsd_zonestats_%s_queries_by_rcode_total{rcode=\"%s\"} %lu\n", - n, rcstr[i], (unsigned long)st->rcode[i]); - } - - /* nsd_zonestats_%s_queries_by_transport_total */ - print_metric_help_and_type_zonestats(buf, "queries_by_transport_total", - "Total number of queries recieved by transport.", "counter", n); - evbuffer_add_printf(buf, - "nsd_zonestats_%s_queries_by_transport_total{" - "transport=\"udp\"} %lu\n", - n, (unsigned long)st->qudp); - evbuffer_add_printf(buf, - "nsd_zonestats_%s_queries_by_transport_total{" - "transport=\"udp6\"} %lu\n", - n, (unsigned long)st->qudp6); - - /* nsd_zonestats_%s_queries_with_edns_total */ - print_metric_help_and_type_zonestats(buf, "queries_with_edns_total", - "Total number of queries recieved with EDNS OPT.", "counter", n); - evbuffer_add_printf(buf, "nsd_zonestats_%s_queries_with_edns_total %lu\n", - n, (unsigned long)st->edns); - - /* nsd_zonestats_%s_queries_with_edns_failed_total */ - print_metric_help_and_type_zonestats(buf, "queries_with_edns_failed_total", - "Total number of queries recieved with EDNS OPT where EDNS parsing failed.", - "counter", n); - evbuffer_add_printf(buf, "nsd_zonestats_%s_queries_with_edns_failed_total %lu\n", - n, (unsigned long)st->ednserr); - - /* nsd_zonestats_%s_connections_total */ - print_metric_help_and_type_zonestats(buf, "connections_total", - "Total number of connections.", "counter", n); - evbuffer_add_printf(buf, - "nsd_zonestats_%s_connections_total{transport=\"tcp\"} %lu\n", - n, (unsigned long)st->ctcp); - evbuffer_add_printf(buf, - "nsd_zonestats_%s_connections_total{transport=\"tcp6\"} %lu\n", - n, (unsigned long)st->ctcp6); - evbuffer_add_printf(buf, - "nsd_zonestats_%s_connections_total{transport=\"tls\"} %lu\n", - n, (unsigned long)st->ctls); - evbuffer_add_printf(buf, - "nsd_zonestats_%s_connections_total{transport=\"tls6\"} %lu\n", - n, (unsigned long)st->ctls6); - - /* nsd_zonestats_%s_xfr_requests_served_total */ - print_metric_help_and_type_zonestats(buf, "xfr_requests_served_total", - "Total number of answered zone transfers.", "counter", n); - evbuffer_add_printf(buf, - "nsd_zonestats_%s_xfr_requests_served_total{xfrtype=\"AXFR\"} %lu\n", - n, (unsigned long)st->raxfr); - evbuffer_add_printf(buf, - "nsd_zonestats_%s_xfr_requests_served_total{xfrtype=\"IXFR\"} %lu\n", - n, (unsigned long)st->rixfr); - - /* nsd_zonestats_%s_zonestats_%s_queries_dropped_total */ - print_metric_help_and_type_zonestats(buf, "queries_dropped_total", - "Total number of dropped queries.", "counter", n); - evbuffer_add_printf(buf, - "nsd_zonestats_%s_queries_dropped_total %lu\n", - n, (unsigned long)st->dropped); - - /* nsd_zonestats_%s_queries_rx_failed_total */ - print_metric_help_and_type_zonestats(buf, "queries_rx_failed_total", - "Total number of queries where receive failed.", "counter", n); - evbuffer_add_printf(buf, - "nsd_zonestats_%s_queries_rx_failed_total %lu\n", - n, (unsigned long)st->rxerr); - - /* nsd_zonestats_%s_answers_tx_failed_total */ - print_metric_help_and_type_zonestats(buf, "answers_tx_failed_total", - "Total number of answers where transmit failed.", "counter", n); - evbuffer_add_printf(buf, - "nsd_zonestats_%s_answers_tx_failed_total %lu\n", - n, (unsigned long)st->txerr); - - /* nsd_zonestats_%s_answers_without_aa_total */ - print_metric_help_and_type_zonestats(buf, "answers_without_aa_total", - "Total number of NOERROR answers without AA flag set.", "counter", n); - evbuffer_add_printf(buf, - "nsd_zonestats_%s_answers_without_aa_total %lu\n", - n, (unsigned long)st->nona); - - /* nsd_zonestats_%s_answers_truncated_total */ - print_metric_help_and_type_zonestats(buf, "answers_truncated_total", - "Total number of truncated answers.", "counter", n); - evbuffer_add_printf(buf, - "nsd_zonestats_%s_answers_truncated_total %lu\n", - n, (unsigned long)st->truncated); + evbuffer_add_printf(buf, "%sanswers_truncated_total %lu\n", prefix, (unsigned long)st->truncated); } #ifdef USE_ZONE_STATS @@ -745,13 +597,16 @@ zonestat_print(struct evbuffer *buf, xfrd_state_type* xfrd, int clear, } /*stat0 contains the details that we want to print*/ - print_metric_help_and_type_zonestats(buf, "queries_total", - "Total number of queries recieved.", - "counter", name); + + char prefix[512] = {0}; + snprintf(prefix, sizeof(prefix), "nsd_zonestats_%s_", name); + + print_metric_help_and_type(buf, prefix, "queries_total", + "Total number of queries recieved.", "counter"); evbuffer_add_printf(buf, "nsd_zonestats_%s_queries_total %lu\n", name, (unsigned long)(stat0.qudp + stat0.qudp6 + stat0.ctcp + stat0.ctcp6 + stat0.ctls + stat0.ctls6)); - print_stat_block_with_zone(buf, name, &stat0); + print_stat_block(buf, &stat0, name); } } #endif /*USE_ZONE_STATS*/ @@ -764,7 +619,7 @@ print_stats(struct evbuffer *buf, xfrd_state_type* xfrd, struct timeval* now, in struct timeval elapsed, uptime; /* nsd_queries_total */ - print_metric_help_and_type(buf, "nsd_queries_total", + print_metric_help_and_type(buf, "nsd_", "queries_total", "Total number of queries recieved.", "counter"); /*per CPU and total*/ for(i=0; insd->child_count; i++) { @@ -772,17 +627,17 @@ print_stats(struct evbuffer *buf, xfrd_state_type* xfrd, struct timeval* now, in (int)i, (unsigned long)xfrd->nsd->children[i].query_count); } - print_stat_block(buf, st, zonestats); + print_stat_block(buf, st, NULL); /*time elapsed and uptime (in seconds)*/ timeval_subtract(&uptime, now, &xfrd->nsd->metrics->boot_time); timeval_subtract(&elapsed, now, &xfrd->nsd->metrics->stats_time); - print_metric_help_and_type(buf, "nsd_time_up_seconds_total", + print_metric_help_and_type(buf, "nsd_", "time_up_seconds_total", "Uptime since server boot in seconds.", "counter"); evbuffer_add_printf(buf, "nsd_time_up_seconds_total %lu.%6.6lu\n", (unsigned long)uptime.tv_sec, (unsigned long)uptime.tv_usec); /* TODO: re-add when elapsed time resetting on nsd-control stats is implemented - print_metric_help_and_type(buf, "nsd_time_elapsed_seconds", + print_metric_help_and_type(buf, "nsd_", "time_elapsed_seconds", "Time since last statistics printout in seconds.", "untyped"); evbuffer_add_printf(buf, "nsd_time_elapsed_seconds %lu.%6.6lu\n", @@ -790,37 +645,37 @@ print_stats(struct evbuffer *buf, xfrd_state_type* xfrd, struct timeval* now, in */ /*mem info, database on disksize*/ - print_metric_help_and_type(buf, "nsd_size_db_on_disk_bytes", + print_metric_help_and_type(buf, "nsd_", "size_db_on_disk_bytes", "Size of DNS database on disk.", "gauge"); print_longnum(buf, "nsd_size_db_on_disk_bytes ", st->db_disk); - print_metric_help_and_type(buf, "nsd_size_db_in_mem_bytes", + print_metric_help_and_type(buf, "nsd_", "size_db_in_mem_bytes", "Size of DNS database in memory.", "gauge"); print_longnum(buf, "nsd_size_db_in_mem_bytes ", st->db_mem); - print_metric_help_and_type(buf, "nsd_size_xfrd_in_mem_bytes", + print_metric_help_and_type(buf, "nsd_", "size_xfrd_in_mem_bytes", "Size of zone transfers and notifies in xfrd process, excluding TSIG data.", "gauge"); print_longnum(buf, "nsd_size_xfrd_in_mem_bytes ", region_get_mem(xfrd->region)); - print_metric_help_and_type(buf, "nsd_size_config_on_disk_bytes", + print_metric_help_and_type(buf, "nsd_", "size_config_on_disk_bytes", "Size of zonelist file on disk, excluding nsd.conf.", "gauge"); print_longnum(buf, "nsd_size_config_on_disk_bytes ", xfrd->nsd->options->zonelist_off); - print_metric_help_and_type(buf, "nsd_size_config_in_mem_bytes", + print_metric_help_and_type(buf, "nsd_", "size_config_in_mem_bytes", "Size of config data in memory.", "gauge"); print_longnum(buf, "nsd_size_config_in_mem_bytes ", region_get_mem( xfrd->nsd->options->region)); /* number of zones serverd */ - print_metric_help_and_type(buf, "nsd_zones_primary", + print_metric_help_and_type(buf, "nsd_", "zones_primary", "Number of primary zones served.", "gauge"); evbuffer_add_printf(buf, "nsd_zones_primary %lu\n", (unsigned long)(xfrd->notify_zones->count - xfrd->zones->count)); - print_metric_help_and_type(buf, "nsd_zones_secondary", + print_metric_help_and_type(buf, "nsd_", "zones_secondary", "Number of secondary zones served.", "gauge"); evbuffer_add_printf(buf, "nsd_zones_secondary %lu\n", (unsigned long)xfrd->zones->count); From 01ee8aeba5c6b0bedacec1d78ba8b87c57a62e3b Mon Sep 17 00:00:00 2001 From: Jannik Peters Date: Mon, 17 Feb 2025 14:40:52 +0100 Subject: [PATCH 8/9] Update comments and remove unused function --- metrics.c | 5 +---- nsd.c | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/metrics.c b/metrics.c index a2b79539..dd806d49 100644 --- a/metrics.c +++ b/metrics.c @@ -38,7 +38,7 @@ const int metrics_inhibit_zero = 1; /** - * list of events for accepting connections + * list of connection accepting file descriptors */ struct metrics_acceptlist { struct metrics_acceptlist* next; @@ -67,9 +67,6 @@ metrics_http_callback(struct evhttp_request *req, void *p); #ifdef BIND8_STATS static void process_stats(struct evbuffer* buf, xfrd_state_type* xfrd, int peek); - -static void -do_stats(struct evbuffer *buf, xfrd_state_type *xfrd, int peek); #endif /*BIND8_STATS*/ struct daemon_metrics* diff --git a/nsd.c b/nsd.c index f0bdb0ae..fc2e963a 100644 --- a/nsd.c +++ b/nsd.c @@ -1522,7 +1522,6 @@ main(int argc, char *argv[]) } #ifdef USE_METRICS if(nsd.options->metrics_enable) { - /* read ssl keys while superuser and outside chroot */ if(!(nsd.metrics = daemon_metrics_create(nsd.options))) error("could not perform metrics server setup"); } From 844eff84668aa050772277c1b6601d9bf9a60a7e Mon Sep 17 00:00:00 2001 From: Jannik Peters Date: Mon, 17 Feb 2025 15:25:54 +0100 Subject: [PATCH 9/9] Rename metrics feature flag to prometheus-metrics --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 23796451..c115b926 100644 --- a/configure.ac +++ b/configure.ac @@ -1157,8 +1157,8 @@ case "$enable_packed" in ;; esac -AC_ARG_ENABLE(metrics, AS_HELP_STRING([--enable-metrics],[Enable prometheus metrics support.])) -case "$enable_metrics" in +AC_ARG_ENABLE(prometheus-metrics, AS_HELP_STRING([--enable-prometheus-metrics],[Enable prometheus metrics support.])) +case "$enable_prometheus_metrics" in yes) AC_DEFINE_UNQUOTED([USE_METRICS], [], [Define this to expose NSD statistics via a prometheus metrics HTTP endpoint.]) AC_DEFINE_UNQUOTED([NSD_METRICS_PORT], [9100], [Define to the default metrics HTTP endpoint port.])