# From this table all metrics related files are generated by the metrics.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 relevant 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 legacy 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': '''Since version 5.3.0 this metric computes a rough estimate of the number of bytes allocated by the record cache. Older versions return a number that cannot be relied upon. Disabled by default, as computing this number is CPU intensive, see :ref:`setting-yaml-recursor.stats_rec_control_disabled_list`.''',
        '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-yaml-recursor.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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-yaml-dnssec.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 auth-rcode-answers are a bit different than others: separate rec_control and SNMP metrics, but a multicounter entry for Prometheus. The alphabetically first 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-yaml-recursor.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-yaml-recursor.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
    },
    {
        'name': 'ecs-missing',
        'lambda': '[] { return g_Counters.sum(rec::Counter::ecsMissingCount); }',
        'desc': 'Number of answers where ECS info was missing',
        'snmp': 153,
    },
]
