1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
|
.. SPDX-License-Identifier: GPL-3.0-or-later
.. _mod-stats:
Statistics collector
====================
Module ``stats`` gathers various counters from the query resolution
and server internals, and offers them as a key-value storage.
These metrics can be either exported to :ref:`mod-graphite`,
exposed as :ref:`mod-http-prometheus`, or processed using user-provided script
as described in chapter :ref:`async-events`.
.. note:: Please remember that each Knot Resolver instance keeps its own
statistics, and instances can be started and stopped dynamically. This might
affect your data postprocessing procedures if you are using
:ref:`systemd-multiple-instances`.
.. _mod-stats-list:
Built-in statistics
-------------------
Built-in counters keep track of number of queries and answers matching specific criteria.
+-----------------------------------------------------------------+
| **Global request counters** |
+------------------+----------------------------------------------+
| request.total | total number of DNS requests |
| | (including internal client requests) |
+------------------+----------------------------------------------+
| request.internal | internal requests generated by Knot Resolver |
| | (e.g. DNSSEC trust anchor updates) |
+------------------+----------------------------------------------+
| request.udp | external requests received over plain UDP |
| | (:rfc:`1035`) |
+------------------+----------------------------------------------+
| request.tcp | external requests received over plain TCP |
| | (:rfc:`1035`) |
+------------------+----------------------------------------------+
| request.dot | external requests received over |
| | DNS-over-TLS (:rfc:`7858`) |
+------------------+----------------------------------------------+
| request.doh | external requests received over |
| | DNS-over-HTTP (:rfc:`8484`) |
+------------------+----------------------------------------------+
| request.xdp | external requests received over plain UDP |
| | via an AF_XDP socket |
+------------------+----------------------------------------------+
+----------------------------------------------------+
| **Global answer counters** |
+-----------------+----------------------------------+
| answer.total | total number of answered queries |
+-----------------+----------------------------------+
| answer.cached | queries answered from cache |
+-----------------+----------------------------------+
+-----------------+----------------------------------+
| **Answers categorized by RCODE** |
+-----------------+----------------------------------+
| answer.noerror | NOERROR answers |
+-----------------+----------------------------------+
| answer.nodata | NOERROR, but empty answers |
+-----------------+----------------------------------+
| answer.nxdomain | NXDOMAIN answers |
+-----------------+----------------------------------+
| answer.servfail | SERVFAIL answers |
+-----------------+----------------------------------+
+-----------------+----------------------------------+
| **Answer latency** |
+-----------------+----------------------------------+
| answer.1ms | completed in 1ms |
+-----------------+----------------------------------+
| answer.10ms | completed in 10ms |
+-----------------+----------------------------------+
| answer.50ms | completed in 50ms |
+-----------------+----------------------------------+
| answer.100ms | completed in 100ms |
+-----------------+----------------------------------+
| answer.250ms | completed in 250ms |
+-----------------+----------------------------------+
| answer.500ms | completed in 500ms |
+-----------------+----------------------------------+
| answer.1000ms | completed in 1000ms |
+-----------------+----------------------------------+
| answer.1500ms | completed in 1500ms |
+-----------------+----------------------------------+
| answer.slow | completed in more than 1500ms |
+-----------------+----------------------------------+
+-----------------+----------------------------------+
| **Answer flags** |
+-----------------+----------------------------------+
| answer.aa | authoritative answer |
+-----------------+----------------------------------+
| answer.tc | truncated answer |
+-----------------+----------------------------------+
| answer.ra | recursion available |
+-----------------+----------------------------------+
| answer.rd | recursion desired (in answer!) |
+-----------------+----------------------------------+
| answer.ad | authentic data (DNSSEC) |
+-----------------+----------------------------------+
| answer.cd | checking disabled (DNSSEC) |
+-----------------+----------------------------------+
| answer.do | DNSSEC answer OK |
+-----------------+----------------------------------+
| answer.edns0 | EDNS0 present |
+-----------------+----------------------------------+
+-----------------+----------------------------------+
| **Query flags** |
+-----------------+----------------------------------+
| query.edns | queries with EDNS present |
+-----------------+----------------------------------+
| query.dnssec | queries with DNSSEC DO=1 |
+-----------------+----------------------------------+
Example:
.. code-block:: none
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
----------------
.. function:: stats.get(key)
:param string key: i.e. ``"answer.total"``
:return: ``number``
Return nominal value of given metric.
.. function:: stats.set('key val')
Set nominal value of given metric.
Example:
.. code-block:: lua
stats.set('answer.total 5')
-- or syntactic sugar
stats['answer.total'] = 5
.. function:: stats.list([prefix])
:param string prefix: optional metric prefix, i.e. ``"answer"`` shows only metrics beginning with "answer"
Outputs collected metrics as a JSON dictionary.
.. function:: stats.upstreams()
Outputs a list of recent upstreams and their RTT. It is sorted by time and stored in a ring buffer of
a fixed size. This means it's not aggregated and readable by multiple consumers, but also that
you may lose entries if you don't read quickly enough. The default ring size is 512 entries, and may be overridden on compile time by ``-DUPSTREAMS_COUNT=X``.
.. function:: 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.
.. function:: stats.clear_frequent()
Clear the list of most frequent iterative queries.
.. include:: ../modules/graphite/README.rst
.. include:: ../modules/http/prometheus.rst
|