]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: generate metrics related files from a single source
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 4 Sep 2024 12:02:08 +0000 (14:02 +0200)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Fri, 27 Sep 2024 09:29:46 +0000 (11:29 +0200)
12 files changed:
pdns/recursordist/.gitignore
pdns/recursordist/Makefile.am
pdns/recursordist/RECURSOR-MIB.in [new file with mode: 0644]
pdns/recursordist/RECURSOR-MIB.txt
pdns/recursordist/docs/.gitignore
pdns/recursordist/docs/metrics.rst
pdns/recursordist/meson.build
pdns/recursordist/metrics.py [new file with mode: 0644]
pdns/recursordist/metrics_table.py [new file with mode: 0644]
pdns/recursordist/rec-snmp.cc
pdns/recursordist/rec_channel_rec.cc
pdns/recursordist/ws-recursor.cc

index 6d14c0950481ddfd3bda7c563969bb2d15bd4277..7a77fb95d03b1e6c125228b2239fbab4931a3ff9 100644 (file)
@@ -59,3 +59,8 @@ PowerDNS-Recursor.pdf
 /.cache
 /.clang-tidy
 /recursor.yml
+/rec-metrics-gen.h
+/rec-oids-gen.h
+/rec-prometheus-gen.h
+rec-snmp-gen.h
+
index a6427ef7042eb8066fed328356b5db260637be60..0d525767a66ef5032c11de0b51985c1530bf41c2 100644 (file)
@@ -39,7 +39,12 @@ AM_LDFLAGS = \
 ACLOCAL_AMFLAGS = -I m4
 
 BUILT_SOURCES=htmlfiles.h \
-       dnslabeltext.cc
+       dnslabeltext.cc \
+       rec-metrics-gen.h \
+       rec-prometheus-gen.h \
+       rec-snmp-gen.h \
+       rec-oids-gen.h \
+       RECURSOR-MIB.txt
 
 CLEANFILES = htmlfiles.h \
        recursor.yml-dist
@@ -48,6 +53,10 @@ htmlfiles.h: incfiles ${srcdir}/html/* ${srcdir}/html/js/*
        $(AM_V_GEN)$(srcdir)/incfiles > $@.tmp
        @mv $@.tmp $@
 
+# Use patterns to avoid having two instances of generate run simultaneously, a well-known hack for GNU make
+rec-metrics-gen%h rec-prometheus-gen%h rec-snmp-gen%h rec-oids-gen%h RECURSOR-MIB%txt: metrics.py metrics_table.py RECURSOR-MIB.in
+       $(PYTHON) metrics.py
+
 # We explicitly build settings in two steps, as settings modifies files in the settings/rust subdir
 SUBDIRS=ext settings settings/rust
 
@@ -78,6 +87,13 @@ EXTRA_DIST = \
        test_libcrypto \
        pdns-recursor.service.in \
        RECURSOR-MIB.txt \
+       metrics.py \
+       metrics_table.py \
+       RECURSOR-MIB.in \
+       rec-metrics-gen.h \
+       rec-prometheus-gen.h \
+       rec-snmp-gen.h \
+       rec-oids-gen.h \
        builder-support/gen-version
 
 dist-hook:
diff --git a/pdns/recursordist/RECURSOR-MIB.in b/pdns/recursordist/RECURSOR-MIB.in
new file mode 100644 (file)
index 0000000..638b214
--- /dev/null
@@ -0,0 +1,138 @@
+-- -*- snmpv2 -*-
+-- ----------------------------------------------------------------------
+-- MIB file for PowerDNS Recursor
+-- ----------------------------------------------------------------------
+
+PDNSRECURSOR-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+    OBJECT-TYPE, MODULE-IDENTITY, enterprises,
+    Counter64, NOTIFICATION-TYPE
+        FROM SNMPv2-SMI
+    CounterBasedGauge64
+        FROM HCNUM-TC
+    OBJECT-GROUP, MODULE-COMPLIANCE, NOTIFICATION-GROUP
+        FROM SNMPv2-CONF;
+
+rec MODULE-IDENTITY
+    LAST-UPDATED "202408280000Z"
+    ORGANIZATION "PowerDNS BV"
+    CONTACT-INFO "support@powerdns.com"
+    DESCRIPTION
+       "This MIB module describes information gathered through PowerDNS Recursor."
+
+    REVISION "202408280000Z"
+    DESCRIPTION "Added metric for too many incoming TCP connections"
+
+    REVISION "202408130000Z"
+    DESCRIPTION "Added metric for chain limits reached"
+
+    REVISION "202405230000Z"
+    DESCRIPTION "Added metrics for maximum chain length and weight"
+
+    REVISION "202306080000Z"
+    DESCRIPTION "Added metrics for NOD and UDR events"
+
+    REVISION "202302240000Z"
+    DESCRIPTION "Added metrics for sharded packet cache contention"
+
+    REVISION "202209120000Z"
+    DESCRIPTION "Added metrics for answers from auths by rcode"
+
+    REVISION "202208220000Z"
+    DESCRIPTION "Added internal maintenance metrics."
+
+    REVISION "202201310000Z"
+    DESCRIPTION "Added non-resolving NS name metric."
+
+    REVISION "202111090000Z"
+    DESCRIPTION "Added NOTIFY-related metrics."
+
+    REVISION "202110270000Z"
+    DESCRIPTION "Added more UDP errors metric."
+
+    REVISION "202107200000Z"
+    DESCRIPTION "Added almost expired task metrics."
+
+    REVISION "202101050000Z"
+    DESCRIPTION "Added Aggressive NSEC cache metrics."
+
+    REVISION "202002170000Z"
+    DESCRIPTION "Added proxyProtocolInvalid metric."
+
+    REVISION "201911140000Z"
+    DESCRIPTION "Added qnameMinFallbackSuccess stats."
+
+    REVISION "201812240000Z"
+    DESCRIPTION "Added the dnssecAuthenticDataQueries and dnssecCheckDisabledQueries stats."
+
+    REVISION "201611290000Z"
+    DESCRIPTION "Initial revision."
+
+    ::= { powerdns 2 }
+
+powerdns               OBJECT IDENTIFIER ::= { enterprises 43315 }
+
+stats OBJECT IDENTIFIER ::= { rec 1 }
+REPL_OBJECTS1
+---
+--- Traps / Notifications
+---
+
+trap OBJECT IDENTIFIER ::= { rec 10 }
+traps OBJECT IDENTIFIER ::= { trap 0 } --- reverse-mappable
+trapObjects OBJECT IDENTIFIER ::= { rec 11 }
+
+trapReason OBJECT-TYPE
+    SYNTAX OCTET STRING
+    MAX-ACCESS read-only
+    STATUS current
+    DESCRIPTION
+        "Reason for this trap"
+    ::= { trapObjects 1 }
+
+--- { trapObjects 5000 } up to and including { trapObjects 5999 } are reserved for local, product-specific extensions to the Recursor MIB
+
+customTrap NOTIFICATION-TYPE
+    OBJECTS {
+        trapReason
+    }
+    STATUS current
+    DESCRIPTION "Trap sent by sendCustomTrap"
+    ::= { traps 1 }
+
+--- { traps 5000 } up to and including { traps 5999 } are reserved for local, product-specific extensions to the Recursor MIB
+
+---
+--- Conformance
+---
+
+recConformance OBJECT IDENTIFIER ::= { rec 100 }
+
+recCompliances MODULE-COMPLIANCE
+    STATUS current
+    DESCRIPTION "PowerDNS Recursor compliance statement"
+    MODULE
+    MANDATORY-GROUPS {
+        recGroup,
+        recTrapsGroup
+    }
+    ::= { recConformance 1 }
+
+recGroup OBJECT-GROUP
+    OBJECTS {
+REPL_OBJECTS2
+    }
+    STATUS current
+    DESCRIPTION "Objects conformance group for PowerDNS Recursor"
+    ::= { recConformance 2 }
+
+recTrapsGroup NOTIFICATION-GROUP
+    NOTIFICATIONS {
+        customTrap
+    }
+    STATUS current
+    DESCRIPTION "Traps conformance group for PowerDNS Recursor"
+    ::= { recConformance 3 }
+
+END
index 7103ead6ff4b12ee8ba547807b4ee4b465b26ed6..2f95b69bf5a8460a55c9d715b5c3487291ae909f 100644 (file)
@@ -15,59 +15,59 @@ IMPORTS
         FROM SNMPv2-CONF;
 
 rec MODULE-IDENTITY
-    LAST-UPDATED "202107200000Z"
+    LAST-UPDATED "202408280000Z"
     ORGANIZATION "PowerDNS BV"
     CONTACT-INFO "support@powerdns.com"
     DESCRIPTION
        "This MIB module describes information gathered through PowerDNS Recursor."
 
-    REVISION "201611290000Z"
-    DESCRIPTION "Initial revision."
-
-    REVISION "201812240000Z"
-    DESCRIPTION "Added the dnssecAuthenticDataQueries and dnssecCheckDisabledQueries stats."
+    REVISION "202408280000Z"
+    DESCRIPTION "Added metric for too many incoming TCP connections"
 
-    REVISION "201911140000Z"
-    DESCRIPTION "Added qnameMinFallbackSuccess stats."
+    REVISION "202408130000Z"
+    DESCRIPTION "Added metric for chain limits reached"
 
-    REVISION "202002170000Z"
-    DESCRIPTION "Added proxyProtocolInvalid metric."
+    REVISION "202405230000Z"
+    DESCRIPTION "Added metrics for maximum chain length and weight"
 
-    REVISION "202101050000Z"
-    DESCRIPTION "Added Aggressive NSEC cache metrics."
+    REVISION "202306080000Z"
+    DESCRIPTION "Added metrics for NOD and UDR events"
 
-    REVISION "202107200000Z"
-    DESCRIPTION "Added almost expired task metrics."
+    REVISION "202302240000Z"
+    DESCRIPTION "Added metrics for sharded packet cache contention"
 
-    REVISION "202110270000Z"
-    DESCRIPTION "Added more UDP errors metric."
+    REVISION "202209120000Z"
+    DESCRIPTION "Added metrics for answers from auths by rcode"
 
-    REVISION "202111090000Z"
-    DESCRIPTION "Added NOTIFY-related metrics."
+    REVISION "202208220000Z"
+    DESCRIPTION "Added internal maintenance metrics."
 
     REVISION "202201310000Z"
     DESCRIPTION "Added non-resolving NS name metric."
 
-    REVISION "202208220000Z"
-    DESCRIPTION "Added internal maintenance metrics."
+    REVISION "202111090000Z"
+    DESCRIPTION "Added NOTIFY-related metrics."
 
-    REVISION "202209120000Z"
-    DESCRIPTION "Added metrics for answers from auths by rcode"
+    REVISION "202110270000Z"
+    DESCRIPTION "Added more UDP errors metric."
 
-    REVISION "202302240000Z"
-    DESCRIPTION "Added metrics for sharded packet cache contention"
+    REVISION "202107200000Z"
+    DESCRIPTION "Added almost expired task metrics."
 
-    REVISION "202306080000Z"
-    DESCRIPTION "Added metrics for NOD and UDR events"
+    REVISION "202101050000Z"
+    DESCRIPTION "Added Aggressive NSEC cache metrics."
 
-    REVISION "202405230000Z"
-    DESCRIPTION "Added metrics for maximum chain length and weight"
+    REVISION "202002170000Z"
+    DESCRIPTION "Added proxyProtocolInvalid metric."
 
-    REVISION "202408130000Z"
-    DESCRIPTION "Added metric for chain limits reached"
+    REVISION "201911140000Z"
+    DESCRIPTION "Added qnameMinFallbackSuccess stats."
 
-    REVISION "202408280000Z"
-    DESCRIPTION "Added metric for too many incoming TCP connections"
+    REVISION "201812240000Z"
+    DESCRIPTION "Added the dnssecAuthenticDataQueries and dnssecCheckDisabledQueries stats."
+
+    REVISION "201611290000Z"
+    DESCRIPTION "Initial revision."
 
     ::= { powerdns 2 }
 
@@ -120,7 +120,7 @@ cacheEntries OBJECT-TYPE
     MAX-ACCESS read-only
     STATUS current
     DESCRIPTION
-        "Number of cache entries"
+        "Number of record cache entries"
     ::= { stats 6 }
 
 cacheBytes OBJECT-TYPE
@@ -368,7 +368,7 @@ qaLatency OBJECT-TYPE
     MAX-ACCESS read-only
     STATUS current
     DESCRIPTION
-        "Average latency in microseconds"
+        "Shows the current latency average, in microseconds, exponentially weighted over past 'latency-statistic-size' packets"
     ::= { stats 37 }
 
 unexpectedPackets OBJECT-TYPE
@@ -452,11 +452,11 @@ ignoredPackets OBJECT-TYPE
     ::= { stats 47 }
 
 maxMthreadStack OBJECT-TYPE
-    SYNTAX CounterBasedGauge64
+    SYNTAX Counter64
     MAX-ACCESS read-only
     STATUS current
     DESCRIPTION
-        "Maximum size of the Mthread stack"
+        "Maximum amount of the mthread stack ever used"
     ::= { stats 48 }
 
 negcacheEntries OBJECT-TYPE
@@ -544,7 +544,7 @@ allOutqueries OBJECT-TYPE
     MAX-ACCESS read-only
     STATUS current
     DESCRIPTION
-        "Number of outgoing queries sent"
+        "Number of outgoing queries"
     ::= { stats 59 }
 
 ipv6Outqueries OBJECT-TYPE
@@ -656,7 +656,7 @@ nopingOutqueries OBJECT-TYPE
     MAX-ACCESS read-only
     STATUS current
     DESCRIPTION
-        "Number of outgoing queries w/o ping"
+        "Number of outgoing queries without ping"
     ::= { stats 73 }
 
 noednsOutqueries OBJECT-TYPE
@@ -664,7 +664,7 @@ noednsOutqueries OBJECT-TYPE
     MAX-ACCESS read-only
     STATUS current
     DESCRIPTION
-        "Number of outgoing queries w/o EDNS"
+        "Number of outgoing queries without EDNS"
     ::= { stats 74 }
 
 uptime OBJECT-TYPE
@@ -692,7 +692,7 @@ fdUsage OBJECT-TYPE
     ::= { stats 77 }
 
 userMsec OBJECT-TYPE
-    SYNTAX CounterBasedGauge64
+    SYNTAX Counter64
     MAX-ACCESS read-only
     STATUS current
     DESCRIPTION
@@ -700,7 +700,7 @@ userMsec OBJECT-TYPE
     ::= { stats 78 }
 
 sysMsec OBJECT-TYPE
-    SYNTAX CounterBasedGauge64
+    SYNTAX Counter64
     MAX-ACCESS read-only
     STATUS current
     DESCRIPTION
@@ -924,7 +924,7 @@ taskQueueExpired OBJECT-TYPE
     ::= { stats 106 }
 
 taskQueueSize OBJECT-TYPE
-    SYNTAX Counter64
+    SYNTAX CounterBasedGauge64
     MAX-ACCESS read-only
     STATUS current
     DESCRIPTION
@@ -976,7 +976,7 @@ dotOutqueries OBJECT-TYPE
     MAX-ACCESS read-only
     STATUS current
     DESCRIPTION
-        "Number of outgoing DoT queries since starting"
+        "Number of outgoing DoT queries"
     ::= { stats 113 }
 
 dns64PrefixAnswers OBJECT-TYPE
@@ -1000,7 +1000,7 @@ almostExpiredRun OBJECT-TYPE
     MAX-ACCESS read-only
     STATUS current
     DESCRIPTION
-        "Number of almost-expired tasks run"
+        "Number of almost-expired tasks run to completion"
     ::= { stats 116 }
 
 almostExpiredExceptions OBJECT-TYPE
@@ -1337,6 +1337,7 @@ recCompliances MODULE-COMPLIANCE
 
 recGroup OBJECT-GROUP
     OBJECTS {
+        trapReason,
         questions,
         ipv6Questions,
         tcpQuestions,
@@ -1413,7 +1414,6 @@ recGroup OBJECT-GROUP
         noednsOutqueries,
         uptime,
         realMemoryUsage,
-        specialMemoryUsage,
         fdUsage,
         userMsec,
         sysMsec,
@@ -1437,7 +1437,6 @@ recGroup OBJECT-GROUP
         variableResponses,
         specialMemoryUsage,
         rebalancedQueries,
-        trapReason,
         qnameMinFallbackSuccess,
         proxyProtocolInvalid,
         recordCacheContended,
index d0c946e6363e42239fafecfe74be663809135282..fd7ed220e9d299adab36780bfd7f35ca50ae99c2 100644 (file)
@@ -1,3 +1,4 @@
 _build
 /settings.rst
 /yamlsettings.rst
+/rec-metrics-gen.rst
index 07811ce8ab23c6a04ba81963d2e228088e0d2767..c84c55541066b3e58f8ce1f49eac4ce1cd5d7311 100644 (file)
@@ -40,7 +40,7 @@ Multi-threading and metrics
 ---------------------------
 Some metrics are collected in thread-local variables, and an aggregate values is computed to report.
 Other statistics are recorded in global memory and each thread updates the one instance, taking proper precautions to make sure consistency is maintained.
-The only exception are the `cpu-msec-thread-N`_ metrics, which report per-thread data.
+The only exception are the ``cpu-msec-thread-n`` metrics, which report per-thread data.
 
 .. _metricscarbon:
 
@@ -124,802 +124,5 @@ It should be noted that answers0-1 + answers1-10 + answers10-100 + answers100-10
 
 Also note that unauthorized-tcp and unauthorized-udp packets do not end up in the 'questions' count.
 
-almost-expired-pushed
-^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.6
-
-number of almost-expired tasks pushed
-
-almost-expired-run
-^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.6
-
-number of almost-expired tasks run
-
-almost-expired-exceptions
-^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.6
-
-number of almost-expired tasks that caused an exception
-
-aggressive-nsec-cache-entries
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.5
-
-number of entries in the aggressive NSEC cache
-
-aggressive-nsec-cache-nsec-hits
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.5
-
-number of negative answers generated from NSEC entries by the aggressive NSEC cache
-
-aggressive-nsec-cache-nsec3-wc-hits
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.5
-
-number of answers synthesized from NSEC entries and wildcards by the NSEC aggressive cache
-
-aggressive-nsec-cache-nsec3-wc-hits
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.5
-
-number of answers synthesized from NSEC entries and wildcards by the NSEC3 aggressive cache
-
-all-outqueries
-^^^^^^^^^^^^^^
-counts the number of outgoing queries since starting, this includes UDP, TCP, DoT queries both over IPv4 and IPv6
-
-answers-slow
-^^^^^^^^^^^^
-counts the number of queries answered after 1 second
-
-answers0-1
-^^^^^^^^^^
-counts the number of queries answered within 1 millisecond
-
-answers1-10
-^^^^^^^^^^^
-counts the number of queries answered within 10 milliseconds
-
-answers10-100
-^^^^^^^^^^^^^
-counts the number of queries answered within 100 milliseconds
-
-answers100-1000
-^^^^^^^^^^^^^^^
-counts the number of queries answered within 1 second
-
-auth4-answers-slow
-^^^^^^^^^^^^^^^^^^
-counts the number of queries answered by auth4s after 1 second (4.0)
-
-auth4-answers0-1
-^^^^^^^^^^^^^^^^
-counts the number of queries answered by auth4s within 1 millisecond (4.0)
-
-auth4-answers1-10
-^^^^^^^^^^^^^^^^^
-counts the number of queries answered by auth4s within 10 milliseconds (4.0)
-
-auth4-answers10-100
-^^^^^^^^^^^^^^^^^^^
-counts the number of queries answered by auth4s within 100 milliseconds (4.0)
-
-auth4-answers100-1000
-^^^^^^^^^^^^^^^^^^^^^
-counts the number of queries answered by auth4s within 1 second (4.0)
-
-auth6-answers-slow
-^^^^^^^^^^^^^^^^^^
-counts the number of queries answered by auth6s after 1 second (4.0)
-
-auth6-answers0-1
-^^^^^^^^^^^^^^^^
-counts the number of queries answered by auth6s within 1 millisecond (4.0)
-
-auth6-answers1-10
-^^^^^^^^^^^^^^^^^
-counts the number of queries answered by auth6s within 10 milliseconds (4.0)
-
-auth6-answers10-100
-^^^^^^^^^^^^^^^^^^^
-counts the number of queries answered by  auth6s within 100 milliseconds (4.0)
-
-auth6-answers100-1000
-^^^^^^^^^^^^^^^^^^^^^
-counts the number of queries answered by auth6s within 1 second (4.0)
-
-auth-xxx-answers
-^^^^^^^^^^^^^^^^
-where ``xxx`` is an rcode name (``noerror``, ``formerr``, ``servfail``, ``nxdomain``, ``notimp``, ``refused``, ``yxdomain``, ``yxrrset``, ``nxrrset``, ``notauth``, ``rcode10``, ``rcode11``, ``rcode2``, ``rcode13``, ``rcode14``, ``rcode15``).
-Counts the rcodes returned by authoritative servers.
-The corresponding Prometheus metrics consist of multiple entries of the form ``pdns_recursor_auth_rcode_answers{rcode="xxx"}``.
-
-
-auth-zone-queries
-^^^^^^^^^^^^^^^^^
-counts the number of queries to locally hosted authoritative zones (:ref:`setting-auth-zones`) since starting
-
-cache-bytes
-^^^^^^^^^^^
-size of the cache in bytes (disabled by default, see :ref:`setting-stats-rec-control-disabled-list`)
-This metric is a rough estimate and takes a long time to compute, and is therefore not enabled in default outputs.
-
-cache-entries
-^^^^^^^^^^^^^
-shows the number of entries in the cache
-
-cache-hits
-^^^^^^^^^^
-counts the number of cache hits since starting, this does **not** include hits that got answered from the packet-cache
-
-cache-misses
-^^^^^^^^^^^^
-counts the number of cache misses since starting
-
-case-mismatches
-^^^^^^^^^^^^^^^
-counts the number of mismatches in character   case since starting
-
-chain-limits
-^^^^^^^^^^^^
-counts the number of times a chain limit (size or age) has been hit
-
-chain-resends
-^^^^^^^^^^^^^
-number of queries chained to existing outstanding   query
-
-client-parse-errors
-^^^^^^^^^^^^^^^^^^^
-counts number of client packets that could   not be parsed
-
-.. _stat-concurrent-queries:
-
-concurrent-queries
-^^^^^^^^^^^^^^^^^^
-shows the number of MThreads currently   running
-
-cpu-msec-thread-n
-^^^^^^^^^^^^^^^^^
-shows the number of milliseconds spent in thread n. Available since 4.1.12.
-
-cpu-iowait
-^^^^^^^^^^
-.. versionadded:: 4.4
-
-Time spent waiting for I/O to complete by the whole system, in units of USER_HZ.
-
-cpu-steal
-^^^^^^^^^
-.. versionadded:: 4.4
-
-Stolen time, which is the time spent by the whole system in other operating systems when running in a virtualized environment, in units of USER_HZ.
-
-
-cumul-authanswers-x
-^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.6
-
-Cumulative counts of answer times of authoritative servers in buckets less than x microseconds.
-(disabled by default, see :ref:`setting-stats-rec-control-disabled-list`)
-These metrics are useful for Prometheus and not listed in other outputs by default.
-
-cumul-clientanswers-x
-^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.6
-
-Cumulative counts of our answer times to clients in buckets less or equal than x microseconds.
-These metrics include packet cache hits.
-These metrics are useful for Prometheus and not listed in other outputs by default.
-
-dns64-prefix-answers
-^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.6
-
-number of ``AAAA`` and ``PTR`` answers generated by :ref:`setting-dns64-prefix` matching.
-
-dnssec-authentic-data-queries
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.2
-
-number of queries received with the AD bit set
-
-dnssec-check-disabled-queries
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.2
-
-number of queries received with the CD bit set
-
-dnssec-queries
-^^^^^^^^^^^^^^
-number of queries received with the DO bit set
-
-.. _stat-dnssec-result-bogus:
-
-dnssec-result-bogus
-^^^^^^^^^^^^^^^^^^^
-number of responses sent, packet-cache hits excluded, that were in the DNSSEC Bogus state. Since 4.4.2 detailed counters are available, see below.
-Since 4.5.0, if :ref:`setting-x-dnssec-names` is set, a separate set of ``x-dnssec-result-...`` metrics become available, counting
-the DNSSEC validation results for names suffix-matching a name in ``x-dnssec-names``.
-
-
-dnssec-result-bogus-no-valid-dnskey
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DNSKEY could not be found.
-
-dnssec-result-bogus-invalid-denial
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid denial of existence proof could not be found.
-
-dnssec-result-bogus-unable-to-get-dss
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DS could not be retrieved.
-
-dnssec-result-bogus-unable-to-get-dnskeys
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DNSKEY could not be retrieved.
-
-dnssec-result-bogus-self-signed-ds
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DS record was signed by itself.
-
-dnssec-result-bogus-no-rrsig
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because required RRSIG records were not present in an answer.
-
-dnssec-result-bogus-no-valid-rrsig
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because only invalid RRSIG records were present in an answer.
-
-dnssec-result-bogus-missing-negative-indication
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because a NODATA or NXDOMAIN answer lacked the required SOA and/or NSEC(3) records.
-
-dnssec-result-bogus-signature-not-yet-valid
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature inception time in the RRSIG was not yet valid.
-
-dnssec-result-bogus-signature-expired
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature expired time in the RRSIG was in the past.
-
-dnssec-result-bogus-unsupported-dnskey-algo
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DNSKEY RRset contained only unsupported DNSSEC algorithms.
-
-dnssec-result-bogus-unsupported-ds-digest-type
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DS RRset contained only unsupported digest types.
-
-dnssec-result-bogus-no-zone-key-bit-set
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because no DNSKEY with the Zone Key bit set was found.
-
-dnssec-result-bogus-revoked-dnskey
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because all DNSKEYs were revoked.
-
-dnssec-result-bogus-invalid-dnskey-protocol
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.2
-
-number of responses sent, packet-cache hits excluded, that were in the Bogus state because all DNSKEYs had invalid protocols.
-
-dnssec-result-indeterminate
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-number of DNSSEC validations that   had the Indeterminate state
-
-dnssec-result-insecure
-^^^^^^^^^^^^^^^^^^^^^^
-number of responses sent, packet-cache hits excluded, that were in the Insecure state
-
-dnssec-result-nta
-^^^^^^^^^^^^^^^^^
-number of responses sent, packet-cache hits excluded, that were in the NTA (negative trust anchor) state
-
-dnssec-result-secure
-^^^^^^^^^^^^^^^^^^^^
-number of responses sent, packet-cache hits excluded, that were in the Secure state
-
-dnssec-validations
-^^^^^^^^^^^^^^^^^^
-number of responses sent, packet-cache hits excluded, for which a DNSSEC validation was requested by either the client or the configuration
-
-dont-outqueries
-^^^^^^^^^^^^^^^
-number of outgoing queries dropped because of   :ref:`setting-dont-query` setting (since 3.3)
-
-dot-outqueries
-^^^^^^^^^^^^^^
-counts the number of outgoing DoT queries since starting, both using IPv4 and IPv6
-
-qname-min-fallback-success
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.3.0
-
-number of successful queries due to fallback mechanism within :ref:`setting-qname-minimization` setting.
-
-ecs-queries
-^^^^^^^^^^^
-number of outgoing queries adorned with an EDNS Client Subnet option (since 4.1)
-
-ecs-responses
-^^^^^^^^^^^^^
-number of responses received from authoritative servers with an EDNS Client Subnet option we used (since 4.1)
-
-ecs-v4-response-bits-*
-^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.2.0
-
-number of responses received from authoritative servers with an IPv4 EDNS Client Subnet option we used, of this subnet size (1 to 32).
-(disabled by default, see :ref:`setting-stats-rec-control-disabled-list`)
-
-ecs-v6-response-bits-*
-^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.2.0
-
-number of responses received from authoritative servers with an IPv6 EDNS Client Subnet option we used, of this subnet size (1 to 128).
-(disabled by default, see :ref:`setting-stats-rec-control-disabled-list`)
-
-edns-ping-matches
-^^^^^^^^^^^^^^^^^
-number of servers that sent a valid EDNS PING   response
-
-edns-ping-mismatches
-^^^^^^^^^^^^^^^^^^^^
-number of servers that sent an invalid EDNS   PING response
-
-failed-host-entries
-^^^^^^^^^^^^^^^^^^^
-number of addresses in the failed NS cache.
-
-.. _stat-fd-usage:
-
-fd-usage
-^^^^^^^^
-Number of currently used file descriptors.
-Currently, this metric is available on Linux and OpenBSD only.
-
-ignored-packets
-^^^^^^^^^^^^^^^
-counts the number of non-query packets received   on server sockets that should only get query packets
-
-ipv6-outqueries
-^^^^^^^^^^^^^^^
-number of outgoing queries over IPv6 using UDP, since version 5.0.0 also including TCP and DoT
-
-ipv6-questions
-^^^^^^^^^^^^^^
-counts all client initiated queries using IPv6
-
-maintenance-usec
-^^^^^^^^^^^^^^^^
-time spent doing internal maintenance, including Lua maintenance
-
-maintenance-calls
-^^^^^^^^^^^^^^^^^
-number of times internal maintenance has been called, including Lua maintenance
-
-malloc-bytes
-^^^^^^^^^^^^
-returns the number of bytes allocated by the process (broken, always returns 0)
-
-max-cache-entries
-^^^^^^^^^^^^^^^^^
-currently configured maximum number of cache entries
-
-max-chain-length
-^^^^^^^^^^^^^^^^
-maximum chain length
-
-max-chain-weight
-^^^^^^^^^^^^^^^^
-maximum chain weight. The weight of a chain of outgoing queries is the product of the number of chained queries by the size of the response received from the external authoritative server. 
-
-max-packetcache-entries
-^^^^^^^^^^^^^^^^^^^^^^^
-currently configured maximum number of packet cache entries
-
-max-mthread-stack
-^^^^^^^^^^^^^^^^^
-maximum amount of thread stack ever used
-
-negcache-entries
-^^^^^^^^^^^^^^^^
-shows the number of entries in the negative   answer cache
-
-no-packet-error
-^^^^^^^^^^^^^^^
-number of erroneous received packets
-
-nod-events
-^^^^^^^^^^
-.. versionadded:: 4.9.0
-
-Count of NOD events
-
-udr-events
-^^^^^^^^^^
-.. versionadded:: 4.9.0
-
-Count of UDR events
-
-nod-lookups-dropped-oversize
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Number of NOD lookups dropped because they would exceed the maximum name length
-
-noedns-outqueries
-^^^^^^^^^^^^^^^^^
-number of queries sent out without EDNS
-
-noerror-answers
-^^^^^^^^^^^^^^^
-counts the number of times it answered NOERROR   since starting
-
-non-resolving-nameserver-entries
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-number of entries in the non-resolving NS name cache
-
-noping-outqueries
-^^^^^^^^^^^^^^^^^
-number of queries sent out without ENDS PING
-
-nsset-invalidations
-^^^^^^^^^^^^^^^^^^^
-number of times an nsset was dropped because   it no longer worked
-
-nsspeeds-entries
-^^^^^^^^^^^^^^^^
-shows the number of entries in the NS speeds   map
-
-nxdomain-answers
-^^^^^^^^^^^^^^^^
-counts the number of times it answered NXDOMAIN   since starting
-
-outgoing-timeouts
-^^^^^^^^^^^^^^^^^
-counts the number of timeouts on outgoing UDP   queries since starting
-
-outgoing4-timeouts
-^^^^^^^^^^^^^^^^^^
-counts the number of timeouts on outgoing UDP   IPv4 queries since starting (since 4.0)
-
-outgoing6-timeouts
-^^^^^^^^^^^^^^^^^^
-counts the number of timeouts on outgoing UDP   IPv6 queries since starting (since 4.0)
-
-.. _stat-over-capacity-drops:
-
-over-capacity-drops
-^^^^^^^^^^^^^^^^^^^
-questions dropped because over maximum   concurrent query limit (since 3.2)
-
-packetcache-bytes
-^^^^^^^^^^^^^^^^^
-size of the packet cache in bytes (since 3.3.1) (disabled by default, see :ref:`setting-stats-rec-control-disabled-list`)
-This metric is a rough estimate and takes a long time to compute, and is therefore not enabled in default outputs.
-
-packetcache-entries
-^^^^^^^^^^^^^^^^^^^
-size of packet cache (since 3.2)
-
-packetcache-hits
-^^^^^^^^^^^^^^^^
-packet cache hits (since 3.2)
-
-packetcache-misses
-^^^^^^^^^^^^^^^^^^
-packet cache misses (since 3.2)
-
-policy-drops
-^^^^^^^^^^^^
-packets dropped because of (Lua) policy decision
-
-policy-hits
-^^^^^^^^^^^
-Number of policy decisions based on Lua (``type = "filter"``), or RPZ (``type = "rpz"``). RPZ hits include the :ref:`rpz-policyName`.
-These metrics are useful for Prometheus and not listed in other outputs by default.
-
-policy-result-noaction
-^^^^^^^^^^^^^^^^^^^^^^
-packets that were not acted upon by   the RPZ/filter engine
-
-policy-result-drop
-^^^^^^^^^^^^^^^^^^
-packets that were dropped by the RPZ/filter   engine
-
-policy-result-nxdomain
-^^^^^^^^^^^^^^^^^^^^^^
-packets that were replied to with   NXDOMAIN by the RPZ/filter engine
-
-policy-result-nodata
-^^^^^^^^^^^^^^^^^^^^
-packets that were replied to with no data   by the RPZ/filter engine
-
-policy-result-truncate
-^^^^^^^^^^^^^^^^^^^^^^
-packets that were forced to TCP by the   RPZ/filter engine
-
-policy-result-custom
-^^^^^^^^^^^^^^^^^^^^
-packets that were sent a custom answer by   the RPZ/filter engine
-
-proxy-protocol-invalid
-^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4
-
-Invalid proxy-protocol headers received.
-
-qa-latency
-^^^^^^^^^^
-shows the current latency average, in microseconds,   exponentially weighted over past 'latency-statistic-size' packets
-
-query-pipe-full-drops
-^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.2
-
-questions dropped because the query distribution pipe was full
-
-questions
-^^^^^^^^^
-counts all end-user initiated queries with the RD bit   set
-
-rebalanced-queries
-^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.1.12
-
-number of queries balanced to a different worker thread because the first selected one was above the target load configured with 'distribution-load-factor'
-
-record-cache-acquired
-^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.0
-
-number of record cache lock acquisitions
-
-record-cache-contended
-^^^^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.4.0
-
-number of contended record cache lock acquisitions
-
-resource-limits
-^^^^^^^^^^^^^^^
-Counts the number of queries that could not be performed because of resource limits. 
-This counter is increased when Recursor encounters a network issue that does not seem to be caused by the remote end. 
-For example when it runs out of file descriptors (monitor :ref:`stat-fd-usage`) or when there is no route to a
-given IP address.
-
-security-status
-^^^^^^^^^^^^^^^
-security status based on :ref:`securitypolling`
-
-server-parse-errors
-^^^^^^^^^^^^^^^^^^^
-counts number of server replied packets that   could not be parsed
-
-servfail-answers
-^^^^^^^^^^^^^^^^
-counts the number of times it answered SERVFAIL   since starting
-
-spoof-prevents
-^^^^^^^^^^^^^^
-number of times PowerDNS considered itself   spoofed, and dropped the data
-
-sys-msec
-^^^^^^^^
-number of CPU milliseconds spent in 'system' mode
-
-taskqueue-pushed
-^^^^^^^^^^^^^^^^
-.. versionadded:: 4.5.0
-
-number of tasks pushed to the taskqueue
-
-taskqueue-expired
-^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.5.0
-
-number of tasks expired before they could be run
-
-taskqueue-size
-^^^^^^^^^^^^^^
-.. versionadded:: 4.5.0
-
-number of tasks currently in the taskqueues
-
-.. _stat-tcp-overflow:
-
-tcp-overflow
-^^^^^^^^^^^^
-number of times an incoming TCP connection was closed immediately because there were too many open connections already
-
-.. _stat-tcp-client-overflow:
-
-tcp-client-overflow
-^^^^^^^^^^^^^^^^^^^
-number of times an IP address was denied TCP   access because it already had too many connections
-
-.. _stat-tcp-clients:
-
-tcp-clients
-^^^^^^^^^^^
-counts the number of currently active TCP/IP clients
-
-tcp-outqueries
-^^^^^^^^^^^^^^
-counts the number of outgoing TCP queries since starting, both using IPv4 and IPV6
-
-tcp-questions
-^^^^^^^^^^^^^
-counts all incoming TCP queries (since starting)
-
-throttle-entries
-^^^^^^^^^^^^^^^^
-shows the number of entries in the throttle map
-
-throttled-out
-^^^^^^^^^^^^^
-counts the number of throttled outgoing UDP   queries since starting
-
-throttled-outqueries
-^^^^^^^^^^^^^^^^^^^^
-idem to throttled-out
-
-too-old-drops
-^^^^^^^^^^^^^
-questions dropped that were too old
-
-truncated-drops
-^^^^^^^^^^^^^^^
-.. versionadded:: 4.2
-
-questions dropped because they were larger than 512 bytes
-
-empty-queries
-^^^^^^^^^^^^^
-.. versionadded:: 4.2
-
-questions dropped because they had a QD count of 0
-
-unauthorized-tcp
-^^^^^^^^^^^^^^^^
-number of TCP questions denied because of   allow-from restrictions
-
-unauthorized-udp
-^^^^^^^^^^^^^^^^
-number of UDP questions denied because of   allow-from restrictions
-
-source-disallowed-notify
-^^^^^^^^^^^^^^^^^^^^^^^^
-number of NOTIFY operations denied because of allow-notify-from restrictions
-
-zone-disallowed-notify
-^^^^^^^^^^^^^^^^^^^^^^
-number of NOTIFY operations denied because of allow-notify-for restrictions
-
-unexpected-packets
-^^^^^^^^^^^^^^^^^^
-number of answers from remote servers that   were unexpected (might point to spoofing)
-
-unreachables
-^^^^^^^^^^^^
-number of times nameservers were unreachable since   starting
-
-uptime
-^^^^^^
-number of seconds process has been running (since 3.1.5)
-
-user-msec
-^^^^^^^^^
-number of CPU milliseconds spent in 'user' mode
-
-variable-responses
-^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.2
-
-Responses that were marked as 'variable'. This could be because of EDNS
-Client Subnet or Lua rules that indicate this variable status (dependent on
-time or who is asking, for example).
-
-.. _stat-x-our-latency:
-
-x-our-latency
-^^^^^^^^^^^^^
-.. versionadded:: 4.1
-  Not yet proven to be reliable
-
-PowerDNS measures per query how much time has been spent waiting on authoritative servers.
-In addition, the Recursor measures the total amount of time needed to answer a question.
-The difference between these two durations is a measure of how much time was spent within PowerDNS.
-This metric is the average of that difference, in microseconds.
-
-x-ourtime0-1
-^^^^^^^^^^^^
-.. versionadded:: 4.1
-  Not yet proven to be reliable
-
-Counts responses where between 0 and 1 milliseconds was spent within the Recursor.
-See :ref:`stat-x-our-latency` for further details.
-
-x-ourtime1-2
-^^^^^^^^^^^^
-.. versionadded:: 4.1
-  Not yet proven to be reliable
-
-Counts responses where between 1 and 2 milliseconds was spent within the Recursor.
-See :ref:`stat-x-our-latency` for further details.
-
-x-ourtime2-4
-^^^^^^^^^^^^
-.. versionadded:: 4.1
-  Not yet proven to be reliable
-
-Counts responses where between 2 and 4 milliseconds was spent within the Recursor. Since 4.1.
-See :ref:`stat-x-our-latency` for further details.
-
-x-ourtime4-8
-^^^^^^^^^^^^
-.. versionadded:: 4.1
-  Not yet proven to be reliable
-
-Counts responses where between 4 and 8 milliseconds was spent within the Recursor.
-See :ref:`stat-x-our-latency` for further details.
-
-x-ourtime8-16
-^^^^^^^^^^^^^
-.. versionadded:: 4.1
-  Not yet proven to be reliable
-
-Counts responses where between 8 and 16 milliseconds was spent within the Recursor.
-See :ref:`stat-x-our-latency` for further details.
-
-x-ourtime16-32
-^^^^^^^^^^^^^^
-.. versionadded:: 4.1
-  Not yet proven to be reliable
-
-Counts responses where between 16 and 32 milliseconds was spent within the Recursor.
-See :ref:`stat-x-our-latency` for further details.
-
-x-ourtime-slow
-^^^^^^^^^^^^^^
-.. versionadded:: 4.1
-  Not yet proven to be reliable
-
-Counts responses where more than 32 milliseconds was spent within the Recursor.
-See :ref:`stat-x-our-latency` for further details.
-
-x-dnssec-result-...
-^^^^^^^^^^^^^^^^^^^
-.. versionadded:: 4.5.0
+.. include:: rec-metrics-gen.rst
 
-See :ref:`stat-dnssec-result-bogus`.
index ef9f4edff5009b15390d09f5061835882d9901a1..31c39799caab9c0cc0f6ae5a6bd7fb0e5a0300e0 100644 (file)
@@ -263,6 +263,32 @@ dep_htmlfiles = declare_dependency(
   sources: [htmlfiles],
 )
 
+metric_sources = [
+  src_dir / 'metrics.py',
+  src_dir / 'metrics_table.py',
+  src_dir / 'RECURSOR-MIB.in',
+]
+
+py = import('python')
+python = py.find_installation('python3', required: true)
+
+metricfiles = custom_target(
+  command: [python, '@INPUT0@', '@SOURCE_ROOT@'],
+  input: metric_sources,
+  output: [
+          'rec-metrics-gen.h',
+          'rec-prometheus-gen.h',
+          'rec-snmp-gen.h',
+          'rec-oids-gen.h',
+          'RECURSOR-MIB.txt',
+  ],
+  capture: false,
+)
+
+dep_metrics = declare_dependency(
+  sources: [metricfiles],
+)
+
 deps = [
   dep_pdns,
   dep_no_config_in_source,
@@ -282,6 +308,7 @@ deps = [
   dep_htmlfiles,
   dep_dnstap,
   dep_libcurl,
+  dep_metrics,
 ]
 
 # Conditional sources that need to be separated into standalone libraries for special
diff --git a/pdns/recursordist/metrics.py b/pdns/recursordist/metrics.py
new file mode 100644 (file)
index 0000000..21edb3e
--- /dev/null
@@ -0,0 +1,163 @@
+import os
+import sys
+
+# default: 'type': uint64
+# ptype: "'counter' (vs gauge')
+
+srcdir = '.'
+if len(sys.argv) == 2:
+    print("metrics.py: using srcdir from arguments")
+    srcdir = sys.argv[1]
+
+print("Generating metrics related files")
+print("metrics.py cwd: " + os.getcwd())
+print("metrics.py srcdir: " + srcdir + " = " + os.path.realpath(srcdir))
+
+def dedashForSNMP(name):
+    cap = False
+    ret= ''
+    for ch in name:
+        if ch =='-':
+            cap = True
+        elif cap:
+            ret += ch.upper()
+            cap = False
+        else:
+            ret += ch
+    ret = ret.replace('Nsec', 'NSEC')
+    return ret
+
+# read table
+with open(srcdir + '/metrics_table.py', mode='r', encoding="utf-8") as file:
+    table = eval(file.read())
+
+with open(srcdir + '/rec-oids-gen.h', 'w', encoding='utf-8') as file:
+    file.write('// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n')
+    for entry in table:
+        if 'snmp' not in entry:
+            continue
+        if 'ifdef' in entry:
+            ifdef = entry['ifdef']
+            file.write(f'#ifdef {ifdef}\n')
+        name = dedashForSNMP(entry['name'])
+        snmp = entry['snmp']
+        file.write(f'static const oid10 {name}OID = {{RECURSOR_STATS_OID, {snmp}}};\n')
+        if 'ifdef' in entry:
+            file.write(f'#endif\n')
+
+with open(srcdir + '/rec-snmp-gen.h', 'w', encoding='utf-8') as file:
+    file.write('// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n')
+    for entry in table:
+        if 'snmp' not in entry:
+            continue
+        name = entry['name']
+        dname = dedashForSNMP(name)
+        if 'ifdef' in entry:
+            ifdef = entry['ifdef']
+            file.write(f'#ifdef {ifdef}\n')
+        file.write(f'registerCounter64Stat("{name}", {dname}OID);\n')
+        if 'ifdef' in entry:
+            file.write(f'#endif\n')
+
+with open(srcdir + '/rec-prometheus-gen.h', 'w', encoding='utf-8') as file:
+    file.write('// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n')
+    for entry in table:
+        name = entry['name']
+        if 'pname' in entry:
+            name = entry['pname']
+        desc = ''
+        desc = entry['desc']
+        if 'pdesc' in entry:
+            desc = entry['pdesc']
+            if desc == '':
+                continue
+        ptype = 'counter'
+        if 'ptype' in entry:
+          ptype = entry['ptype']
+        file.write(f'{{"{name}", MetricDefinition(PrometheusMetricType::{ptype}, "{desc}")}},\n')
+
+with open(srcdir + '/rec-metrics-gen.h', 'w', encoding='utf-8') as file:
+    file.write('// THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n')
+    for entry in table:
+        name = entry['name']
+        if 'lambda' not in entry:
+            continue
+        lam = entry['lambda']
+        if 'ifdef' in entry:
+            ifdef = entry['ifdef']
+            file.write(f'#ifdef {ifdef}\n')
+        if 'if' in entry:
+            iff = entry['if']
+            file.write(f'if ({iff}) {{\n')
+        file.write(f'addGetStat("{name}", {lam});\n')
+        if 'if' in entry:
+            file.write(f'}}\n')
+        if 'ifdef' in entry:
+            file.write(f'#endif\n')
+
+if os.path.isdir(srcdir + '/docs'):
+    with open(srcdir + '/docs/rec-metrics-gen.rst', 'w', encoding='utf-8') as file:
+        file.write('.. THIS IS A GENERATED FILE. DO NOT EDIT. SOURCE metrics.py AND metrics_table.py\n')
+        sortedtable = sorted(table, key = lambda value: value['name'])
+        file.write('.. csv-table:: **Metrics**\n')
+        file.write('    :header: "rec_control name", "Description", "SNMP Object and OID"\n')
+        file.write('    :widths: 20, 50, 20\n\n')
+        for entry in sortedtable:
+            name = entry['name']
+            desc = entry['desc']
+            if not desc.endswith('.'):
+                desc += '.'
+            if 'longdesc' in entry:
+                desc = desc + ' ' + entry['longdesc'].strip()
+            if not desc.endswith('.'):
+                desc += '.'
+            file.write(f'    "**{name}**", ')
+            file.write(f'"{desc}"')
+            if 'snmp' in entry:
+                snmp = entry['snmp']
+                snmpname = dedashForSNMP(name)
+                if 'snmpname' in entry:
+                    name = entry['snmpname']
+                file.write(f', "{snmpname} ({snmp})"')
+            else:
+                file.write(',')
+            file.write('\n')
+
+str1 = ''
+for entry in table:
+    if 'snmp' not in entry:
+        continue
+    name = dedashForSNMP(entry['name'])
+    if 'snmpname' in entry:
+        name = entry['snmpname']
+    snmp = entry['snmp']
+    desc = entry['desc']
+    type = 'Counter64'
+    if 'ptype' in entry and entry['ptype'] == 'gauge':
+        type = 'CounterBasedGauge64'
+    str1 += f'''
+{name} OBJECT-TYPE
+    SYNTAX {type}
+    MAX-ACCESS read-only
+    STATUS current
+    DESCRIPTION
+        "{desc}"
+    ::= {{ stats {snmp} }}
+'''
+
+str2 = '        trapReason'
+for entry in table:
+    if 'snmp' not in entry:
+        continue
+    name = dedashForSNMP(entry['name'])
+    if 'snmpname' in entry:
+        name = entry['snmpname']
+    str2 += f',\n        {name}'
+
+
+with open(srcdir + '/RECURSOR-MIB.in', mode='r', encoding='UTF-8') as file:
+    text = file.read()
+    text = text.replace('REPL_OBJECTS1', str1)
+    text = text.replace('REPL_OBJECTS2', str2)
+    with open(srcdir + '/RECURSOR-MIB.txt', 'w', encoding='utf-8') as file2:
+        file2.write(text)
diff --git a/pdns/recursordist/metrics_table.py b/pdns/recursordist/metrics_table.py
new file mode 100644 (file)
index 0000000..8efea77
--- /dev/null
@@ -0,0 +1,1404 @@
+# From this table all metrics related files are generated by the metric.py script:
+#
+# - RECURSOR-MIB.txt
+# - docs/rec-metrics-gen.rst
+# - rec-metrics-gen.h
+# - rec-oids-gen.h
+# - rec-prometheus-gen.h
+# - rec-snmp-gen.h
+#
+# The .h files are included by the relavant C++ code.
+# Keep the order sorted by SNMP OID (if present).
+#
+#    {
+#        'name': Name of entry required. SNMP name is generated from it using the SNMP naming conventions.
+#        'lambda': Expression to get value for rec_control, if empty: do not generate rec_control table entry
+#        'desc':  One line description ending up in docs, SNMP MIB and Prometheus HELP. Required. A dot is added at the end if absent.
+#        'longdesc': Extra description added to docs entry. Optional. A dot is added at the end if absent.
+#        'snmp': 1 SNMP OID count, must be unique. If absent, no SNMP entry is generated
+#        'snmpname': Override of SNMP name (if legeacy name did not follow convention)
+#        'ptype': The promethheus type, default counter. Can also be gauge, histogram, multicounter. Also determines SNMP type.
+#        'pdesc': Override of Prometheus HELP text, if empty, no Prometheus entry is generated.
+#        'if': rec_control metrics conditionalized on expression
+#        'ifdef': rec_control and snmp metrics conditionalized #ifdef name
+#   }
+#
+
+[
+    {
+        'name': 'questions',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::qcounter); }',
+        'desc':  'Number of questions',
+        'longdesc': 'Counts all end-user initiated queries with the RD bit set',
+        'snmp': 1,
+    },
+    {
+        'name': 'ipv6-questions',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::ipv6qcounter); }',
+        'desc': 'Number of IPv6 questions',
+        'longdesc': 'Counts all end-user initiated queries with the RD bit set, received over IPv6 UDP',
+        'snmp': 2,
+    },
+    {
+        'name': 'tcp-questions',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::tcpqcounter); }',
+        'desc': 'Number of TCP questions',
+        'snmp': 3,
+    },
+    {
+        'name': 'cache-hits',
+        'lambda': '[]() { return g_recCache->getCacheHits(); }',
+        'desc': 'Number of cache hits',
+        'longdesc': 'This does *not* include hits that got answered from the packet-cache',
+        'snmp': 4,
+    },
+    {
+        'name': 'cache-misses',
+        'lambda': '[]() { return g_recCache->getCacheMisses(); }',
+        'desc': 'Number of cache misses',
+        'longdesc': 'This does *not* include hits that got answered from the packet-cache',
+        'snmp': 5,
+    },
+    {
+        'name': 'cache-entries',
+        'lambda': 'doGetCacheSize',
+        'ptype': 'gauge',
+        'desc': 'Number of record cache entries',
+        'snmp': 6,
+    },
+    {
+        'name': 'max-cache-entries',
+        'lambda': '[]() { return g_maxCacheEntries.load(); }',
+        'desc': 'Currently configured maximum number of cache entries',
+        'ptype': 'gauge',
+        # No SNMP
+    },
+    {
+        'name': 'max-packetcache-entries',
+        'lambda': '[]() { return g_maxPacketCacheEntries.load(); }',
+        'desc': 'Currently configured maximum number of packet cache entries',
+        'ptype': 'gauge',
+        # No SNMP
+    },
+    {
+        'name': 'cache-bytes',
+        'lambda': 'doGetCacheBytes',
+        'ptype': 'gauge',
+        'desc': 'Size of the cache in bytes',
+        'longdesc': '''Disabled by default, see :ref:`setting-stats-rec-control-disabled-list`. This metric is currently broken, it always is 0.''',
+        'snmp': 7,
+    },
+    {
+        'name': 'packetcache-hits',
+        'lambda': '[] { return g_packetCache ? g_packetCache->getHits() : 0; }',
+        'desc': 'Number of packetcache hits',
+        'snmp': 8,
+    },
+    {
+        'name': 'packetcache-misses',
+        'lambda': '[] { return g_packetCache ? g_packetCache->getMisses() : 0; }',
+        'desc': 'Number of packetcache misses',
+        'snmp': 9,
+    },
+    {
+        'name': 'packetcache-entries',
+        'lambda': '[] { return g_packetCache ? g_packetCache->size() : 0; }',
+        'desc': 'Number of packetcache entries',
+        'ptype': 'gauge',
+        'snmp': 10,
+    },
+    {
+        'name': 'packetcache-bytes',
+        'lambda': '[] { return g_packetCache ? g_packetCache->bytes() : 0; }',
+        'ptype': 'gauge',
+        'desc': 'Size of the packetcache in bytes',
+        'longdesc': '''Disabled by default, see :ref:`setting-stats-rec-control-disabled-list`. This metric is currently broken, it always is 0.''',
+        'snmp': 11,
+    },
+    {
+        'name': 'malloc-bytes',
+        'lambda': 'doGetMallocated',
+        'ptype': 'gauge',
+        'desc': 'Number of bytes allocated by malloc',
+        'longdesc': 'Broken, always returns 0',
+        'snmp': 12,
+    },
+    {
+        'name': 'servfail-answers',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::servFails); }',
+        'desc': 'Number of servfail answers',
+        'snmp': 13,
+    },
+    {
+        'name': 'nxdomain-answers',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::nxDomains); }',
+        'desc': 'Number of nxdomain answers',
+        'snmp': 14,
+    },
+    {
+        'name': 'noerror-answers',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::noErrors); }',
+        'desc': 'Number of noerror answers',
+        'snmp': 15,
+    },
+    {
+        'name': 'unauthorized-udp',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::unauthorizedUDP); }',
+        'desc': 'Number of unauthorized UDP queries',
+        'snmp': 16,
+    },
+    {
+        'name': 'unauthorized-tcp',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::unauthorizedTCP); }',
+        'desc': 'Number of unauthorized TCP queries',
+        'snmp': 17,
+    },
+    {
+        'name': 'tcp-client-overflow',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::tcpClientOverflow); }',
+        'desc': 'Number of TCP client connections refused because of too many connections',
+        'snmp': 18,
+    },
+    {
+        'name': 'client-parse-errors',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::clientParseError); }',
+        'desc': 'Number of client parse errors',
+        'snmp': 19,
+    },
+    {
+        'name': 'server-parse-errors',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::serverParseError); }',
+        'desc': 'Number of server parse errors',
+        'snmp': 20,
+    },
+    {
+        'name': 'too-old-drops',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::tooOldDrops); }',
+        'desc': 'Number of queries dropped because of a timeout',
+        'snmp': 21,
+    },
+    {
+        'name': 'answers0-1',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::answers).getCount(0); }',
+        'desc': 'Number of queries answered in less than 1 ms',
+        'snmp': 22,
+    },
+    {
+        'name': 'answers1-10',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::answers).getCount(1); }',
+        'desc': 'Number of queries answered in 1-10 ms',
+        'snmp': 23,
+    },
+    {
+        'name': 'answers10-100',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::answers).getCount(2); }',
+        'desc': 'Number of queries answered in 10-100 ms',
+        'snmp': 24,
+    },
+    {
+        'name': 'answers100-1000',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::answers).getCount(3); }',
+        'desc': 'Number of queries answered in 100-1000 ms',
+        'snmp': 25,
+    },
+    {
+        'name': 'answers-slow',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::answers).getCount(4); }',
+        'desc': 'Number of queries answered in more than 1000 ms',
+        'snmp': 26,
+    },
+    {
+        'name': 'x-ourtime0-1',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(0); }',
+        'desc': 'Counts responses where between 0 and 1 milliseconds was spent within the Recursor',
+        'longdesc': 'Not yet proven to be reliable'
+    },
+    {
+        'name': 'x-ourtime1-2',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(1); }',
+        'desc': 'Counts responses where between 1 and 2 milliseconds was spent within the Recursor',
+        'longdesc': 'Not yet proven to be reliable'
+    },
+    {
+        'name': 'x-ourtime2-4',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(2); }',
+        'desc': 'Counts responses where between 16 and 32 milliseconds was spent within the Recursor',
+        'longdesc': 'Not yet proven to be reliable'
+    },
+    {
+        'name': 'x-ourtime4-8',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(3); }',
+        'desc': 'Counts responses where between 4 and 8 milliseconds was spent within the Recursor',
+        'longdesc': 'Not yet proven to be reliable'
+    },
+    {
+        'name': 'x-ourtime8-16',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(4); }',
+        'desc': 'Counts responses where between 8 and 16 milliseconds was spent within the Recursor',
+        'longdesc': 'Not yet proven to be reliable'
+    },
+    {
+        'name': 'x-ourtime16-32',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(5); }',
+        'desc': 'Counts responses where between 16 and 32 milliseconds was spent within the Recursor',
+        'longdesc': 'Not yet proven to be reliable'
+    },
+    {
+        'name': 'x-ourtime-slow',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::ourtime).getCount(6); }',
+        'desc': 'Counts responses where more than 32 milliseconds was spent within the Recursor',
+        'longdesc': 'Not yet proven to be reliable'
+    },
+    {
+        'name': 'auth4-answers0-1',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(0); }',
+        'desc': 'Number of IPv4 queries answered in less than 1 ms',
+        'snmp': 27,
+    },
+    {
+        'name': 'auth4-answers1-10',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(1); }',
+        'desc': 'Number of IPv4 queries answered in 1-10 ms',
+        'snmp': 28,
+    },
+    {
+        'name': 'auth4-answers10-100',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(2); }',
+        'desc': 'Number of IPv4 queries answered in 10-100 ms',
+        'snmp': 29,
+    },
+    {
+        'name': 'auth4-answers100-1000',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(3); }',
+        'desc': 'Number of IPv4 queries answered in 100-1000 ms',
+        'snmp': 30,
+    },
+    {
+        'name': 'auth4-answers-slow',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(4); }',
+        'desc': 'Number of IPv4 queries answered in more than 1000 ms',
+        'snmp': 31,
+        'snmpname': 'auth4Answersslow',
+    },
+    {
+        'name': 'auth6-answers0-1',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(0); }',
+        'desc': 'Number of IPv6 queries answered in less than 1 ms',
+        'snmp': 32,
+    },
+    {
+        'name': 'auth6-answers1-10',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(1); }',
+        'desc': 'Number of IPv6 queries answered in 1-10 ms',
+        'snmp': 33,
+    },
+    {
+        'name': 'auth6-answers10-100',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(2); }',
+        'desc': 'Number of IPv6 queries answered in 10-100 ms',
+        'snmp': 34,
+    },
+    {
+        'name': 'auth6-answers100-1000',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(3); }',
+        'desc': 'Number of IPv6 queries answered in 100-1000 ms',
+        'snmp': 35,
+    },
+    {
+        'name': 'auth6-answers-slow',
+        'lambda': '[]() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(4); }',
+        'desc': 'Number of IPv6 queries answered in more than 1000 ms',
+        'snmp': 36,
+    },
+    {
+        'name': 'qa-latency',
+        'lambda': '[]() { return round(g_Counters.avg(rec::DoubleWAvgCounter::avgLatencyUsec)); }',
+        'ptype': 'gauge',
+        'desc': 'Shows the current latency average, in microseconds, exponentially weighted over past \'latency-statistic-size\' packets',
+        'snmp': 37,
+    },
+    {
+        'name': 'x-our-latency',
+        'lambda': '[]() { return round(g_Counters.avg(rec::DoubleWAvgCounter::avgLatencyOursUsec)); }',
+        'ptype': 'gauge',
+        'desc': 'Shows the averaged time spent within PowerDNS, in microseconds, exponentially weighted over past \'latency-statistic-size\' packets',
+    },
+    {
+        'name': 'unexpected-packets',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::unexpectedCount); }',
+        'desc': 'Number of unexpected packets',
+        'snmp': 38,
+    },
+    {
+        'name': 'case-mismatches',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::caseMismatchCount); }',
+        'desc': 'Number of case mismatches',
+        'snmp': 39,
+    },
+    {
+        'name': 'spoof-prevents',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::spoofCount); }',
+        'desc': 'Number of spoof prevents',
+        'snmp': 40,
+    },
+    {
+        'name': 'nsset-invalidations',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::nsSetInvalidations); }',
+        'desc': 'Number of nsset invalidations',
+        'snmp': 41,
+    },
+    {
+        'name': 'resource-limits',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::resourceLimits); }',
+        'desc': 'Number of resolution aborted because of a local resource limit',
+        'snmp': 42,
+    },
+    {
+        'name': 'over-capacity-drops',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::overCapacityDrops); }',
+        'desc': 'Number of queries dropped because the threads limit was reached',
+        'snmp': 43,
+    },
+    {
+        'name': 'policy-drops',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::policyDrops); }',
+        'desc': 'Number of queries dropped because of a policy',
+        'snmp': 44,
+    },
+    {
+        'name': 'no-packet-error',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::noPacketError); }',
+        'desc': 'Number of calls to recvmsg() that returned no packet even though the socket was ready',
+        'snmp': 45,
+    },
+    {
+        'name': 'dlg-only-drops',
+        'desc': 'Obsolete',
+        'snmp': 46,
+    },
+    {
+        'name': 'ignored-packets',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::ignoredCount); }',
+        'desc': 'Number of ignored packets',
+        'snmp': 47,
+    },
+    {
+        'name': 'max-mthread-stack',
+        'lambda': '[] { return g_Counters.max(rec::Counter::maxMThreadStackUsage); }',
+        'ptype': 'counter',
+        'desc': 'Maximum amount of the mthread stack ever used',
+        'snmp': 48,
+    },
+    {
+        'name': 'negcache-entries',
+        'lambda': 'getNegCacheSize',
+        'ptype': 'gauge',
+        'snmp': 49,
+        'desc': 'Number of negcache entries',
+    },
+    {
+        'name': 'throttle-entries',
+        'lambda': 'SyncRes::getThrottledServersSize',
+        'ptype': 'gauge',
+        'snmp': 50,
+        'desc': 'Number of throttle entries',
+    },
+    {
+        'name': 'nsspeeds-entries',
+        'lambda': 'SyncRes::getNSSpeedsSize',
+        'ptype': 'gauge',
+        'snmp': 51,
+        'desc': 'Number of nsspeeds entries',
+    },
+    {
+        'name': 'failed-host-entries',
+        'lambda': 'SyncRes::getFailedServersSize',
+        'ptype': 'gauge',
+        'snmp': 52,
+        'desc': 'Number of entries in the failed NS cache',
+    },
+    {
+        'name': 'concurrent-queries',
+        'lambda': 'getConcurrentQueries',
+        'ptype': 'gauge',
+        'snmp': 53,
+        'desc': 'Number of concurrent queries',
+    },
+    {
+        'name': 'security-status',
+        'lambda': '&g_security_status',
+        'ptype': 'gauge',
+        'snmp': 54,
+        'desc': 'Current security status',
+    },
+    {
+        'name': 'outgoing-timeouts',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::outgoingtimeouts); }',
+        'snmp': 55,
+        'desc': 'Number of outgoing timeouts',
+    },
+    {
+        'name': 'outgoing4-timeouts',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::outgoing4timeouts); }',
+        'snmp': 56,
+        'desc': 'Number of IPv4 outgoing timeouts',
+    },
+    {
+        'name': 'outgoing6-timeouts',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::outgoing6timeouts); }',
+        'snmp': 57,
+        'desc': 'Number of IPv6 outgoing timeouts',
+    },
+    {
+        'name': 'auth-zone-queries',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::authzonequeries); }',
+        'desc': 'Number of queries to locally hosted authoritative zones (\'setting-auth-zones\')',
+    },
+    {
+        'name': 'tcp-outqueries',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::tcpoutqueries); }',
+        'snmp': 58,
+        'desc': 'Number of outgoing TCP queries sent',
+    },
+    {
+        'name': 'all-outqueries',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::outqueries); }',
+        'snmp': 59,
+        'desc': 'Number of outgoing queries',
+    },
+    {
+        'name': 'ipv6-outqueries',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::ipv6queries); }',
+        'snmp': 60,
+        'desc': 'Number of IPv6 outgoing queries sent',
+    },
+    {
+        'name': 'throttled-outqueries',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::throttledqueries); }',
+        'snmp': 61,
+        'desc': 'Number of throttled outgoing queries',
+    },
+    {
+        'name': 'dont-outqueries',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::dontqueries); }',
+        'snmp': 62,
+        'desc': 'Number of outgoing queries not sent because of a \'dont-query\' setting',
+    },
+    {
+        'name': 'throttled-out',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::throttledqueries); }',
+        'desc': 'Number of throttled outgoing queries',
+    },
+    {
+        'name': 'unreachables',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::unreachables); }',
+        'snmp': 63,
+        'desc': 'Number of errors due to an unreachable server',
+    },
+    {
+        'name': 'ecs-queries',
+        'lambda': '&SyncRes::s_ecsqueries',
+        'desc': 'Number of outgoing queries adorned with an EDNS Client Subnet option',
+    },
+    {
+        'name': 'ecs-responses',
+        'lambda': '&SyncRes::s_ecsresponses',
+        'desc': 'Number of responses received from authoritative servers with an EDNS Client Subnet option we used',
+    },
+    {
+        'name': 'chain-resends',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::chainResends); }',
+        'snmp': 64,
+        'desc': 'Number of chain resends',
+    },
+    {
+        'name': 'tcp-clients',
+        'lambda': '[] { return TCPConnection::getCurrentConnections(); }',
+        'ptype': 'gauge',
+        'snmp': 65,
+        'desc': 'Number of TCP clients',
+    },
+    {
+        'name': 'udp-recvbuf-errors',
+        'lambda': '[] { return udpErrorStats("udp-recvbuf-errors"); }',
+        'ifdef': '__linux',
+        'snmp': 66,
+        'desc': 'Number of UDP recvbuf errors (Linux only)',
+    },
+    {
+        'name': 'udp-sndbuf-errors',
+        'lambda': '[] { return udpErrorStats("udp-sndbuf-errors"); }',
+        'snmp': 67,
+        'ifdef': '__linux',
+        'desc': 'Number of UDP sndbuf errors (Linux only)',
+    },
+    {
+        'name': 'udp-noport-errors',
+        'lambda': '[] { return udpErrorStats("udp-noport-errors"); }',
+        'ifdef': '__linux',
+        'snmp': 68,
+        'desc': 'Number of UDP noport errors (Linux only)',
+    },
+    {
+        'name': 'udp-in-errors',
+        'lambda': '[] { return udpErrorStats("udp-in-errors"); }',
+        'ifdef': '__linux',
+        'snmp': 69,
+        'snmpname': 'udpinErrors',
+        'desc': 'Number of UDP in errors (Linux only)',
+    },
+    {
+        'name': 'edns-ping-matches',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::ednsPingMatches); }',
+        'snmp': 70,
+        'desc': 'Number of EDNS Ping matches',
+    },
+    {
+        'name': 'edns-ping-mismatches',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::ednsPingMismatches); }',
+        'snmp': 71,
+        'desc': 'Number of EDNS Ping mismatches',
+    },
+    {
+        'name': 'dnssec-queries',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::dnssecQueries); }',
+        'snmp': 72,
+        'desc': 'Number of DNSSEC queries',
+    },
+    {
+        'name': 'noping-outqueries', # XXX obsolete?
+        'lambda': '[] { return g_Counters.sum(rec::Counter::noPingOutQueries); }',
+        'snmp': 73,
+        'desc': 'Number of outgoing queries without ping', 
+    },
+    {
+        'name': 'noedns-outqueries',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::noEdnsOutQueries); }',
+        'snmp': 74,
+        'desc': 'Number of outgoing queries without EDNS',
+    },
+    {
+        'name': 'uptime',
+        'lambda': '[] { return time(nullptr) - s_startupTime; }',
+        'snmp': 75,
+        'desc': 'Process uptime in seconds',
+    },
+    {
+        'name': 'real-memory-usage',
+        'lambda': '[] { return getRealMemoryUsage(string()); }',
+        'ptype': 'gauge',
+        'snmp': 76,
+        'desc': 'Memory usage',
+    },
+    {
+        'name': 'fd-usage',
+        'lambda': '[] { return getOpenFileDescriptors(string()); }',
+        'ptype': 'gauge',
+        'snmp': 77,
+        'desc': 'File descriptors usage',
+    },
+
+    {
+        'name': 'user-msec',
+        'lambda': 'getUserTimeMsec',
+        'ptype': 'counter',
+        'snmp': 78,
+        'desc': 'CPU usage (user) in ms',
+    },
+    {
+        'name': 'sys-msec',
+        'lambda': 'getSysTimeMsec',
+        'ptype': 'counter',
+        'snmp': 79,
+        'desc': 'CPU usage (system) in ms',
+    },
+    {
+        'name': 'dnssec-validations',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::dnssecValidations); }',
+        'snmp': 80,
+        'desc': 'Number of responses sent, packet-cache hits excluded, for which a DNSSEC validation was requested by either the client or the configuration',
+    },
+    {
+        'name': 'dnssec-result-insecure',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Insecure); }',
+        'snmp': 81,
+        'desc': 'Number of responses sent, excluding packet-cache hits, that were in the DNSSEC insecure state',
+    },
+    {
+        'name': 'dnssec-result-secure',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Secure); }',
+        'snmp': 82,
+        'desc': 'Number of responses sent, excluding packet-cache hits, that were in the DNSSEC secure state',
+    },
+    {
+        'name': 'dnssec-result-bogus',
+        'lambda': '''[]() {
+            std::set<vState> const bogusStates = {vState::BogusNoValidDNSKEY, vState::BogusInvalidDenial, vState::BogusUnableToGetDSs, vState::BogusUnableToGetDNSKEYs, vState::BogusSelfSignedDS, vState::BogusNoRRSIG, vState::BogusNoValidRRSIG, vState::BogusMissingNegativeIndication, vState::BogusSignatureNotYetValid, vState::BogusSignatureExpired, vState::BogusUnsupportedDNSKEYAlgo, vState::BogusUnsupportedDSDigestType, vState::BogusNoZoneKeyBitSet, vState::BogusRevokedDNSKEY, vState::BogusInvalidDNSKEYProtocol};
+            auto counts = g_Counters.sum(rec::DNSSECHistogram::dnssec);
+            uint64_t total = 0;
+            for (const auto& state : bogusStates) {
+              total += counts.at(state);
+            }
+            return total;
+          }''',
+        'snmp': 83,
+        'desc': 'Number of responses sent, excluding packet-cache hits, that were in the DNSSEC bogus state',
+    },
+    {
+        'name': 'dnssec-result-indeterminate',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Indeterminate); }',
+        'snmp': 84,
+        'desc': 'Number of responses sent, excluding packet-cache hits, that were in the DNSSEC indeterminate state',
+    },
+    {
+        'name': 'dnssec-result-nta',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::NTA); }',
+        'snmp': 85,
+        'desc': 'Number of responses sent, excluding packet-cache hits, that were in the DNSSEC NTA state',
+    },
+    {
+        'name': 'policy-result-noaction',
+        'lambda': '[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NoAction); }',
+        'snmp': 86,
+        'desc': 'Number of policy-mandated no-action results',
+    },
+    {
+        'name': 'policy-result-drop',
+        'lambda': '[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Drop); }',
+        'snmp': 87,
+        'desc': 'Number of policy-mandated drops',
+    },
+    {
+        'name': 'policy-result-nxdomain',
+        'lambda': '[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NXDOMAIN); }',
+        'snmp': 88,
+        'desc': 'Number of policy-mandated NXdomain results',
+    },
+    {
+        'name': 'policy-result-nodata',
+        'lambda': '[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NODATA); }',
+        'snmp': 89,
+        'desc': 'Number of policy-mandated nodata results',
+    },
+    {
+        'name': 'policy-result-truncate',
+        'lambda': '[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Truncate); }',
+        'snmp': 90,
+        'desc': 'Number of policy-mandated truncate results',
+    },
+    {
+        'name': 'policy-result-custom',
+        'lambda': '[] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Custom); }',
+        'snmp': 91,
+        'desc': 'Number of policy-mandated custom results',
+    },
+    {
+        'name': 'query-pipe-full-drops',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::queryPipeFullDrops); }',
+        'desc': 'Number of queries dropped because the query distribution pipe was full',
+        'snmp': 92,
+    },
+    {
+        'name': 'truncated-drops',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::truncatedDrops); }',
+        'desc': 'Number of queries dropped because they were larger than 512 bytes',
+        'snmp': 93,
+    },
+    {
+        'name': 'empty-queries',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::emptyQueriesCount); }',
+        'desc': 'Number of queries dropped because they had a QD count of 0',
+        'snmp': 94,
+    },
+    {
+        'name': 'dnssec-authentic-data-queries',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::dnssecAuthenticDataQueries); }',
+        'snmp': 95,
+        'desc': 'Number of queries received with the AD bit set',
+    },
+    {
+        'name': 'dnssec-check-disabled-queries',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::dnssecCheckDisabledQueries); }',
+        'snmp': 96,
+        'desc': 'Number of queries received with the CD bit set',
+    },
+    {
+        'name': 'variable-responses',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::variableResponses); }',
+        'snmp': 97,
+        'desc': 'Number of variable responses',
+    },
+    {
+        'name': 'special-memory-usage',
+        'lambda': '[] { return getSpecialMemoryUsage(string()); }',
+        'ptype': 'gauge',
+        'snmp': 98,
+        'desc': 'Memory usage (more precise but expensive to retrieve)',
+    },
+    {
+        'name': 'rebalanced-queries',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::rebalancedQueries); }',
+        'snmp': 99,
+        'desc': 'Number of queries re-distributed because the first selected worker thread was above the target load',
+    },
+    {
+        'name': 'qname-min-fallback-success',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::qnameminfallbacksuccess); }',
+        'snmp': 100,
+        'desc': 'Number of successful queries due to fallback mechanism within \'qname-minimization\' setting',
+    },
+    {
+        'name': 'proxy-protocol-invalid',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::proxyProtocolInvalidCount); }',
+        'snmp': 101,
+        'desc': 'Number of invalid proxy protocol headers received',
+    },
+    {
+        'name': 'record-cache-contended',
+        'lambda': '[]() { return g_recCache->stats().first; }',
+        'desc': 'Number of contended record cache lock acquisitions',
+        'snmp': 102,
+    },
+    {
+        'name': 'record-cache-acquired',
+        'lambda': '[]() { return g_recCache->stats().second; }',
+        'desc': 'Number of record cache lock acquisitions',
+        'snmp': 103,
+    },
+    {
+        'name': 'nod-lookups-dropped-oversize',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::nodLookupsDroppedOversize); }',
+        'snmp': 104,
+        'desc': 'Number of NOD lookups dropped because they would exceed the maximum name length',
+    },
+    {
+        'name': 'taskqueue-pushed',
+        'lambda': '[]() { return getTaskPushes(); }',
+        'snmp': 105,
+        'snmpname': 'taskQueuePushed',
+        'desc': 'Number of tasks pushed to the taskqueues',
+    },
+    {
+        'name': 'taskqueue-expired',
+        'lambda': '[]() { return getTaskExpired(); }',
+        'snmp': 106,
+        'snmpname': 'taskQueueExpired',
+        'desc': 'Number of tasks expired before they could be run',
+    },
+    {
+        'name': 'taskqueue-size',
+        'lambda': '[]() { return getTaskSize(); }',
+        'ptype': 'gauge',
+        'snmp': 107,
+        'snmpname': 'taskQueueSize',
+        'desc': 'Number of tasks currently in the taskqueues',
+    },
+    {
+        'name': 'aggressive-nsec-cache-entries',
+        'lambda': '[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getEntriesCount() : 0; }',
+        'desc': 'Number of entries in the aggressive NSEC cache',
+        'snmp': 108,
+    },
+    {
+        'name': 'aggressive-nsec-cache-nsec-hits',
+        'lambda': '[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSECHits() : 0; }',
+        'desc': 'Number of NSEC-related hits from the aggressive NSEC cache',
+        'snmp': 109,
+    },
+    {
+        'name': 'aggressive-nsec-cache-nsec3-hits',
+        'lambda': '[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSEC3Hits() : 0; }',
+        'desc': 'Number of NSEC3-related hits from the aggressive NSEC cache',
+        'snmp': 110,
+    },
+    {
+        'name': 'aggressive-nsec-cache-nsec-wc-hits',
+        'lambda': '[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSECWildcardHits() : 0; }',
+        'desc': 'Number of answers synthesized from the NSEC aggressive cache',
+        'snmp': 111
+    },
+    {
+        'name': 'aggressive-nsec-cache-nsec3-wc-hits',
+        'lambda': '[]() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSEC3WildcardHits() : 0; }',
+        'desc': 'Number of answers synthesized from the NSEC3 aggressive cache',
+        'snmp': 112
+    },
+    {
+        'name': 'dot-outqueries',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::dotoutqueries); }',
+        'snmp': 113,
+        'desc': 'Number of outgoing DoT queries',
+    },
+    {
+        'name': 'dns64-prefix-answers',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::dns64prefixanswers); }',
+        'snmp': 114,
+        'desc': 'Number of answers generated by dns64-prefix matching',
+    },
+    {
+         'name': 'almost-expired-pushed',
+         'lambda': '[]() { return getAlmostExpiredTasksPushed(); }',
+         'snmp': 115,
+         'desc': 'Number of almost-expired tasks pushed',
+    },
+    {
+         'name': 'almost-expired-run',
+         'lambda': '[]() { return getAlmostExpiredTasksRun(); }',
+         'snmp': 116,
+         'desc': 'Number of almost-expired tasks run to completion',
+    },
+    {
+         'name': 'almost-expired-exceptions',
+         'lambda': '[]() { return getAlmostExpiredTaskExceptions(); }',
+         'snmp': 117,
+         'desc': 'Number of almost-expired tasks that caused an exception',
+    },
+    {
+        'name': 'udp-in-csum-errors',
+        'lambda': '[] { return udpErrorStats("udp-in-csum-errors"); }',
+        'ifdef': '__linux',
+        'snmp': 118,
+        'desc': 'Number of UDP in checksum errors (Linux only)',
+    },
+    {
+        'name': 'udp6-recvbuf-errors',
+        'lambda': '[] { return udp6ErrorStats("udp6-recvbuf-errors"); }',
+        'ifdef': '__linux',
+        'snmp': 119,
+        'desc': 'Number of UDP6 recvbuf errors (Linux only)',
+    },
+    {
+        'name': 'udp6-sndbuf-errors',
+        'lambda': '[] { return udp6ErrorStats("udp6-sndbuf-errors"); }',
+        'ifdef': '__linux',
+        'snmp': 120,
+        'desc': 'Number of UDP6 sndbuf errors (Linux only)',
+    },
+    {
+        'name': 'udp6-noport-errors',
+        'lambda': '[] { return udp6ErrorStats("udp6-noport-errors"); }',
+        'ifdef': '__linux',
+        'snmp': 121,
+        'desc': 'Number of UDP6 noport errors (Linux only)',
+    },
+    {
+        'name': 'udp6-in-errors',
+        'lambda': '[] { return udp6ErrorStats("udp6-in-errors"); }',
+        'ifdef': '__linux',
+        'snmp': 122,
+        'snmpname': 'udp6inErrors',
+        'desc': 'Number of UDP6 in errors (Linux only)',
+    },
+    {
+        'name': 'udp6-in-csum-errors',
+        'ifdef': '__linux',
+        'lambda': '[] { return udp6ErrorStats("udp6-in-csum-errors"); }',
+        'snmp': 123,
+        'desc': 'Number of UDP6 in checksum errors (Linux only)',
+    },
+    {
+        'name': 'cpu-iowait',
+        'lambda': '[] { return getCPUIOWait(string()); }',
+        'ifdef': '__linux',
+        'desc': 'Time spent waiting for I/O to complete by the whole system, in units of USER_HZ.'
+    },
+    {
+        'name': 'cpu-steal',
+        'lambda': '[] { return getCPUSteal(string()); }',
+        'ifdef': '__linux',
+        'desc': 'Stolen time, which is the time spent by the whole system in other operating systems when running in a virtualized environment, in units of USER_HZ',
+    },
+    {
+        'name': 'cpu-msec-thread-n',
+        'lambda': '[]() { return toCPUStatsMap("cpu-msec"); }',
+        'desc': 'Number of milliseconds spent in thread n',
+        'ptype': 'multicounter',
+        'pname': 'cpu-msec-thread-0',
+    },
+    {
+        'name': 'memory-allocs',
+        'lambda': '[] { return g_mtracer->getAllocs(string()); }',
+        'ifdef': 'MALLOC_TRACE',
+        'desc': 'Only relevant for development and if malloc tracing is enabled',
+    },
+    {
+        'name': 'memory-alloc-flux',
+        'lambda': '[] { return g_mtracer->getAllocFlux(string()); }',
+        'ifdef': 'MALLOC_TRACE',
+        'desc': 'Only relevant for development and if malloc tracing is enabled',
+    },
+    {
+        'name': 'memory-allocated',
+        'lambda': '[] { return g_mtracer->getTotAllocated(string()); }',
+        'ifdef': 'MALLOC_TRACE',
+        'desc': 'Only relevant for development and if malloc tracing is enabled',
+    },
+    {
+        'name': 'dnssec-result-bogus-no-valid-dnskey',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoValidDNSKEY); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DNSKEY could not be found',
+    },
+    {
+        'name': 'dnssec-result-bogus-invalid-denial',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusInvalidDenial); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid denial of existence proof could not be found',
+    },
+    {
+        'name': 'dnssec-result-bogus-unable-to-get-dss',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnableToGetDSs); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DS could not be retrieved',
+    },
+    {
+        'name': 'dnssec-result-bogus-unable-to-get-dnskeys',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnableToGetDNSKEYs); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DNSKEY could not be retrieved',
+    },
+    {
+        'name': 'dnssec-result-bogus-self-signed-ds',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSelfSignedDS); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DS record was signed by itself',
+    },
+    {
+        'name': 'dnssec-result-bogus-no-rrsig',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoRRSIG); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because required RRSIG records were not present in an answer',
+    },
+    {
+        'name': 'dnssec-result-bogus-no-valid-rrsig',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoValidRRSIG); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because only invalid RRSIG records were present in an answer',
+    },
+    {
+        'name': 'dnssec-result-bogus-missing-negative-indication',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusMissingNegativeIndication); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a NODATA or NXDOMAIN answer lacked the required SOA and/or NSEC(3) records',
+    },
+    {
+        'name': 'dnssec-result-bogus-signature-not-yet-valid',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSignatureNotYetValid); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature inception time in the RRSIG was not yet valid',
+    },
+    {
+        'name': 'dnssec-result-bogus-signature-expired',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSignatureExpired); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature expired time in the RRSIG was in the past',
+    },
+    {
+        'name': 'dnssec-result-bogus-unsupported-dnskey-algo',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnsupportedDNSKEYAlgo); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DNSKEY RRset contained only unsupported DNSSEC algorithms',
+    },
+    {
+        'name': 'dnssec-result-bogus-unsupported-ds-digest-type',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnsupportedDSDigestType); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DS RRset contained only unsupported digest types',
+    },
+    {
+        'name': 'dnssec-result-bogus-no-zone-key-bit-set',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoZoneKeyBitSet); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because no DNSKEY with the Zone Key bit set was found',
+    },
+    {
+        'name': 'dnssec-result-bogus-revoked-dnskey',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusRevokedDNSKEY); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because all DNSKEYs were revoked',
+    },
+    {
+        'name': 'dnssec-result-bogus-invalid-dnskey-protocol',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusInvalidDNSKEYProtocol); }',
+        'desc': 'Number of responses sent, packet-cache hits excluded, that were in the Bogus state because all DNSKEYs had invalid protocols',
+    },
+    {
+        'name': 'x-dnssec-result-bogus',
+        'lambda': '''[]() {
+         std::set<vState> const bogusStates = {vState::BogusNoValidDNSKEY, vState::BogusInvalidDenial, vState::BogusUnableToGetDSs, vState::BogusUnableToGetDNSKEYs, vState::BogusSelfSignedDS, vState::BogusNoRRSIG, vState::BogusNoValidRRSIG, vState::BogusMissingNegativeIndication, vState::BogusSignatureNotYetValid, vState::BogusSignatureExpired, vState::BogusUnsupportedDNSKEYAlgo, vState::BogusUnsupportedDSDigestType, vState::BogusNoZoneKeyBitSet, vState::BogusRevokedDNSKEY, vState::BogusInvalidDNSKEYProtocol};
+          auto counts = g_Counters.sum(rec::DNSSECHistogram::xdnssec);
+          uint64_t total = 0;
+          for (const auto& state : bogusStates) {
+            total += counts.at(state);
+          }
+          return total;
+         }''',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-no-valid-dnskey',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoValidDNSKEY); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-invalid-denial',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusInvalidDenial); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-unable-to-get-dss',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnableToGetDSs); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-unable-to-get-dnskeys',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnableToGetDNSKEYs); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-self-signed-ds',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSelfSignedDS); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-no-rrsig',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoRRSIG); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-no-valid-rrsig',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoValidRRSIG); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-missing-negative-indication',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusMissingNegativeIndication); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-signature-not-yet-valid',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSignatureNotYetValid); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-signature-expired',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSignatureExpired); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-unsupported-dnskey-algo',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnsupportedDNSKEYAlgo); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-unsupported-ds-digest-type',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnsupportedDSDigestType); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-no-zone-key-bit-set',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoZoneKeyBitSet); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-revoked-dnskey',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusRevokedDNSKEY); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-bogus-invalid-dnskey-protocol',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusInvalidDNSKEYProtocol); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-indeterminate',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Indeterminate); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-nta',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::NTA); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-insecure',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Insecure); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'x-dnssec-result-secure',
+        'lambda': '[] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Secure); }',
+        'if': '::arg()["x-dnssec-names"].length() > 0',
+        'desc': 'Same as corresponding metric without ``x-`` prefix, for names in :ref:`setting-x-dnssec-names`.'
+    },
+    {
+        'name': 'idle-tcpout-connections',
+        'lambda': 'getCurrentIdleTCPConnections',
+        'ptype': 'gauge',
+        'desc': 'Number of connections in the TCP idle outgoing connections pool',
+    },
+    {
+        'name': 'source-disallowed-notify',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::sourceDisallowedNotify); }',
+        'desc': 'Number of NOTIFY operations not allowed by allow-notify-from',
+        'snmp': 124,
+    },
+    {
+        'name': 'zone-disallowed-notify',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::zoneDisallowedNotify); }',
+        'desc': 'Number of NOTIFY operations not allowed by allow-notify-for',
+        'snmp': 125,
+    },
+    {
+        'name': 'non-resolving-nameserver-entries',
+        'lambda': 'SyncRes::getNonResolvingNSSize',
+        'ptype': 'gauge',
+        'snmp': 126,
+        'desc': 'Number of entries in the non-resolving NS name cache',
+    },
+    {
+        'name': 'maintenance-usec',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::maintenanceUsec); }',
+        'snmp': 127,
+        'snmpname': 'maintenanceUSec',
+        'desc': 'Time spent doing internal maintenance, including Lua maintenance',
+    },
+    {
+        'name': 'maintenance-calls',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::maintenanceCalls); }',
+        'snmp': 128,
+        'snmpname': 'maintenanceCount',
+        'desc': 'Number of times internal maintenance has been called, including Lua maintenance',
+    },
+
+    # Entries for aith-rcode-answers are a bit different than others: separate rec_control and SNMP metrics, but a multicounter entry for Prometheus. THe alphabetically firts gets a real pname, the others an empty one.
+    # We only generate the Prometheus comment for the first one
+    {
+        'name': 'auth-noerror-answers',
+        'ptype': 'multicounter',
+        'snmp': 129,
+        'snmpname': 'authrcode0Count',
+        'desc': 'Number of rcode 0 (noerror) answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'auth-formerr-answers',  # This entry is alphabetically the first, so state the Prometheus HELP text
+        'ptype': 'multicounter',
+        'snmp': 130,
+        'snmpname': 'authrcode1Count',
+        'desc': 'Number of rcode 1 (formerr) answers received',
+        'pdesc':  'Counts the rcodes returned by authoritative servers.'
+    },
+    {
+        'name': 'auth-servfail-answers',
+        'ptype': 'multicounter',
+        'snmp': 131,
+        'snmpname': 'authrcode2Count',
+        'desc': 'Number of rcode 2 (servfail) answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'auth-nxdomain-answers',
+        'ptype': 'multicounter',
+        'snmp': 132,
+        'snmpname': 'authrcode3Count',
+        'desc': 'Number of rcode 3 (nxdomain) answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'auth-notimp-answers',
+        'ptype': 'multicounter',
+        'snmp': 133,
+        'snmpname': 'authrcode4Count',
+        'desc': 'Number of rcode 4 (notimp) answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'auth-refused-answers',
+        'ptype': 'multicounter',
+        'snmp': 134,
+        'snmpname': 'authrcode5Count',
+        'desc': 'Number of rcode 5 (refused) answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'auth-yxdomain-answers',
+        'ptype': 'multicounter',
+        'snmp': 135,
+        'snmpname': 'authrcode6Count',
+        'desc': 'Number of rcode 6 (yxdomain) answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'auth-yxrrset-answers',
+        'ptype': 'multicounter',
+        'snmp': 136,
+        'snmpname': 'authrcode7Count',
+        'desc': 'Number of rcode 7 (yxrrset) answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'auth-nxrrset-answers',
+        'ptype': 'multicounter',
+        'snmp': 137,
+        'snmpname': 'authrcode8Count',
+        'desc': 'Number of rcode 8 (nxrrset) answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'auth-notauth-answers',
+        'ptype': 'multicounter',
+        'snmp': 138,
+        'snmpname': 'authrcode9Count',
+        'desc': 'Number of rcode 9 (notauth) answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'auth-rcode10-answers',
+        'ptype': 'multicounter',
+        'snmp': 139,
+        'snmpname': 'authrcode10Count',
+        'desc': 'Number of rcode 10 answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'auth-rcode11-answers',
+        'ptype': 'multicounter',
+        'snmp': 140,
+        'snmpname': 'authrcode11Count',
+        'desc': 'Number of rcode 11 answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'auth-rcode12-answers',
+        'ptype': 'multicounter',
+        'snmp': 141,
+        'snmpname': 'authrcode12Count',
+        'desc': 'Number of rcode 12 answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'auth-rcode13-answers',
+        'ptype': 'multicounter',
+        'snmp': 142,
+        'snmpname': 'authrcode13Count',
+        'desc': 'Number of rcode 13 answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'auth-rcode14-answers',
+        'ptype': 'multicounter',
+        'snmp': 143,
+        'snmpname': 'authrcode14Count',
+        'desc': 'Number of rcode 14 answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'auth-rcode15-answers',
+        'ptype': 'multicounter',
+        'snmp': 144,
+        'snmpname': 'authrcode15Count',
+        'desc': 'Number of rcode 15 answers received',
+        'pdesc': '',
+    },
+    {
+        'name': 'packetcache-contended',
+        'lambda': '[]() { return g_packetCache ? g_packetCache->stats().first : 0; }',
+        'desc': 'Number of contended packet cache lock acquisitions',
+        'snmp': 145,
+        'snmpname': 'packetCacheContended',
+    },
+    {
+        'name': 'packetcache-acquired',
+        'lambda': '[]() { return g_packetCache ? g_packetCache->stats().second : 0; }',
+        'desc': 'Number of packet cache lock acquisitions',
+        'snmp': 146,
+        'snmpname': 'packetCacheAcquired',
+    },
+    {
+        'name': 'nod-events',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::nodCount); }',
+        'snmp': 147,
+        'desc': 'Count of NOD events',
+    },
+    {
+        'name': 'udr-events',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::udrCount); }',
+        'snmp': 148,
+        'desc': 'Count of UDR events',
+    },
+    {
+        'name': 'max-chain-length',
+        'lambda': '[] { return g_Counters.max(rec::Counter::maxChainLength); }',
+        'snmp': 149,
+        'desc': 'Maximum chain length',
+    },
+    {
+        'name': 'max-chain-weight',
+        'lambda': '[] { return g_Counters.max(rec::Counter::maxChainWeight); }',
+        'snmp': 150,
+        'desc': 'Maximum chain weight',
+    },
+    {
+        'name': 'chain-limits',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::chainLimits); }',
+        'snmp': 151,
+        'desc': 'Chain limits reached',
+    },
+    {
+        'name': 'tcp-overflow',
+        'lambda': '[] { return g_Counters.sum(rec::Counter::tcpOverflow); }',
+        'desc': 'Incoming TCP limits reached',
+        'snmp': 152,
+    },
+    {
+        'name': 'remote-logger-count',
+        'lambda':  '''[]() {
+    return toRemoteLoggerStatsMap("remote-logger-count");
+        }''',
+        'desc': 'Number of remote logging events',
+        'ptype': 'multicounter',
+        'pname': 'remote-logger-count-o-0', #  For multicounters, state the first
+        # No SNMP
+    },
+    {
+        'name': 'cumul-clientanswers-x',
+        # No lambda
+        'desc': 'Cumulative counts of answer times of authoritative servers in buckets less than x microseconds.',
+        'longdesc': 'Disabled by default, see :ref:`setting-stats-rec-control-disabled-list`. These metrics are useful for Prometheus and not listed in other outputs by default.',
+        'ptype': 'histogram',
+        'pname': 'cumul-clientanswers-count', # For cumulative histogram, state the xxx_count name where xxx matches the name in rec_channel_rec
+        # No SNMP
+    },
+    {
+        'name': 'cumul-authanswers-x',
+        # No lambda
+        'desc': 'Cumulative counts of answer times to clients in buckets less than x microseconds.',
+        'longdesc': 'Disabled by default, see :ref:`setting-stats-rec-control-disabled-list`. These metrics are useful for Prometheus and not listed in other outputs by default.',
+        'ptype': 'histogram',
+        'pname': 'cumul-authanswers-count4', # For cumulative histogram, state the xxx_count name where xxx matches the name in rec_channel_rec
+        # No SNMP
+    },
+    {
+        'name': 'policy-hits',
+        # No lambda
+        'desc': 'Number of policy decisions based on Lua',
+        'longdesc': '(``type = ""filter""``), or RPZ (``type = ""rpz""``). RPZ hits include the :ref:`rpz-policyName`. These metrics are useful for Prometheus and not listed in other outputs by default.',
+        'ptype': 'multicounter',
+        'pname': 'policy-hits', # For multicounters, state the first
+        # No SNMP
+    },
+    {
+        'name': 'proxy-mapping',
+        # No lambda
+        'desc': 'Proxy mappings done',
+        'ptype': 'multicounter',
+        'pname': 'proxy-mapping-total-n-0', # For multicounters, state the first
+        # No SNMP
+    },
+]
index 5825defd3018b40da828b15d491543c2b1577ff2..430b8a41c7e8815a11372c02f8f2f6d0baa8fe14 100644 (file)
@@ -25,7 +25,6 @@
 #include "rec-snmp.hh"
 #include "rec_channel.hh"
 
-#include "logger.hh"
 #include "logging.hh"
 
 #ifdef HAVE_NET_SNMP
@@ -49,164 +48,7 @@ using oid11 = std::array<oid, 11>;
 static const oid11 trapReasonOID = {RECURSOR_TRAP_OBJECTS_OID, 1, 0};
 static const oid11 customTrapOID = {RECURSOR_TRAPS_OID, 1};
 
-static const oid10 questionsOID = {RECURSOR_STATS_OID, 1};
-static const oid10 ipv6QuestionsOID = {RECURSOR_STATS_OID, 2};
-static const oid10 tcpQuestionsOID = {RECURSOR_STATS_OID, 3};
-static const oid10 cacheHitsOID = {RECURSOR_STATS_OID, 4};
-static const oid10 cacheMissesOID = {RECURSOR_STATS_OID, 5};
-static const oid10 cacheEntriesOID = {RECURSOR_STATS_OID, 6};
-static const oid10 cacheBytesOID = {RECURSOR_STATS_OID, 7};
-static const oid10 packetcacheHitsOID = {RECURSOR_STATS_OID, 8};
-static const oid10 packetcacheMissesOID = {RECURSOR_STATS_OID, 9};
-static const oid10 packetcacheEntriesOID = {RECURSOR_STATS_OID, 10};
-static const oid10 packetcacheBytesOID = {RECURSOR_STATS_OID, 11};
-static const oid10 mallocBytesOID = {RECURSOR_STATS_OID, 12};
-static const oid10 servfailAnswersOID = {RECURSOR_STATS_OID, 13};
-static const oid10 nxdomainAnswersOID = {RECURSOR_STATS_OID, 14};
-static const oid10 noerrorAnswersOID = {RECURSOR_STATS_OID, 15};
-static const oid10 unauthorizedUdpOID = {RECURSOR_STATS_OID, 16};
-static const oid10 unauthorizedTcpOID = {RECURSOR_STATS_OID, 17};
-static const oid10 tcpClientOverflowOID = {RECURSOR_STATS_OID, 18};
-static const oid10 clientParseErrorsOID = {RECURSOR_STATS_OID, 19};
-static const oid10 serverParseErrorsOID = {RECURSOR_STATS_OID, 20};
-static const oid10 tooOldDropsOID = {RECURSOR_STATS_OID, 21};
-static const oid10 answers01OID = {RECURSOR_STATS_OID, 22};
-static const oid10 answers110OID = {RECURSOR_STATS_OID, 23};
-static const oid10 answers10100OID = {RECURSOR_STATS_OID, 24};
-static const oid10 answers1001000OID = {RECURSOR_STATS_OID, 25};
-static const oid10 answersSlowOID = {RECURSOR_STATS_OID, 26};
-static const oid10 auth4Answers01OID = {RECURSOR_STATS_OID, 27};
-static const oid10 auth4Answers110OID = {RECURSOR_STATS_OID, 28};
-static const oid10 auth4Answers10100OID = {RECURSOR_STATS_OID, 29};
-static const oid10 auth4Answers1001000OID = {RECURSOR_STATS_OID, 30};
-static const oid10 auth4AnswersslowOID = {RECURSOR_STATS_OID, 31};
-static const oid10 auth6Answers01OID = {RECURSOR_STATS_OID, 32};
-static const oid10 auth6Answers110OID = {RECURSOR_STATS_OID, 33};
-static const oid10 auth6Answers10100OID = {RECURSOR_STATS_OID, 34};
-static const oid10 auth6Answers1001000OID = {RECURSOR_STATS_OID, 35};
-static const oid10 auth6AnswersSlowOID = {RECURSOR_STATS_OID, 36};
-static const oid10 qaLatencyOID = {RECURSOR_STATS_OID, 37};
-static const oid10 unexpectedPacketsOID = {RECURSOR_STATS_OID, 38};
-static const oid10 caseMismatchesOID = {RECURSOR_STATS_OID, 39};
-static const oid10 spoofPreventsOID = {RECURSOR_STATS_OID, 40};
-static const oid10 nssetInvalidationsOID = {RECURSOR_STATS_OID, 41};
-static const oid10 resourceLimitsOID = {RECURSOR_STATS_OID, 42};
-static const oid10 overCapacityDropsOID = {RECURSOR_STATS_OID, 43};
-static const oid10 policyDropsOID = {RECURSOR_STATS_OID, 44};
-static const oid10 noPacketErrorOID = {RECURSOR_STATS_OID, 45};
-static const oid10 dlgOnlyDropsOID = {RECURSOR_STATS_OID, 46};
-static const oid10 ignoredPacketsOID = {RECURSOR_STATS_OID, 47};
-static const oid10 maxMthreadStackOID = {RECURSOR_STATS_OID, 48};
-static const oid10 negcacheEntriesOID = {RECURSOR_STATS_OID, 49};
-static const oid10 throttleEntriesOID = {RECURSOR_STATS_OID, 50};
-static const oid10 nsspeedsEntriesOID = {RECURSOR_STATS_OID, 51};
-static const oid10 failedHostEntriesOID = {RECURSOR_STATS_OID, 52};
-static const oid10 concurrentQueriesOID = {RECURSOR_STATS_OID, 53};
-static const oid10 securityStatusOID = {RECURSOR_STATS_OID, 54};
-static const oid10 outgoingTimeoutsOID = {RECURSOR_STATS_OID, 55};
-static const oid10 outgoing4TimeoutsOID = {RECURSOR_STATS_OID, 56};
-static const oid10 outgoing6TimeoutsOID = {RECURSOR_STATS_OID, 57};
-static const oid10 tcpOutqueriesOID = {RECURSOR_STATS_OID, 58};
-static const oid10 allOutqueriesOID = {RECURSOR_STATS_OID, 59};
-static const oid10 ipv6OutqueriesOID = {RECURSOR_STATS_OID, 60};
-static const oid10 throttledOutqueriesOID = {RECURSOR_STATS_OID, 61};
-static const oid10 dontOutqueriesOID = {RECURSOR_STATS_OID, 62};
-static const oid10 unreachablesOID = {RECURSOR_STATS_OID, 63};
-static const oid10 chainResendsOID = {RECURSOR_STATS_OID, 64};
-static const oid10 tcpClientsOID = {RECURSOR_STATS_OID, 65};
-#ifdef __linux__
-static const oid10 udpRecvbufErrorsOID = {RECURSOR_STATS_OID, 66};
-static const oid10 udpSndbufErrorsOID = {RECURSOR_STATS_OID, 67};
-static const oid10 udpNoportErrorsOID = {RECURSOR_STATS_OID, 68};
-static const oid10 udpinErrorsOID = {RECURSOR_STATS_OID, 69};
-#endif /* __linux__ */
-static const oid10 ednsPingMatchesOID = {RECURSOR_STATS_OID, 70};
-static const oid10 ednsPingMismatchesOID = {RECURSOR_STATS_OID, 71};
-static const oid10 dnssecQueriesOID = {RECURSOR_STATS_OID, 72};
-static const oid10 nopingOutqueriesOID = {RECURSOR_STATS_OID, 73};
-static const oid10 noednsOutqueriesOID = {RECURSOR_STATS_OID, 74};
-static const oid10 uptimeOID = {RECURSOR_STATS_OID, 75};
-static const oid10 realMemoryUsageOID = {RECURSOR_STATS_OID, 76};
-static const oid10 fdUsageOID = {RECURSOR_STATS_OID, 77};
-static const oid10 userMsecOID = {RECURSOR_STATS_OID, 78};
-static const oid10 sysMsecOID = {RECURSOR_STATS_OID, 79};
-static const oid10 dnssecValidationsOID = {RECURSOR_STATS_OID, 80};
-static const oid10 dnssecResultInsecureOID = {RECURSOR_STATS_OID, 81};
-static const oid10 dnssecResultSecureOID = {RECURSOR_STATS_OID, 82};
-static const oid10 dnssecResultBogusOID = {RECURSOR_STATS_OID, 83};
-static const oid10 dnssecResultIndeterminateOID = {RECURSOR_STATS_OID, 84};
-static const oid10 dnssecResultNtaOID = {RECURSOR_STATS_OID, 85};
-static const oid10 policyResultNoactionOID = {RECURSOR_STATS_OID, 86};
-static const oid10 policyResultDropOID = {RECURSOR_STATS_OID, 87};
-static const oid10 policyResultNxdomainOID = {RECURSOR_STATS_OID, 88};
-static const oid10 policyResultNodataOID = {RECURSOR_STATS_OID, 89};
-static const oid10 policyResultTruncateOID = {RECURSOR_STATS_OID, 90};
-static const oid10 policyResultCustomOID = {RECURSOR_STATS_OID, 91};
-static const oid10 queryPipeFullDropsOID = {RECURSOR_STATS_OID, 92};
-static const oid10 truncatedDropsOID = {RECURSOR_STATS_OID, 93};
-static const oid10 emptyQueriesOID = {RECURSOR_STATS_OID, 94};
-static const oid10 dnssecAuthenticDataQueriesOID = {RECURSOR_STATS_OID, 95};
-static const oid10 dnssecCheckDisabledQueriesOID = {RECURSOR_STATS_OID, 96};
-static const oid10 variableResponsesOID = {RECURSOR_STATS_OID, 97};
-static const oid10 specialMemoryUsageOID = {RECURSOR_STATS_OID, 98};
-static const oid10 rebalancedQueriesOID = {RECURSOR_STATS_OID, 99};
-static const oid10 qnameMinFallbackSuccessOID = {RECURSOR_STATS_OID, 100};
-static const oid10 proxyProtocolInvalidOID = {RECURSOR_STATS_OID, 101};
-static const oid10 recordCacheContendedOID = {RECURSOR_STATS_OID, 102};
-static const oid10 recordCacheAcquiredOID = {RECURSOR_STATS_OID, 103};
-static const oid10 nodLookupsDroppedOversizeOID = {RECURSOR_STATS_OID, 104};
-static const oid10 taskQueuePushedOID = {RECURSOR_STATS_OID, 105};
-static const oid10 taskQueueExpiredOID = {RECURSOR_STATS_OID, 106};
-static const oid10 taskQueueSizeOID = {RECURSOR_STATS_OID, 107};
-static const oid10 aggressiveNSECCacheEntriesOID = {RECURSOR_STATS_OID, 108};
-static const oid10 aggressiveNSECCacheNSECHitsOID = {RECURSOR_STATS_OID, 109};
-static const oid10 aggressiveNSECCacheNSEC3HitsOID = {RECURSOR_STATS_OID, 110};
-static const oid10 aggressiveNSECCacheNSECWCHitsOID = {RECURSOR_STATS_OID, 111};
-static const oid10 aggressiveNSECCacheNSEC3WCHitsOID = {RECURSOR_STATS_OID, 112};
-static const oid10 dotOutqueriesOID = {RECURSOR_STATS_OID, 113};
-static const oid10 dns64PrefixAnswers = {RECURSOR_STATS_OID, 114};
-static const oid10 almostExpiredPushed = {RECURSOR_STATS_OID, 115};
-static const oid10 almostExpiredRun = {RECURSOR_STATS_OID, 116};
-static const oid10 almostExpiredExceptions = {RECURSOR_STATS_OID, 117};
-#ifdef __linux__
-static const oid10 udpInCsumErrorsOID = {RECURSOR_STATS_OID, 118};
-static const oid10 udp6RecvbufErrorsOID = {RECURSOR_STATS_OID, 119};
-static const oid10 udp6SndbufErrorsOID = {RECURSOR_STATS_OID, 120};
-static const oid10 udp6NoportErrorsOID = {RECURSOR_STATS_OID, 121};
-static const oid10 udp6InErrorsOID = {RECURSOR_STATS_OID, 122};
-static const oid10 udp6InCsumErrorsOID = {RECURSOR_STATS_OID, 123};
-#endif /* __linux__ */
-static const oid10 sourceDisallowedNotifyOID = {RECURSOR_STATS_OID, 124};
-static const oid10 zoneDisallowedNotifyOID = {RECURSOR_STATS_OID, 125};
-static const oid10 nonResolvingNameserverEntriesOID = {RECURSOR_STATS_OID, 126};
-static const oid10 maintenanceUSecOID = {RECURSOR_STATS_OID, 127};
-static const oid10 maintenanceCallsOID = {RECURSOR_STATS_OID, 128};
-
-static const oid10 rcode0AnswersOID = {RECURSOR_STATS_OID, 129};
-static const oid10 rcode1AnswersOID = {RECURSOR_STATS_OID, 130};
-static const oid10 rcode2AnswersOID = {RECURSOR_STATS_OID, 131};
-static const oid10 rcode3AnswersOID = {RECURSOR_STATS_OID, 132};
-static const oid10 rcode4AnswersOID = {RECURSOR_STATS_OID, 133};
-static const oid10 rcode5AnswersOID = {RECURSOR_STATS_OID, 134};
-static const oid10 rcode6AnswersOID = {RECURSOR_STATS_OID, 135};
-static const oid10 rcode7AnswersOID = {RECURSOR_STATS_OID, 136};
-static const oid10 rcode8AnswersOID = {RECURSOR_STATS_OID, 137};
-static const oid10 rcode9AnswersOID = {RECURSOR_STATS_OID, 138};
-static const oid10 rcode10AnswersOID = {RECURSOR_STATS_OID, 139};
-static const oid10 rcode11AnswersOID = {RECURSOR_STATS_OID, 140};
-static const oid10 rcode12AnswersOID = {RECURSOR_STATS_OID, 141};
-static const oid10 rcode13AnswersOID = {RECURSOR_STATS_OID, 142};
-static const oid10 rcode14AnswersOID = {RECURSOR_STATS_OID, 143};
-static const oid10 rcode15AnswersOID = {RECURSOR_STATS_OID, 144};
-
-static const oid10 packetCacheContendedOID = {RECURSOR_STATS_OID, 145};
-static const oid10 packetCacheAcquiredOID = {RECURSOR_STATS_OID, 146};
-static const oid10 nodEventsOID = {RECURSOR_STATS_OID, 147};
-static const oid10 udrEventsOID = {RECURSOR_STATS_OID, 148};
-static const oid10 maxChainLengthOID = {RECURSOR_STATS_OID, 149};
-static const oid10 maxChainWeightOID = {RECURSOR_STATS_OID, 150};
-static const oid10 chainLimitsOID = {RECURSOR_STATS_OID, 151};
-static const oid10 tcpOverflowOID = {RECURSOR_STATS_OID, 152};
+#include "rec-oids-gen.h"
 
 static std::unordered_map<oid, std::string> s_statsMap;
 
@@ -307,163 +149,8 @@ RecursorSNMPAgent::RecursorSNMPAgent(const std::string& name, const std::string&
   SNMPAgent(name, daemonSocket)
 {
 #ifdef HAVE_NET_SNMP
-  registerCounter64Stat("questions", questionsOID);
-  registerCounter64Stat("ipv6-questions", ipv6QuestionsOID);
-  registerCounter64Stat("tcp-questions", tcpQuestionsOID);
-  registerCounter64Stat("cache-hits", cacheHitsOID);
-  registerCounter64Stat("cache-misses", cacheMissesOID);
-  registerCounter64Stat("cache-entries", cacheEntriesOID);
-  registerCounter64Stat("cache-bytes", cacheBytesOID);
-  registerCounter64Stat("packetcache-hits", packetcacheHitsOID);
-  registerCounter64Stat("packetcache-misses", packetcacheMissesOID);
-  registerCounter64Stat("packetcache-entries", packetcacheEntriesOID);
-  registerCounter64Stat("packetcache-bytes", packetcacheBytesOID);
-  registerCounter64Stat("malloc-bytes", mallocBytesOID);
-  registerCounter64Stat("servfail-answers", servfailAnswersOID);
-  registerCounter64Stat("nxdomain-answers", nxdomainAnswersOID);
-  registerCounter64Stat("noerror-answers", noerrorAnswersOID);
-  registerCounter64Stat("unauthorized-udp", unauthorizedUdpOID);
-  registerCounter64Stat("unauthorized-tcp", unauthorizedTcpOID);
-  registerCounter64Stat("source-disallowed-notify", sourceDisallowedNotifyOID);
-  registerCounter64Stat("zone-disallowed-notify", zoneDisallowedNotifyOID);
-  registerCounter64Stat("tcp-client-overflow", tcpClientOverflowOID);
-  registerCounter64Stat("client-parse-errors", clientParseErrorsOID);
-  registerCounter64Stat("server-parse-errors", serverParseErrorsOID);
-  registerCounter64Stat("too-old-drops", tooOldDropsOID);
-  registerCounter64Stat("query-pipe-full-drops", queryPipeFullDropsOID);
-  registerCounter64Stat("truncated-drops", truncatedDropsOID);
-  registerCounter64Stat("empty-queries", emptyQueriesOID);
-  registerCounter64Stat("variable-responses", variableResponsesOID);
-  registerCounter64Stat("answers0-1", answers01OID);
-  registerCounter64Stat("answers1-10", answers110OID);
-  registerCounter64Stat("answers10-100", answers10100OID);
-  registerCounter64Stat("answers100-1000", answers1001000OID);
-  registerCounter64Stat("answers-slow", answersSlowOID);
-  registerCounter64Stat("auth4-answers0-1", auth4Answers01OID);
-  registerCounter64Stat("auth4-answers1-10", auth4Answers110OID);
-  registerCounter64Stat("auth4-answers10-100", auth4Answers10100OID);
-  registerCounter64Stat("auth4-answers100-1000", auth4Answers1001000OID);
-  registerCounter64Stat("auth4-answers-slow", auth4AnswersslowOID);
-  registerCounter64Stat("auth6-answers0-1", auth6Answers01OID);
-  registerCounter64Stat("auth6-answers1-10", auth6Answers110OID);
-  registerCounter64Stat("auth6-answers10-100", auth6Answers10100OID);
-  registerCounter64Stat("auth6-answers100-1000", auth6Answers1001000OID);
-  registerCounter64Stat("auth6-answers-slow", auth6AnswersSlowOID);
-  registerCounter64Stat("qa-latency", qaLatencyOID);
-  registerCounter64Stat("unexpected-packets", unexpectedPacketsOID);
-  registerCounter64Stat("case-mismatches", caseMismatchesOID);
-  registerCounter64Stat("spoof-prevents", spoofPreventsOID);
-  registerCounter64Stat("nsset-invalidations", nssetInvalidationsOID);
-  registerCounter64Stat("resource-limits", resourceLimitsOID);
-  registerCounter64Stat("over-capacity-drops", overCapacityDropsOID);
-  registerCounter64Stat("policy-drops", policyDropsOID);
-  registerCounter64Stat("no-packet-error", noPacketErrorOID);
-  registerCounter64Stat("dlg-only-drops", dlgOnlyDropsOID);
-  registerCounter64Stat("ignored-packets", ignoredPacketsOID);
-  registerCounter64Stat("max-mthread-stack", maxMthreadStackOID);
-  registerCounter64Stat("negcache-entries", negcacheEntriesOID);
-  registerCounter64Stat("throttle-entries", throttleEntriesOID);
-  registerCounter64Stat("nsspeeds-entries", nsspeedsEntriesOID);
-  registerCounter64Stat("failed-host-entries", failedHostEntriesOID);
-  registerCounter64Stat("concurrent-queries", concurrentQueriesOID);
-  registerCounter64Stat("security-status", securityStatusOID);
-  registerCounter64Stat("outgoing-timeouts", outgoingTimeoutsOID);
-  registerCounter64Stat("outgoing4-timeouts", outgoing4TimeoutsOID);
-  registerCounter64Stat("outgoing6-timeouts", outgoing6TimeoutsOID);
-  registerCounter64Stat("tcp-outqueries", tcpOutqueriesOID);
-  registerCounter64Stat("all-outqueries", allOutqueriesOID);
-  registerCounter64Stat("ipv6-outqueries", ipv6OutqueriesOID);
-  registerCounter64Stat("throttled-outqueries", throttledOutqueriesOID);
-  registerCounter64Stat("dont-outqueries", dontOutqueriesOID);
-  registerCounter64Stat("qname-min-fallback-success", qnameMinFallbackSuccessOID);
-  registerCounter64Stat("unreachables", unreachablesOID);
-  registerCounter64Stat("chain-resends", chainResendsOID);
-  registerCounter64Stat("tcp-clients", tcpClientsOID);
-#ifdef __linux__
-  registerCounter64Stat("udp-recvbuf-errors", udpRecvbufErrorsOID);
-  registerCounter64Stat("udp-sndbuf-errors", udpSndbufErrorsOID);
-  registerCounter64Stat("udp-noport-errors", udpNoportErrorsOID);
-  registerCounter64Stat("udp-in-errors", udpinErrorsOID);
-  registerCounter64Stat("udp-in-csums-errors", udpInCsumErrorsOID);
-  registerCounter64Stat("udp6-recvbuf-errors", udp6RecvbufErrorsOID);
-  registerCounter64Stat("udp6-sndbuf-errors", udp6SndbufErrorsOID);
-  registerCounter64Stat("udp6-noport-errors", udp6NoportErrorsOID);
-  registerCounter64Stat("udp6-in-errors", udp6InErrorsOID);
-  registerCounter64Stat("udp6-in-csums-errors", udp6InCsumErrorsOID);
-#endif /* __linux__ */
-  registerCounter64Stat("edns-ping-matches", ednsPingMatchesOID);
-  registerCounter64Stat("edns-ping-mismatches", ednsPingMismatchesOID);
-  registerCounter64Stat("dnssec-queries", dnssecQueriesOID);
-  registerCounter64Stat("dnssec-authentic-data-queries", dnssecAuthenticDataQueriesOID);
-  registerCounter64Stat("dnssec-check-disabled-queries", dnssecCheckDisabledQueriesOID);
-  registerCounter64Stat("noping-outqueries", nopingOutqueriesOID);
-  registerCounter64Stat("noedns-outqueries", noednsOutqueriesOID);
-  registerCounter64Stat("uptime", uptimeOID);
-  registerCounter64Stat("real-memory-usage", realMemoryUsageOID);
-  registerCounter64Stat("fd-usage", fdUsageOID);
-  registerCounter64Stat("user-msec", userMsecOID);
-  registerCounter64Stat("sys-msec", sysMsecOID);
-  registerCounter64Stat("dnssec-validations", dnssecValidationsOID);
-  registerCounter64Stat("dnssec-result-insecure", dnssecResultInsecureOID);
-  registerCounter64Stat("dnssec-result-secure", dnssecResultSecureOID);
-  registerCounter64Stat("dnssec-result-bogus", dnssecResultBogusOID);
-  registerCounter64Stat("dnssec-result-indeterminate", dnssecResultIndeterminateOID);
-  registerCounter64Stat("dnssec-result-nta", dnssecResultNtaOID);
-  registerCounter64Stat("policy-result-noaction", policyResultNoactionOID);
-  registerCounter64Stat("policy-result-drop", policyResultDropOID);
-  registerCounter64Stat("policy-result-nxdomain", policyResultNxdomainOID);
-  registerCounter64Stat("policy-result-nodata", policyResultNodataOID);
-  registerCounter64Stat("policy-result-truncate", policyResultTruncateOID);
-  registerCounter64Stat("policy-result-custom", policyResultCustomOID);
-  registerCounter64Stat("special-memory-usage", specialMemoryUsageOID);
-  registerCounter64Stat("rebalanced-queries", rebalancedQueriesOID);
-  registerCounter64Stat("proxy-protocol-invalid", proxyProtocolInvalidOID);
-  registerCounter64Stat("record-cache-contended", recordCacheContendedOID);
-  registerCounter64Stat("record-cache-acquired", recordCacheAcquiredOID);
-  registerCounter64Stat("nod-lookups-dropped-oversize", nodLookupsDroppedOversizeOID);
-  registerCounter64Stat("tasqueue-pushed", taskQueuePushedOID);
-  registerCounter64Stat("taskqueue-expired", taskQueueExpiredOID);
-  registerCounter64Stat("taskqueue-size", taskQueueSizeOID);
-  registerCounter64Stat("aggressive-nsec-cache-entries", aggressiveNSECCacheEntriesOID);
-  registerCounter64Stat("aggressive-nsec-cache-nsec-hits", aggressiveNSECCacheNSECHitsOID);
-  registerCounter64Stat("aggressive-nsec-cache-nsec3-hits", aggressiveNSECCacheNSEC3HitsOID);
-  registerCounter64Stat("aggressive-nsec-cache-nsec-wc-hits", aggressiveNSECCacheNSECWCHitsOID);
-  registerCounter64Stat("aggressive-nsec-cache-nsec-wc3-hits", aggressiveNSECCacheNSEC3WCHitsOID);
-  registerCounter64Stat("dot-outqueries", dotOutqueriesOID);
-  registerCounter64Stat("dns64-prefix-answers", dns64PrefixAnswers);
-  registerCounter64Stat("almost-expired-pushed", almostExpiredPushed);
-  registerCounter64Stat("almost-expired-run", almostExpiredRun);
-  registerCounter64Stat("almost-expired-exceptions", almostExpiredExceptions);
-  registerCounter64Stat("non-resolving-nameserver-entries", nonResolvingNameserverEntriesOID);
-  registerCounter64Stat("maintenance-usec", maintenanceUSecOID);
-  registerCounter64Stat("maintenance-calls", maintenanceCallsOID);
-  registerCounter64Stat("chain-limits", chainLimitsOID);
-
-#define RCODE(num) registerCounter64Stat("auth-" + RCode::to_short_s(num) + "-answers", rcode##num##AnswersOID) // NOLINT(cppcoreguidelines-macro-usage)
-  RCODE(0);
-  RCODE(1);
-  RCODE(2);
-  RCODE(3);
-  RCODE(4);
-  RCODE(5);
-  RCODE(6);
-  RCODE(7);
-  RCODE(8);
-  RCODE(9);
-  RCODE(10);
-  RCODE(11);
-  RCODE(12);
-  RCODE(13);
-  RCODE(14);
-  RCODE(15);
 
-  registerCounter64Stat("packetcache-contended", packetCacheContendedOID);
-  registerCounter64Stat("packetcache-acquired", packetCacheAcquiredOID);
-  registerCounter64Stat("nod-events", nodEventsOID);
-  registerCounter64Stat("udr-events", udrEventsOID);
-  registerCounter64Stat("max-chain-length", maxChainLengthOID);
-  registerCounter64Stat("max-chain-weight", maxChainWeightOID);
-  registerCounter64Stat("tcp-overflow", tcpOverflowOID);
+#include "rec-snmp-gen.h"
 
 #endif /* HAVE_NET_SNMP */
 }
index f4eb031a91f3d1d7cb691a729c8842fa3120666b..dbbfecb01322d2ff4ae493faa57b9178efedeb5d 100644 (file)
 #include "validate-recursor.hh"
 #include "filterpo.hh"
 
-#include "secpoll-recursor.hh"
+#include "secpoll-recursor.hh" // IWYU pragma: keep, needed by included generated file
 #include "pubsuffix.hh"
 #include "namespaces.hh"
 #include "rec-taskqueue.hh"
-#include "rec-tcpout.hh"
+#include "rec-tcpout.hh" // IWYU pragma: keep, needed by included generated file
 #include "rec-main.hh"
 #include "rec-system-resolve.hh"
 
@@ -127,22 +127,34 @@ void disableStats(StatComponent component, const string& stats)
 
 static void addGetStat(const string& name, const uint32_t* place)
 {
-  d_get32bitpointers[name] = place;
+  if (!d_get32bitpointers.emplace(name, place).second) {
+    cerr << "addGetStat: double def " << name << endl;
+    _exit(1);
+  }
 }
 
 static void addGetStat(const string& name, const pdns::stat_t* place)
 {
-  d_getatomics[name] = place;
+  if (!d_getatomics.emplace(name, place).second) {
+    cerr << "addGetStat: double def " << name << endl;
+    _exit(1);
+  }
 }
 
-static void addGetStat(const string& name, std::function<uint64_t()> f)
+static void addGetStat(const string& name, std::function<uint64_t()> func)
 {
-  d_get64bitmembers[name] = std::move(f);
+  if (!d_get64bitmembers.emplace(name, std::move(func)).second) {
+    cerr << "addGetStat: double def " << name << endl;
+    _exit(1);
+  }
 }
 
-static void addGetStat(const string& name, std::function<StatsMap()> f)
+static void addGetStat(const string& name, std::function<StatsMap()> func)
 {
-  d_getmultimembers[name] = std::move(f);
+  if (!d_getmultimembers.emplace(name, std::move(func)).second) {
+    cerr << "addGetStat: double def " << name << endl;
+    _exit(1);
+  }
 }
 
 static std::string getPrometheusName(const std::string& arg)
@@ -1313,263 +1325,7 @@ static time_t s_startupTime = time(nullptr);
 
 static void registerAllStats1()
 {
-  addGetStat("questions", [] { return g_Counters.sum(rec::Counter::qcounter); });
-  addGetStat("ipv6-questions", [] { return g_Counters.sum(rec::Counter::ipv6qcounter); });
-  addGetStat("tcp-questions", [] { return g_Counters.sum(rec::Counter::tcpqcounter); });
-
-  addGetStat("cache-hits", []() { return g_recCache->getCacheHits(); });
-  addGetStat("cache-misses", []() { return g_recCache->getCacheMisses(); });
-  addGetStat("cache-entries", doGetCacheSize);
-  addGetStat("max-cache-entries", []() { return g_maxCacheEntries.load(); });
-  addGetStat("max-packetcache-entries", []() { return g_maxPacketCacheEntries.load(); });
-  addGetStat("cache-bytes", doGetCacheBytes);
-  addGetStat("record-cache-contended", []() { return g_recCache->stats().first; });
-  addGetStat("record-cache-acquired", []() { return g_recCache->stats().second; });
-
-  addGetStat("packetcache-hits", [] { return g_packetCache ? g_packetCache->getHits() : 0; });
-  addGetStat("packetcache-misses", [] { return g_packetCache ? g_packetCache->getMisses() : 0; });
-  addGetStat("packetcache-entries", [] { return g_packetCache ? g_packetCache->size() : 0; });
-  addGetStat("packetcache-bytes", [] { return g_packetCache ? g_packetCache->bytes() : 0; });
-  addGetStat("packetcache-contended", []() { return g_packetCache ? g_packetCache->stats().first : 0; });
-  addGetStat("packetcache-acquired", []() { return g_packetCache ? g_packetCache->stats().second : 0; });
-
-  addGetStat("aggressive-nsec-cache-entries", []() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getEntriesCount() : 0; });
-  addGetStat("aggressive-nsec-cache-nsec-hits", []() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSECHits() : 0; });
-  addGetStat("aggressive-nsec-cache-nsec3-hits", []() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSEC3Hits() : 0; });
-  addGetStat("aggressive-nsec-cache-nsec-wc-hits", []() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSECWildcardHits() : 0; });
-  addGetStat("aggressive-nsec-cache-nsec3-wc-hits", []() { return g_aggressiveNSECCache ? g_aggressiveNSECCache->getNSEC3WildcardHits() : 0; });
-
-  addGetStat("malloc-bytes", doGetMallocated);
-
-  addGetStat("servfail-answers", [] { return g_Counters.sum(rec::Counter::servFails); });
-  addGetStat("nxdomain-answers", [] { return g_Counters.sum(rec::Counter::nxDomains); });
-  addGetStat("noerror-answers", [] { return g_Counters.sum(rec::Counter::noErrors); });
-
-  addGetStat("unauthorized-udp", [] { return g_Counters.sum(rec::Counter::unauthorizedUDP); });
-  addGetStat("unauthorized-tcp", [] { return g_Counters.sum(rec::Counter::unauthorizedTCP); });
-  addGetStat("source-disallowed-notify", [] { return g_Counters.sum(rec::Counter::sourceDisallowedNotify); });
-  addGetStat("zone-disallowed-notify", [] { return g_Counters.sum(rec::Counter::zoneDisallowedNotify); });
-  addGetStat("tcp-overflow", [] { return g_Counters.sum(rec::Counter::tcpOverflow); });
-  addGetStat("tcp-client-overflow", [] { return g_Counters.sum(rec::Counter::tcpClientOverflow); });
-
-  addGetStat("client-parse-errors", [] { return g_Counters.sum(rec::Counter::clientParseError); });
-  addGetStat("server-parse-errors", [] { return g_Counters.sum(rec::Counter::serverParseError); });
-  addGetStat("too-old-drops", [] { return g_Counters.sum(rec::Counter::tooOldDrops); });
-  addGetStat("truncated-drops", [] { return g_Counters.sum(rec::Counter::truncatedDrops); });
-  addGetStat("query-pipe-full-drops", [] { return g_Counters.sum(rec::Counter::queryPipeFullDrops); });
-
-  addGetStat("answers0-1", []() { return g_Counters.sum(rec::Histogram::answers).getCount(0); });
-  addGetStat("answers1-10", []() { return g_Counters.sum(rec::Histogram::answers).getCount(1); });
-  addGetStat("answers10-100", []() { return g_Counters.sum(rec::Histogram::answers).getCount(2); });
-  addGetStat("answers100-1000", []() { return g_Counters.sum(rec::Histogram::answers).getCount(3); });
-  addGetStat("answers-slow", []() { return g_Counters.sum(rec::Histogram::answers).getCount(4); });
-
-  addGetStat("x-ourtime0-1", []() { return g_Counters.sum(rec::Histogram::ourtime).getCount(0); });
-  addGetStat("x-ourtime1-2", []() { return g_Counters.sum(rec::Histogram::ourtime).getCount(1); });
-  addGetStat("x-ourtime2-4", []() { return g_Counters.sum(rec::Histogram::ourtime).getCount(2); });
-  addGetStat("x-ourtime4-8", []() { return g_Counters.sum(rec::Histogram::ourtime).getCount(3); });
-  addGetStat("x-ourtime8-16", []() { return g_Counters.sum(rec::Histogram::ourtime).getCount(4); });
-  addGetStat("x-ourtime16-32", []() { return g_Counters.sum(rec::Histogram::ourtime).getCount(5); });
-  addGetStat("x-ourtime-slow", []() { return g_Counters.sum(rec::Histogram::ourtime).getCount(6); });
-
-  addGetStat("auth4-answers0-1", []() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(0); });
-  addGetStat("auth4-answers1-10", []() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(1); });
-  addGetStat("auth4-answers10-100", []() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(2); });
-  addGetStat("auth4-answers100-1000", []() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(3); });
-  addGetStat("auth4-answers-slow", []() { return g_Counters.sum(rec::Histogram::auth4Answers).getCount(4); });
-
-  addGetStat("auth6-answers0-1", []() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(0); });
-  addGetStat("auth6-answers1-10", []() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(1); });
-  addGetStat("auth6-answers10-100", []() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(2); });
-  addGetStat("auth6-answers100-1000", []() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(3); });
-  addGetStat("auth6-answers-slow", []() { return g_Counters.sum(rec::Histogram::auth6Answers).getCount(4); });
-
-  addGetStat("qa-latency", []() { return round(g_Counters.avg(rec::DoubleWAvgCounter::avgLatencyUsec)); });
-  addGetStat("x-our-latency", []() { return round(g_Counters.avg(rec::DoubleWAvgCounter::avgLatencyOursUsec)); });
-  addGetStat("unexpected-packets", [] { return g_Counters.sum(rec::Counter::unexpectedCount); });
-  addGetStat("case-mismatches", [] { return g_Counters.sum(rec::Counter::caseMismatchCount); });
-  addGetStat("spoof-prevents", [] { return g_Counters.sum(rec::Counter::spoofCount); });
-
-  addGetStat("nsset-invalidations", [] { return g_Counters.sum(rec::Counter::nsSetInvalidations); });
-
-  addGetStat("resource-limits", [] { return g_Counters.sum(rec::Counter::resourceLimits); });
-  addGetStat("over-capacity-drops", [] { return g_Counters.sum(rec::Counter::overCapacityDrops); });
-  addGetStat("policy-drops", [] { return g_Counters.sum(rec::Counter::policyDrops); });
-  addGetStat("no-packet-error", [] { return g_Counters.sum(rec::Counter::noPacketError); });
-  addGetStat("ignored-packets", [] { return g_Counters.sum(rec::Counter::ignoredCount); });
-  addGetStat("empty-queries", [] { return g_Counters.sum(rec::Counter::emptyQueriesCount); });
-  addGetStat("max-mthread-stack", [] { return g_Counters.max(rec::Counter::maxMThreadStackUsage); });
-
-  addGetStat("negcache-entries", getNegCacheSize);
-  addGetStat("throttle-entries", SyncRes::getThrottledServersSize);
-
-  addGetStat("nsspeeds-entries", SyncRes::getNSSpeedsSize);
-  addGetStat("failed-host-entries", SyncRes::getFailedServersSize);
-  addGetStat("non-resolving-nameserver-entries", SyncRes::getNonResolvingNSSize);
-
-  addGetStat("concurrent-queries", getConcurrentQueries);
-  addGetStat("security-status", &g_security_status);
-  addGetStat("outgoing-timeouts", [] { return g_Counters.sum(rec::Counter::outgoingtimeouts); });
-  addGetStat("outgoing4-timeouts", [] { return g_Counters.sum(rec::Counter::outgoing4timeouts); });
-  addGetStat("outgoing6-timeouts", [] { return g_Counters.sum(rec::Counter::outgoing6timeouts); });
-  addGetStat("auth-zone-queries", [] { return g_Counters.sum(rec::Counter::authzonequeries); });
-  addGetStat("tcp-outqueries", [] { return g_Counters.sum(rec::Counter::tcpoutqueries); });
-  addGetStat("dot-outqueries", [] { return g_Counters.sum(rec::Counter::dotoutqueries); });
-  addGetStat("all-outqueries", [] { return g_Counters.sum(rec::Counter::outqueries); });
-  addGetStat("ipv6-outqueries", [] { return g_Counters.sum(rec::Counter::ipv6queries); });
-  addGetStat("throttled-outqueries", [] { return g_Counters.sum(rec::Counter::throttledqueries); });
-  addGetStat("dont-outqueries", [] { return g_Counters.sum(rec::Counter::dontqueries); });
-  addGetStat("qname-min-fallback-success", [] { return g_Counters.sum(rec::Counter::qnameminfallbacksuccess); });
-  addGetStat("throttled-out", [] { return g_Counters.sum(rec::Counter::throttledqueries); });
-  addGetStat("unreachables", [] { return g_Counters.sum(rec::Counter::unreachables); });
-  addGetStat("ecs-queries", &SyncRes::s_ecsqueries);
-  addGetStat("ecs-responses", &SyncRes::s_ecsresponses);
-  addGetStat("chain-resends", [] { return g_Counters.sum(rec::Counter::chainResends); });
-  addGetStat("tcp-clients", [] { return TCPConnection::getCurrentConnections(); });
-
-#ifdef __linux__
-  addGetStat("udp-recvbuf-errors", [] { return udpErrorStats("udp-recvbuf-errors"); });
-  addGetStat("udp-sndbuf-errors", [] { return udpErrorStats("udp-sndbuf-errors"); });
-  addGetStat("udp-noport-errors", [] { return udpErrorStats("udp-noport-errors"); });
-  addGetStat("udp-in-errors", [] { return udpErrorStats("udp-in-errors"); });
-  addGetStat("udp-in-csum-errors", [] { return udpErrorStats("udp-in-csum-errors"); });
-  addGetStat("udp6-recvbuf-errors", [] { return udp6ErrorStats("udp6-recvbuf-errors"); });
-  addGetStat("udp6-sndbuf-errors", [] { return udp6ErrorStats("udp6-sndbuf-errors"); });
-  addGetStat("udp6-noport-errors", [] { return udp6ErrorStats("udp6-noport-errors"); });
-  addGetStat("udp6-in-errors", [] { return udp6ErrorStats("udp6-in-errors"); });
-  addGetStat("udp6-in-csum-errors", [] { return udp6ErrorStats("udp6-in-csum-errors"); });
-#endif
-
-  addGetStat("edns-ping-matches", [] { return g_Counters.sum(rec::Counter::ednsPingMatches); });
-  addGetStat("edns-ping-mismatches", [] { return g_Counters.sum(rec::Counter::ednsPingMismatches); });
-  addGetStat("dnssec-queries", [] { return g_Counters.sum(rec::Counter::dnssecQueries); });
-
-  addGetStat("dnssec-authentic-data-queries", [] { return g_Counters.sum(rec::Counter::dnssecAuthenticDataQueries); });
-  addGetStat("dnssec-check-disabled-queries", [] { return g_Counters.sum(rec::Counter::dnssecCheckDisabledQueries); });
-
-  addGetStat("variable-responses", [] { return g_Counters.sum(rec::Counter::variableResponses); });
-
-  addGetStat("noping-outqueries", [] { return g_Counters.sum(rec::Counter::noPingOutQueries); });
-  addGetStat("noedns-outqueries", [] { return g_Counters.sum(rec::Counter::noEdnsOutQueries); });
-
-  addGetStat("uptime", [] { return time(nullptr) - s_startupTime; });
-  addGetStat("real-memory-usage", [] { return getRealMemoryUsage(string()); });
-  addGetStat("special-memory-usage", [] { return getSpecialMemoryUsage(string()); });
-  addGetStat("fd-usage", [] { return getOpenFileDescriptors(string()); });
-
-  //  addGetStat("query-rate", getQueryRate);
-  addGetStat("user-msec", getUserTimeMsec);
-  addGetStat("sys-msec", getSysTimeMsec);
-
-#ifdef __linux__
-  addGetStat("cpu-iowait", [] { return getCPUIOWait(string()); });
-  addGetStat("cpu-steal", [] { return getCPUSteal(string()); });
-#endif
-
-  addGetStat("cpu-msec", []() { return toCPUStatsMap("cpu-msec"); });
-
-#ifdef MALLOC_TRACE
-  addGetStat("memory-allocs", [] { return g_mtracer->getAllocs(string()); });
-  addGetStat("memory-alloc-flux", [] { return g_mtracer->getAllocFlux(string()); });
-  addGetStat("memory-allocated", [] { return g_mtracer->getTotAllocated(string()); });
-#endif
-
-  addGetStat("dnssec-validations", [] { return g_Counters.sum(rec::Counter::dnssecValidations); });
-  addGetStat("dnssec-result-insecure", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Insecure); });
-  addGetStat("dnssec-result-secure", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Secure); });
-  addGetStat("dnssec-result-bogus", []() {
-    std::set<vState> const bogusStates = {vState::BogusNoValidDNSKEY, vState::BogusInvalidDenial, vState::BogusUnableToGetDSs, vState::BogusUnableToGetDNSKEYs, vState::BogusSelfSignedDS, vState::BogusNoRRSIG, vState::BogusNoValidRRSIG, vState::BogusMissingNegativeIndication, vState::BogusSignatureNotYetValid, vState::BogusSignatureExpired, vState::BogusUnsupportedDNSKEYAlgo, vState::BogusUnsupportedDSDigestType, vState::BogusNoZoneKeyBitSet, vState::BogusRevokedDNSKEY, vState::BogusInvalidDNSKEYProtocol};
-    auto counts = g_Counters.sum(rec::DNSSECHistogram::dnssec);
-    uint64_t total = 0;
-    for (const auto& state : bogusStates) {
-      total += counts.at(state);
-    }
-    return total;
-  });
-
-  addGetStat("dnssec-result-bogus-no-valid-dnskey", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoValidDNSKEY); });
-  addGetStat("dnssec-result-bogus-invalid-denial", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusInvalidDenial); });
-  addGetStat("dnssec-result-bogus-unable-to-get-dss", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnableToGetDSs); });
-  addGetStat("dnssec-result-bogus-unable-to-get-dnskeys", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnableToGetDNSKEYs); });
-  addGetStat("dnssec-result-bogus-self-signed-ds", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSelfSignedDS); });
-  addGetStat("dnssec-result-bogus-no-rrsig", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoRRSIG); });
-  addGetStat("dnssec-result-bogus-no-valid-rrsig", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoValidRRSIG); });
-  addGetStat("dnssec-result-bogus-missing-negative-indication", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusMissingNegativeIndication); });
-  addGetStat("dnssec-result-bogus-signature-not-yet-valid", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSignatureNotYetValid); });
-  addGetStat("dnssec-result-bogus-signature-expired", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusSignatureExpired); });
-  addGetStat("dnssec-result-bogus-unsupported-dnskey-algo", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnsupportedDNSKEYAlgo); });
-  addGetStat("dnssec-result-bogus-unsupported-ds-digest-type", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusUnsupportedDSDigestType); });
-  addGetStat("dnssec-result-bogus-no-zone-key-bit-set", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusNoZoneKeyBitSet); });
-  addGetStat("dnssec-result-bogus-revoked-dnskey", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusRevokedDNSKEY); });
-  addGetStat("dnssec-result-bogus-invalid-dnskey-protocol", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::BogusInvalidDNSKEYProtocol); });
-  addGetStat("dnssec-result-indeterminate", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::Indeterminate); });
-  addGetStat("dnssec-result-nta", [] { return g_Counters.sum(rec::DNSSECHistogram::dnssec).at(vState::NTA); });
-
-  if (::arg()["x-dnssec-names"].length() > 0) {
-    addGetStat("x-dnssec-result-bogus", []() {
-      std::set<vState> const bogusStates = {vState::BogusNoValidDNSKEY, vState::BogusInvalidDenial, vState::BogusUnableToGetDSs, vState::BogusUnableToGetDNSKEYs, vState::BogusSelfSignedDS, vState::BogusNoRRSIG, vState::BogusNoValidRRSIG, vState::BogusMissingNegativeIndication, vState::BogusSignatureNotYetValid, vState::BogusSignatureExpired, vState::BogusUnsupportedDNSKEYAlgo, vState::BogusUnsupportedDSDigestType, vState::BogusNoZoneKeyBitSet, vState::BogusRevokedDNSKEY, vState::BogusInvalidDNSKEYProtocol};
-      auto counts = g_Counters.sum(rec::DNSSECHistogram::xdnssec);
-      uint64_t total = 0;
-      for (const auto& state : bogusStates) {
-        total += counts.at(state);
-      }
-      return total;
-    });
-    addGetStat("x-dnssec-result-bogus-no-valid-dnskey", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoValidDNSKEY); });
-    addGetStat("x-dnssec-result-bogus-invalid-denial", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusInvalidDenial); });
-    addGetStat("x-dnssec-result-bogus-unable-to-get-dss", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnableToGetDSs); });
-    addGetStat("x-dnssec-result-bogus-unable-to-get-dnskeys", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnableToGetDNSKEYs); });
-    addGetStat("x-dnssec-result-bogus-self-signed-ds", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSelfSignedDS); });
-    addGetStat("x-dnssec-result-bogus-no-rrsig", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoRRSIG); });
-    addGetStat("x-dnssec-result-bogus-no-valid-rrsig", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoValidRRSIG); });
-    addGetStat("x-dnssec-result-bogus-missing-negative-indication", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusMissingNegativeIndication); });
-    addGetStat("x-dnssec-result-bogus-signature-not-yet-valid", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSignatureNotYetValid); });
-    addGetStat("x-dnssec-result-bogus-signature-expired", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusSignatureExpired); });
-    addGetStat("x-dnssec-result-bogus-unsupported-dnskey-algo", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnsupportedDNSKEYAlgo); });
-    addGetStat("x-dnssec-result-bogus-unsupported-ds-digest-type", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusUnsupportedDSDigestType); });
-    addGetStat("x-dnssec-result-bogus-no-zone-key-bit-set", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusNoZoneKeyBitSet); });
-    addGetStat("x-dnssec-result-bogus-revoked-dnskey", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusRevokedDNSKEY); });
-    addGetStat("x-dnssec-result-bogus-invalid-dnskey-protocol", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::BogusInvalidDNSKEYProtocol); });
-    addGetStat("x-dnssec-result-indeterminate", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Indeterminate); });
-    addGetStat("x-dnssec-result-nta", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::NTA); });
-    addGetStat("x-dnssec-result-insecure", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Insecure); });
-    addGetStat("x-dnssec-result-secure", [] { return g_Counters.sum(rec::DNSSECHistogram::xdnssec).at(vState::Secure); });
-  }
-
-  addGetStat("policy-result-noaction", [] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NoAction); });
-  addGetStat("policy-result-drop", [] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Drop); });
-  addGetStat("policy-result-nxdomain", [] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NXDOMAIN); });
-  addGetStat("policy-result-nodata", [] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::NODATA); });
-  addGetStat("policy-result-truncate", [] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Truncate); });
-  addGetStat("policy-result-custom", [] { return g_Counters.sum(rec::PolicyHistogram::policy).at(DNSFilterEngine::PolicyKind::Custom); });
-
-  addGetStat("rebalanced-queries", [] { return g_Counters.sum(rec::Counter::rebalancedQueries); });
-
-  addGetStat("proxy-protocol-invalid", [] { return g_Counters.sum(rec::Counter::proxyProtocolInvalidCount); });
-
-  addGetStat("nod-lookups-dropped-oversize", [] { return g_Counters.sum(rec::Counter::nodLookupsDroppedOversize); });
-
-  addGetStat("taskqueue-pushed", []() { return getTaskPushes(); });
-  addGetStat("taskqueue-expired", []() { return getTaskExpired(); });
-  addGetStat("taskqueue-size", []() { return getTaskSize(); });
-
-  addGetStat("dns64-prefix-answers", [] { return g_Counters.sum(rec::Counter::dns64prefixanswers); });
-
-  addGetStat("almost-expired-pushed", []() { return getAlmostExpiredTasksPushed(); });
-  addGetStat("almost-expired-run", []() { return getAlmostExpiredTasksRun(); });
-  addGetStat("almost-expired-exceptions", []() { return getAlmostExpiredTaskExceptions(); });
-
-  addGetStat("idle-tcpout-connections", getCurrentIdleTCPConnections);
-
-  addGetStat("maintenance-usec", [] { return g_Counters.sum(rec::Counter::maintenanceUsec); });
-  addGetStat("maintenance-calls", [] { return g_Counters.sum(rec::Counter::maintenanceCalls); });
-
-  addGetStat("nod-events", [] { return g_Counters.sum(rec::Counter::nodCount); });
-  addGetStat("udr-events", [] { return g_Counters.sum(rec::Counter::udrCount); });
-
-  addGetStat("max-chain-length", [] { return g_Counters.max(rec::Counter::maxChainLength); });
-  addGetStat("max-chain-weight", [] { return g_Counters.max(rec::Counter::maxChainWeight); });
-  addGetStat("chain-limits", [] { return g_Counters.sum(rec::Counter::chainLimits); });
+#include "rec-metrics-gen.h"
 
   /* make sure that the ECS stats are properly initialized */
   SyncRes::clearECSStats();
@@ -1597,9 +1353,6 @@ static void registerAllStats1()
   addGetStat("auth-rcode-answers", []() {
     return toAuthRCodeStatsMap("auth-rcode-answers");
   });
-  addGetStat("remote-logger-count", []() {
-    return toRemoteLoggerStatsMap("remote-logger-count");
-  });
 }
 
 void registerAllStats()
index 54f4773ff4e5f05dc4a648c51bf217d638660617..d6d8ed89c6e26aaf99aad41fc206bb1c2229a6a9 100644 (file)
 #include "json11.hpp"
 #include "webserver.hh"
 #include "ws-api.hh"
-#include "logger.hh"
 #include "logging.hh"
 #include "rec-lua-conf.hh"
 #include "rpzloader.hh"
 #include "uuid-utils.hh"
 #include "tcpiohandler.hh"
 #include "rec-main.hh"
-#include "settings/cxxsettings.hh"
+#include "settings/cxxsettings.hh" // IWYU pragma: keep, needed by included generated file
 
 using json11::Json;
 
@@ -610,660 +609,7 @@ static void serveStuff(HttpRequest* req, HttpResponse* resp)
 }
 
 const std::map<std::string, MetricDefinition> MetricDefinitionStorage::d_metrics = {
-  {"all-outqueries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of outgoing queries since starting")},
-
-  {"answers-slow",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered after 1 second")},
-  {"answers0-1",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered within 1 millisecond")},
-  {"answers1-10",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered within 10 milliseconds")},
-  {"answers10-100",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered within 100 milliseconds")},
-  {"answers100-1000",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered within 1 second")},
-
-  {"auth4-answers-slow",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered by authoritatives over IPv4 after 1 second")},
-  {"auth4-answers0-1",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered by authoritatives over IPv4within 1 millisecond")},
-  {"auth4-answers1-10",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered by authoritatives over IPv4 within 10 milliseconds")},
-  {"auth4-answers10-100",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered by authoritatives over IPv4 within 100 milliseconds")},
-  {"auth4-answers100-1000",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered by authoritatives over IPv4 within 1 second")},
-
-  {"auth6-answers-slow",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered by authoritatives over IPv6 after 1 second")},
-  {"auth6-answers0-1",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered by authoritatives over IPv6 within 1 millisecond")},
-  {"auth6-answers1-10",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered by authoritatives over IPv6 within 10 milliseconds")},
-  {"auth6-answers10-100",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered by authoritatives over IPv6 within 100 milliseconds")},
-  {"auth6-answers100-1000",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries answered by authoritatives over IPv6 within 1 second")},
-
-  {"auth-zone-queries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries to locally hosted authoritative zones (`setting-auth-zones`) since starting")},
-  {"cache-bytes",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Size of the cache in bytes")},
-  {"cache-entries",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Number of entries in the cache")},
-  {"cache-hits",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of of cache hits since starting, this does **not** include hits that got answered from the packet-cache")},
-  {"cache-misses",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of cache misses since starting")},
-  {"case-mismatches",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of mismatches in character case since starting")},
-  {"chain-resends",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries chained to existing outstanding")},
-  {"client-parse-errors",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of client packets that could not be parsed")},
-  {"concurrent-queries",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Number of MThreads currently running")},
-
-  // For multicounters, state the first
-  {"cpu-msec-thread-0",
-   MetricDefinition(PrometheusMetricType::multicounter,
-                    "Number of milliseconds spent in thread n")},
-
-  {"zone-disallowed-notify",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of NOTIFY operations denied because of allow-notify-for restrictions")},
-  {"dnssec-authentic-data-queries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries received with the AD bit set")},
-  {"dnssec-check-disabled-queries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries received with the CD bit set")},
-  {"dnssec-queries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries received with the DO bit set")},
-  {"dnssec-result-bogus",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state")},
-  {"dnssec-result-indeterminate",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Indeterminate state")},
-  {"dnssec-result-insecure",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Insecure state")},
-  {"dnssec-result-nta",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the (negative trust anchor) state")},
-  {"dnssec-result-secure",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Secure state")},
-  {"x-dnssec-result-bogus",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state")},
-  {"x-dnssec-result-indeterminate",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Indeterminate state")},
-  {"x-dnssec-result-insecure",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Insecure state")},
-  {"x-dnssec-result-nta",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the (negative trust anchor) state")},
-  {"x-dnssec-result-secure",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Secure state")},
-
-  {"dnssec-validations",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, for which a DNSSEC validation was requested by either the client or the configuration")},
-  {"dont-outqueries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of outgoing queries dropped because of `setting-dont-query` setting")},
-  {"qname-min-fallback-success",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of successful queries due to fallback mechanism within 'qname-minimization' setting")},
-  {"ecs-queries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of outgoing queries adorned with an EDNS Client Subnet option")},
-  {"ecs-responses",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses received from authoritative servers with an EDNS Client Subnet option we used")},
-  {"edns-ping-matches",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of servers that sent a valid EDNS PING response")},
-  {"edns-ping-mismatches",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of servers that sent an invalid EDNS PING response")},
-  {"failed-host-entries",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Number of entries in the failed NS cache")},
-  {"non-resolving-nameserver-entries",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Number of entries in the non-resolving NS name cache")},
-  {"ignored-packets",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of non-query packets received on server sockets that should only get query packets")},
-  {"ipv6-outqueries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of outgoing queries over IPv6")},
-  {"ipv6-questions",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of end-user initiated queries with the RD bit set, received over IPv6 UDP")},
-  {"malloc-bytes",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of bytes allocated by the process (broken, always returns 0)")},
-  {"max-cache-entries",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Currently configured maximum number of cache entries")},
-  {"max-packetcache-entries",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Currently configured maximum number of packet cache entries")},
-  {"max-mthread-stack",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Maximum amount of thread stack ever used")},
-
-  {"negcache-entries",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Number of entries in the negative answer cache")},
-  {"no-packet-error",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of erroneous received packets")},
-  {"nod-lookups-dropped-oversize",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of NOD lookups dropped because they would exceed the maximum name length")},
-  {"noedns-outqueries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries sent out without EDNS")},
-  {"noerror-answers",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of NOERROR answers since starting")},
-  {"noping-outqueries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries sent out without ENDS PING")},
-  {"nsset-invalidations",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of times an nsset was dropped because it no longer worked")},
-  {"nsspeeds-entries",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Number of entries in the NS speeds map")},
-  {"nxdomain-answers",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of NXDOMAIN answers since starting")},
-  {"outgoing-timeouts",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of timeouts on outgoing UDP queries since starting")},
-  {"outgoing4-timeouts",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of timeouts on outgoing UDP IPv4 queries since starting")},
-  {"outgoing6-timeouts",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of timeouts on outgoing UDP IPv6 queries since starting")},
-  {"over-capacity-drops",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of questions dropped because over maximum concurrent query limit")},
-  {"packetcache-bytes",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Size of the packet cache in bytes")},
-  {"packetcache-entries",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Number of packet cache entries")},
-  {"packetcache-hits",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of packet cache hits")},
-  {"packetcache-misses",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of packet cache misses")},
-
-  {"policy-drops",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of packets dropped because of (Lua) policy decision")},
-  {"policy-result-noaction",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of packets that were not acted upon by the RPZ/filter engine")},
-  {"policy-result-drop",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of packets that were dropped by the RPZ/filter engine")},
-  {"policy-result-nxdomain",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of packets that were replied to with NXDOMAIN by the RPZ/filter engine")},
-  {"policy-result-nodata",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of packets that were replied to with no data by the RPZ/filter engine")},
-  {"policy-result-truncate",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of packets that were were forced to TCP by the RPZ/filter engine")},
-  {"policy-result-custom",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of packets that were sent a custom answer by the RPZ/filter engine")},
-
-  {"qa-latency",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Shows the current latency average, in microseconds, exponentially weighted over past 'latency-statistic-size' packets")},
-  {"query-pipe-full-drops",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of questions dropped because the query distribution pipe was full")},
-  {"questions",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Counts all end-user initiated queries with the RD bit set")},
-  {"rebalanced-queries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries balanced to a different worker thread because the first selected one was above the target load configured with 'distribution-load-factor'")},
-  {"resource-limits",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of queries that could not be performed because of resource limits")},
-  {"security-status",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "security status based on `securitypolling`")},
-  {"server-parse-errors",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of server replied packets that could not be parsed")},
-  {"servfail-answers",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of SERVFAIL answers since starting")},
-  {"spoof-prevents",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of times PowerDNS considered itself spoofed, and dropped the data")},
-  {"sys-msec",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of CPU milliseconds spent in 'system' mode")},
-  {"tcp-client-overflow",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of times an IP address was denied TCP access because it already had too many connections")},
-  {"tcp-overflow",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of times a TCP connection was denied access because too many connections")},
-  {"tcp-clients",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Number of currently active TCP/IP clients")},
-  {"tcp-outqueries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of outgoing TCP queries since starting")},
-  {"tcp-questions",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of all incoming TCP queries since starting")},
-  {"throttle-entries",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Number of of entries in the throttle map")},
-  {"throttled-out",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of throttled outgoing UDP queries since starting")},
-  {"throttled-outqueries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of throttled outgoing UDP queries since starting")},
-  {"too-old-drops",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of questions dropped that were too old")},
-  {"truncated-drops",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of questions dropped because they were larger than 512 bytes")},
-  {"empty-queries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Questions dropped because they had a QD count of 0")},
-  {"unauthorized-tcp",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of TCP questions denied because of allow-from restrictions")},
-  {"unauthorized-udp",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of UDP questions denied because of allow-from restrictions")},
-  {"source-disallowed-notify",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of NOTIFY operations denied because of allow-notify-from restrictions")},
-  {"unexpected-packets",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of answers from remote servers that were unexpected (might point to spoofing)")},
-  {"unreachables",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of times nameservers were unreachable since starting")},
-  {"uptime",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of seconds process has been running")},
-  {"user-msec",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of CPU milliseconds spent in 'user' mode")},
-  {"variable-responses",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses that were marked as 'variable'")},
-
-  {"x-our-latency",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Shows the averaged time spent within PowerDNS, in microseconds, exponentially weighted over past 'latency-statistic-size' packets")},
-  {"x-ourtime0-1",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Counts responses where between 0 and 1 milliseconds was spent within the Recursor")},
-  {"x-ourtime1-2",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Counts responses where between 1 and 2 milliseconds was spent within the Recursor")},
-  {"x-ourtime2-4",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Counts responses where between 2 and 4 milliseconds was spent within the Recursor")},
-  {"x-ourtime4-8",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Counts responses where between 4 and 8 milliseconds was spent within the Recursor")},
-  {"x-ourtime8-16",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Counts responses where between 8 and 16 milliseconds was spent within the Recursor")},
-  {"x-ourtime16-32",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Counts responses where between 16 and 32 milliseconds was spent within the Recursor")},
-  {"x-ourtime-slow",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Counts responses where more than 32 milliseconds was spent within the Recursor")},
-
-  {"fd-usage",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Number of open file descriptors")},
-  {"real-memory-usage",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Number of bytes real process memory usage")},
-  {"udp-in-errors",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "From /proc/net/snmp InErrors")},
-  {"udp-noport-errors",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "From /proc/net/snmp NoPorts")},
-  {"udp-recvbuf-errors",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "From /proc/net/snmp RcvbufErrors")},
-  {"udp-sndbuf-errors",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "From /proc/net/snmp SndbufErrors")},
-  {"udp-in-csum-errors",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "From /proc/net/snmp InCsumErrors")},
-  {"udp6-in-errors",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "From /proc/net/snmp6 InErrors")},
-  {"udp6-noport-errors",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "From /proc/net/snmp6 NoPorts")},
-  {"udp6-recvbuf-errors",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "From /proc/net/snmp6 RcvbufErrors")},
-  {"udp6-sndbuf-errors",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "From /proc/net/snmp6 SndbufErrors")},
-  {"udp6-in-csum-errors",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "From /proc/net/snmp6 InCsumErrors")},
-
-  {"cpu-iowait",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Time spent waiting for I/O to complete by the whole system, in units of USER_HZ")},
-  {"cpu-steal",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Stolen time, which is the time spent by the whole system in other operating systems when running in a virtualized environment, in units of USER_HZ")},
-
-  {"dnssec-result-bogus-invalid-denial",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid denial of existence proof could not be found")},
-
-  {"dnssec-result-bogus-invalid-dnskey-protocol",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because all DNSKEYs had invalid protocols")},
-
-  {"dnssec-result-bogus-missing-negative-indication",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a NODATA or NXDOMAIN answer lacked the required SOA and/or NSEC(3) records")},
-
-  {"dnssec-result-bogus-no-rrsig",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because required RRSIG records were not present in an answer")},
-
-  {"dnssec-result-bogus-no-valid-dnskey",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DNSKEY could not be found")},
-
-  {"dnssec-result-bogus-no-valid-rrsig",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because only invalid RRSIG records were present in an answer")},
-
-  {"dnssec-result-bogus-no-zone-key-bit-set",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because no DNSKEY with the Zone Key bit set was found")},
-
-  {"dnssec-result-bogus-revoked-dnskey",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because all DNSKEYs were revoked")},
-
-  {"dnssec-result-bogus-self-signed-ds",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DS record was signed by itself")},
-
-  {"dnssec-result-bogus-signature-expired",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature expired time in the RRSIG was in the past")},
-
-  {"dnssec-result-bogus-signature-not-yet-valid",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature inception time in the RRSIG was not yet valid")},
-
-  {"dnssec-result-bogus-unable-to-get-dnskeys",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DNSKEY could not be retrieved")},
-
-  {"dnssec-result-bogus-unable-to-get-dss",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DS could not be retrieved")},
-  {"dnssec-result-bogus-unsupported-dnskey-algo",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DNSKEY RRset contained only unsupported DNSSEC algorithms")},
-
-  {"dnssec-result-bogus-unsupported-ds-digest-type",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DS RRset contained only unsupported digest types")},
-  {"x-dnssec-result-bogus-invalid-denial",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid denial of existence proof could not be found")},
-
-  {"x-dnssec-result-bogus-invalid-dnskey-protocol",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because all DNSKEYs had invalid protocols")},
-
-  {"x-dnssec-result-bogus-missing-negative-indication",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a NODATA or NXDOMAIN answer lacked the required SOA and/or NSEC(3) records")},
-
-  {"x-dnssec-result-bogus-no-rrsig",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because required RRSIG records were not present in an answer")},
-
-  {"x-dnssec-result-bogus-no-valid-dnskey",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DNSKEY could not be found")},
-
-  {"x-dnssec-result-bogus-no-valid-rrsig",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because only invalid RRSIG records were present in an answer")},
-
-  {"x-dnssec-result-bogus-no-zone-key-bit-set",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because no DNSKEY with the Zone Key bit set was found")},
-
-  {"x-dnssec-result-bogus-revoked-dnskey",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because all DNSKEYs were revoked")},
-
-  {"x-dnssec-result-bogus-self-signed-ds",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DS record was signed by itself")},
-
-  {"x-dnssec-result-bogus-signature-expired",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature expired time in the RRSIG was in the past")},
-
-  {"x-dnssec-result-bogus-signature-not-yet-valid",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because the signature inception time in the RRSIG was not yet valid")},
-
-  {"x-dnssec-result-bogus-unable-to-get-dnskeys",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DNSKEY could not be retrieved")},
-
-  {"x-dnssec-result-bogus-unable-to-get-dss",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a valid DS could not be retrieved")},
-  {"x-dnssec-result-bogus-unsupported-dnskey-algo",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DNSKEY RRset contained only unsupported DNSSEC algorithms")},
-
-  {"x-dnssec-result-bogus-unsupported-ds-digest-type",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of responses sent, packet-cache hits excluded, that were in the Bogus state because a DS RRset contained only unsupported digest types")},
-
-  {"proxy-protocol-invalid",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of invalid proxy-protocol headers received")},
-
-  {"record-cache-acquired",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of record cache lock acquisitions")},
-
-  {"record-cache-contended",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of contended record cache lock acquisitions")},
-
-  {"packetcache-acquired",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of packet cache lock acquisitions")},
-
-  {"packetcache-contended",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of contended packet cache lock acquisitions")},
-
-  {"taskqueue-expired",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of tasks expired before they could be run")},
-
-  {"taskqueue-pushed",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of tasks pushed to the taskqueues")},
-
-  {"taskqueue-size",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Number of tasks currently in the taskqueue")},
-
-  {"dot-outqueries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of outgoing DoT queries since starting")},
-
-  {"dns64-prefix-answers",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of AAAA and PTR generated by a matching dns64-prefix")},
-  {"aggressive-nsec-cache-entries",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of entries in the aggressive NSEC cache")},
-
-  {"aggressive-nsec-cache-nsec-hits",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of NSEC-related hits from the aggressive NSEC cache")},
-
-  {"aggressive-nsec-cache-nsec-wc-hits",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of answers synthesized from the NSEC aggressive cache")},
-
-  {"aggressive-nsec-cache-nsec3-hits",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of NSEC3-related hits from the aggressive NSEC cache")},
-
-  {"aggressive-nsec-cache-nsec3-wc-hits",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of answers synthesized from the NSEC3 aggressive cache")},
-
-  // For cumulative histogram, state the xxx_count name where xxx matches the name in rec_channel_rec
-  {"cumul-clientanswers-count",
-   MetricDefinition(PrometheusMetricType::histogram,
-                    "histogram of our answer times to clients")},
-  // For cumulative histogram, state the xxx_count name where xxx matches the name in rec_channel_rec
-  {"cumul-authanswers-count4",
-   MetricDefinition(PrometheusMetricType::histogram,
-                    "histogram of answer times of authoritative servers")},
-  {"almost-expired-pushed",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of almost-expired tasks pushed")},
-
-  {"almost-expired-run",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of almost-expired tasks run to completion")},
-
-  {"almost-expired-exceptions",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of almost-expired tasks that caused an exception")},
-
-  // For multicounters, state the first
-  {"policy-hits",
-   MetricDefinition(PrometheusMetricType::multicounter,
-                    "Number of filter or RPZ policy hits")},
-
-  {"idle-tcpout-connections",
-   MetricDefinition(PrometheusMetricType::gauge,
-                    "Number of connections in the TCP idle outgoing connections pool")},
-
-  {"maintenance-usec",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Time spent doing internal maintenance, including Lua maintenance")},
-
-  {"maintenance-calls",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Number of times internal maintenance has been called, including Lua maintenance")},
-
-  // For multicounters, state the first
-  {"proxy-mapping-total-n-0",
-   MetricDefinition(PrometheusMetricType::multicounter,
-                    "Number of queries matching proxyMappings")},
-
-  // For multicounters, state the first
-  {"auth-formerr-answers",
-   MetricDefinition(PrometheusMetricType::multicounter,
-                    "Count of RCodes returned by authoritative servers")},
-
-  // For multicounters, state the first
-  {"remote-logger-count-o-0",
-   MetricDefinition(PrometheusMetricType::multicounter,
-                    "Number of remote logging events")},
-  {"nod-events",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Count of NOD events")},
-
-  {"udr-events",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Count of UDR events")},
-
-  {"max-chain-length",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Maximum chain length")},
-
-  {"max-chain-weight",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Maximum chain weight")},
-
-  {"chain-limits",
-   MetricDefinition(PrometheusMetricType::counter,
-                    "Chain limits reached")},
+#include "rec-prometheus-gen.h"
 };
 
 constexpr bool CHECK_PROMETHEUS_METRICS = false;
@@ -1275,6 +621,7 @@ static void validatePrometheusMetrics()
   auto varmap = getAllStatsMap(StatComponent::API);
   for (const auto& tup : varmap) {
     std::string metricName = tup.first;
+    // A few special cases not handled correctly by the check below
     if (metricName.find("cpu-msec-") == 0) {
       continue;
     }
@@ -1284,6 +631,9 @@ static void validatePrometheusMetrics()
     if (metricName.find("auth-") == 0 && metricName.find("-answers") != string::npos) {
       continue;
     }
+    if (metricName.find("proxy-mapping-total") == 0) {
+      continue;
+    }
     MetricDefinition metricDetails;
 
     if (!s_metricDefinitions.getMetricDetails(metricName, metricDetails)) {