Explore the statistics: a query log to drill down by client, name, view and more; storage on the dashboard
jarld keeps every answer for a while (stats.retention.queries, default 7 days) in the statistics database: time, client, view, name, type, result and what blocked it. Every client, name, view, record type, result and blocklist on the Statistics page leads to an explore page for it: answers over time, the top values of every other dimension (each a link that narrows further) and the latest answers. GET /stats/explore. The dashboard shows the size of Jarl's databases (and the query log's rows) and, per disk Jarl uses, how full it is and the databases' share. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fef916b7ab
commit
01ec37b9b2
21 files changed
+922
-27
No files matched your search
@@ -565,6 +565,7 @@ Needs `stats:read`. When statistics are disabled, every endpoint but
|
||||
| GET | `/stats/timeline` | `since`, `step` (auto, 1m, 5m, 15m, 1h, 6h, 1d), `key` (repeatable or comma separated; `rcode:*` = every counter of a group; default `queries`) | `{step, times: [unix...], series: [{key, values}]}` |
|
||||
| GET | `/stats/top` | `kind` (name, client, nxdomain, servfail, refused, blocked, blocked_client), `since`, `limit` (default 20) | `[{key, count}]`; client, refused and blocked_client entries add `name`, the host name of Jarl's record for the address (the summary's client list too) |
|
||||
| GET | `/stats/heatmap` | `since` (default 28d), `key` (default queries) | `{key, from, avg[7][24], samples[7][24]}`, Monday first, local time, `-1` = no data |
|
||||
| GET | `/stats/explore` | `?client=&name=&domain=&view=&type=&rcode=&blocked=yes\|no\|LIST&since=24h&views=` | The query log for a filter ([stats.md](stats.md#exploring)): `total`, `blocked`, `series` (per `step` seconds: `t`, `count`, `blocked`), `by` (top 15 of each dimension the filter leaves open: client, name, view, type, rcode, blocked; clients with `name`), `recent` (latest 100: ts, client, client_name, view, name, type, rcode, blocked), `oldest`, `retention`, `client_name`. 404 `query_log_off` without a query log |
|
||||
| GET | `/stats/server` | | `{server: {rss, mem_in_use, cpu_percent, threads, pid, cache_rrsets, cache_mem, sockets_udp, sockets_tcp, recursion_highwater, tcp_highwater, version, boot_time, config_time, host: {mem_total, mem_available, load, cpus, uptime}}, named: {recursive_clients, tcp_clients, zones, cpus, worker_threads}, disks: [{path, holds, total, free}]}`; gauges over time: `/stats/timeline?key=g:named:rss` (averages, -1 without a sample) |
|
||||
| GET | `/stats/breakdown` | `group` (qtype, rcode, view, zone, answer, transport, rtt, dnssec, cache, ratelimit, blocklist), `since` | `[{key, count}]` |
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ stats:
|
||||
minute: 7d # per-minute counters
|
||||
hour: 90d # hourly counters and top lists
|
||||
day: 730d # daily counters and top lists
|
||||
queries: 7d # every answer, for exploring (0: none)
|
||||
top_n: 100 # names and clients kept per hour and per day
|
||||
anonymize_clients: false # store 10.10.0.0/24 instead of 10.10.0.37 (IPv6: /48)
|
||||
exclude_clients: [] # e.g. [10.10.0.250] to ignore a monitoring probe
|
||||
@@ -192,6 +193,37 @@ jarl stats summary --since 30d -o json # export (also -o yaml)
|
||||
`operator` roles include it, `dns-editor` doesn't. Statistics show client
|
||||
addresses and what they look up, so grant it with care.
|
||||
|
||||
## Exploring
|
||||
|
||||
The counters and top lists say how much, not who asked for what: "100
|
||||
NXDOMAIN answers in the external view" can't tell you which clients asked.
|
||||
For that, jarld also keeps every answer for a while, the **query log**: time,
|
||||
client, view, name, record type, result, and the blocklist (or your rules)
|
||||
that blocked it. It is in the statistics database, from the response log
|
||||
named writes anyway, and answers older than `retention.queries` (default
|
||||
7 days) are deleted every hour; `0` keeps none.
|
||||
|
||||
With it, every client, name, view, record type, result and blocklist on the
|
||||
Statistics page is a link to the **explore** page (`#/stats/explore`),
|
||||
which shows, for what you clicked:
|
||||
|
||||
* the answers over time (and how many were blocked);
|
||||
* the top clients, names, views, record types, results and blocklists
|
||||
among them, each a link that narrows the filter further;
|
||||
* the latest 100 answers, every cell a link.
|
||||
|
||||
So "external, NXDOMAIN" leads to the clients asking, a client to everything
|
||||
it asks, one of its names to who else asks for it. Filters combine (this
|
||||
client, in this view, blocked only) and each has a ✕ to take it out. A name
|
||||
can be widened to the names below it (`domain=`). The Statistics page's
|
||||
view switches apply here too.
|
||||
|
||||
`anonymize_clients` and `exclude_clients` apply to the query log as to
|
||||
everything else. Its size: each answer takes about 150 to 200 bytes with
|
||||
its indexes, so 50,000 answers a day for 7 days is about 60 MB, 200,000 a
|
||||
day about 250 MB. The dashboard's Storage panel shows the databases' size
|
||||
and how many answers the query log holds.
|
||||
|
||||
## Views
|
||||
|
||||
With views, the Statistics page has a toggle per view (and **All** and
|
||||
|
||||
Reference in new issue
Block a user