Skip to content

feat(monitoring): dashboard and alert rules for iroh-dns-server - #201

Merged
thiras merged 3 commits into
mainfrom
feat/monitoring-iroh-dns-server
Nov 1, 2026
Merged

thiras merged 3 commits into
mainfrom
feat/monitoring-iroh-dns-server

Conversation

@thiras

@thiras thiras commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Closes #118.

Adds monitoring/iroh-dns-server/, mirroring monitoring/iroh-relay/. Alloy already scrapes the server as job="iroh-dns-server" on the Ansible path and Compose's dns profile, and labels its journal unit="iroh-dns-server.service".

What's in it

  • exported-metrics.txt: the /metrics of the pinned iroh-dns-server 1.3.0, captured from a fresh process. It was the x86_64 release asset, checked against the role's sha256. The header has the re-capture command. make lint-helm now checks dns_server_* names against it, as it does relayserver_*. This also pins the role's gate metric, dns_server_dns_requests_total.
  • Dashboard (uid: decdn-iroh-dns-server):
    • stats: up (an instant query, as in feat(monitoring): scrape the public gateway, with its dashboard and alert rules #188), publishes and DNS requests per day, zones cached, mean HTTP duration;
    • pkarr publishes, update vs no-op;
    • the record store: inserted, updated, expired, removed;
    • cached zones;
    • DNS requests by transport (TCP is total − udp − https, because TCP increments only the total);
    • lookups: success, not found, error;
    • HTTP requests, 2xx vs non-2xx, and the mean duration;
    • the log.
  • Rule group iroh-dns-server, with promtool unit tests:
  • Wiring and docs:
    • render-test.sh: promtool check and tests, the uid check, the name check, and the chart-leak substring and its negative.
    • Docs: monitoring/README.md gets a new section and the *Down list. In the role README, "no dashboard yet" is gone and the bump checklist gets a re-capture step. "No dashboard or alert rules yet" is gone from ansible/README.md and compose/README.md.
    • docs/lifecycle.md: silence the alerts before a migration or decommission. Repointing the nodes fires NoPublishes.
    • AGENTS.md and the grafana-dashboards skill.

Why the lookup-error rule is a rise, not a share

I ran the real 1.3.0 binary to see what moves dns_server_dns_lookup_error_total. It counts every answer other than NOERROR or NXDOMAIN:

  • A non-query opcode (a scanner's UPDATE or STATUS probe) gets NOTIMP and counts as an error.
  • A query for a name outside the origins is NXDOMAIN, because the server is also authoritative for ., so it counts as not found.
  • A packet that does not parse is not counted.

So a public udp/53 has a steady floor of errors, and a quiet server could sit above any fixed share for good. Comparing against the server's own day absorbs that floor. The 0.1/s floor keeps a server with no baseline from firing on a handful of probes. The rule comment documents one limit: a server less than a day old has an understated baseline, and a unit test pins that.

Certificate expiry is not exported. The docs point to an external https://<hostname>/healthz probe and an external dig, as the relay's do.

Verification

  • make lint-helm: promtool check (3 rules), the unit tests, the uid check, and "iroh-dns-server dashboard and rules name only exported series" all pass. The new chart-leak negative also passes.
  • Negatives, not committed:
    • dns_server_bogus_total in the dashboard → the name check fails.
    • A rule threshold of 30× → the unit tests fail.
    • Publishes that resume → the unit tests fail.
  • make lint, make test-scripts: pass.

🤖 Generated with Claude Code

- monitoring/iroh-dns-server/exported-metrics.txt: the /metrics of the pinned
  iroh-dns-server 1.3.0 (x86_64 release asset, sha256-checked), captured from a
  fresh process. make lint-helm checks every dns_server_* name against it, as it
  does relayserver_* (this also pins the role's readiness-gate metric).
- dashboard-iroh-dns-server.json (uid decdn-iroh-dns-server): up (instant),
  publishes and DNS requests per day, zones cached, mean HTTP duration; pkarr
  publishes (update vs no-op), the record store, cached zones; DNS requests by
  transport (tcp = total - udp - https), lookups by answer; HTTP requests and
  mean duration; the server's log.
- Rule group iroh-dns-server with promtool tests: IrohDnsServerDown (the *Down
  shape with the absence arm), IrohDnsServerLookupErrors (a rise against the
  server's own last day with a 0.1/s floor: a scanner's NOTIMP counts as an
  error, an out-of-zone query is NXDOMAIN, both checked on the real binary),
  IrohDnsServerNoPublishes (no pkarr put in 30m after some in the last day).
- render-test.sh, docs (monitoring/README, the role README and its bump
  checklist, ansible/ and compose/ READMEs, lifecycle silence notes, AGENTS.md,
  the grafana-dashboards skill).

Closes #118

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 1, 2026 12:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Dashboard and alert descriptions misrepresent packet acceptance, lookup-cache occupancy, and store retention, potentially misleading operators about address churn, published-node counts, and cached-answer expiry.

3 open issues
What changed in this PR

Adds monitoring for self-hosted iroh DNS servers, using the existing Alloy metrics and logs on Ansible and Compose deployments.

Changes:

  • Adds a dashboard covering publishes, DNS lookups, HTTP traffic, cache activity, and logs.
  • Adds three alert rules with unit tests and an exported-metrics snapshot.
  • Extends validation and documents monitoring setup, maintenance, and alert silencing.
File Description
monitoring/​README.md Documents DNS monitoring assets and external probes.
monitoring/​iroh-dns-server/​prometheus-alerts.yml Adds downtime, lookup-error, and stopped-publish alerts.
monitoring/​iroh-dns-server/​prometheus-alerts_test.yml Tests alert timing and representative failure scenarios.
monitoring/​iroh-dns-server/​exported-metrics.txt Records the pinned server’s exported metrics.
monitoring/​iroh-dns-server/​dashboard-iroh-dns-server.json Adds the DNS server dashboard.
docs/​lifecycle.md Documents silencing alerts during migration and decommission.
compose/​README.md Links monitoring assets and describes Alloy integration.
charts/​decdn-node/​tests/​render-test.sh Extends rule, metric-name, dashboard, and package-isolation checks.
ansible/​roles/​iroh_dns_server/​vars/​main.yml Adds a comment linking the readiness metric to the snapshot.
ansible/​roles/​iroh_dns_server/​README.md Links monitoring assets and adds metric recapture guidance.
ansible/​README.md Links the new dashboard and alerts.
AGENTS.md Updates the monitoring map and release-maintenance guidance.
.github/​workflows/​ci.yml Clarifies monitoring coverage in a comment.
.claude/​skills/​grafana-dashboards/​SKILL.md Documents DNS dashboard metrics and maintenance.

Review effort: Balanced

thiras and others added 2 commits November 1, 2026 15:55
… boundaries

Review of #201 against upstream v1.3.0 (and the real binary):
- every node republish is a pkarr *update* (re-signed with a fresh
  timestamp); no-op is only a put older than the stored packet. The
  publishes and record-store panels said the opposite.
- a failing record store answers REFUSED (node_zone_handler's err_refused),
  not SERVFAIL; the rule comment, annotation (now naming the store's real
  WARN/ERROR lines), the lookups panel and the README say so. An AXFR is
  NOERROR with no answer (checked on the binary), so it counts as not found.
- dns_server_cache_zones is the lookup cache: a key enters on a lookup and
  leaves on its next publish. It is not a node count.
- the mean HTTP duration includes /healthz and truncates to whole ms.
- a series under ~8 hours old fires on any steady error rate over the floor;
  say so in the rule and its annotation.

Tests: pin the 3x multiplier (2.5x silent, 4x fires), the 0.1/s floor
(0.083 vs 0.117), the 15m for to the minute, the 1d memory and resolution of
LookupErrors; each summed publish counter on its own in both arms, resolution
when puts resume, the reset inside a window, and the 94m fire time.

Also: the root README's monitoring row, NoPublishes silencing on Compose,
both dig checks named alike, AGENTS.md no longer implies test-scripts checks
exported-metrics.txt, and render-test cleans up its new negative.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the cache outlives them

Store eviction runs on the packet's signed timestamp (each republish re-signs,
so about its last accepted put) and does not clear the lookup cache, so a
cached key can keep resolving past the 7 days (Copilot review on #201).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@thiras
thiras merged commit 616d415 into main Nov 1, 2026
31 checks passed
@thiras
thiras deleted the feat/monitoring-iroh-dns-server branch November 1, 2026 13:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

monitoring: dashboard and alert rules for iroh-dns-server

2 participants