]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
doc: split and redistribute HTTP module pieces into server & monitoring chapters
authorPetr Špaček <petr.spacek@nic.cz>
Mon, 6 Jan 2020 18:53:08 +0000 (19:53 +0100)
committerTomas Krizek <tomas.krizek@nic.cz>
Wed, 15 Jan 2020 09:38:17 +0000 (10:38 +0100)
daemon/bindings/net.rst
daemon/bindings/net_tlssrv.rst [new file with mode: 0644]
doc/config.rst
modules/graphite/README.rst
modules/http/README.rst
modules/http/prometheus.rst [new file with mode: 0644]
modules/http/trace.rst [new file with mode: 0644]
modules/stats/README.rst
modules/workarounds/README.rst

index 80ed9b5dae8c68b23db29f390ab2e03973184b36..7ce1083bfa0894b64223aa3527ae7cf07c9518c5 100644 (file)
@@ -1,7 +1,7 @@
 .. _network-configuration:
 
-Network
-=======
+Server addresses
+-----------------
 
 Modern Linux distributions use so-called *Systemd socket activation*, which
 effectively means that IP addresses and ports to listen on are configured
@@ -212,18 +212,6 @@ Examples:
 
 Following commands are useful in special situations and can be usef with and without systemd socket activation:
 
-.. envvar:: net.ipv6 = true|false
-
-   :return: boolean (default: true)
-
-   Enable/disable using IPv6 for contacting upstream nameservers.
-
-.. envvar:: net.ipv4 = true|false
-
-   :return: boolean (default: true)
-
-   Enable/disable using IPv4 for contacting upstream nameservers.
-
 .. function:: net.list()
 
    :return: Table of bound interfaces.
@@ -284,21 +272,6 @@ Following commands are useful in special situations and can be usef with and wit
 
    .. tip:: You can use ``net.<iface>`` as a shortcut for specific interface, e.g. ``net.eth0``
 
-.. function:: net.bufsize([udp_bufsize])
-
-   Get/set maximum EDNS payload size advertised in DNS packets. Default is 4096 bytes and the default will be lowered to value around 1220 bytes in future, once `DNS Flag Day 2020 <https://dnsflagday.net/>`_ becomes effective.
-
-   Minimal value allowed by standard :rfc:`6891` is 512 bytes, which is equal to DNS packet size without Extension Mechanisms for DNS. Value 1220 bytes is minimum size required in DNSSEC standard :rfc:`4035`.
-
-   Example output:
-
-   .. code-block:: lua
-
-       > net.bufsize(4096)
-       nil
-       > net.bufsize()
-       4096
-
 .. function:: net.tcp_pipeline([len])
 
    Get/set per-client TCP pipeline limit, i.e. the number of outstanding queries that a single client connection can make in parallel.  Default is 100.
@@ -312,71 +285,50 @@ Following commands are useful in special situations and can be usef with and wit
 
    .. warning:: Please note that too large limit may have negative impact on performance and can lead to increased number of SERVFAIL answers.
 
-.. function:: net.outgoing_v4([string address])
-
-   Get/set the IPv4 address used to perform queries.  There is also ``net.outgoing_v6`` for IPv6.
-   The default is ``nil``, which lets the OS choose any address.
+Client
+------
+Following settings affect client part of the resolver, i.e. communication between the resolver itself and other DNS servers.
 
+.. envvar:: net.ipv4 = true|false
 
-.. _tls-server-config:
-
-TLS server
-==========
-DNS-over-TLS server (:rfc:`7858`) is enabled by default on loopback interface port 853.
-Information how to configure listening on specific IP addresses is in previous sections
-:ref:`network-configuration`.
+   :return: boolean (default: true)
 
-By default a self-signed certificate is generated. For serious deployments
-it is strongly recommended to configure your own TLS certificates signed
-by a trusted CA. This is done using function :c:func:`net.tls()`.
+   Enable/disable using IPv4 for contacting upstream nameservers.
 
-.. function:: net.tls([cert_path], [key_path])
+.. function:: net.outgoing_v4([string address])
 
-   Get/set path to a server TLS certificate and private key for DNS/TLS.
+   Get/set the IPv4 address used to perform queries.
+   The default is ``nil``, which lets the OS choose any address.
 
-   Example output:
+.. envvar:: net.ipv6 = true|false
 
-   .. code-block:: lua
+   :return: boolean (default: true)
 
-      > net.tls("/etc/knot-resolver/server-cert.pem", "/etc/knot-resolver/server-key.pem")
-      > net.tls()  -- print configured paths
-      ("/etc/knot-resolver/server-cert.pem", "/etc/knot-resolver/server-key.pem")
+   Enable/disable using IPv6 for contacting upstream nameservers.
 
-.. function:: net.tls_padding([true | false])
+.. function:: net.outgoing_v6([string address])
 
-   Get/set EDNS(0) padding of answers to queries that arrive over TLS
-   transport.  If set to `true` (the default), it will use a sensible
-   default padding scheme, as implemented by libknot if available at
-   compile time.  If set to a numeric value >= 2 it will pad the
-   answers to nearest *padding* boundary, e.g. if set to `64`, the
-   answer will have size of a multiple of 64 (64, 128, 192, ...).  If
-   set to `false` (or a number < 2), it will disable padding entirely.
+   Get/set the IPv6 address used to perform queries.
+   The default is ``nil``, which lets the OS choose any address.
 
-.. function:: net.tls_sticket_secret([string with pre-shared secret])
+DNS protocol
+------------
+Following settings change low-level details of DNS protocol implementation.
+Default values should not be changed except for very special cases.
 
-   Set secret for TLS session resumption via tickets, by :rfc:`5077`.
+.. function:: net.bufsize([udp_bufsize])
 
-   The server-side key is rotated roughly once per hour.
-   By default or if called without secret, the key is random.
-   That is good for long-term forward secrecy, but multiple kresd instances
-   won't be able to resume each other's sessions.
+   Get/set maximum EDNS payload size advertised in DNS packets. Default is 4096 bytes and the default will be lowered to value around 1220 bytes in future, once `DNS Flag Day 2020 <https://dnsflagday.net/>`_ becomes effective.
 
-   If you provide the same secret to multiple instances, they will be able to resume
-   each other's sessions *without* any further communication between them.
-   This synchronization works only among instances having the same endianess
-   and time_t structure and size (`sizeof(time_t)`).
+   Minimal value allowed by standard :rfc:`6891` is 512 bytes, which is equal to DNS packet size without Extension Mechanisms for DNS. Value 1220 bytes is minimum size required in DNSSEC standard :rfc:`4035`.
 
-   **For good security** the secret must have enough entropy to be hard to guess,
-   and it should still be occasionally rotated manually and securely forgotten,
-   to reduce the scope of privacy leak in case the
-   `secret leaks eventually <https://en.wikipedia.org/wiki/Forward_secrecy>`_.
+   Example output:
 
-   .. warning:: **Setting the secret is probably too risky with TLS <= 1.2**.
-      GnuTLS stable release supports TLS 1.3 since 3.6.3 (summer 2018).
-      Therefore setting the secrets should be considered experimental for now
-      and might not be available on your system.
+   .. code-block:: lua
 
-.. function:: net.tls_sticket_secret_file([string with path to a file containing pre-shared secret])
+       > net.bufsize(4096)
+       nil
+       > net.bufsize()
+       4096
 
-   The same as :func:`net.tls_sticket_secret`,
-   except the secret is read from a (binary) file.
+.. include:: ../modules/workarounds/README.rst
diff --git a/daemon/bindings/net_tlssrv.rst b/daemon/bindings/net_tlssrv.rst
new file mode 100644 (file)
index 0000000..699cc94
--- /dev/null
@@ -0,0 +1,62 @@
+.. _tls-server-config:
+
+DNS-over-TLS server (DoT)
+-------------------------
+DNS-over-TLS server (:rfc:`7858`) is enabled by default on loopback interface port 853.
+Information how to configure listening on specific IP addresses is in previous sections
+:ref:`network-configuration`.
+
+By default a self-signed certificate is generated. For serious deployments
+it is strongly recommended to configure your own TLS certificates signed
+by a trusted CA. This is done using function :c:func:`net.tls()`.
+
+.. function:: net.tls([cert_path], [key_path])
+
+   Get/set path to a server TLS certificate and private key for DNS/TLS.
+
+   Example output:
+
+   .. code-block:: lua
+
+      > net.tls("/etc/knot-resolver/server-cert.pem", "/etc/knot-resolver/server-key.pem")
+      > net.tls()  -- print configured paths
+      ("/etc/knot-resolver/server-cert.pem", "/etc/knot-resolver/server-key.pem")
+
+.. function:: net.tls_padding([true | false])
+
+   Get/set EDNS(0) padding of answers to queries that arrive over TLS
+   transport.  If set to `true` (the default), it will use a sensible
+   default padding scheme, as implemented by libknot if available at
+   compile time.  If set to a numeric value >= 2 it will pad the
+   answers to nearest *padding* boundary, e.g. if set to `64`, the
+   answer will have size of a multiple of 64 (64, 128, 192, ...).  If
+   set to `false` (or a number < 2), it will disable padding entirely.
+
+.. function:: net.tls_sticket_secret([string with pre-shared secret])
+
+   Set secret for TLS session resumption via tickets, by :rfc:`5077`.
+
+   The server-side key is rotated roughly once per hour.
+   By default or if called without secret, the key is random.
+   That is good for long-term forward secrecy, but multiple kresd instances
+   won't be able to resume each other's sessions.
+
+   If you provide the same secret to multiple instances, they will be able to resume
+   each other's sessions *without* any further communication between them.
+   This synchronization works only among instances having the same endianess
+   and time_t structure and size (`sizeof(time_t)`).
+
+   **For good security** the secret must have enough entropy to be hard to guess,
+   and it should still be occasionally rotated manually and securely forgotten,
+   to reduce the scope of privacy leak in case the
+   `secret leaks eventually <https://en.wikipedia.org/wiki/Forward_secrecy>`_.
+
+   .. warning:: **Setting the secret is probably too risky with TLS <= 1.2**.
+      GnuTLS stable release supports TLS 1.3 since 3.6.3 (summer 2018).
+      Therefore setting the secrets should be considered experimental for now
+      and might not be available on your system.
+
+.. function:: net.tls_sticket_secret_file([string with path to a file containing pre-shared secret])
+
+   The same as :func:`net.tls_sticket_secret`,
+   except the secret is read from a (binary) file.
index ee2cbfe9ae0468a8d60dca48feb0a9789ab9ccd0..d3daaf61a500e2a083d3911e156c67f03d8c27de 100644 (file)
@@ -66,9 +66,14 @@ One last thing before we dive into configuring features:
 Now you know what configuration file to modify, how to read examples and what modules are so you are ready for a real configuration work!
 
 .. include:: ../daemon/README.rst
-.. include:: ../daemon/bindings/net.rst
 .. include:: ../daemon/lua/trust_anchors.rst
 
+Networking and protocols
+========================
+.. include:: ../daemon/bindings/net.rst
+.. include:: ../daemon/bindings/net_tlssrv.rst
+.. include:: ../modules/http/README.rst
+.. include:: ../modules/http/README.doh.rst
 
 Logging, monitoring, diagnostics
 ================================
@@ -98,10 +103,17 @@ More fine-grained tools are available in following modules:
    :local:
 
 .. include:: ../modules/nsid/README.rst
+
+.. include:: ../modules/stats/README.rst
+.. .. subchapter of stats module
 .. include:: ../modules/graphite/README.rst
+.. .. subchapter of stats module
+.. include:: ../modules/http/prometheus.rst
+
 .. include:: ../modules/dnstap/README.rst
 .. include:: ../modules/watchdog/README.rst
 .. include:: ../modules/bogus_log/README.rst
+.. include:: ../modules/http/trace.rst
 .. include:: ../modules/ta_sentinel/README.rst
 .. include:: ../modules/ta_signal_query/README.rst
 .. include:: ../modules/detect_time_skew/README.rst
@@ -116,7 +128,6 @@ Features in this section allow to configure what clients can get access to what
    :local:
 
 .. include:: ../modules/hints/README.rst
-.. include:: ../modules/stats/README.rst
 .. include:: ../modules/policy/README.rst
 .. include:: ../modules/view/README.rst
 .. include:: ../modules/daf/README.rst
@@ -167,15 +178,8 @@ impact than cache settings and number of instances.
 .. include:: ../modules/rfc7706.rst
 .. include:: ../modules/prefill/README.rst
 .. include:: ../modules/serve_stale/README.rst
-.. include:: ../modules/workarounds/README.rst
 .. include:: ../modules/edns_keepalive/README.rst
 
-
-TODO: Other
-===========
-.. include:: ../modules/http/README.rst
-.. include:: ../modules/http/README.doh.rst
-
 Experimental features
 =====================
 .. include:: ../modules/experimental_dot_auth/README.rst
index 0ceef45a72da9d79b0943773c95d3593c6b1245a..415bb9e44b5d1b0537c0dc0d168ff54fe2f43faa 100644 (file)
@@ -1,14 +1,13 @@
 .. _mod-graphite:
 
 Graphite/InfluxDB/Metronome
----------------------------
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 The ``graphite`` sends statistics over the Graphite_ protocol to either Graphite_, 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 with Grafana_ 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
-^^^^^^^^^^^^^^^^^^^^^
+Example configuration:
 
 Only the ``host`` parameter is mandatory.
 
@@ -36,8 +35,7 @@ The module supports sending data to multiple servers at once.
                }
        }
 
-Dependencies
-^^^^^^^^^^^^
+Dependencies:
 
 * `lua cqueues <https://25thandclement.com/~william/projects/cqueues.html>`_ package.
 
index 89f89ef7cb27541b97b36b3d4f80eda2c43bd0fb..a4816ad32981fc2f737ee5b49fc9050c4d451fe7 100644 (file)
@@ -63,8 +63,8 @@ Now you can reach the web services and APIs, done!
 
 .. _mod-http-tls:
 
-Configuring TLS
-^^^^^^^^^^^^^^^
+HTTPS (TLS for HTTP)
+^^^^^^^^^^^^^^^^^^^^
 
 By default, the web interface starts HTTPS/2 on specified port using an ephemeral
 TLS certificate that is valid for 90 days and is automatically renewed. It is of
@@ -133,73 +133,6 @@ The HTTP module has several built-in services to use.
  "``/trace/:name/:type``", "Tracking", ":ref:`Trace resolution <mod-http-trace>` of a DNS query and return the verbose logs."
  "``/doh``", "DNS-over-HTTP", ":rfc:`8484` endpoint, see :ref:`mod-http-doh`."
 
-Prometheus metrics endpoint
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The module exposes ``/metrics`` endpoint that serves internal metrics in Prometheus_ text format.
-You can use it out of the box:
-
-.. code-block:: bash
-
-       $ curl -k https://localhost:8453/metrics | tail
-       # TYPE latency histogram
-       latency_bucket{le=10} 2.000000
-       latency_bucket{le=50} 2.000000
-       latency_bucket{le=100} 2.000000
-       latency_bucket{le=250} 2.000000
-       latency_bucket{le=500} 2.000000
-       latency_bucket{le=1000} 2.000000
-       latency_bucket{le=1500} 2.000000
-       latency_bucket{le=+Inf} 2.000000
-       latency_count 2.000000
-       latency_sum 11.000000
-
-You can namespace the metrics in configuration, using `http.prometheus.namespace` attribute:
-
-.. code-block:: lua
-
-        modules.load('http')
-        -- Set Prometheus namespace
-        http.prometheus.namespace = 'resolver_'
-
-You can also add custom metrics or rewrite existing metrics before they are returned to Prometheus client.
-
-.. code-block:: lua
-
-        modules.load('http')
-        -- Add an arbitrary metric to Prometheus
-        http.prometheus.finalize = function (metrics)
-               table.insert(metrics, 'build_info{version="1.2.3"} 1')
-        end
-
-.. _mod-http-trace:
-
-Tracing requests
-^^^^^^^^^^^^^^^^
-
-With the ``/trace`` endpoint you can trace various aspects of the request execution.
-The basic mode allows you to resolve a query and trace verbose logs (and messages received):
-
-.. code-block:: bash
-
-   $ curl https://localhost:8453/trace/e.root-servers.net
-   [ 8138] [iter] 'e.root-servers.net.' type 'A' created outbound query, parent id 0
-   [ 8138] [ rc ] => rank: 020, lowest 020, e.root-servers.net. A
-   [ 8138] [ rc ] => satisfied from cache
-   [ 8138] [iter] <= answer received:
-   ;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 8138
-   ;; Flags: qr aa  QUERY: 1; ANSWER: 0; AUTHORITY: 0; ADDITIONAL: 0
-
-   ;; QUESTION SECTION
-   e.root-servers.net.         A
-
-   ;; ANSWER SECTION
-   e.root-servers.net.         3556353 A       192.203.230.10
-
-   [ 8138] [iter] <= rcode: NOERROR
-   [ 8138] [resl] finished: 4, queries: 1, mempool: 81952 B
-
-
 .. _mod-http-custom-endpoint:
 
 How to expose custom services over HTTP
@@ -355,7 +288,7 @@ Dependencies
 
        $ luarocks install http
 
-* `mmdblua <https://github.com/daurnimator/mmdblua>`_ available in LuaRocks
+* (*optional*) `mmdblua <https://github.com/daurnimator/mmdblua>`_ available in LuaRocks
 
     .. code-block:: bash
 
diff --git a/modules/http/prometheus.rst b/modules/http/prometheus.rst
new file mode 100644 (file)
index 0000000..d98a0a6
--- /dev/null
@@ -0,0 +1,42 @@
+.. _mod-http-prometheus:
+
+Prometheus metrics endpoint
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The `HTTP module <mod-http>`_ exposes ``/metrics`` endpoint that serves metrics
+from :ref:`mod-stats` in Prometheus_ text format.
+You can use it as soon as HTTP module is configured:
+
+.. code-block:: bash
+
+       $ curl -k https://localhost:8453/metrics | tail
+       # TYPE latency histogram
+       latency_bucket{le=10} 2.000000
+       latency_bucket{le=50} 2.000000
+       latency_bucket{le=100} 2.000000
+       latency_bucket{le=250} 2.000000
+       latency_bucket{le=500} 2.000000
+       latency_bucket{le=1000} 2.000000
+       latency_bucket{le=1500} 2.000000
+       latency_bucket{le=+Inf} 2.000000
+       latency_count 2.000000
+       latency_sum 11.000000
+
+You can namespace the metrics in configuration, using `http.prometheus.namespace` attribute:
+
+.. code-block:: lua
+
+        modules.load('http')
+        -- Set Prometheus namespace
+        http.prometheus.namespace = 'resolver_'
+
+You can also add custom metrics or rewrite existing metrics before they are returned to Prometheus client.
+
+.. code-block:: lua
+
+        modules.load('http')
+        -- Add an arbitrary metric to Prometheus
+        http.prometheus.finalize = function (metrics)
+               table.insert(metrics, 'build_info{version="1.2.3"} 1')
+        end
+
diff --git a/modules/http/trace.rst b/modules/http/trace.rst
new file mode 100644 (file)
index 0000000..7232859
--- /dev/null
@@ -0,0 +1,29 @@
+.. _mod-http-trace:
+
+Tracing requests
+----------------
+
+The `HTTP module <mod-http>`_ provides ``/trace`` endpoint which allows to trace various
+aspects of the request execution. The basic mode allows you to resolve a query
+and trace verbose logs (and messages received):
+
+.. code-block:: bash
+
+   $ curl https://localhost:8453/trace/e.root-servers.net
+   [ 8138] [iter] 'e.root-servers.net.' type 'A' created outbound query, parent id 0
+   [ 8138] [ rc ] => rank: 020, lowest 020, e.root-servers.net. A
+   [ 8138] [ rc ] => satisfied from cache
+   [ 8138] [iter] <= answer received:
+   ;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 8138
+   ;; Flags: qr aa  QUERY: 1; ANSWER: 0; AUTHORITY: 0; ADDITIONAL: 0
+
+   ;; QUESTION SECTION
+   e.root-servers.net.         A
+
+   ;; ANSWER SECTION
+   e.root-servers.net.         3556353 A       192.203.230.10
+
+   [ 8138] [iter] <= rcode: NOERROR
+   [ 8138] [resl] finished: 4, queries: 1, mempool: 81952 B
+
+See chapter about `HTTP module <mod-http>`_ for further instructions how to load HTTP module.
index 0d19060ec89a2604f49b486525f6084630790bfb..27f67e88ede53d1b3788abde383e9f442269a73d 100644 (file)
@@ -3,90 +3,11 @@
 Statistics collector
 --------------------
 
-This modules gathers various counters from the query resolution and server internals,
-and offers them as a key-value storage. Any module may update the metrics or simply hook
-in new ones.
-
-.. 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
-
-       -- Set custom metrics from modules
-       > stats['filter.match'] = 5
-       > stats['filter.match']
-       5
-
-       -- 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
-       }
-
-Properties
-^^^^^^^^^^
-
-.. function:: stats.get(key)
-
-  :param string key: i.e. ``"answer.total"``
-  :return: ``number``
-
-Return nominal value of given metric. 
-
-.. function:: stats.set(key, val)
-
-  :param string key:  i.e. ``"answer.total"``
-  :param number val:  i.e. ``5``
-
-Set nominal value of given metric.
-
-.. 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 overriden 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.
+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`.
 
 .. _mod-stats-list:
 
@@ -98,7 +19,7 @@ Built-in counters keep track of number of queries and answers matching specific
 +-----------------------------------------------------------------+
 | **Global request counters**                                     |
 +------------------+----------------------------------------------+
-| request.total    | total number of DNS requests from clients    |
+| request.total    | total number of DNS requests                 |
 |                  | (including internal client requests)         |
 +------------------+----------------------------------------------+
 | request.internal | internal requests generated by Knot Resolver |
@@ -186,3 +107,88 @@ Built-in counters keep track of number of queries and answers matching specific
 +-----------------+----------------------------------+
 | 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)
+
+  :param string key:  i.e. ``"answer.total"``
+  :param number val:  i.e. ``5``
+
+Set nominal value of given metric.
+
+.. 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 overriden 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.
+
+
index 5aa8970c3c8b3d257a7cfb1dd6185d43f28be1b8..69ef1edf870a660205e3d00d059d4abc9c45a5e4 100644 (file)
@@ -1,14 +1,9 @@
 .. _mod-workarounds:
 
-Workarounds
------------
+Module `workarounds` resolver behavior on specific broken sub-domains.
+Currently it mainly disables case randomization.
 
-A simple module that alters resolver behavior on specific broken sub-domains.
-Currently it mainly disables case randomization on them.
-
-Running
-^^^^^^^
 .. code-block:: lua
 
-    modules = { 'workarounds < iterate' }
+    modules.load('workarounds < iterate')