- add-prometheus-metrics, set metrics to type 'counter', for number of query

metrics, and do not reset the stats. There is a warning when
  statistics-cumulative has the wrong value. But the stats are not reset
  from the metrics endpoint regardless. The contrib/metrics.awk script
  is also updated, and the documentation recommends the cumulative setting.
This commit is contained in:
W.C.A. Wijngaards
2026-04-02 10:37:56 +02:00
parent 286494366c
commit b2590c2022
3 changed files with 35 additions and 24 deletions
+8 -8
View File
@@ -2,7 +2,7 @@
# and output prometheus metrics style output.
# use these options:
# server: extended-statistics: yes
# statistics-cumulative: no
# statistics-cumulative: yes
# statistics-interval: 0
# remote-control: control-enable: yes
# Can use it like unbound-control stats | awk -f "metrics.awk"
@@ -17,7 +17,7 @@ BEGIN {
# print the output metrics
END {
print "# HELP unbound_hits_queries Unbound DNS traffic and cache hits"
print "# TYPE unbound_hits_queries gauge"
print "# TYPE unbound_hits_queries counter"
print "unbound_hits_queries{type=\"total.num.queries\"} " val["total.num.queries"];
for (x=0; x<99; x++) {
if(val["thread" $x ".num.queries"] != "") {
@@ -70,7 +70,7 @@ END {
print ""
print "# HELP unbound_by_type_queries Unbound DNS queries by type"
print "# TYPE unbound_by_type_queries gauge"
print "# TYPE unbound_by_type_queries counter"
for(x in val) {
if(x ~ /^num.query.type./) {
if(val[x] != "") {
@@ -82,7 +82,7 @@ END {
print ""
print "# HELP unbound_by_class_queries Unbound DNS queries by class"
print "# TYPE unbound_by_class_queries gauge"
print "# TYPE unbound_by_class_queries counter"
for(x in val) {
if(x ~ /^num.query.class./) {
if(val[x] != "") {
@@ -94,7 +94,7 @@ END {
print ""
print "# HELP unbound_by_opcode_queries Unbound DNS queries by opcode"
print "# TYPE unbound_by_opcode_queries gauge"
print "# TYPE unbound_by_opcode_queries counter"
for(x in val) {
if(x ~ /^num.query.opcode./) {
if(val[x] != "") {
@@ -106,7 +106,7 @@ END {
print ""
print "# HELP unbound_by_rcode_queries Unbound DNS answers by rcode"
print "# TYPE unbound_by_rcode_queries gauge"
print "# TYPE unbound_by_rcode_queries counter"
for(x in val) {
if(x ~ /^num.answer.rcode./) {
if(val[x] != "") {
@@ -118,7 +118,7 @@ END {
print ""
print "# HELP unbound_by_flags_queries Unbound DNS queries by flags"
print "# TYPE unbound_by_flags_queries gauge"
print "# TYPE unbound_by_flags_queries counter"
for(x in val) {
if(x ~ /^num.query.flags./) {
if(val[x] != "") {
@@ -136,7 +136,7 @@ END {
print ""
print "# HELP unbound_histogram_seconds Unbound DNS histogram of reply time"
print "# TYPE unbound_histogram_seconds gauge"
print "# TYPE unbound_histogram_seconds counter"
print "unbound_histogram_seconds{bucket=\"000000.000000.to.000000.000001\"} " val["histogram.000000.000000.to.000000.000001"];
print "unbound_histogram_seconds{bucket=\"000000.000001.to.000000.000002\"} " val["histogram.000000.000001.to.000000.000002"];
print "unbound_histogram_seconds{bucket=\"000000.000002.to.000000.000004\"} " val["histogram.000000.000002.to.000000.000004"];
+16 -15
View File
@@ -257,6 +257,8 @@ daemon_metrics_open_ports(struct daemon_metrics* metrics,
struct config_file* cfg)
{
assert(cfg->metrics_enable);
if(!cfg->stat_cumulative)
log_warn("metrics-enable: yes but statistics-cumulative: no, access to control command 'stats' would reset the stat counters, perhaps set 'statistics-cumulative: yes'.");
if(cfg->metrics_ifs.first) {
char** rcif = NULL;
int i, num_rcif = 0;
@@ -334,7 +336,7 @@ metrics_print_types(struct evbuffer *reply)
{
char* prefix = METRICS_PREFIX;
print_metric_help_and_type(reply, prefix, "hits_queries",
"Unbound DNS traffic and cache hits", "gauge");
"Unbound DNS traffic and cache hits", "counter");
print_metric_help_and_type(reply, prefix, "queue_queries",
"Unbound requestlist size", "gauge");
print_metric_help_and_type(reply, prefix, "recursion_time",
@@ -540,7 +542,7 @@ metrics_print_hist(struct evbuffer* reply, struct ub_stats_info* s)
size_t i;
print_metric_help_and_type(reply, prefix, "histogram_seconds",
"Unbound DNS histogram of reply time", "gauge");
"Unbound DNS histogram of reply time", "counter");
hist = timehist_setup();
if(!hist) {
@@ -581,7 +583,7 @@ metrics_print_ext(struct evbuffer* reply, struct ub_stats_info* s,
/* TYPE */
print_metric_help_and_type(reply, prefix, "by_type_queries",
"Unbound DNS queries by type", "gauge");
"Unbound DNS queries by type", "counter");
for(i=0; i<UB_STATS_QTYPE_NUM; i++) {
if(inhibit_zero && s->svr.qtype[i] == 0)
continue;
@@ -610,7 +612,7 @@ metrics_print_ext(struct evbuffer* reply, struct ub_stats_info* s,
/* CLASS */
print_metric_help_and_type(reply, prefix, "by_class_queries",
"Unbound DNS queries by class", "gauge");
"Unbound DNS queries by class", "counter");
for(i=0; i<UB_STATS_QCLASS_NUM; i++) {
if(inhibit_zero && s->svr.qclass[i] == 0)
continue;
@@ -630,7 +632,7 @@ metrics_print_ext(struct evbuffer* reply, struct ub_stats_info* s,
/* OPCODE */
print_metric_help_and_type(reply, prefix, "by_opcode_queries",
"Unbound DNS queries by opcode", "gauge");
"Unbound DNS queries by opcode", "counter");
for(i=0; i<UB_STATS_OPCODE_NUM; i++) {
if(inhibit_zero && s->svr.qopcode[i] == 0)
continue;
@@ -646,7 +648,7 @@ metrics_print_ext(struct evbuffer* reply, struct ub_stats_info* s,
/* RCODE */
print_metric_help_and_type(reply, prefix, "by_rcode_queries",
"Unbound DNS answers by rcode", "gauge");
"Unbound DNS answers by rcode", "counter");
for(i=0; i<UB_STATS_RCODE_NUM; i++) {
/* Always include RCODEs 0-5 */
if(inhibit_zero && i > LDNS_RCODE_REFUSED && s->svr.ans_rcode[i] == 0)
@@ -667,7 +669,7 @@ metrics_print_ext(struct evbuffer* reply, struct ub_stats_info* s,
/* FLAGS */
print_metric_help_and_type(reply, prefix, "by_flags_queries",
"Unbound DNS queries by flags", "gauge");
"Unbound DNS queries by flags", "counter");
INFO_EXT_STATS("by_flags_queries", "flag", "QR", s->svr.qbit_QR);
INFO_EXT_STATS("by_flags_queries", "flag", "AA", s->svr.qbit_AA);
INFO_EXT_STATS("by_flags_queries", "flag", "TC", s->svr.qbit_TC);
@@ -683,7 +685,7 @@ metrics_print_ext(struct evbuffer* reply, struct ub_stats_info* s,
/* transport */
print_metric_help_and_type(reply, prefix, "by_transport_queries",
"Unbound DNS queries by transport", "gauge");
"Unbound DNS queries by transport", "counter");
INFO_EXT_STATS("by_transport_queries", "transport", "tcp",
s->svr.qtcp);
INFO_EXT_STATS("by_transport_queries", "transport", "tcpout",
@@ -705,13 +707,13 @@ metrics_print_ext(struct evbuffer* reply, struct ub_stats_info* s,
/* iteration */
print_metric_help_and_type(reply, prefix, "ratelimited_queries",
"Unbound DNS queries ratelimited", "gauge");
"Unbound DNS queries ratelimited", "counter");
INFO_EXT_STATS("ratelimited_queries", "type", "ratelimited",
s->svr.queries_ratelimited);
/* validation */
print_metric_help_and_type(reply, prefix, "validation_queries",
"Unbound DNS queries DNSSEC validated", "gauge");
"Unbound DNS queries DNSSEC validated", "counter");
INFO_EXT_STATS("validation_queries", "type", "secure",
s->svr.ans_secure);
INFO_EXT_STATS("validation_queries", "type", "bogus",
@@ -727,7 +729,7 @@ metrics_print_ext(struct evbuffer* reply, struct ub_stats_info* s,
/* threat detection */
print_metric_help_and_type(reply, prefix, "threat_queries",
"Unbound DNS queries threats", "gauge");
"Unbound DNS queries threats", "counter");
INFO_EXT_STATS("threat_queries", "type", "unwanted.queries",
s->svr.unwanted_queries);
INFO_EXT_STATS("threat_queries", "type", "unwanted.replies",
@@ -753,7 +755,7 @@ metrics_print_ext(struct evbuffer* reply, struct ub_stats_info* s,
/* applied RPZ actions */
print_metric_help_and_type(reply, prefix, "rpz_actions",
"Unbound DNS RPZ actions", "gauge");
"Unbound DNS RPZ actions", "counter");
for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++) {
if(i == RPZ_NO_OVERRIDE_ACTION)
continue;
@@ -765,7 +767,7 @@ metrics_print_ext(struct evbuffer* reply, struct ub_stats_info* s,
/* handling mechanism */
print_metric_help_and_type(reply, prefix, "handled_queries",
"Unbound DNS queries by handling mechanism", "gauge");
"Unbound DNS queries by handling mechanism", "counter");
#ifdef USE_DNSCRYPT
INFO_EXT_STATS("cache_items", "count", "dnscrypt_shared_secret.cache",
s->svr.shared_secret_cache_count);
@@ -867,8 +869,7 @@ metrics_http_callback(struct evhttp_request *req, void *p)
evhttp_add_header(evhttp_request_get_output_headers(req),
"Content-Type", "text/plain; version=0.0.4");
do_metrics_stats(reply, metrics->worker,
!metrics->worker->daemon->cfg->stat_cumulative);
do_metrics_stats(reply, metrics->worker, 0 /* no reset */);
evhttp_send_reply(req, HTTP_OK, NULL, reply);
verbose(VERB_DETAIL, "metrics operation completed, response sent");
evbuffer_free(reply);
+11 -1
View File
@@ -3443,10 +3443,20 @@ These options are part of the ``server:`` section.
command, but with metric names
following the prometheus specification. (Requires libevent2)
Beware, that when using
Use it with settings, extended-statistics: yes that collects more
information,
:ref:`extended-statistics<unbound.conf.extended-statistics>` .
And set statistics-cumulative: yes, because the metrics are
defined as cumulative counters for the number of queries,
:ref:`statistics-cumulative<unbound.conf.statistics-cumulative>` .
Access from the metrics endpoint does not reset the statistics.
Beware, if statistics-cumulative is disabled, that when using
:ref:`stats<unbound-control.commands.stats`
(instead of stats_noreset), the statistics will be reset for
the HTTP metrics endpoint as well.
With statistics-cumulative enabled, the stats (and stats_noreset)
command can be used to also get a look at the statistics information.
Default: no