Statistics collector

Modulestats gathers various counters from the query resolutionand server internals, and offers them as a key-value storage.These metrics can be either exported toGraphite/InfluxDB/Metronome,exposed asPrometheus metrics endpoint, or processed using user-provided scriptas described in chapterAsynchronous events.

Note

Please remember that each Knot Resolver instance keeps its ownstatistics, and instances can be started and stopped dynamically. This mightaffect your data postprocessing procedures if you are usingMultiple instances.

Built-in statistics

Built-in counters keep track of number of queries and answers matching specific criteria.

Global request counters
request.totaltotal number of DNS requests(including internal client requests)
request.internalinternal requests generated by Knot Resolver(e.g. DNSSEC trust anchor updates)
request.udpexternal requests received over plain UDP(RFC 1035)
request.tcpexternal requests received over plain TCP(RFC 1035)
request.dotexternal requests received overDNS-over-TLS (RFC 7858)
request.dohexternal requests received overDNS-over-HTTP (RFC 8484)
Global answer counters
answer.totaltotal number of answered queries
answer.cachedqueries answered from cache
Answers categorized by RCODE
answer.noerrorNOERROR answers
answer.nodataNOERROR, but empty answers
answer.nxdomainNXDOMAIN answers
answer.servfailSERVFAIL answers
Answer latency
answer.1mscompleted in 1ms
answer.10mscompleted in 10ms
answer.50mscompleted in 50ms
answer.100mscompleted in 100ms
answer.250mscompleted in 250ms
answer.500mscompleted in 500ms
answer.1000mscompleted in 1000ms
answer.1500mscompleted in 1500ms
answer.slowcompleted in more than 1500ms
Answer flags
answer.aaauthoritative answer
answer.tctruncated answer
answer.rarecursion available
answer.rdrecursion desired (in answer!)
answer.adauthentic data (DNSSEC)
answer.cdchecking disabled (DNSSEC)
answer.doDNSSEC answer OK
answer.edns0EDNS0 present
Query flags
query.ednsqueries with EDNS present
query.dnssecqueries with DNSSEC DO=1

Example:

modules.load('stats')-- Enumerate metrics> stats.list()[answer.cached] => 486178[iterator.tcp] => 490[answer.noerror] => 507367[answer.total] => 618631[iterator.udp] => 102408[query.concurrent] => 149-- Query metrics by prefix> stats.list('iter')[iterator.udp] => 105104[iterator.tcp] => 490-- Fetch most common queries> stats.frequent()[1] => {        [type] => 2        [count] => 4        [name] => cz.}-- Fetch most common queries (sorted by frequency)> table.sort(stats.frequent(), function (a, b) return a.count > b.count end)-- Show recently contacted authoritative servers> stats.upstreams()[2a01:618:404::1] => {    [1] => 26 -- RTT}[128.241.220.33] => {    [1] => 31 - RTT}-- Set custom metrics from modules> stats['filter.match'] = 5> stats['filter.match']5

Module reference

stats.get(key)
Parameters:
  • key (string) – i.e."answer.total"
Returns:

number

Return nominal value of given metric.

stats.set(key, val)
Parameters:
  • key (string) – i.e."answer.total"
  • val (number) – i.e.5

Set nominal value of given metric.

stats.list([prefix])
Parameters:
  • prefix (string) – optional metric prefix, i.e."answer" shows only metrics beginning with “answer”

Outputs collected metrics as a JSON dictionary.

stats.upstreams()

Outputs a list of recent upstreams and their RTT. It is sorted by time and stored in a ring buffer ofa fixed size. This means it’s not aggregated and readable by multiple consumers, but also thatyou may lose entries if you don’t read quickly enough. The default ring size is 512 entries, and may be overriden on compile time by-DUPSTREAMS_COUNT=X.

stats.frequent()

Outputs list of most frequent iterative queries as a JSON array. The queries are sampled probabilistically,and include subrequests. The list maximum size is 5000 entries, make diffs if you want to track it over time.

stats.clear_frequent()

Clear the list of most frequent iterative queries.

Graphite/InfluxDB/Metronome

Thegraphite sends statistics over theGraphite protocol to eitherGraphite,Metronome,InfluxDB or any compatible storage. This allows powerful visualization over metrics collected by Knot Resolver.

Tip

The Graphite server is challenging to get up and running,InfluxDB combined withGrafana are much easier, and provide richer set of options and available front-ends.Metronome by PowerDNS alternatively provides a mini-graphite server for much simpler setups.

Example configuration:

Only thehost parameter is mandatory.

By default the module uses UDP so it doesn’t guarantee the delivery, settcp=true to enable Graphite over TCP. If the TCP consumer goes down or the connection with Graphite is lost, resolver will periodically attempt to reconnect with it.

modules={graphite={prefix=hostname(),-- optional metric prefixhost='127.0.0.1',-- graphite server addressport=2003,-- graphite server portinterval=5*sec,-- publish intervaltcp=false-- set to true if want TCP mode}}

The module supports sending data to multiple servers at once.

modules={graphite={host={'127.0.0.1','1.2.3.4','::1'},}}

Dependencies

Prometheus metrics endpoint

TheHTTP module exposes/metrics endpoint that serves metricsfromStatistics collector inPrometheus text format.You can use it as soon as HTTP module is configured:

$ curl -k https://localhost:8453/metrics| tail# TYPE latency histogramlatency_bucket{le=10}2.000000latency_bucket{le=50}2.000000latency_bucket{le=100}2.000000latency_bucket{le=250}2.000000latency_bucket{le=500}2.000000latency_bucket{le=1000}2.000000latency_bucket{le=1500}2.000000latency_bucket{le=+Inf}2.000000latency_count2.000000latency_sum11.000000

You can namespace the metrics in configuration, usinghttp.prometheus.namespace attribute:

modules.load('http')-- Set Prometheus namespacehttp.prometheus.namespace='resolver_'

You can also add custom metrics or rewrite existing metrics before they are returned to Prometheus client.

modules.load('http')-- Add an arbitrary metric to Prometheushttp.prometheus.finalize=function(metrics)table.insert(metrics,'build_info{version="1.2.3"} 1')end